summaryrefslogtreecommitdiffstats
path: root/chromium/chrome/browser/resources
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@theqtcompany.com>2016-05-09 14:22:11 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2016-05-09 15:11:45 +0000
commit2ddb2d3e14eef3de7dbd0cef553d669b9ac2361c (patch)
treee75f511546c5fd1a173e87c1f9fb11d7ac8d1af3 /chromium/chrome/browser/resources
parenta4f3d46271c57e8155ba912df46a05559d14726e (diff)
BASELINE: Update Chromium to 51.0.2704.41
Also adds in all smaller components by reversing logic for exclusion. Change-Id: Ibf90b506e7da088ea2f65dcf23f2b0992c504422 Reviewed-by: Joerg Bornemann <joerg.bornemann@theqtcompany.com>
Diffstat (limited to 'chromium/chrome/browser/resources')
-rw-r--r--chromium/chrome/browser/resources/BUILD.gn20
-rw-r--r--chromium/chrome/browser/resources/about_memory.css312
-rw-r--r--chromium/chrome/browser/resources/about_memory.html350
-rw-r--r--chromium/chrome/browser/resources/about_memory.js84
-rw-r--r--chromium/chrome/browser/resources/about_memory_linux.css25
-rw-r--r--chromium/chrome/browser/resources/about_memory_linux.html210
-rw-r--r--chromium/chrome/browser/resources/about_memory_mac.html253
-rw-r--r--chromium/chrome/browser/resources/bookmark_manager/js/compiled_resources.gyp1
-rw-r--r--chromium/chrome/browser/resources/bookmark_manager/js/main.js2
-rw-r--r--chromium/chrome/browser/resources/chromeos/arc_support/manifest.json19
-rw-r--r--chromium/chrome/browser/resources/chromeos/braille_ime/compiled_resources.gyp21
-rw-r--r--chromium/chrome/browser/resources/chromeos/braille_ime/compiled_resources2.gyp26
-rw-r--r--chromium/chrome/browser/resources/chromeos/chromevox/chromevox.gyp1
-rw-r--r--chromium/chrome/browser/resources/chromeos/chromevox/chromevox/background/keymaps/next_keymap.json209
-rw-r--r--chromium/chrome/browser/resources/chromeos/chromevox/chromevox_tests.gypi8
-rw-r--r--chromium/chrome/browser/resources/chromeos/chromevox/strings/chromevox_strings.grd12
-rw-r--r--chromium/chrome/browser/resources/chromeos/network_ui/compiled_resources2.gyp18
-rw-r--r--chromium/chrome/browser/resources/component_extension_resources.grd8
-rw-r--r--chromium/chrome/browser/resources/cryptotoken/gnubbies.js65
-rw-r--r--chromium/chrome/browser/resources/cryptotoken/gnubby-u2f.js26
-rw-r--r--chromium/chrome/browser/resources/cryptotoken/gnubby.js19
-rw-r--r--chromium/chrome/browser/resources/cryptotoken/gnubbycodetypes.js32
-rw-r--r--chromium/chrome/browser/resources/cryptotoken/gnubbyfactory.js6
-rw-r--r--chromium/chrome/browser/resources/cryptotoken/gnubbymsgtypes.js46
-rw-r--r--chromium/chrome/browser/resources/cryptotoken/hidgnubbydevice.js28
-rw-r--r--chromium/chrome/browser/resources/cryptotoken/manifest.json2
-rw-r--r--chromium/chrome/browser/resources/cryptotoken/singlesigner.js19
-rw-r--r--chromium/chrome/browser/resources/cryptotoken/usbgnubbydevice.js10
-rw-r--r--chromium/chrome/browser/resources/cryptotoken/usbgnubbyfactory.js8
-rw-r--r--chromium/chrome/browser/resources/cryptotoken/webrequest.js10
-rw-r--r--chromium/chrome/browser/resources/device_log_ui/device_log_ui.css2
-rw-r--r--chromium/chrome/browser/resources/device_log_ui/device_log_ui.html4
-rw-r--r--chromium/chrome/browser/resources/device_log_ui/device_log_ui.js7
-rw-r--r--chromium/chrome/browser/resources/downloads/OWNERS2
-rw-r--r--chromium/chrome/browser/resources/downloads/compiled_resources.gyp33
-rw-r--r--chromium/chrome/browser/resources/downloads/constants.html2
-rw-r--r--chromium/chrome/browser/resources/downloads/constants.js38
-rw-r--r--chromium/chrome/browser/resources/downloads/downloads.css163
-rw-r--r--chromium/chrome/browser/resources/downloads/downloads.html104
-rw-r--r--chromium/chrome/browser/resources/downloads/externs.js36
-rw-r--r--chromium/chrome/browser/resources/downloads/focus_row.js32
-rw-r--r--chromium/chrome/browser/resources/downloads/item_view.js395
-rw-r--r--chromium/chrome/browser/resources/downloads/manager.js256
-rw-r--r--chromium/chrome/browser/resources/downloads/throttled_icon_loader.js61
-rw-r--r--chromium/chrome/browser/resources/engagement/engagement_table.css36
-rw-r--r--chromium/chrome/browser/resources/engagement/engagement_table.html30
-rw-r--r--chromium/chrome/browser/resources/engagement/engagement_table.js107
-rw-r--r--chromium/chrome/browser/resources/engagement/site_engagement.html79
-rw-r--r--chromium/chrome/browser/resources/engagement/site_engagement.js141
-rw-r--r--chromium/chrome/browser/resources/extensions/compiled_resources.gyp1
-rw-r--r--chromium/chrome/browser/resources/extensions/extension_commands_overlay.html9
-rw-r--r--chromium/chrome/browser/resources/extensions/extension_error.html10
-rw-r--r--chromium/chrome/browser/resources/extensions/extension_error.js2
-rw-r--r--chromium/chrome/browser/resources/extensions/extension_error_overlay.html12
-rw-r--r--chromium/chrome/browser/resources/extensions/extension_error_overlay.js2
-rw-r--r--chromium/chrome/browser/resources/extensions/extension_list.js2
-rw-r--r--chromium/chrome/browser/resources/extensions/extension_load_error.html16
-rw-r--r--chromium/chrome/browser/resources/extensions/extensions.html128
-rw-r--r--chromium/chrome/browser/resources/extensions/focus_row.js2
-rw-r--r--chromium/chrome/browser/resources/extensions/pack_extension_overlay.html36
-rw-r--r--chromium/chrome/browser/resources/feedback/css/feedback.css4
-rw-r--r--chromium/chrome/browser/resources/feedback/js/event_handler.js156
-rw-r--r--chromium/chrome/browser/resources/feedback/js/feedback.js118
-rw-r--r--chromium/chrome/browser/resources/gaia_auth_host/authenticator.js39
-rw-r--r--chromium/chrome/browser/resources/help/compiled_resources.gyp1
-rw-r--r--chromium/chrome/browser/resources/help/help_content.css5
-rw-r--r--chromium/chrome/browser/resources/help/help_content.html1
-rw-r--r--chromium/chrome/browser/resources/help/help_page.js65
-rw-r--r--chromium/chrome/browser/resources/history/compiled_resources.gyp35
-rw-r--r--chromium/chrome/browser/resources/history/compiled_resources2.gyp (renamed from chromium/chrome/browser/resources/downloads/compiled_resources2.gyp)49
-rw-r--r--chromium/chrome/browser/resources/history/externs.js67
-rw-r--r--chromium/chrome/browser/resources/history/history.css59
-rw-r--r--chromium/chrome/browser/resources/history/history.js179
-rw-r--r--chromium/chrome/browser/resources/history/history_mobile.css37
-rw-r--r--chromium/chrome/browser/resources/inline_login/inline_login.css11
-rw-r--r--chromium/chrome/browser/resources/inline_login/inline_login.js30
-rw-r--r--chromium/chrome/browser/resources/inline_login/new_inline_login.html4
-rw-r--r--chromium/chrome/browser/resources/input_ime/OWNERS2
-rw-r--r--chromium/chrome/browser/resources/input_ime/ime_window_close.pngbin0 -> 270 bytes
-rw-r--r--chromium/chrome/browser/resources/input_ime/ime_window_close_click.pngbin0 -> 299 bytes
-rw-r--r--chromium/chrome/browser/resources/input_ime/ime_window_close_hover.pngbin0 -> 299 bytes
-rw-r--r--chromium/chrome/browser/resources/local_ntp/most_visited_single.js41
-rw-r--r--chromium/chrome/browser/resources/local_ntp/most_visited_util.js5
-rw-r--r--chromium/chrome/browser/resources/md_downloads/compiled_resources.gyp40
-rw-r--r--chromium/chrome/browser/resources/md_downloads/compiled_resources2.gyp7
-rw-r--r--chromium/chrome/browser/resources/md_downloads/crisper.js11023
-rw-r--r--chromium/chrome/browser/resources/md_downloads/downloads.html9
-rw-r--r--chromium/chrome/browser/resources/md_downloads/externs.js2
-rw-r--r--chromium/chrome/browser/resources/md_downloads/item.css9
-rw-r--r--chromium/chrome/browser/resources/md_downloads/item.html2
-rw-r--r--chromium/chrome/browser/resources/md_downloads/manager.html2
-rw-r--r--chromium/chrome/browser/resources/md_downloads/manager.js8
-rw-r--r--chromium/chrome/browser/resources/md_downloads/toolbar.html8
-rw-r--r--chromium/chrome/browser/resources/md_downloads/toolbar.js8
-rwxr-xr-xchromium/chrome/browser/resources/md_downloads/vulcanize.py19
-rw-r--r--chromium/chrome/browser/resources/md_downloads/vulcanize_readme.md25
-rw-r--r--chromium/chrome/browser/resources/md_downloads/vulcanized.html2212
-rw-r--r--chromium/chrome/browser/resources/md_extensions/compiled_resources.gyp1
-rw-r--r--chromium/chrome/browser/resources/md_extensions/extensions.html2
-rw-r--r--chromium/chrome/browser/resources/md_extensions/icons.html2
-rw-r--r--chromium/chrome/browser/resources/md_extensions/item.html2
-rw-r--r--chromium/chrome/browser/resources/md_extensions/item.js1
-rw-r--r--chromium/chrome/browser/resources/md_extensions/item_list.html2
-rw-r--r--chromium/chrome/browser/resources/md_extensions/manager.html2
-rw-r--r--chromium/chrome/browser/resources/md_extensions/sidebar.html2
-rw-r--r--chromium/chrome/browser/resources/md_extensions/toolbar.html4
-rw-r--r--chromium/chrome/browser/resources/md_history/compiled_resources2.gyp75
-rw-r--r--chromium/chrome/browser/resources/md_history/constants.html1
-rw-r--r--chromium/chrome/browser/resources/md_history/constants.js13
-rw-r--r--chromium/chrome/browser/resources/md_history/elements.html4
-rw-r--r--chromium/chrome/browser/resources/md_history/history.html95
-rw-r--r--chromium/chrome/browser/resources/md_history/history.js156
-rw-r--r--chromium/chrome/browser/resources/md_history/history_item.html145
-rw-r--r--chromium/chrome/browser/resources/md_history/history_item.js146
-rw-r--r--chromium/chrome/browser/resources/md_history/history_list.html61
-rw-r--r--chromium/chrome/browser/resources/md_history/history_list.js295
-rw-r--r--chromium/chrome/browser/resources/md_history/history_toolbar.html118
-rw-r--r--chromium/chrome/browser/resources/md_history/history_toolbar.js114
-rw-r--r--chromium/chrome/browser/resources/md_history/shared_style.html57
-rw-r--r--chromium/chrome/browser/resources/md_history/side_bar.html46
-rw-r--r--chromium/chrome/browser/resources/md_history/side_bar.js17
-rw-r--r--chromium/chrome/browser/resources/md_history/synced_device_card.html109
-rw-r--r--chromium/chrome/browser/resources/md_history/synced_device_card.js72
-rw-r--r--chromium/chrome/browser/resources/md_history/synced_device_manager.html26
-rw-r--r--chromium/chrome/browser/resources/md_history/synced_device_manager.js76
-rw-r--r--chromium/chrome/browser/resources/md_user_manager/compiled_resources2.gyp50
-rw-r--r--chromium/chrome/browser/resources/md_user_manager/control_bar.css37
-rw-r--r--chromium/chrome/browser/resources/md_user_manager/control_bar.html22
-rw-r--r--chromium/chrome/browser/resources/md_user_manager/control_bar.js58
-rw-r--r--chromium/chrome/browser/resources/md_user_manager/create_profile.css159
-rw-r--r--chromium/chrome/browser/resources/md_user_manager/create_profile.html83
-rw-r--r--chromium/chrome/browser/resources/md_user_manager/create_profile.js350
-rw-r--r--chromium/chrome/browser/resources/md_user_manager/profile_browser_proxy.html (renamed from chromium/chrome/browser/resources/downloads/throttled_icon_loader.html)2
-rw-r--r--chromium/chrome/browser/resources/md_user_manager/profile_browser_proxy.js156
-rw-r--r--chromium/chrome/browser/resources/md_user_manager/shared_styles.html10
-rw-r--r--chromium/chrome/browser/resources/md_user_manager/strings.html2
-rw-r--r--chromium/chrome/browser/resources/md_user_manager/supervised_user_learn_more.css56
-rw-r--r--chromium/chrome/browser/resources/md_user_manager/supervised_user_learn_more.html28
-rw-r--r--chromium/chrome/browser/resources/md_user_manager/supervised_user_learn_more.js22
-rw-r--r--chromium/chrome/browser/resources/md_user_manager/user_manager.html47
-rw-r--r--chromium/chrome/browser/resources/md_user_manager/user_manager.js123
-rw-r--r--chromium/chrome/browser/resources/md_user_manager/user_manager_pages.css12
-rw-r--r--chromium/chrome/browser/resources/md_user_manager/user_manager_pages.html35
-rw-r--r--chromium/chrome/browser/resources/md_user_manager/user_manager_pages.js45
-rw-r--r--chromium/chrome/browser/resources/md_user_manager/user_manager_styles.html217
-rw-r--r--chromium/chrome/browser/resources/md_user_manager/user_manager_tutorial.css160
-rw-r--r--chromium/chrome/browser/resources/md_user_manager/user_manager_tutorial.html96
-rw-r--r--chromium/chrome/browser/resources/md_user_manager/user_manager_tutorial.js118
-rw-r--r--chromium/chrome/browser/resources/media_router/compiled_resources.gyp2
-rw-r--r--chromium/chrome/browser/resources/media_router/elements/issue_banner/issue_banner.css4
-rw-r--r--chromium/chrome/browser/resources/media_router/elements/issue_banner/issue_banner.html6
-rw-r--r--chromium/chrome/browser/resources/media_router/elements/media_router_container/media_router_container.css134
-rw-r--r--chromium/chrome/browser/resources/media_router/elements/media_router_container/media_router_container.html253
-rw-r--r--chromium/chrome/browser/resources/media_router/elements/media_router_container/media_router_container.js692
-rw-r--r--chromium/chrome/browser/resources/media_router/elements/media_router_header/media_router_header.css50
-rw-r--r--chromium/chrome/browser/resources/media_router/elements/media_router_header/media_router_header.html30
-rw-r--r--chromium/chrome/browser/resources/media_router/elements/media_router_header/media_router_header.js161
-rw-r--r--chromium/chrome/browser/resources/media_router/elements/media_router_search_highlighter/media_router_search_highlighter.css (renamed from chromium/chrome/browser/resources/ntp4/guest_tab.css)6
-rw-r--r--chromium/chrome/browser/resources/media_router/elements/media_router_search_highlighter/media_router_search_highlighter.html8
-rw-r--r--chromium/chrome/browser/resources/media_router/elements/media_router_search_highlighter/media_router_search_highlighter.js81
-rw-r--r--chromium/chrome/browser/resources/media_router/elements/route_details/route_details.css10
-rw-r--r--chromium/chrome/browser/resources/media_router/elements/route_details/route_details.html10
-rw-r--r--chromium/chrome/browser/resources/media_router/elements/route_details/route_details.js18
-rw-r--r--chromium/chrome/browser/resources/media_router/externs.js6
-rw-r--r--chromium/chrome/browser/resources/media_router/icons/media_router_icons.html10
-rw-r--r--chromium/chrome/browser/resources/media_router/media_router.css1
-rw-r--r--chromium/chrome/browser/resources/media_router/media_router.html14
-rw-r--r--chromium/chrome/browser/resources/media_router/media_router.js93
-rw-r--r--chromium/chrome/browser/resources/media_router/media_router_common.css11
-rw-r--r--chromium/chrome/browser/resources/media_router/media_router_data.js23
-rw-r--r--chromium/chrome/browser/resources/media_router/media_router_ui_interface.js150
-rw-r--r--chromium/chrome/browser/resources/memory_internals/OWNERS1
-rw-r--r--chromium/chrome/browser/resources/memory_internals/extension_view.css22
-rw-r--r--chromium/chrome/browser/resources/memory_internals/extension_view.html14
-rw-r--r--chromium/chrome/browser/resources/memory_internals/list.css27
-rw-r--r--chromium/chrome/browser/resources/memory_internals/memory_internals.css39
-rw-r--r--chromium/chrome/browser/resources/memory_internals/memory_internals.html23
-rw-r--r--chromium/chrome/browser/resources/memory_internals/memory_internals.js172
-rw-r--r--chromium/chrome/browser/resources/memory_internals/snapshot_view.css41
-rw-r--r--chromium/chrome/browser/resources/memory_internals/snapshot_view.html21
-rw-r--r--chromium/chrome/browser/resources/memory_internals_resources.grd15
-rw-r--r--chromium/chrome/browser/resources/net_internals/alt_svc_view.html22
-rw-r--r--chromium/chrome/browser/resources/net_internals/alt_svc_view.js61
-rw-r--r--chromium/chrome/browser/resources/net_internals/browser_bridge.js14
-rw-r--r--chromium/chrome/browser/resources/net_internals/index.html3
-rw-r--r--chromium/chrome/browser/resources/net_internals/index.js3
-rw-r--r--chromium/chrome/browser/resources/net_internals/main.css4
-rw-r--r--chromium/chrome/browser/resources/net_internals/main.js2
-rw-r--r--chromium/chrome/browser/resources/net_internals/quic_view.html9
-rw-r--r--chromium/chrome/browser/resources/net_internals/spdy_view.html28
-rw-r--r--chromium/chrome/browser/resources/net_internals/spdy_view.js20
-rw-r--r--chromium/chrome/browser/resources/net_internals/waterfall_row.js406
-rw-r--r--chromium/chrome/browser/resources/net_internals/waterfall_view.css178
-rw-r--r--chromium/chrome/browser/resources/net_internals/waterfall_view.html31
-rw-r--r--chromium/chrome/browser/resources/net_internals/waterfall_view.js283
-rw-r--r--chromium/chrome/browser/resources/ntp4/compiled_resources.gyp2
-rw-r--r--chromium/chrome/browser/resources/ntp4/guest_tab.html5
-rw-r--r--chromium/chrome/browser/resources/ntp4/incognito_and_guest_tab.css28
-rw-r--r--chromium/chrome/browser/resources/ntp4/incognito_tab.css13
-rw-r--r--chromium/chrome/browser/resources/ntp4/incognito_tab.html2
-rw-r--r--chromium/chrome/browser/resources/ntp4/new_incognito_tab_theme.css12
-rw-r--r--chromium/chrome/browser/resources/ntp4/new_tab.css60
-rw-r--r--chromium/chrome/browser/resources/ntp4/new_tab.html11
-rw-r--r--chromium/chrome/browser/resources/ntp4/new_tab.js217
-rw-r--r--chromium/chrome/browser/resources/ntp4/new_tab_theme.css58
-rw-r--r--chromium/chrome/browser/resources/ntp4/page_list_view.js36
-rw-r--r--chromium/chrome/browser/resources/ntp4/tile_page.css4
-rw-r--r--chromium/chrome/browser/resources/ntp4/tile_page.js49
-rw-r--r--chromium/chrome/browser/resources/omnibox/omnibox.js2
-rw-r--r--chromium/chrome/browser/resources/options/autofill_edit_address_overlay.js4
-rw-r--r--chromium/chrome/browser/resources/options/autofill_options.css14
-rw-r--r--chromium/chrome/browser/resources/options/autofill_options.html21
-rw-r--r--chromium/chrome/browser/resources/options/browser_options.html101
-rw-r--r--chromium/chrome/browser/resources/options/browser_options.js101
-rw-r--r--chromium/chrome/browser/resources/options/clear_browser_data_history_notice_overlay.html13
-rw-r--r--chromium/chrome/browser/resources/options/clear_browser_data_history_notice_overlay.js45
-rw-r--r--chromium/chrome/browser/resources/options/clear_browser_data_overlay.css27
-rw-r--r--chromium/chrome/browser/resources/options/clear_browser_data_overlay.html4
-rw-r--r--chromium/chrome/browser/resources/options/clear_browser_data_overlay.js30
-rw-r--r--chromium/chrome/browser/resources/options/compiled_resources.gyp1
-rw-r--r--chromium/chrome/browser/resources/options/content_settings.html124
-rw-r--r--chromium/chrome/browser/resources/options/content_settings.js30
-rw-r--r--chromium/chrome/browser/resources/options/content_settings_exceptions_area.html3
-rw-r--r--chromium/chrome/browser/resources/options/googleg.svg7
-rw-r--r--chromium/chrome/browser/resources/options/info.svg4
-rw-r--r--chromium/chrome/browser/resources/options/language_list.js5
-rw-r--r--chromium/chrome/browser/resources/options/language_options.html3
-rw-r--r--chromium/chrome/browser/resources/options/language_options.js94
-rw-r--r--chromium/chrome/browser/resources/options/manage_profile_overlay.js2
-rw-r--r--chromium/chrome/browser/resources/options/options.html1
-rw-r--r--chromium/chrome/browser/resources/options/options.js4
-rw-r--r--chromium/chrome/browser/resources/options/options_bundle.js4
-rw-r--r--chromium/chrome/browser/resources/options/password_manager.html2
-rw-r--r--chromium/chrome/browser/resources/options/password_manager.js46
-rw-r--r--chromium/chrome/browser/resources/options/password_manager_list.css21
-rw-r--r--chromium/chrome/browser/resources/options/password_manager_list.js165
-rw-r--r--chromium/chrome/browser/resources/options/search_page.js79
-rw-r--r--chromium/chrome/browser/resources/options/sync_setup_overlay.js5
-rw-r--r--chromium/chrome/browser/resources/pdf/elements/viewer-bookmark/viewer-bookmark.js2
-rw-r--r--chromium/chrome/browser/resources/pdf/elements/viewer-pdf-toolbar/viewer-pdf-toolbar.html2
-rw-r--r--chromium/chrome/browser/resources/pdf/elements/viewer-pdf-toolbar/viewer-pdf-toolbar.js4
-rw-r--r--chromium/chrome/browser/resources/pdf/pdf.js4
-rw-r--r--chromium/chrome/browser/resources/plugin_metadata/plugins_chromeos.json8
-rw-r--r--chromium/chrome/browser/resources/plugin_metadata/plugins_linux.json8
-rw-r--r--chromium/chrome/browser/resources/plugin_metadata/plugins_mac.json10
-rw-r--r--chromium/chrome/browser/resources/plugin_metadata/plugins_win.json10
-rw-r--r--chromium/chrome/browser/resources/plugins.html32
-rw-r--r--chromium/chrome/browser/resources/plugins.js232
-rw-r--r--chromium/chrome/browser/resources/popular_sites_internals.css3
-rw-r--r--chromium/chrome/browser/resources/popular_sites_internals.html22
-rw-r--r--chromium/chrome/browser/resources/popular_sites_internals.js17
-rw-r--r--chromium/chrome/browser/resources/print_preview/compiled_resources.gyp1
-rw-r--r--chromium/chrome/browser/resources/print_preview/data/destination_store.js8
-rw-r--r--chromium/chrome/browser/resources/print_preview/data/ticket_items/page_range.js25
-rw-r--r--chromium/chrome/browser/resources/print_preview/native_layer.js17
-rw-r--r--chromium/chrome/browser/resources/print_preview/previewarea/margin_control.js16
-rw-r--r--chromium/chrome/browser/resources/print_preview/print_preview.html1
-rw-r--r--chromium/chrome/browser/resources/print_preview/print_preview.js7
-rw-r--r--chromium/chrome/browser/resources/print_preview/print_preview_utils.js35
-rw-r--r--chromium/chrome/browser/resources/print_preview/print_preview_utils_unittest.gtestjs19
-rw-r--r--chromium/chrome/browser/resources/print_preview/search/provisional_destination_resolver.js39
-rw-r--r--chromium/chrome/browser/resources/print_preview/settings/page_settings.js64
-rw-r--r--chromium/chrome/browser/resources/settings/OWNERS2
-rw-r--r--chromium/chrome/browser/resources/settings/a11y_page/a11y_page.css20
-rw-r--r--chromium/chrome/browser/resources/settings/a11y_page/a11y_page.html46
-rw-r--r--chromium/chrome/browser/resources/settings/a11y_page/a11y_page.js16
-rw-r--r--chromium/chrome/browser/resources/settings/advanced_page/advanced_page.html53
-rw-r--r--chromium/chrome/browser/resources/settings/advanced_page/advanced_page.js18
-rw-r--r--chromium/chrome/browser/resources/settings/advanced_page/compiled_resources.gyp18
-rw-r--r--chromium/chrome/browser/resources/settings/advanced_page/compiled_resources2.gyp18
-rw-r--r--chromium/chrome/browser/resources/settings/appearance_page/appearance_fonts_page.html157
-rw-r--r--chromium/chrome/browser/resources/settings/appearance_page/appearance_fonts_page.js397
-rw-r--r--chromium/chrome/browser/resources/settings/appearance_page/appearance_page.html101
-rw-r--r--chromium/chrome/browser/resources/settings/appearance_page/appearance_page.js44
-rw-r--r--chromium/chrome/browser/resources/settings/appearance_page/compiled_resources.gyp53
-rw-r--r--chromium/chrome/browser/resources/settings/appearance_page/compiled_resources2.gyp41
-rw-r--r--chromium/chrome/browser/resources/settings/appearance_page/fonts_browser_proxy.html2
-rw-r--r--chromium/chrome/browser/resources/settings/appearance_page/fonts_browser_proxy.js43
-rw-r--r--chromium/chrome/browser/resources/settings/basic_page/basic_page.html53
-rw-r--r--chromium/chrome/browser/resources/settings/basic_page/basic_page.js20
-rw-r--r--chromium/chrome/browser/resources/settings/basic_page/compiled_resources.gyp17
-rw-r--r--chromium/chrome/browser/resources/settings/basic_page/compiled_resources2.gyp18
-rw-r--r--chromium/chrome/browser/resources/settings/bluetooth_page/bluetooth_add_device_dialog.html7
-rw-r--r--chromium/chrome/browser/resources/settings/bluetooth_page/bluetooth_add_device_dialog.js3
-rw-r--r--chromium/chrome/browser/resources/settings/bluetooth_page/bluetooth_device_list_item.css6
-rw-r--r--chromium/chrome/browser/resources/settings/bluetooth_page/bluetooth_device_list_item.html2
-rw-r--r--chromium/chrome/browser/resources/settings/bluetooth_page/bluetooth_dialog.css2
-rw-r--r--chromium/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.html10
-rw-r--r--chromium/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.js5
-rw-r--r--chromium/chrome/browser/resources/settings/bluetooth_page/bluetooth_pair_device_dialog.html9
-rw-r--r--chromium/chrome/browser/resources/settings/bluetooth_page/bluetooth_pair_device_dialog.js3
-rw-r--r--chromium/chrome/browser/resources/settings/bluetooth_page/compiled_resources.gyp72
-rw-r--r--chromium/chrome/browser/resources/settings/bluetooth_page/compiled_resources2.gyp43
-rw-r--r--chromium/chrome/browser/resources/settings/certificate_manager_page/ca_trust_edit_dialog.html46
-rw-r--r--chromium/chrome/browser/resources/settings/certificate_manager_page/ca_trust_edit_dialog.js79
-rw-r--r--chromium/chrome/browser/resources/settings/certificate_manager_page/certificate_delete_confirmation_dialog.html27
-rw-r--r--chromium/chrome/browser/resources/settings/certificate_manager_page/certificate_delete_confirmation_dialog.js95
-rw-r--r--chromium/chrome/browser/resources/settings/certificate_manager_page/certificate_entry.html33
-rw-r--r--chromium/chrome/browser/resources/settings/certificate_manager_page/certificate_entry.js27
-rw-r--r--chromium/chrome/browser/resources/settings/certificate_manager_page/certificate_list.html30
-rw-r--r--chromium/chrome/browser/resources/settings/certificate_manager_page/certificate_list.js110
-rw-r--r--chromium/chrome/browser/resources/settings/certificate_manager_page/certificate_manager_page.css7
-rw-r--r--chromium/chrome/browser/resources/settings/certificate_manager_page/certificate_manager_page.html133
-rw-r--r--chromium/chrome/browser/resources/settings/certificate_manager_page/certificate_manager_page.js172
-rw-r--r--chromium/chrome/browser/resources/settings/certificate_manager_page/certificate_password_decryption_dialog.html31
-rw-r--r--chromium/chrome/browser/resources/settings/certificate_manager_page/certificate_password_decryption_dialog.js51
-rw-r--r--chromium/chrome/browser/resources/settings/certificate_manager_page/certificate_password_encryption_dialog.html41
-rw-r--r--chromium/chrome/browser/resources/settings/certificate_manager_page/certificate_password_encryption_dialog.js67
-rw-r--r--chromium/chrome/browser/resources/settings/certificate_manager_page/certificate_subentry.html73
-rw-r--r--chromium/chrome/browser/resources/settings/certificate_manager_page/certificate_subentry.js179
-rw-r--r--chromium/chrome/browser/resources/settings/certificate_manager_page/certificates_browser_proxy.html1
-rw-r--r--chromium/chrome/browser/resources/settings/certificate_manager_page/certificates_browser_proxy.js275
-rw-r--r--chromium/chrome/browser/resources/settings/certificate_manager_page/certificates_error_dialog.html28
-rw-r--r--chromium/chrome/browser/resources/settings/certificate_manager_page/certificates_error_dialog.js36
-rw-r--r--chromium/chrome/browser/resources/settings/clear_browsing_data_dialog/clear_browsing_data_dialog.html69
-rw-r--r--chromium/chrome/browser/resources/settings/clear_browsing_data_dialog/clear_browsing_data_dialog.js (renamed from chromium/chrome/browser/resources/settings/clear_browsing_data_page/clear_browsing_data_page.js)23
-rw-r--r--chromium/chrome/browser/resources/settings/clear_browsing_data_page/clear_browsing_data_page.css4
-rw-r--r--chromium/chrome/browser/resources/settings/clear_browsing_data_page/clear_browsing_data_page.html64
-rw-r--r--chromium/chrome/browser/resources/settings/compiled_resources.gyp26
-rw-r--r--chromium/chrome/browser/resources/settings/compiled_resources2.gyp39
-rw-r--r--chromium/chrome/browser/resources/settings/controls/compiled_resources.gyp67
-rw-r--r--chromium/chrome/browser/resources/settings/controls/compiled_resources2.gyp62
-rw-r--r--chromium/chrome/browser/resources/settings/controls/pref_control_behavior.html3
-rw-r--r--chromium/chrome/browser/resources/settings/controls/pref_control_behavior.js43
-rw-r--r--chromium/chrome/browser/resources/settings/controls/settings_checkbox.css21
-rw-r--r--chromium/chrome/browser/resources/settings/controls/settings_checkbox.html36
-rw-r--r--chromium/chrome/browser/resources/settings/controls/settings_checkbox.js13
-rw-r--r--chromium/chrome/browser/resources/settings/controls/settings_dropdown_menu.html27
-rw-r--r--chromium/chrome/browser/resources/settings/controls/settings_dropdown_menu.js13
-rw-r--r--chromium/chrome/browser/resources/settings/controls/settings_input.html5
-rw-r--r--chromium/chrome/browser/resources/settings/controls/settings_input.js7
-rw-r--r--chromium/chrome/browser/resources/settings/controls/settings_radio_group.html11
-rw-r--r--chromium/chrome/browser/resources/settings/controls/settings_radio_group.js13
-rw-r--r--chromium/chrome/browser/resources/settings/date_time_page/date_time_page.css14
-rw-r--r--chromium/chrome/browser/resources/settings/date_time_page/date_time_page.html21
-rw-r--r--chromium/chrome/browser/resources/settings/date_time_page/date_time_page.js3
-rw-r--r--chromium/chrome/browser/resources/settings/default_browser_page/default_browser_page.css2
-rw-r--r--chromium/chrome/browser/resources/settings/default_browser_page/default_browser_page.html20
-rw-r--r--chromium/chrome/browser/resources/settings/default_browser_page/default_browser_page.js37
-rw-r--r--chromium/chrome/browser/resources/settings/device_page/compiled_resources2.gyp37
-rw-r--r--chromium/chrome/browser/resources/settings/device_page/device_page.html54
-rw-r--r--chromium/chrome/browser/resources/settings/device_page/device_page.js49
-rw-r--r--chromium/chrome/browser/resources/settings/device_page/display.html72
-rw-r--r--chromium/chrome/browser/resources/settings/device_page/display.js100
-rw-r--r--chromium/chrome/browser/resources/settings/device_page/keyboard.html61
-rw-r--r--chromium/chrome/browser/resources/settings/device_page/keyboard.js87
-rw-r--r--chromium/chrome/browser/resources/settings/device_page/touchpad.html33
-rw-r--r--chromium/chrome/browser/resources/settings/device_page/touchpad.js19
-rw-r--r--chromium/chrome/browser/resources/settings/direction_delegate.html4
-rw-r--r--chromium/chrome/browser/resources/settings/direction_delegate.js29
-rw-r--r--chromium/chrome/browser/resources/settings/downloads_page/downloads_page.html31
-rw-r--r--chromium/chrome/browser/resources/settings/downloads_page/downloads_page.js3
-rw-r--r--chromium/chrome/browser/resources/settings/icons.html7
-rw-r--r--chromium/chrome/browser/resources/settings/internet_page/compiled_resources.gyp190
-rw-r--r--chromium/chrome/browser/resources/settings/internet_page/compiled_resources2.gyp112
-rw-r--r--chromium/chrome/browser/resources/settings/internet_page/internet_detail_page.html5
-rw-r--r--chromium/chrome/browser/resources/settings/internet_page/internet_detail_page.js8
-rw-r--r--chromium/chrome/browser/resources/settings/internet_page/internet_known_networks_page.html5
-rw-r--r--chromium/chrome/browser/resources/settings/internet_page/internet_known_networks_page.js3
-rw-r--r--chromium/chrome/browser/resources/settings/internet_page/internet_page.html49
-rw-r--r--chromium/chrome/browser/resources/settings/internet_page/internet_page.js7
-rw-r--r--chromium/chrome/browser/resources/settings/internet_page/network_apnlist.css4
-rw-r--r--chromium/chrome/browser/resources/settings/internet_page/network_apnlist.html2
-rw-r--r--chromium/chrome/browser/resources/settings/internet_page/network_ip_config.css2
-rw-r--r--chromium/chrome/browser/resources/settings/internet_page/network_ip_config.html2
-rw-r--r--chromium/chrome/browser/resources/settings/internet_page/network_nameservers.css2
-rw-r--r--chromium/chrome/browser/resources/settings/internet_page/network_nameservers.html2
-rw-r--r--chromium/chrome/browser/resources/settings/internet_page/network_property_list.html2
-rw-r--r--chromium/chrome/browser/resources/settings/internet_page/network_proxy.css2
-rw-r--r--chromium/chrome/browser/resources/settings/internet_page/network_proxy.html2
-rw-r--r--chromium/chrome/browser/resources/settings/internet_page/network_proxy_exclusions.html2
-rw-r--r--chromium/chrome/browser/resources/settings/internet_page/network_proxy_input.css4
-rw-r--r--chromium/chrome/browser/resources/settings/internet_page/network_proxy_input.html2
-rw-r--r--chromium/chrome/browser/resources/settings/internet_page/network_siminfo.html2
-rw-r--r--chromium/chrome/browser/resources/settings/internet_page/network_summary.html2
-rw-r--r--chromium/chrome/browser/resources/settings/internet_page/network_summary_item.css6
-rw-r--r--chromium/chrome/browser/resources/settings/internet_page/network_summary_item.html2
-rw-r--r--chromium/chrome/browser/resources/settings/languages_page/compiled_resources.gyp75
-rw-r--r--chromium/chrome/browser/resources/settings/languages_page/compiled_resources2.gyp62
-rw-r--r--chromium/chrome/browser/resources/settings/languages_page/edit_dictionary_page.css25
-rw-r--r--chromium/chrome/browser/resources/settings/languages_page/edit_dictionary_page.html53
-rw-r--r--chromium/chrome/browser/resources/settings/languages_page/edit_dictionary_page.js3
-rw-r--r--chromium/chrome/browser/resources/settings/languages_page/language_detail_page.css20
-rw-r--r--chromium/chrome/browser/resources/settings/languages_page/language_detail_page.html95
-rw-r--r--chromium/chrome/browser/resources/settings/languages_page/language_detail_page.js3
-rw-r--r--chromium/chrome/browser/resources/settings/languages_page/languages.html2
-rw-r--r--chromium/chrome/browser/resources/settings/languages_page/languages.js49
-rw-r--r--chromium/chrome/browser/resources/settings/languages_page/languages_page.css9
-rw-r--r--chromium/chrome/browser/resources/settings/languages_page/languages_page.html183
-rw-r--r--chromium/chrome/browser/resources/settings/languages_page/languages_page.js78
-rw-r--r--chromium/chrome/browser/resources/settings/languages_page/languages_types.js2
-rw-r--r--chromium/chrome/browser/resources/settings/languages_page/manage_languages_page.css15
-rw-r--r--chromium/chrome/browser/resources/settings/languages_page/manage_languages_page.html84
-rw-r--r--chromium/chrome/browser/resources/settings/languages_page/manage_languages_page.js20
-rw-r--r--chromium/chrome/browser/resources/settings/on_startup_page/compiled_resources.gyp34
-rw-r--r--chromium/chrome/browser/resources/settings/on_startup_page/compiled_resources2.gyp33
-rw-r--r--chromium/chrome/browser/resources/settings/on_startup_page/on_startup_page.html49
-rw-r--r--chromium/chrome/browser/resources/settings/on_startup_page/on_startup_page.js3
-rw-r--r--chromium/chrome/browser/resources/settings/on_startup_page/on_startup_shared.css4
-rw-r--r--chromium/chrome/browser/resources/settings/on_startup_page/startup_urls_page.html92
-rw-r--r--chromium/chrome/browser/resources/settings/on_startup_page/startup_urls_page.js76
-rw-r--r--chromium/chrome/browser/resources/settings/on_startup_page/startup_urls_page_browser_proxy.html4
-rw-r--r--chromium/chrome/browser/resources/settings/on_startup_page/startup_urls_page_browser_proxy.js69
-rw-r--r--chromium/chrome/browser/resources/settings/passwords_and_forms_page/compiled_resources2.gyp37
-rw-r--r--chromium/chrome/browser/resources/settings/passwords_and_forms_page/password_edit_dialog.html55
-rw-r--r--chromium/chrome/browser/resources/settings/passwords_and_forms_page/password_edit_dialog.js95
-rw-r--r--chromium/chrome/browser/resources/settings/passwords_and_forms_page/passwords_and_forms_page.html77
-rw-r--r--chromium/chrome/browser/resources/settings/passwords_and_forms_page/passwords_and_forms_page.js205
-rw-r--r--chromium/chrome/browser/resources/settings/passwords_and_forms_page/passwords_section.css27
-rw-r--r--chromium/chrome/browser/resources/settings/passwords_and_forms_page/passwords_section.html150
-rw-r--r--chromium/chrome/browser/resources/settings/passwords_and_forms_page/passwords_section.js108
-rw-r--r--chromium/chrome/browser/resources/settings/people_page/camera.css60
-rw-r--r--chromium/chrome/browser/resources/settings/people_page/camera.html33
-rw-r--r--chromium/chrome/browser/resources/settings/people_page/camera.js212
-rw-r--r--chromium/chrome/browser/resources/settings/people_page/change_picture.css64
-rw-r--r--chromium/chrome/browser/resources/settings/people_page/change_picture.html79
-rw-r--r--chromium/chrome/browser/resources/settings/people_page/change_picture.js433
-rw-r--r--chromium/chrome/browser/resources/settings/people_page/change_picture_browser_proxy.html1
-rw-r--r--chromium/chrome/browser/resources/settings/people_page/change_picture_browser_proxy.js112
-rw-r--r--chromium/chrome/browser/resources/settings/people_page/change_picture_private_api.html1
-rw-r--r--chromium/chrome/browser/resources/settings/people_page/change_picture_private_api.js74
-rw-r--r--chromium/chrome/browser/resources/settings/people_page/compiled_resources.gyp67
-rw-r--r--chromium/chrome/browser/resources/settings/people_page/compiled_resources2.gyp102
-rw-r--r--chromium/chrome/browser/resources/settings/people_page/easy_unlock_browser_proxy.html1
-rw-r--r--chromium/chrome/browser/resources/settings/people_page/easy_unlock_browser_proxy.js83
-rw-r--r--chromium/chrome/browser/resources/settings/people_page/easy_unlock_turn_off_dialog.html33
-rw-r--r--chromium/chrome/browser/resources/settings/people_page/easy_unlock_turn_off_dialog.js206
-rw-r--r--chromium/chrome/browser/resources/settings/people_page/manage_profile.css12
-rw-r--r--chromium/chrome/browser/resources/settings/people_page/manage_profile.html61
-rw-r--r--chromium/chrome/browser/resources/settings/people_page/manage_profile.js76
-rw-r--r--chromium/chrome/browser/resources/settings/people_page/manage_profile_browser_proxy.html2
-rw-r--r--chromium/chrome/browser/resources/settings/people_page/manage_profile_browser_proxy.js52
-rw-r--r--chromium/chrome/browser/resources/settings/people_page/people_page.css21
-rw-r--r--chromium/chrome/browser/resources/settings/people_page/people_page.html201
-rw-r--r--chromium/chrome/browser/resources/settings/people_page/people_page.js83
-rw-r--r--chromium/chrome/browser/resources/settings/people_page/sync_page.css2
-rw-r--r--chromium/chrome/browser/resources/settings/people_page/sync_page.html11
-rw-r--r--chromium/chrome/browser/resources/settings/people_page/sync_page.js3
-rw-r--r--chromium/chrome/browser/resources/settings/people_page/sync_private_api.js37
-rw-r--r--chromium/chrome/browser/resources/settings/people_page/user_list.css9
-rw-r--r--chromium/chrome/browser/resources/settings/people_page/user_list.html6
-rw-r--r--chromium/chrome/browser/resources/settings/people_page/user_list.js3
-rw-r--r--chromium/chrome/browser/resources/settings/people_page/users_page.html9
-rw-r--r--chromium/chrome/browser/resources/settings/people_page/users_page.js3
-rw-r--r--chromium/chrome/browser/resources/settings/pref_tracker/pref_tracker.html6
-rw-r--r--chromium/chrome/browser/resources/settings/pref_tracker/pref_tracker.js59
-rw-r--r--chromium/chrome/browser/resources/settings/prefs/compiled_resources.gyp24
-rw-r--r--chromium/chrome/browser/resources/settings/prefs/compiled_resources2.gyp39
-rw-r--r--chromium/chrome/browser/resources/settings/prefs/prefs.html3
-rw-r--r--chromium/chrome/browser/resources/settings/prefs/prefs.js5
-rw-r--r--chromium/chrome/browser/resources/settings/privacy_page/privacy_page.css11
-rw-r--r--chromium/chrome/browser/resources/settings/privacy_page/privacy_page.html259
-rw-r--r--chromium/chrome/browser/resources/settings/privacy_page/privacy_page.js28
-rw-r--r--chromium/chrome/browser/resources/settings/privacy_page/privacy_page_browser_proxy.html3
-rw-r--r--chromium/chrome/browser/resources/settings/privacy_page/privacy_page_browser_proxy.js34
-rw-r--r--chromium/chrome/browser/resources/settings/reset_page/compiled_resources2.gyp15
-rw-r--r--chromium/chrome/browser/resources/settings/reset_page/powerwash_dialog.html45
-rw-r--r--chromium/chrome/browser/resources/settings/reset_page/powerwash_dialog.js7
-rw-r--r--chromium/chrome/browser/resources/settings/reset_page/reset_browser_proxy.html2
-rw-r--r--chromium/chrome/browser/resources/settings/reset_page/reset_browser_proxy.js89
-rw-r--r--chromium/chrome/browser/resources/settings/reset_page/reset_page.html25
-rw-r--r--chromium/chrome/browser/resources/settings/reset_page/reset_page.js3
-rw-r--r--chromium/chrome/browser/resources/settings/reset_page/reset_page_dialog.css4
-rw-r--r--chromium/chrome/browser/resources/settings/reset_page/reset_profile_banner.html3
-rw-r--r--chromium/chrome/browser/resources/settings/reset_page/reset_profile_banner.js5
-rw-r--r--chromium/chrome/browser/resources/settings/reset_page/reset_profile_dialog.css14
-rw-r--r--chromium/chrome/browser/resources/settings/reset_page/reset_profile_dialog.html49
-rw-r--r--chromium/chrome/browser/resources/settings/reset_page/reset_profile_dialog.js46
-rw-r--r--chromium/chrome/browser/resources/settings/search_engines_page/omnibox_extension_entry.html50
-rw-r--r--chromium/chrome/browser/resources/settings/search_engines_page/omnibox_extension_entry.js41
-rw-r--r--chromium/chrome/browser/resources/settings/search_engines_page/search_engine_adder.css15
-rw-r--r--chromium/chrome/browser/resources/settings/search_engines_page/search_engine_adder.html45
-rw-r--r--chromium/chrome/browser/resources/settings/search_engines_page/search_engine_adder.js29
-rw-r--r--chromium/chrome/browser/resources/settings/search_engines_page/search_engine_dialog.html40
-rw-r--r--chromium/chrome/browser/resources/settings/search_engines_page/search_engine_dialog.js117
-rw-r--r--chromium/chrome/browser/resources/settings/search_engines_page/search_engine_entry.css27
-rw-r--r--chromium/chrome/browser/resources/settings/search_engines_page/search_engine_entry.html87
-rw-r--r--chromium/chrome/browser/resources/settings/search_engines_page/search_engine_entry.js87
-rw-r--r--chromium/chrome/browser/resources/settings/search_engines_page/search_engines_browser_proxy.html1
-rw-r--r--chromium/chrome/browser/resources/settings/search_engines_page/search_engines_browser_proxy.js141
-rw-r--r--chromium/chrome/browser/resources/settings/search_engines_page/search_engines_list.css24
-rw-r--r--chromium/chrome/browser/resources/settings/search_engines_page/search_engines_list.html25
-rw-r--r--chromium/chrome/browser/resources/settings/search_engines_page/search_engines_list.js9
-rw-r--r--chromium/chrome/browser/resources/settings/search_engines_page/search_engines_page.html63
-rw-r--r--chromium/chrome/browser/resources/settings/search_engines_page/search_engines_page.js73
-rw-r--r--chromium/chrome/browser/resources/settings/search_page/search_page.css11
-rw-r--r--chromium/chrome/browser/resources/settings/search_page/search_page.html73
-rw-r--r--chromium/chrome/browser/resources/settings/search_page/search_page.js88
-rw-r--r--chromium/chrome/browser/resources/settings/settings.html13
-rw-r--r--chromium/chrome/browser/resources/settings/settings.js11
-rw-r--r--chromium/chrome/browser/resources/settings/settings_dialog.css69
-rw-r--r--chromium/chrome/browser/resources/settings/settings_dialog.html99
-rw-r--r--chromium/chrome/browser/resources/settings/settings_dialog.js37
-rw-r--r--chromium/chrome/browser/resources/settings/settings_main/settings_main.css4
-rw-r--r--chromium/chrome/browser/resources/settings/settings_main/settings_main.html2
-rw-r--r--chromium/chrome/browser/resources/settings/settings_main/settings_main.js30
-rw-r--r--chromium/chrome/browser/resources/settings/settings_menu/settings_menu.css8
-rw-r--r--chromium/chrome/browser/resources/settings/settings_menu/settings_menu.html172
-rw-r--r--chromium/chrome/browser/resources/settings/settings_menu/settings_menu.js20
-rw-r--r--chromium/chrome/browser/resources/settings/settings_page.css (renamed from chromium/chrome/browser/resources/settings/basic_page/basic_page.css)10
-rw-r--r--chromium/chrome/browser/resources/settings/settings_page/compiled_resources.gyp21
-rw-r--r--chromium/chrome/browser/resources/settings/settings_page/compiled_resources2.gyp58
-rw-r--r--chromium/chrome/browser/resources/settings/settings_page/main_page_behavior.html18
-rw-r--r--chromium/chrome/browser/resources/settings/settings_page/main_page_behavior.js379
-rw-r--r--chromium/chrome/browser/resources/settings/settings_page/settings_animated_pages.css11
-rw-r--r--chromium/chrome/browser/resources/settings/settings_page/settings_animated_pages.html9
-rw-r--r--chromium/chrome/browser/resources/settings/settings_page/settings_animated_pages.js67
-rw-r--r--chromium/chrome/browser/resources/settings/settings_page/settings_page_visibility.js2
-rw-r--r--chromium/chrome/browser/resources/settings/settings_page/settings_router.html2
-rw-r--r--chromium/chrome/browser/resources/settings/settings_page/settings_router.js159
-rw-r--r--chromium/chrome/browser/resources/settings/settings_page/settings_section.css43
-rw-r--r--chromium/chrome/browser/resources/settings/settings_page/settings_section.html3
-rw-r--r--chromium/chrome/browser/resources/settings/settings_page/settings_section.js150
-rw-r--r--chromium/chrome/browser/resources/settings/settings_page/settings_subheader.css13
-rw-r--r--chromium/chrome/browser/resources/settings/settings_page/settings_subheader.html13
-rw-r--r--chromium/chrome/browser/resources/settings/settings_page/settings_subpage.html37
-rw-r--r--chromium/chrome/browser/resources/settings/settings_page/settings_subpage.js (renamed from chromium/chrome/browser/resources/settings/settings_page/settings_subheader.js)25
-rw-r--r--chromium/chrome/browser/resources/settings/settings_page/transition_behavior.html2
-rw-r--r--chromium/chrome/browser/resources/settings/settings_page/transition_behavior.js86
-rw-r--r--chromium/chrome/browser/resources/settings/settings_resources.grd404
-rw-r--r--chromium/chrome/browser/resources/settings/settings_shared.css115
-rw-r--r--chromium/chrome/browser/resources/settings/settings_shared_css.html258
-rw-r--r--chromium/chrome/browser/resources/settings/settings_ui/breadcrumb.css3
-rw-r--r--chromium/chrome/browser/resources/settings/settings_ui/breadcrumb.html17
-rw-r--r--chromium/chrome/browser/resources/settings/settings_ui/breadcrumb.js55
-rw-r--r--chromium/chrome/browser/resources/settings/settings_ui/compiled_resources2.gyp12
-rw-r--r--chromium/chrome/browser/resources/settings/settings_ui/settings_ui.css32
-rw-r--r--chromium/chrome/browser/resources/settings/settings_ui/settings_ui.html58
-rw-r--r--chromium/chrome/browser/resources/settings/settings_ui/settings_ui.js14
-rw-r--r--chromium/chrome/browser/resources/settings/site_settings/all_sites.css (renamed from chromium/chrome/browser/resources/settings/advanced_page/advanced_page.css)4
-rw-r--r--chromium/chrome/browser/resources/settings/site_settings/all_sites.html16
-rw-r--r--chromium/chrome/browser/resources/settings/site_settings/all_sites.js33
-rw-r--r--chromium/chrome/browser/resources/settings/site_settings/compiled_resources.gyp95
-rw-r--r--chromium/chrome/browser/resources/settings/site_settings/compiled_resources2.gyp109
-rw-r--r--chromium/chrome/browser/resources/settings/site_settings/constants.js24
-rw-r--r--chromium/chrome/browser/resources/settings/site_settings/site_details.css5
-rw-r--r--chromium/chrome/browser/resources/settings/site_settings/site_details.html54
-rw-r--r--chromium/chrome/browser/resources/settings/site_settings/site_details.js94
-rw-r--r--chromium/chrome/browser/resources/settings/site_settings/site_details_permission.css2
-rw-r--r--chromium/chrome/browser/resources/settings/site_settings/site_details_permission.html12
-rw-r--r--chromium/chrome/browser/resources/settings/site_settings/site_details_permission.js99
-rw-r--r--chromium/chrome/browser/resources/settings/site_settings/site_list.css7
-rw-r--r--chromium/chrome/browser/resources/settings/site_settings/site_list.html63
-rw-r--r--chromium/chrome/browser/resources/settings/site_settings/site_list.js284
-rw-r--r--chromium/chrome/browser/resources/settings/site_settings/site_settings_behavior.html2
-rw-r--r--chromium/chrome/browser/resources/settings/site_settings/site_settings_behavior.js87
-rw-r--r--chromium/chrome/browser/resources/settings/site_settings/site_settings_category.css2
-rw-r--r--chromium/chrome/browser/resources/settings/site_settings/site_settings_category.html26
-rw-r--r--chromium/chrome/browser/resources/settings/site_settings/site_settings_category.js75
-rw-r--r--chromium/chrome/browser/resources/settings/site_settings/site_settings_prefs_browser_proxy.html1
-rw-r--r--chromium/chrome/browser/resources/settings/site_settings/site_settings_prefs_browser_proxy.js130
-rw-r--r--chromium/chrome/browser/resources/settings/site_settings/website_usage_private_api.html3
-rw-r--r--chromium/chrome/browser/resources/settings/site_settings/website_usage_private_api.js123
-rw-r--r--chromium/chrome/browser/resources/settings/site_settings_page/compiled_resources.gyp26
-rw-r--r--chromium/chrome/browser/resources/settings/site_settings_page/compiled_resources2.gyp19
-rw-r--r--chromium/chrome/browser/resources/settings/site_settings_page/site_settings_page.css2
-rw-r--r--chromium/chrome/browser/resources/settings/site_settings_page/site_settings_page.html3
-rw-r--r--chromium/chrome/browser/resources/settings/site_settings_page/site_settings_page.js113
-rw-r--r--chromium/chrome/browser/resources/settings/system_page/compiled_resources2.gyp23
-rw-r--r--chromium/chrome/browser/resources/settings/system_page/system_page.html46
-rw-r--r--chromium/chrome/browser/resources/settings/system_page/system_page.js40
-rw-r--r--chromium/chrome/browser/resources/settings/system_page/system_page_browser_proxy.html2
-rw-r--r--chromium/chrome/browser/resources/settings/system_page/system_page_browser_proxy.js54
-rw-r--r--chromium/chrome/browser/resources/signin_internals/signin_index.css78
-rw-r--r--chromium/chrome/browser/resources/signin_internals/signin_index.html89
-rw-r--r--chromium/chrome/browser/resources/signin_internals/signin_internals.js189
-rw-r--r--chromium/chrome/browser/resources/signin_internals_resources.grd18
-rw-r--r--chromium/chrome/browser/resources/supervised_user_block_interstitial.css141
-rw-r--r--chromium/chrome/browser/resources/supervised_user_block_interstitial.html64
-rw-r--r--chromium/chrome/browser/resources/supervised_user_block_interstitial.js98
-rw-r--r--chromium/chrome/browser/resources/sync_confirmation/sync_confirmation.css325
-rw-r--r--chromium/chrome/browser/resources/sync_confirmation/sync_confirmation.html71
-rw-r--r--chromium/chrome/browser/resources/sync_confirmation/sync_confirmation.js54
-rw-r--r--chromium/chrome/browser/resources/uber/compiled_resources.gyp32
-rw-r--r--chromium/chrome/browser/resources/uber/compiled_resources2.gyp41
-rw-r--r--chromium/chrome/browser/resources/uber/uber_frame.js4
-rw-r--r--chromium/chrome/browser/resources/user_manager/user_manager.js31
577 files changed, 21905 insertions, 20578 deletions
diff --git a/chromium/chrome/browser/resources/BUILD.gn b/chromium/chrome/browser/resources/BUILD.gn
index d0af3400612..e37e45745ab 100644
--- a/chromium/chrome/browser/resources/BUILD.gn
+++ b/chromium/chrome/browser/resources/BUILD.gn
@@ -5,16 +5,6 @@
import("//chrome/common/features.gni")
import("//tools/grit/grit_rule.gni")
-grit("memory_internals_resources") {
- source = "memory_internals_resources.grd"
- defines = chrome_grit_defines
- outputs = [
- "grit/memory_internals_resources.h",
- "memory_internals_resources.pak",
- ]
- output_dir = "$root_gen_dir/chrome"
-}
-
grit("net_internals_resources") {
source = "net_internals_resources.grd"
defines = chrome_grit_defines
@@ -56,16 +46,6 @@ grit("policy_resources") {
output_dir = "$root_gen_dir/chrome"
}
-grit("signin_internals_resources") {
- source = "signin_internals_resources.grd"
- defines = chrome_grit_defines
- outputs = [
- "grit/signin_internals_resources.h",
- "signin_internals_resources.pak",
- ]
- output_dir = "$root_gen_dir/chrome"
-}
-
grit("translate_internals_resources") {
source = "translate_internals_resources.grd"
defines = chrome_grit_defines
diff --git a/chromium/chrome/browser/resources/about_memory.css b/chromium/chrome/browser/resources/about_memory.css
deleted file mode 100644
index 5bb2535efc2..00000000000
--- a/chromium/chrome/browser/resources/about_memory.css
+++ /dev/null
@@ -1,312 +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. */
-
-body {
- font-size: 84%;
- margin: 0;
- min-width: 45em;
- padding: 0.75em;
-}
-
-h1 {
- color: rgb(74, 142, 230);
- font-size: 110%;
- font-weight: bold;
- letter-spacing: -1px;
- margin: 0;
- padding: 0;
-}
-
-h2 {
- border-top: 1px solid rgb(58, 117, 189);
- color: rgb(58, 117, 189);
- font-size: 110%;
- font-weight: normal;
- letter-spacing: -1px;
- margin: 0;
- margin-left: -38px;
- padding: 0.5em 1em 0.5em 38px;
-}
-
-h2:first-child {
- border-top: 0;
- padding-top: 0;
-}
-
-span.th {
- padding-left: 0.35em;
-}
-
-a {
- color: black;
-}
-
-div#header {
- background: rgb(82, 150, 222);
- background-size: 100%;
- border: 1px solid rgb(58, 117, 189);
- border-radius: 6px;
- color: white;
- margin-bottom: 0.75em;
- overflow: hidden;
- padding: 0.5em 0;
- position: relative;
- text-shadow: 0 0 2px black;
-}
-
-div#header h1 {
- color: white;
- display: inline;
-}
-
-div#header h1::before {
- /* grit doesn't flatten -webkit-mask, so define the properties separately
- * for now. */
- -webkit-mask-image: url(../../../ui/webui/resources/images/settings.svg);
- -webkit-mask-position: center;
- -webkit-mask-repeat: no-repeat;
- -webkit-mask-size: 24px;
- background-color: white;
- content: '';
- display: inline-block;
- height: 20px;
- vertical-align: middle;
- width: 37px;
-}
-
-div#header p {
- color: white;
- display: inline;
- font-size: 84%;
- font-style: italic;
- margin: 0;
- padding: 0;
- padding-left: 0.4em;
-}
-
-div#header div.navigation {
- font-size: 92%;
- line-height: 3.5em;
- position: absolute;
- right: 1em;
- top: 0;
-}
-
-div#header select {
- border: 1px solid rgb(58, 117, 189);
- color: rgb(49, 93, 148);
- font-size: 100%;
- line-height: 140%;
-}
-
-div#header select option {
- padding: 0 0.2em;
-}
-
-div#sidebar {
- border-right: 1px solid #cfcfcf;
- display: none;
- float: left;
- margin-left: 26px;
- min-height: 20em;
- padding: 0.75em;
- padding-top: 0;
- width: 45em;
-}
-
-div#content {
- margin-left: 0;
-}
-
-hr {
- display: inline;
- padding: 0 0.5em;
- visibility: hidden;
-}
-
-.k {
- font-weight: normal;
- opacity: 0.4;
- padding-left: 0.1em;
-}
-
-.legend {
- color: #7f7f7f;
- font-size: 84%;
- line-height: 140%;
- margin-top: 2em;
- padding: 0.4em 0 0;
- text-align: right;
-}
-
-.legend h3 {
- color: black;
- display: inline;
- font-size: 100%;
- font-weight: normal;
- margin: 0;
- padding: 0 0.5em 0 0;
-}
-
-.legend .swatch {
- display: inline-block;
- height: 0.9em;
- margin-right: 0.2em;
- opacity: 0.66;
- padding: 0 0.5em;
-}
-
-table.list {
- border-collapse: collapse;
- font-size: 84%;
- line-height: 200%;
- table-layout: fixed;
- width: 100%;
-}
-
-table.list:not([class*='filtered']) tr:nth-child(odd) td {
- background: rgb(239, 243, 255);
-}
-
-.hidden {
- display: none;
-}
-
-table.list th {
- color: black;
- font-weight: bold;
- padding: 0 0.5em;
- vertical-align: top;
- white-space: nowrap;
-}
-
-table.list .firstRow th {
- line-height: 100%;
- text-align: left;
-}
-
-table.list .secondRow * {
- border-bottom: 1px solid rgb(181, 198, 222);
- text-align: left;
-}
-
-table.list td {
- line-height: 1.4em;
- padding: 0.35em 0.5em 0;
- vertical-align: top;
-}
-
-table.list tr td:nth-last-child(1),
-table.list tr th:nth-last-child(1) {
- padding-right: 1em;
-}
-
-table.list:not([class*='filtered']) .tab .name {
- padding-left: 1.5em;
-}
-
-table.list .name {
- width: 100%;
-}
-
-table.list .name div {
- height: 1.6em;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
-}
-
-table.list .pid {
- text-align: right;
- width: 4em;
-}
-
-table.list .pid .th {
- padding: 0;
-}
-
-table.list .type {
- width: 5em;
-}
-
-table.list .number {
- text-align: right;
- width: 7em;
-}
-
-table.list .total {
- font-weight: bold;
-}
-
-table.list .total .name {
- color: rgb(49, 93, 148);
- text-align: right;
-}
-
-table.list .total td {
- background: white !important;
- border-top: 1px solid rgb(181, 198, 222);
-}
-
-table.list .noResults {
- display: none;
-}
-
-table.list.noResults .noResults {
- display: table-row;
-}
-
-table.list .noResults td {
- color: #3f3f3f;
- padding: 3em 0;
- text-align: center;
-}
-
-table.list#browserComparison .name {
- background-position: 5px center;
- background-repeat: no-repeat;
- padding-left: 25px;
-}
-
-div.help {
- -webkit-mask-box-image: url(../../../ui/webui/resources/images/help.svg);
- background-color: rgb(66, 133, 244);
- display: inline-block;
- height: 16px;
- margin: -1px 0 0 0;
- opacity: 0.33;
- vertical-align: bottom;
- width: 16px;
-}
-
-div.help:hover {
- opacity: 1;
-}
-
-div.help div {
- display: none;
-}
-
-#helpTooltip {
- background: rgb(214, 232, 255);
- border: 1px solid rgb(168, 207, 255);
- border-radius: 0;
- box-shadow: 3px 3px 4px rgba(0, 0, 0, 0.33);
- font-size: 92%;
- line-height: 140%;
- max-width: 30em;
- padding: 0.3em 0.8em;
- position: absolute;
- z-index: 1000;
-}
-
-#helpTooltip p {
- margin: 0.6em 0;
-}
-
-div.otherbrowsers {
- font-size: 84%;
- text-align: center;
- width: 100%;
-}
diff --git a/chromium/chrome/browser/resources/about_memory.html b/chromium/chrome/browser/resources/about_memory.html
deleted file mode 100644
index 9cfc1f0aa7c..00000000000
--- a/chromium/chrome/browser/resources/about_memory.html
+++ /dev/null
@@ -1,350 +0,0 @@
-<!doctype html>
-
-<!--
-about:memory template page
--->
-<html id="t">
-<head>
- <meta charset="utf-8">
- <title>About Memory</title>
- <link rel="stylesheet" href="chrome://resources/css/text_defaults.css">
- <link rel="stylesheet" href="chrome://memory-redirect/about_memory.css">
-<style>
-
-table.list#browserComparison tr:not([class*='firstRow']) > *:nth-child(1),
-table.list#browserComparison tr:not([class*='firstRow']) > *:nth-child(4),
-table.list#browserComparison tr.firstRow th:nth-child(1),
-table.list#browserComparison tr.firstRow th:nth-child(2) {
- border-right: 1px solid #b5c6de;
-}
-table.list#memoryDetails tr:not([class*='firstRow']) > *:nth-child(2),
-table.list#memoryDetails tr:not([class*='firstRow']) > *:nth-child(5),
-table.list#memoryDetails tr.firstRow th:nth-child(2),
-table.list#memoryDetails tr.firstRow th:nth-child(3) {
- border-right: 1px solid #b5c6de;
-}
-</style>
-<script src="chrome://resources/js/load_time_data.js"></script>
-<script src="chrome://memory-redirect/memory.js"></script>
-<script src="chrome://memory-redirect/strings.js"></script>
-</head>
-<body>
- <div id="header">
- <h1>About memory</h1>
- <p>
- Measuring memory usage in a multi-process browser
- </p>
- </div>
-
- <div id="content">
- <h2>
- Summary
- <div class="help">
- <div>
- <p>
- Summary of memory used by currently active browsers. For browsers
- which use multiple processes, memory reflects aggregate memory
- used across all browser processes.
- </p>
- <p>
- For <span jscontent="current_browser_name"></span>, processes used
- to to display diagnostics information (such as this
- "about:memory") are excluded.
- </p>
- </div>
- </div>
- </h2>
-
- <table class="list" id="browserComparison">
- <colgroup>
- <col class="name">
- <col class="number">
- <col class="number">
- <col class="number">
- <col class="number">
- <col class="number">
- </colgroup>
- <tr class="firstRow doNotFilter">
- <th>
- </th>
- <th colspan="3">
- Memory
- <div class="help">
- <div>
- <p>
- <strong>Memory</strong>
- </p>
- <p>
- <strong>Private:</strong>
- Resident memory size that is not shared with any other
- process. This is the best indicator of browser memory
- resource usage.
- </p>
- <p>
- <strong>Shared:</strong>
- Resident memory size that is currently shared with 2 or more
- processes. Note: For browsers using multiple processes, if we
- simply added the shared memory of each individual process,
- this value would be inflated. Therefore, this value is
- computed as an approximate value for shared memory in each of
- the browser's processes. Note also that shared memory varies
- depending on what other processes are running on the system,
- and may be difficult to measure reproducibly.
- </p>
- <p>
- <strong>Total:</strong>
- The sum of the private + shared resident memory sizes.
- </p>
- </div>
- </div>
- </th>
- <th colspan="2">
- Virtual memory
- <div class="help">
- <div>
- <p>
- <strong>Virtual memory</strong>
- </p>
- <p>
- <strong>Private:</strong>
- The resident and paged bytes committed for use by only this
- process.
- </p>
- <p>
- <strong>Mapped:</strong>
- Total bytes allocated by this process that are mapped into the
- view of a section, backed by either system pagefile or file
- system. This is primarily memory-mapped files.
- </p>
- </div>
- </div>
- </th>
- </tr>
- <tr class="secondRow doNotFilter">
- <th class="name">
- Browser
- </th>
- <th class="name">
- Private
- </th>
- <th class="number">
- Shared
- </th>
- <th class="number">
- Total
- </th>
- <th class="number">
- Private
- </th>
- <th class="number">
- Mapped
- </th>
- </tr>
- <tr jsselect="browsers">
- <td class="name">
- <div>
- <strong jscontent="name"></strong>
- <span jscontent="version"></span>
- </div>
- </td>
- <td class="number">
- <span class="th"
- jscontent="formatNumber(ws_priv + ws_shareable - ws_shared)">
- </span><span class="k">k</span>
- </td>
- <td class="number">
- <span class="th" jscontent="formatNumber(ws_shared / processes)">
- </span><span class="k">k</span>
- </td>
- <td class="number">
- <span class="th"
- jscontent="formatNumber(ws_priv + ws_shareable - ws_shared +
- (ws_shared / processes))"></span><span class="k">k</span>
- </td>
- <td class="number">
- <span class="th" jscontent="formatNumber(comm_priv)"></span>
- <span class="k">k</span>
- </td>
- <td class="number">
- <span class="th" jscontent="formatNumber(comm_map)"></span>
- <span class="k">k</span>
- </td>
- </tr>
- </table>
- <div class="otherbrowsers" jsdisplay="browsers.length == 1">
- Note: This page will show memory use for all running browsers,
- not just Chrome.
- </div>
- <div class="otherbrowsers" jsdisplay="browsers.length > 1">
- Note: Chrome includes memory used by plugins, other browsers may not.
- </div>
-
- <br><br><br>
-
- <h2>
- Processes
- <div class="help">
- <div>
- <p>
- Details of memory usage for each of
- <span jscontent="current_browser_name"></span>'s processes.
- </p>
- </div>
- </div>
- </h2>
-
- <table class="list" id="memoryDetails">
- <colgroup>
- <col class="pid">
- <col class="name">
- <col class="number">
- <col class="number">
- <col class="number">
- <col class="number">
- <col class="number">
- </colgroup>
- <tr class="firstRow doNotFilter">
- <th>
- </th>
- <th>
- </th>
- <th colspan="3">
- Memory
- </th>
- <th colspan="2">
- Virtual memory
- </th>
-
- </tr>
- <tr class="secondRow doNotFilter">
- <th class="pid">
- PID
- </th>
- <th class="name">
- Name
- </th>
- <th class="number">
- Private
- </th>
- <th class="number">
- Shared
- </th>
- <th class="number">
- Total
- </th>
- <th class="number">
- Private
- </th>
- <th class="number">
- Mapped
- </th>
- </tr>
-
- <tr jsselect="browzr_data">
- <td class="pid">
- <span class="th" jscontent="pid"></span>
- </td>
- <td class="name">
- <div>
- Browser
- </div>
- </td>
- <td class="number">
- <span class="th" jseval="addToSum('tot_ws_priv', $this.ws_priv +
- $this.ws_shareable - $this.ws_shared)" jscontent="ws_priv +
- ws_shareable - ws_shared"></span><span class="k">k</span>
- </td>
- <td class="number">
- <span class="th" jscontent="ws_shared"></span>
- <span class="k">k</span>
- </td>
- <td class="number">
- <span class="th" jseval="addToSum('tot_ws_tot', $this.ws_priv +
- $this.ws_shareable)" jscontent="ws_priv +
- ws_shareable"></span><span class="k">k</span>
- </td>
- <td class="number">
- <span class="th" jseval="addToSum('tot_comm_priv', $this.comm_priv)"
- jscontent="comm_priv"></span><span class="k">k</span>
- </td>
- <td class="number">
- <span class="th" jseval="addToSum('tot_comm_map', $this.comm_map)"
- jscontent="comm_map"></span><span class="k">k</span>
- </td>
- </tr>
- <tr jsselect="child_data">
- <td class="pid">
- <span class="th" jscontent="pid"></span>
- </td>
- <td class="name">
- <div jscontent="child_name"></div>
- <div jsselect="titles">
- <span jscontent="$this"></span><br>
- </div>
- </td>
- <td class="number">
- <span class="th" jseval="addToSum('tot_ws_priv', $this.ws_priv +
- $this.ws_shareable - $this.ws_shared)" jscontent="ws_priv +
- ws_shareable - ws_shared"></span><span class="k">k</span>
- </td>
- <td class="number">
- <span class="th" jscontent="ws_shared"></span><span
- class="k">k</span>
- </td>
- <td class="number">
- <span class="th" jseval="addToSum('tot_ws_tot', $this.ws_priv +
- $this.ws_shareable)" jscontent="ws_priv +
- ws_shareable"></span><span class="k">k</span>
- </td>
- <td class="number">
- <span class="th" jseval="addToSum('tot_comm_priv', $this.comm_priv)"
- jscontent="comm_priv"></span><span class="k">k</span>
- </td>
- <td class="number">
- <span class="th" jseval="addToSum('tot_comm_map', $this.comm_map)"
- jscontent="comm_map"></span><span class="k">k</span>
- </td>
- </tr>
- <tr class="total doNotFilter">
- <td class="pid">
- </td>
- <td class="name">
- &Sigma;
- </td>
- <td class="number">
- <span class="th" id="tot_ws_priv">0</span><span class="k">k</span>
- </td>
- <td class="number">
- </td>
- <td class="number">
- <span class="th" id="tot_ws_tot">0</span><span class="k">k</span>
- </td>
- <td class="number">
- <span class="th" id="tot_comm_priv">0</span><span class="k">k</span>
- </td>
- <td class="number">
- <div class="help">
- <div>
- <p>
- This is an approximation. Conceptually, this is the total
- amount of in-memory pages for the entire logical
- <span jscontent="current_browser_name"></span> application,
- without double counting shared pages (e.g. mapped DLLs,
- SharedMemory bitmaps, etc.) across the browser and renderers.
- </p>
- </div>
- </div>
- <span class="th" id="tot_comm_map">0</span><span class="k">k</span>
- </td>
- </tr>
-
- <tr class="noResults">
- <td colspan="99">
- No results found.
- </td>
- </tr>
- </table>
- </div>
- <script src="chrome://resources/js/jstemplate_compiled.js"></script>
-</body>
-</html>
diff --git a/chromium/chrome/browser/resources/about_memory.js b/chromium/chrome/browser/resources/about_memory.js
deleted file mode 100644
index ff288490bc2..00000000000
--- a/chromium/chrome/browser/resources/about_memory.js
+++ /dev/null
@@ -1,84 +0,0 @@
-// 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.
-
-<include src="../../../ui/webui/resources/js/util.js">
-
-function reload() {
- if ($('helpTooltip'))
- return;
- history.go(0);
-}
-
-function formatNumber(str) {
- str += '';
- if (str == '0') {
- return 'N/A ';
- }
- var x = str.split('.');
- var x1 = x[0];
- var x2 = x.length > 1 ? '.' + x[1] : '';
- var regex = /(\d+)(\d{3})/;
- while (regex.test(x1)) {
- x1 = x1.replace(regex, '$1' + ',' + '$2');
- }
- return x1;
-}
-
-function addToSum(id, value) {
- var target = document.getElementById(id);
- var sum = parseInt(target.innerHTML);
- sum += parseInt(value);
- target.innerHTML = sum;
-}
-
-function handleHelpTooltipMouseOver(event) {
- var el = document.createElement('div');
- el.id = 'helpTooltip';
- el.innerHTML = event.toElement.getElementsByTagName('div')[0].innerHTML;
- el.style.top = 0;
- el.style.left = 0;
- el.style.visibility = 'hidden';
- document.body.appendChild(el);
-
- var width = el.offsetWidth;
- var height = el.offsetHeight;
-
- var scrollLeft = scrollLeftForDocument(document);
- if (event.pageX - width - 50 + scrollLeft >= 0)
- el.style.left = (event.pageX - width - 20) + 'px';
- else
- el.style.left = (event.pageX + 20) + 'px';
-
- var scrollTop = scrollTopForDocument(document);
- if (event.pageY - height - 50 + scrollTop >= 0)
- el.style.top = (event.pageY - height - 20) + 'px';
- else
- el.style.top = (event.pageY + 20) + 'px';
-
- el.style.visibility = 'visible';
-}
-
-function handleHelpTooltipMouseOut(event) {
- var el = $('helpTooltip');
- el.parentNode.removeChild(el);
-}
-
-function enableHelpTooltips() {
- var helpEls = document.getElementsByClassName('help');
-
- for (var i = 0, helpEl; helpEl = helpEls[i]; i++) {
- helpEl.onmouseover = handleHelpTooltipMouseOver;
- helpEl.onmouseout = handleHelpTooltipMouseOut;
- }
-}
-
-document.addEventListener('DOMContentLoaded', function() {
- // This is the javascript code that processes the template:
- var input = new JsEvalContext(loadTimeData.getValue('jstemplateData'));
- var output = $('t');
- jstProcess(input, output);
-
- enableHelpTooltips();
-});
-
diff --git a/chromium/chrome/browser/resources/about_memory_linux.css b/chromium/chrome/browser/resources/about_memory_linux.css
deleted file mode 100644
index db1ca1cf487..00000000000
--- a/chromium/chrome/browser/resources/about_memory_linux.css
+++ /dev/null
@@ -1,25 +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. */
-
-.summary-desc {
- white-space: pre-line;
-}
-
-table.list#browserComparison tr:not([class*='firstRow']) > *:nth-child(1),
-table.list#browserComparison tr:not([class*='firstRow']) > *:nth-child(4),
-table.list#browserComparison tr.firstRow th:nth-child(1) {
- border-right: 1px solid rgb(181, 198, 222);
-}
-
-table.list#memoryDetails tr:not([class*='firstRow']) > *:nth-child(2),
-table.list#memoryDetails tr:not([class*='firstRow']) > *:nth-child(5),
-table.list#memoryDetails tr.firstRow th:nth-child(2) {
- border-right: 1px solid rgb(181, 198, 222);
-}
-
-<if expr="is_android">
-body {
- min-width: 35em;
-}
-</if> \ No newline at end of file
diff --git a/chromium/chrome/browser/resources/about_memory_linux.html b/chromium/chrome/browser/resources/about_memory_linux.html
deleted file mode 100644
index da7870ed43b..00000000000
--- a/chromium/chrome/browser/resources/about_memory_linux.html
+++ /dev/null
@@ -1,210 +0,0 @@
-<!doctype html>
-
-<!--
-about:memory template page
--->
-<html id="t">
-<head>
- <meta charset="utf-8">
- <title>About Memory</title>
-<if expr="is_android">
- <meta name="viewport" content="width=device-width">
-</if>
- <link rel="stylesheet" href="chrome://resources/css/text_defaults.css">
- <link rel="stylesheet" href="chrome://memory-redirect/about_memory.css">
- <link rel="stylesheet" href="about_memory_linux.css">
- <script src="chrome://resources/js/load_time_data.js"></script>
- <script src="chrome://memory-redirect/memory.js"></script>
- <script src="chrome://memory-redirect/strings.js"></script>
-</head>
-<body>
- <div id="header">
- <h1>About memory</h1>
- <p>
- Measuring memory usage in a multi-process browser
- </p>
- </div>
-
- <div id="content">
- <h2>
- Summary
- <div class="help">
- <div>
- <p class="summary-desc" i18n-values=".innerHTML:summary_desc"></p>
- </div>
- </div>
- </h2>
-
- <table class="list" id="browserComparison">
- <colgroup>
- <col class="name">
- <col class="number">
- <col class="number">
- </colgroup>
- <tr class="firstRow doNotFilter">
- <th>
- </th>
- <th colspan="2">
- Memory
- <div class="help">
- <div>
- <p>
- <strong>Memory</strong>
- </p>
- <p>
- <strong>Private:</strong>
- Resident memory size that is not shared with any other process.
- This is the best indicator of browser memory resource usage.
- </p>
- <p>
- <strong>Proportional:</strong>
- Accounts for each page of memory as a fraction based on the number of
- processes that have it mapped. Thus, for each page of memory mapped by two
- processes, this sum will count half of the bytes towards each.
- Therefore, this number is greater than the private count.
- </p>
-
- <p><i>(Note that the memory for this tab is not included in the browser totals)</i></p>
- </div>
- </div>
- </th>
- </tr>
- <tr class="secondRow doNotFilter">
- <th class="name">
- Browser
- </th>
- <th class="name">
- Private
- </th>
- <th class="number">
- Proportional
- </th>
- </tr>
- <tr jsselect="browsers">
- <td class="name">
- <div>
- <strong jscontent="name"></strong> <span jscontent="version"></span>
- </div>
- </td>
- <td class="number">
- <span class="th" jscontent="formatNumber(ws_priv)"></span><span class="k">k</span>
- </td>
- <td class="number">
- <span class="th" jscontent="formatNumber(ws_shared)"></span><span class="k">k</span>
- </td>
- </tr>
- </table>
- <div class="otherbrowsers"
- jsdisplay="show_other_browsers && browsers.length == 1">
- Note: This page will show memory use for all running browsers,
- not just Chrome.
- </div>
- <div class="otherbrowsers"
- jsdisplay="show_other_browsers && browsers.length > 1">
- Note: Chrome includes memory used by plugins, other browsers may not.
- </div>
-
- <br><br><br>
-
- <h2>
- Processes
- <div class="help">
- <div>
- <p>
- Details of memory usage for each of Chromium's processes.
- </p>
- </div>
- </div>
- </h2>
-
- <table class="list" id="memoryDetails">
- <colgroup>
- <col class="pid">
- <col class="name" >
- <col class="number">
- <col class="number">
- </colgroup>
- <tr class="firstRow doNotFilter">
- <th>
- </th>
- <th>
- </th>
- <th colspan="2">
- Memory
- </th>
- </tr>
- <tr class="secondRow doNotFilter">
- <th class="pid">
- PID
- </th>
- <th class="name">
- Name
- </th>
- <th class="number">
- Private
- </th>
- <th class="number">
- Proportional
- </th>
- </tr>
-
- <tr jsselect="browzr_data">
- <td class="pid">
- <span class="th" jscontent="pid"></span>
- </td>
- <td class="name">
- <div>
- Browser
- </div>
- </td>
- <td class="number">
- <span class="th" jseval="addToSum('tot_ws_priv', $this.ws_priv)" jscontent="formatNumber(ws_priv)"></span><span class="k">k</span>
- </td>
- <td class="number">
- <span class="th" jscontent="formatNumber(ws_shared)"></span><span class="k">k</span>
- </td>
- </tr>
- <tr jsselect="child_data">
- <td class="pid">
- <span class="th" jscontent="pid"></span>
- </td>
- <td class="name">
- <div jscontent="child_name"></div>
- <div jsselect="titles">
- <span jscontent="$this"></span><br>
- </div>
- </td>
- <td class="number">
- <span class="th" jseval="addToSum('tot_ws_priv', $this.ws_priv)" jscontent="formatNumber(ws_priv)"></span><span class="k">k</span>
- </td>
- <td class="number">
- <span class="th" jscontent="formatNumber(ws_shared)"></span><span class="k">k</span>
- </td>
- </tr>
- <tr class="total doNotFilter">
- <td class="pid">
- </td>
- <td class="name">
- &Sigma;
- </td>
- <td class="number">
- <span class="th" id="tot_ws_priv">0</span><span class="k">k</span>
- </td>
- <td class="number">
- </td>
- </tr>
-
- <tr class="noResults">
- <td colspan="99">
- No results found.
- </td>
- </tr>
- </table>
-
- <div class="otherbrowsers">(The memory usage of our renderer processes is slightly less accurate when they are sandboxed.)</div>
-
- </div>
- <script src="chrome://resources/js/i18n_template.js"></script>
- <script src="chrome://resources/js/jstemplate_compiled.js"></script>
-</body>
-</html>
diff --git a/chromium/chrome/browser/resources/about_memory_mac.html b/chromium/chrome/browser/resources/about_memory_mac.html
deleted file mode 100644
index e947f307ada..00000000000
--- a/chromium/chrome/browser/resources/about_memory_mac.html
+++ /dev/null
@@ -1,253 +0,0 @@
-<!doctype html>
-
-<!--
-about:memory template page
--->
-<html id="t">
-<head>
- <meta charset="utf-8">
- <title>About Memory</title>
- <link rel="stylesheet" href="chrome://resources/css/text_defaults.css">
- <link rel="stylesheet" href="chrome://memory-redirect/about_memory.css">
-<style>
-table.list#browserComparison tr:not([class*='firstRow']) > *:nth-child(1),
-table.list#browserComparison tr:not([class*='firstRow']) > *:nth-child(6),
-table.list#browserComparison tr.firstRow th:nth-child(1) {
- border-right: 1px solid #b5c6de;
-}
-table.list#memoryDetails tr:not([class*='firstRow']) > *:nth-child(2),
-table.list#memoryDetails tr:not([class*='firstRow']) > *:nth-child(7),
-table.list#memoryDetails tr.firstRow th:nth-child(2) {
- border-right: 1px solid #b5c6de;
-}
-</style>
-<script src="chrome://resources/js/load_time_data.js"></script>
-<script src="chrome://memory-redirect/memory.js"></script>
-<script src="chrome://memory-redirect/strings.js"></script>
-</head>
-<body>
- <div id="header">
- <h1>About memory</h1>
- <p>
- Measuring memory usage in a multi-process browser
- </p>
- </div>
-
- <div id="content">
- <h2>
- Summary
- <div class="help">
- <div>
- <p>
- Summary of memory used by currently active browsers.<p>
- For Chromium, processes used to to display diagnostics
- information (such as this "about:memory") are excluded.
- </p>
- </div>
- </div>
- </h2>
-
- <table class="list" id="browserComparison">
- <colgroup>
- <col class="name">
- <col class="number">
- <col class="number">
- <col class="number">
- <col class="number">
- </colgroup>
- <tr class="firstRow doNotFilter">
- <th>
- </th>
- <th colspan="4">
- Memory
- <div class="help">
- <div>
- <p>
- <strong>Memory</strong>
- </p>
- <p>
- <strong>Resident:</strong>
- Amount of memory that is present in physical RAM.
- This is the best indicator of browser memory resource usage.
- </p>
- <p>
- <strong>Shared:</strong>
- Amount of memory that is present in physical RAM and can
- be shared with another process.
- </p>
- <p>
- <strong>Private:</strong>
- Amount of memory that is present in physical RAM and can not
- be shared with another process.
- </p>
- <p>
- <strong>Virtual:</strong>
- Amount of address space allocated in virtual memory.
- </p>
-
- <p>
- <i>(Note that the memory for this tab is not included in the browser totals.)</i>
- </p>
- </div>
- </div>
- </th>
- </tr>
- <tr class="secondRow doNotFilter">
- <th class="name">
- Browser
- </th>
- <th class="number">
- Resident
- </th>
- <th class="number">
- Shared
- </th>
- <th class="number">
- Private
- </th>
- <th class="number">
- Virtual
- </th>
- </tr>
- <tr jsselect="browsers">
- <td class="name">
- <div>
- <strong jscontent="name"></strong> <span jscontent="version"></span>
- </div>
- </td>
- <td class="number">
- <span class="th" jscontent="formatNumber(ws_shareable)"></span><span class="k">k</span>
- </td>
- <td class="number">
- <span class="th" jscontent="formatNumber(ws_shared)"></span><span class="k">k</span>
- </td>
- <td class="number">
- <span class="th" jscontent="formatNumber(ws_priv)"></span><span class="k">k</span>
- </td>
- <td class="number">
- <span class="th" jscontent="formatNumber(comm_priv)"></span><span class="k">k</span>
- </td>
- </tr>
- </table>
- <div class="otherbrowsers" jsdisplay="browsers.length == 1">
- Note: This page will show memory use for all running browsers,
- not just Chrome.
- </div>
- <div class="otherbrowsers" jsdisplay="browsers.length > 1">
- Note: Chrome includes memory used by plugins, other browsers may not.
- </div>
- <div class="otherbrowsers">
- (Bug: We seriously overcount our own memory usage: <a href="http://crbug.com/25454">Issue 25454</a>.)
- </div>
-
- <br><br><br>
-
- <h2>
- Processes
- <div class="help">
- <div>
- <p>
- Details of memory usage for each of Chromium's processes.
- </p>
- </div>
- </div>
- </h2>
-
- <table class="list" id="memoryDetails">
- <colgroup>
- <col class="pid">
- <col class="name">
- <col class="number">
- <col class="number">
- <col class="number">
- <col class="number">
- </colgroup>
- <tr class="firstRow doNotFilter">
- <th>
- </th>
- <th>
- </th>
- <th colspan="4">
- Memory
- </th>
- </tr>
- <tr class="secondRow doNotFilter">
- <th class="pid">
- PID
- </th>
- <th class="name">
- Name
- </th>
- <th class="number">
- Resident
- </th>
- <th class="number">
- Shared
- </th>
- <th class="number">
- Private
- </th>
- <th class="number">
- Virtual
- </th>
- </tr>
-
- <tr jsselect="browzr_data">
- <td class="pid">
- <span class="th" jscontent="pid"></span>
- </td>
- <td class="name">
- <div>
- Browser
- </div>
- </td>
- <td class="number">
- <span class="th" jscontent="formatNumber(ws_shareable)"></span><span class="k">k</span>
- </td>
- <td class="number">
- <span class="th" jscontent="formatNumber(ws_shared)"></span><span class="k">k</span>
- </td>
- <td class="number">
- <span class="th" jscontent="formatNumber(ws_priv)"></span><span class="k">k</span>
- </td>
- <td class="number">
- <span class="th" jscontent="formatNumber(comm_priv)"></span><span class="k">k</span>
- </td>
- </tr>
- <tr jsselect="child_data">
- <td class="pid">
- <span class="th" jscontent="pid"></span>
- </td>
- <td class="name">
- <div jscontent="child_name"></div>
- <div jsselect="titles">
- <span jscontent="$this"></span><br>
- </div>
- </td>
- <td class="number">
- <span class="th" jscontent="formatNumber(ws_shareable)"></span><span class="k">k</span>
- </td>
- <td class="number">
- <span class="th" jscontent="formatNumber(ws_shared)"></span><span class="k">k</span>
- </td>
- <td class="number">
- <span class="th" jscontent="formatNumber(ws_priv)"></span><span class="k">k</span>
- </td>
- <td class="number">
- <span class="th" jscontent="formatNumber(comm_priv)"></span><span class="k">k</span>
- </td>
- </tr>
-
- <tr class="noResults">
- <td colspan="99">
- No results found.
- </td>
- </tr>
- </table>
- <div class="otherbrowsers">
- (Note: Due to memory sharing between processes, summing memory usage does not give total memory usage.)
- </div>
- </div>
- <script src="chrome://resources/js/jstemplate_compiled.js"></script>
-</body>
-</html>
diff --git a/chromium/chrome/browser/resources/bookmark_manager/js/compiled_resources.gyp b/chromium/chrome/browser/resources/bookmark_manager/js/compiled_resources.gyp
index 2a9872b2c40..32334374f53 100644
--- a/chromium/chrome/browser/resources/bookmark_manager/js/compiled_resources.gyp
+++ b/chromium/chrome/browser/resources/bookmark_manager/js/compiled_resources.gyp
@@ -31,6 +31,7 @@
'../../../../../ui/webui/resources/js/event_tracker.js',
'../../../../../ui/webui/resources/js/compiled_resources.gyp:i18n_template_no_process',
'../../../../../ui/webui/resources/js/load_time_data.js',
+ '../../../../../ui/webui/resources/js/promise_resolver.js',
'../../../../../ui/webui/resources/js/util.js',
'../../../../../chrome/browser/resources/bookmark_manager/js/bmm.js',
'../../../../../chrome/browser/resources/bookmark_manager/js/bmm/bookmark_list.js',
diff --git a/chromium/chrome/browser/resources/bookmark_manager/js/main.js b/chromium/chrome/browser/resources/bookmark_manager/js/main.js
index 7dc284f4cde..48e74f28feb 100644
--- a/chromium/chrome/browser/resources/bookmark_manager/js/main.js
+++ b/chromium/chrome/browser/resources/bookmark_manager/js/main.js
@@ -295,7 +295,7 @@ function setSearch(searchText) {
* This returns the user visible path to the folder where the bookmark is
* located.
* @param {number} parentId The ID of the parent folder.
- * @return {string} The path to the the bookmark,
+ * @return {string|undefined} The path to the the bookmark,
*/
function getFolder(parentId) {
var parentNode = bmm.tree.getBookmarkNodeById(parentId);
diff --git a/chromium/chrome/browser/resources/chromeos/arc_support/manifest.json b/chromium/chrome/browser/resources/chromeos/arc_support/manifest.json
new file mode 100644
index 00000000000..e78f738b865
--- /dev/null
+++ b/chromium/chrome/browser/resources/chromeos/arc_support/manifest.json
@@ -0,0 +1,19 @@
+{
+ "app": {
+ "background": {
+ "scripts": [ "background.js" ]
+ },
+ "content_security_policy": "default-src 'self'; style-src 'self' chrome://resources/ 'unsafe-inline'; font-src 'self' chrome://resources/; img-src 'self'; script-src chrome://resources/ 'self'"
+ },
+ "description": "ARC Support",
+ "display_in_launcher": false,
+ // cnbgggchhmkkdmeppjobngjoejnihlei
+ "key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnYsWobpgYLBvlN3PIFXyDwcCqRKcL+1swMf4f1Dnqn1+TYqbGW51ZNQbRo8xgE7y+0D8cz8fE0kZsQXhE7gzDKEyUgePNU75GQ3I9xdqsoNYWHGPegf2p6azj0kzJKCE+aaO4Ys7tSvvIniHfVGFuaqaS1m1JYP0Mlhv+pkwbrbVV3Ymdzb4tYP2y8jrISmyhrzlX9E2p9RU2ObSgZCUgZofMkwWZd1tyZN089sjxcPlN/RGHsB0NtpgFFhSAs9tSrRcvUUcoUTDQYeDB4qBioCJ0QUtjRj21xqsotjUQM4GFOkAxmNbijghvKoMwSulvEbgrb0x3dQl+y+ecr0ybwIDAQAB",
+ "manifest_version": 2,
+ "name": "ARC Support",
+ "icons": {
+ "48": "icon/48.png"
+ },
+ "permissions": [ "webview", "nativeMessaging", "chrome://resources/" ],
+ "version": "0.1.1.0"
+} \ No newline at end of file
diff --git a/chromium/chrome/browser/resources/chromeos/braille_ime/compiled_resources.gyp b/chromium/chrome/browser/resources/chromeos/braille_ime/compiled_resources.gyp
deleted file mode 100644
index 1722255dee1..00000000000
--- a/chromium/chrome/browser/resources/chromeos/braille_ime/compiled_resources.gyp
+++ /dev/null
@@ -1,21 +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.
-
-{
- 'targets': [
- {
- 'target_name': 'main',
- 'variables': {
- 'depends': [
- 'braille_ime.js',
- ],
- 'externs': [
- '<(EXTERNS_DIR)/chrome_extensions.js',
- 'externs.js',
- ],
- },
- 'includes': ['../../../../../third_party/closure_compiler/compile_js.gypi'],
- },
- ],
-}
diff --git a/chromium/chrome/browser/resources/chromeos/braille_ime/compiled_resources2.gyp b/chromium/chrome/browser/resources/chromeos/braille_ime/compiled_resources2.gyp
new file mode 100644
index 00000000000..b02b750ec0d
--- /dev/null
+++ b/chromium/chrome/browser/resources/chromeos/braille_ime/compiled_resources2.gyp
@@ -0,0 +1,26 @@
+# 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': 'braille_ime',
+ 'dependencies': [
+ '<(EXTERNS_GYP):chrome_extensions',
+ 'externs',
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'externs',
+ 'includes': ['../../../../../third_party/closure_compiler/include_js.gypi'],
+ },
+ {
+ 'target_name': 'main',
+ 'dependencies': [
+ 'braille_ime',
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ ],
+}
diff --git a/chromium/chrome/browser/resources/chromeos/chromevox/chromevox.gyp b/chromium/chrome/browser/resources/chromeos/chromevox/chromevox.gyp
index 5406faf0718..739204b5b7f 100644
--- a/chromium/chrome/browser/resources/chromeos/chromevox/chromevox.gyp
+++ b/chromium/chrome/browser/resources/chromeos/chromevox/chromevox.gyp
@@ -74,6 +74,7 @@
'destination': '<(chromevox_dest_dir)/cvox2/background',
'files': [
'cvox2/background/background.html',
+ 'cvox2/background/panel.css',
'cvox2/background/panel.html',
],
},
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 8d0628c980f..6066a0f5fee 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
@@ -1,7 +1,7 @@
{
"bindings": [
{
- "command": "previousElement",
+ "command": "previousObject",
"sequence": {
"cvoxModifier": true,
"keys": {
@@ -19,7 +19,7 @@
}
},
{
- "command": "nextElement",
+ "command": "nextObject",
"sequence": {
"cvoxModifier": true,
"keys": {
@@ -98,7 +98,7 @@
}
},
{
- "command": "nextCheckBox",
+ "command": "nextCheckbox",
"sequence": {
"cvoxModifier": true,
"keys": {
@@ -107,7 +107,7 @@
}
},
{
- "command": "previousCheckBox",
+ "command": "previousCheckbox",
"sequence": {
"cvoxModifier": true,
"keys": {
@@ -117,7 +117,7 @@
}
},
{
- "command": "nextCombobox",
+ "command": "nextComboBox",
"sequence": {
"cvoxModifier": true,
"keys": {
@@ -126,7 +126,7 @@
}
},
{
- "command": "previousCombobox",
+ "command": "previousComboBox",
"sequence": {
"cvoxModifier": true,
"keys": {
@@ -250,7 +250,7 @@
}
},
{
- "command": "goToEnd",
+ "command": "jumpToBottom",
"sequence": {
"cvoxModifier": true,
"keys": {
@@ -260,7 +260,7 @@
}
},
{
- "command": "goToBeginning",
+ "command": "jumpToTop",
"sequence": {
"cvoxModifier": true,
"keys": {
@@ -270,7 +270,7 @@
}
},
{
- "command": "doDefault",
+ "command": "forceClickOnCurrentItem",
"sequence": {
"cvoxModifier": true,
"keys": {
@@ -279,17 +279,16 @@
}
},
{
- "command": "showContextMenu",
+ "command": "contextMenu",
"sequence": {
"cvoxModifier": true,
"keys": {
- "keyCode": [32],
- "shitKey": [true]
+ "keyCode": [77]
}
}
},
{
- "command": "continuousRead",
+ "command": "readFromHere",
"sequence": {
"cvoxModifier": true,
"keys": {
@@ -319,11 +318,189 @@
{
"command": "toggleStickyMode",
"sequence": {
- "cvoxModifier": true,
+ "doubleTap": true,
+ "keys": {
+ "keyCode": [
+ 45
+ ]
+ },
+ "platformFilter": 5
+ }
+ },
+ {
+ "command": "toggleStickyMode",
+ "sequence": {
+ "doubleTap": true,
"keys": {
- "keyCode": [91]
+ "keyCode": [
+ 91
+ ]
},
- "doubleTap": true
+ "platformFilter": 10
+ }
+ },
+ {
+ "command": "passThroughMode",
+ "sequence": {
+ "cvoxModifier": true,
+ "keys": {
+ "keyCode": [27],
+ "shiftKey": [true]
+ }
+ }
+ },
+ {
+ "command": "openChromeVoxMenus",
+ "sequence": {
+ "cvoxModifier": true,
+ "keys": {
+ "keyCode": [190]
+ }
+ }
+ },
+ {
+ "command": "stopSpeech",
+ "sequence": {
+ "cvoxModifier": false,
+ "keys": {
+ "ctrlKey": [true],
+ "keyCode": [17]
+ }
+ }
+ },
+ {
+ "command": "decreaseTtsRate",
+ "sequence": {
+ "cvoxModifier": true,
+ "keys": {
+ "keyCode": [219]
+ }
+ }
+ },
+ {
+ "command": "increaseTtsRate",
+ "sequence": {
+ "cvoxModifier": true,
+ "keys": {
+ "keyCode": [221]
+ }
+ }
+ },
+ {
+ "command": "decreaseTtsPitch",
+ "sequence": {
+ "cvoxModifier": true,
+ "keys": {
+ "keyCode": [186]
+ }
+ }
+ },
+ {
+ "command": "increaseTtsPitch",
+ "sequence": {
+ "cvoxModifier": true,
+ "keys": {
+ "keyCode": [222]
+ }
+ }
+ },
+ {
+ "command": "stopSpeech",
+ "sequence": {
+ "keys": {
+ "ctrlKey": [true],
+ "keyCode": [17]
+ }
+ }
+ },
+ {
+ "command": "cyclePunctuationEcho",
+ "sequence": {
+ "cvoxModifier": true,
+ "keys": {
+ "keyCode": [65, 80]
+ }
+ }
+ },
+ {
+ "command": "showKbExplorerPage",
+ "sequence": {
+ "cvoxModifier": true,
+ "keys": {
+ "keyCode": [79, 75]
+ }
+ }
+ },
+ {
+ "command": "cycleTypingEcho",
+ "sequence": {
+ "cvoxModifier": true,
+ "keys": {
+ "keyCode": [65, 84]
+ }
+ }
+ },
+ {
+ "command": "showOptionsPage",
+ "sequence": {
+ "cvoxModifier": true,
+ "keys": {
+ "keyCode": [79, 79]
+ }
+ }
+ },
+ {
+ "command": "toggleEarcons",
+ "sequence": {
+ "cvoxModifier": true,
+ "keys": {
+ "keyCode": [65, 69]
+ }
+ }
+ },
+ {
+ "command": "speakTimeAndDate",
+ "sequence": {
+ "cvoxModifier": true,
+ "keys": {
+ "keyCode": [65, 68]}
+ }
+ },
+ {
+ "command": "readCurrentTitle",
+ "sequence": {
+ "cvoxModifier": true,
+ "keys": {
+ "keyCode": [65, 87]
+ }
+ }
+ },
+ {
+ "command": "readCurrentURL",
+ "sequence": {
+ "cvoxModifier": true,
+ "keys": {
+ "keyCode": [65, 85]
+ }
+ }
+ },
+ {
+ "command": "reportIssue",
+ "sequence": {
+ "cvoxModifier": true,
+ "keys": {
+ "keyCode": [65, 73]
+ }
+ }
+ },
+ {
+ "command": "toggleSearchWidget",
+ "sequence": {
+ "cvoxModifier": true,
+ "keys": {
+ "keyCode": [70],
+ "ctrlKey": [true]
+ }
}
}
]
diff --git a/chromium/chrome/browser/resources/chromeos/chromevox/chromevox_tests.gypi b/chromium/chrome/browser/resources/chromeos/chromevox/chromevox_tests.gypi
index 15127ca4555..63b56bcf829 100644
--- a/chromium/chrome/browser/resources/chromeos/chromevox/chromevox_tests.gypi
+++ b/chromium/chrome/browser/resources/chromeos/chromevox/chromevox_tests.gypi
@@ -83,6 +83,8 @@
'cvox2/background/automation_util_test.extjs',
'cvox2/background/background_test.extjs',
'cvox2/background/cursors_test.extjs',
+ 'cvox2/background/editing_test.extjs',
+ 'cvox2/background/i_search_test.extjs',
'cvox2/background/live_regions_test.extjs',
'cvox2/background/output_test.extjs',
'cvox2/background/tree_walker_test.extjs',
@@ -105,6 +107,7 @@
'<(DEPTH)/chrome/chrome_resources.gyp:chrome_strings',
'<(DEPTH)/chrome/chrome_resources.gyp:packed_extra_resources',
'<(DEPTH)/chrome/chrome_resources.gyp:packed_resources',
+ '<(DEPTH)/content/content_shell_and_tests.gyp:content_browser_test_base',
'<(DEPTH)/testing/gmock.gyp:gmock',
'<(DEPTH)/testing/gtest.gyp:gtest',
'<(DEPTH)/v8/tools/gyp/v8.gyp:v8',
@@ -124,11 +127,6 @@
'<(DEPTH)/native_client/src/trusted/service_runtime/linux/nacl_bootstrap.gyp:nacl_helper_bootstrap',
],
}],
- ['OS=="win" and win_use_allocator_shim==1', {
- 'dependencies': [
- '<(DEPTH)/base/allocator/allocator.gyp:allocator',
- ],
- }],
],
'defines': [
'HAS_OUT_OF_PROC_TEST_RUNNER',
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 878212fea90..82439a563a4 100644
--- a/chromium/chrome/browser/resources/chromeos/chromevox/strings/chromevox_strings.grd
+++ b/chromium/chrome/browser/resources/chromeos/chromevox/strings/chromevox_strings.grd
@@ -443,6 +443,9 @@
<message desc="An option to enable the page focus following the mouse. Focus represents the current HTML element or group of elements that are being spoken and can be acted upon. There is also a visual UI which highlights the focused elements. * This key's action allows the user to change focus with the mouse. Focus can also be changed using the ChromeVox navigation keys and an API." name="IDS_CHROMEVOX_OPTIONS_MOUSE_FOCUS_FOLLOWS">
Use the mouse to change focus.
</message>
+ <message desc="An option to have an item's context placed at the beginning of its description. For example, reload button, toolbar would become, toolbar, reload button" name="IDS_CHROMEVOX_OPTIONS_OUTPUT_CONTEXT_FIRST">
+ Display an item's context before other information (such as its name).
+ </message>
<message desc="An option to enhance the experience of specific sites such as Google Search." name="IDS_CHROMEVOX_OPTIONS_SITE_SPECIFIC_ENHANCEMENTS">
Enhance specific sites (like Google Search).
</message>
@@ -2390,15 +2393,18 @@
<message desc="Title of the ChromeVox panel, a window that displays the text ChromeVox is speaking and contains controls to manipulate ChromeVox." name="IDS_CHROMEVOX_PANEL_TITLE">
ChromeVox Panel
</message>
- <message desc="Title of the button that opens up the ChromeVox menu." name="IDS_CHROMEVOX_MENU_TITLE">
- ChromeVox Menu
+ <message desc="Title of the button that opens up the ChromeVox menus." name="IDS_CHROMEVOX_MENUS_TITLE">
+ ChromeVox Menus
</message>
- <message desc="Title of the button that opens up the ChromeVox menu." name="IDS_CHROMEVOX_OPTIONS">
+ <message desc="Title of the button that opens up ChromeVox options." name="IDS_CHROMEVOX_OPTIONS">
ChromeVox Options
</message>
<message desc="Title of the button that disables ChromeVox." name="IDS_CHROMEVOX_DISABLE_CHROMEVOX">
Disable ChromeVox
</message>
+ <message desc="Text in parentheses to be appended next to a tab that's currently active." name="IDS_CHROMEVOX_ACTIVE_TAB">
+ (active)
+ </message>
</messages>
</release>
</grit>
diff --git a/chromium/chrome/browser/resources/chromeos/network_ui/compiled_resources2.gyp b/chromium/chrome/browser/resources/chromeos/network_ui/compiled_resources2.gyp
new file mode 100644
index 00000000000..2f02c48d669
--- /dev/null
+++ b/chromium/chrome/browser/resources/chromeos/network_ui/compiled_resources2.gyp
@@ -0,0 +1,18 @@
+# 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': 'network_ui',
+ 'dependencies': [
+ '<(DEPTH)/ui/webui/resources/cr_elements/network/compiled_resources2.gyp:cr_network_icon_externs',
+ '<(DEPTH)/ui/webui/resources/cr_elements/network/compiled_resources2.gyp:cr_onc_types',
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:load_time_data',
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:util',
+ '<(EXTERNS_GYP):networking_private',
+ ],
+ '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 80e80afc8cd..6a84d8e4b9b 100644
--- a/chromium/chrome/browser/resources/component_extension_resources.grd
+++ b/chromium/chrome/browser/resources/component_extension_resources.grd
@@ -144,6 +144,12 @@
<include name="IDR_FIRST_RUN_DIALOG_ICON_96" file="chromeos/first_run/app/icon/96.png" type="BINDATA" />
<include name="IDR_FIRST_RUN_DIALOG_ICON_128" file="chromeos/first_run/app/icon/128.png" type="BINDATA" />
<include name="IDR_FIRST_RUN_DIALOG_ICON_256" file="chromeos/first_run/app/icon/256.png" type="BINDATA" />
+ <include name="IDR_ARC_SUPPORT_BACKGROUND_JS" file="chromeos/arc_support/background.js" flattenhtml="true" type="BINDATA" />
+ <include name="IDR_ARC_SUPPORT_MAIN_CSS" file="chromeos/arc_support/main.css" type="BINDATA" />
+ <include name="IDR_ARC_SUPPORT_MAIN" file="chromeos/arc_support/main.html" allowexternalscript="true" type="BINDATA" />
+ <include name="IDR_ARC_SUPPORT_ICON" file="chromeos/arc_support/icon/48.png" type="BINDATA" />
+ <include name="IDR_ARC_SUPPORT_ICON_PLAYSTORE" file="chromeos/arc_support/images/play_store_96dp.png" type="BINDATA" />
+ <include name="IDR_ARC_SUPPORT_ICON_CHROME" file="chromeos/arc_support/images/chrome_96dp.png" type="BINDATA" />
</if>
<if expr="enable_settings_app">
<include name="IDR_SETTINGS_APP_JS" file="settings_app/settings_app.js" type="BINDATA" />
@@ -205,9 +211,7 @@
<include name="IDR_CRYPTOTOKEN_GNUBBIES_JS" file="cryptotoken/gnubbies.js" type="BINDATA" />
<include name="IDR_CRYPTOTOKEN_GNUBBY_JS" file="cryptotoken/gnubby.js" type="BINDATA" />
<include name="IDR_CRYPTOTOKEN_GNUBBY_U2F_JS" file="cryptotoken/gnubby-u2f.js" type="BINDATA" />
- <include name="IDR_CRYPTOTOKEN_GNUBBYCODETYPES_JS" file="cryptotoken/gnubbycodetypes.js" type="BINDATA" />
<include name="IDR_CRYPTOTOKEN_GNUBBYFACTORY_JS" file="cryptotoken/gnubbyfactory.js" type="BINDATA" />
- <include name="IDR_CRYPTOTOKEN_GNUBBYMSGTYPES_JS" file="cryptotoken/gnubbymsgtypes.js" type="BINDATA" />
<include name="IDR_CRYPTOTOKEN_USBGNUBBYFACTORY_JS" file="cryptotoken/usbgnubbyfactory.js" type="BINDATA" />
<include name="IDR_CRYPTOTOKEN_DEVICESTATUSCODES_JS" file="cryptotoken/devicestatuscodes.js" type="BINDATA" />
<include name="IDR_CRYPTOTOKEN_ENROLLER_JS" file="cryptotoken/enroller.js" type="BINDATA" />
diff --git a/chromium/chrome/browser/resources/cryptotoken/gnubbies.js b/chromium/chrome/browser/resources/cryptotoken/gnubbies.js
index 8cd25282f98..86eb6e6a716 100644
--- a/chromium/chrome/browser/resources/cryptotoken/gnubbies.js
+++ b/chromium/chrome/browser/resources/cryptotoken/gnubbies.js
@@ -16,11 +16,23 @@
var GnubbyDeviceId;
/**
+ * Ways in which gnubby devices are enumerated.
+ * @const
+ * @enum {number}
+ */
+var GnubbyEnumerationTypes = {
+ ANY: 0,
+ VID_PID: 1,
+ FIDO_U2F: 2
+};
+
+/**
* @typedef {{
* isSharedAccess: boolean,
- * enumerate: function(function(Array)),
+ * enumerate: function(function(Array), GnubbyEnumerationTypes=),
* deviceToDeviceId: function(*): GnubbyDeviceId,
- * open: function(Gnubbies, number, *, function(number, GnubbyDevice=))
+ * open: function(Gnubbies, number, *, function(number, GnubbyDevice=)),
+ * cancelOpen: (undefined|function(Gnubbies, number, *))
* }}
*/
var GnubbyNamespaceImpl;
@@ -41,7 +53,7 @@ function Gnubbies() {
this.namespaces_ = [];
/** @private {Object<string, GnubbyNamespaceImpl>} */
this.impl_ = {};
- /** @private {Object<string, Object<number, !GnubbyDevice>>} */
+ /** @private {Object<string, Object<number|string, !GnubbyDevice>>} */
this.openDevs_ = {};
/** @private {Object<string, Object<number, *>>} */
this.pendingOpens_ = {}; // clients awaiting an open
@@ -97,10 +109,20 @@ Gnubbies.prototype.closeAll = function() {
};
/**
+ * @param {string} namespace
+ * @return {function(*)} deviceToDeviceId method associated with given namespace
+ * @private
+ */
+Gnubbies.prototype.getDeviceToDeviceId_ = function(namespace) {
+ return this.impl_[namespace].deviceToDeviceId;
+};
+
+/**
* @param {function(number, Array<GnubbyDeviceId>)} cb Called back with the
* result of enumerating.
+ * @param {GnubbyEnumerationTypes=} opt_type Which type of enumeration to do.
*/
-Gnubbies.prototype.enumerate = function(cb) {
+Gnubbies.prototype.enumerate = function(cb, opt_type) {
if (!cb) {
cb = function(rc, indexes) {
var msg = 'defaultEnumerateCallback(' + rc;
@@ -145,7 +167,7 @@ Gnubbies.prototype.enumerate = function(cb) {
var presentDevs = {};
var deviceIds = [];
- var deviceToDeviceId = self.impl_[namespace].deviceToDeviceId;
+ var deviceToDeviceId = self.getDeviceToDeviceId_(namespace);
for (var i = 0; i < devs.length; ++i) {
var deviceId = deviceToDeviceId(devs[i]);
deviceIds.push(deviceId);
@@ -189,7 +211,7 @@ Gnubbies.prototype.enumerate = function(cb) {
for (var i = 0; i < this.namespaces_.length; i++) {
var namespace = this.namespaces_[i];
var enumerator = this.impl_[namespace].enumerate;
- enumerator(makeEnumerateCb(namespace));
+ enumerator(makeEnumerateCb(namespace), opt_type);
}
}
};
@@ -274,7 +296,7 @@ Gnubbies.prototype.addClient = function(which, who, cb) {
}
var dev = null;
- var deviceToDeviceId = this.impl_[which.namespace].deviceToDeviceId;
+ var deviceToDeviceId = this.getDeviceToDeviceId_(which.namespace);
if (this.devs_[which.namespace]) {
for (var i = 0; i < this.devs_[which.namespace].length; i++) {
var device = this.devs_[which.namespace][i];
@@ -332,6 +354,35 @@ Gnubbies.prototype.addClient = function(which, who, cb) {
};
/**
+ * Called to cancel add client operation
+ * @param {GnubbyDeviceId} which Which device to cancel open.
+ */
+Gnubbies.prototype.cancelAddClient = function(which) {
+ var dev = null;
+ var deviceToDeviceId = this.getDeviceToDeviceId_(which.namespace);
+ if (this.devs_[which.namespace]) {
+ for (var i = 0; i < this.devs_[which.namespace].length; i++) {
+ var device = this.devs_[which.namespace][i];
+ if (deviceToDeviceId(device).device == which.device) {
+ dev = device;
+ break;
+ }
+ }
+ }
+
+ if (!dev) {
+ return;
+ }
+
+ if (this.pendingOpens_[which.namespace] &&
+ this.pendingOpens_[which.namespace][which.device]) {
+ var cancelOpenImpl = this.impl_[which.namespace].cancelOpen;
+ if (cancelOpenImpl)
+ cancelOpenImpl(this, which.device, dev);
+ }
+};
+
+/**
* Removes a client from a low-level gnubby.
* @param {GnubbyDevice} whichDev The gnubby.
* @param {*} who The client.
diff --git a/chromium/chrome/browser/resources/cryptotoken/gnubby-u2f.js b/chromium/chrome/browser/resources/cryptotoken/gnubby-u2f.js
index a5ae8b56666..47ac6f652be 100644
--- a/chromium/chrome/browser/resources/cryptotoken/gnubby-u2f.js
+++ b/chromium/chrome/browser/resources/cryptotoken/gnubby-u2f.js
@@ -134,19 +134,33 @@ Gnubby.prototype.version = function(cb) {
return;
}
var self = this;
+
+ function gotResponse(rc, data) {
+ if (!rc) {
+ self.version_ = data;
+ }
+ cb(rc, data);
+ }
+
var apdu = new Uint8Array([0x00, Gnubby.U2F_VERSION, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00]);
+ 0x00, 0x00]);
this.apduReply(apdu.buffer, function(rc, data) {
if (rc == 0x6d00) {
// Command not implemented. Pretend this is v1.
var v1 = new Uint8Array(UTIL_StringToBytes(Gnubby.U2F_V1));
self.version_ = v1.buffer;
cb(-GnubbyDevice.OK, v1.buffer);
- } else {
- if (!rc) {
- self.version_ = data;
- }
- cb(rc, data);
+ return;
+ }
+ if (rc == 0x6700) {
+ // Wrong length. Try with non-ISO 7816-4-conforming layout defined in
+ // earlier U2F drafts.
+ apdu = new Uint8Array([0x00, Gnubby.U2F_VERSION, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00]);
+ self.apduReply(apdu.buffer, gotResponse);
+ return;
}
+ // Any other response: handle as final result.
+ gotResponse(rc, data);
});
};
diff --git a/chromium/chrome/browser/resources/cryptotoken/gnubby.js b/chromium/chrome/browser/resources/cryptotoken/gnubby.js
index b283ee97a53..197f9fb33d8 100644
--- a/chromium/chrome/browser/resources/cryptotoken/gnubby.js
+++ b/chromium/chrome/browser/resources/cryptotoken/gnubby.js
@@ -57,20 +57,33 @@ Gnubby.hexCid = function(cid) {
};
/**
+ * Cancels open attempt for this gnubby, if available.
+ */
+Gnubby.prototype.cancelOpen = function() {
+ if (this.which)
+ Gnubby.gnubbies_.cancelAddClient(this.which);
+};
+
+/**
* Opens the gnubby with the given index, or the first found gnubby if no
* index is specified.
* @param {GnubbyDeviceId} which The device to open. If null, the first
* gnubby found is opened.
+ * @param {GnubbyEnumerationTypes=} opt_type Which type of device to enumerate.
* @param {function(number)|undefined} opt_cb Called with result of opening the
* gnubby.
+ * @param {string=} opt_caller Identifier for the caller.
*/
-Gnubby.prototype.open = function(which, opt_cb) {
+Gnubby.prototype.open = function(which, opt_type, opt_cb, opt_caller) {
var cb = opt_cb ? opt_cb : Gnubby.defaultCallback;
if (this.closed) {
cb(-GnubbyDevice.NODEVICE);
return;
}
this.closingWhenIdle = false;
+ if (opt_caller) {
+ this.caller_ = opt_caller;
+ }
var self = this;
@@ -94,7 +107,7 @@ Gnubby.prototype.open = function(which, opt_cb) {
if (rc == -GnubbyDevice.NODEVICE && enumerateRetriesRemaining-- > 0) {
// We were trying to open the first device, but now it's not there?
// Do over.
- Gnubby.gnubbies_.enumerate(enumerated);
+ Gnubby.gnubbies_.enumerate(enumerated, opt_type);
return;
}
self.dev = device;
@@ -110,7 +123,7 @@ Gnubby.prototype.open = function(which, opt_cb) {
cb(rc);
});
} else {
- Gnubby.gnubbies_.enumerate(enumerated);
+ Gnubby.gnubbies_.enumerate(enumerated, opt_type);
}
};
diff --git a/chromium/chrome/browser/resources/cryptotoken/gnubbycodetypes.js b/chromium/chrome/browser/resources/cryptotoken/gnubbycodetypes.js
deleted file mode 100644
index 94b8ab5283b..00000000000
--- a/chromium/chrome/browser/resources/cryptotoken/gnubbycodetypes.js
+++ /dev/null
@@ -1,32 +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.
-
-/**
- * @fileoverview This provides the different code types for the gnubby
- * operations.
- */
-
-/**
- * @const
- * @enum {number}
- */
-var GnubbyCodeTypes = {
- /** Request succeeded. */
- 'OK': 0,
-
- /** All plugged in devices are already enrolled. */
- 'ALREADY_ENROLLED': 2,
-
- /** None of the plugged in devices are enrolled. */
- 'NONE_PLUGGED_ENROLLED': 3,
-
- /** One or more devices are waiting for touch. */
- 'WAIT_TOUCH': 4,
-
- /** Unknown error. */
- 'UNKNOWN_ERROR': 7,
-
- /** Bad request. */
- 'BAD_REQUEST': 12
-};
diff --git a/chromium/chrome/browser/resources/cryptotoken/gnubbyfactory.js b/chromium/chrome/browser/resources/cryptotoken/gnubbyfactory.js
index ffe386cac14..5be99d6765c 100644
--- a/chromium/chrome/browser/resources/cryptotoken/gnubbyfactory.js
+++ b/chromium/chrome/browser/resources/cryptotoken/gnubbyfactory.js
@@ -31,9 +31,13 @@ var FactoryOpenCallback;
* @param {string=} opt_appIdHash The base64-encoded hash of the app id for
* which the gnubby being opened.
* @param {string=} opt_logMsgUrl The url to post log messages to.
+ * @param {string=} opt_caller Identifier for the caller.
+ * @return {(function ()|undefined)} Some implementations might return function
+ * that can be used to cancel this pending open operation. Opening device
+ * might take long time or be resource-hungry.
*/
GnubbyFactory.prototype.openGnubby =
- function(which, forEnroll, cb, opt_appIdHash, opt_logMsgUrl) {
+ function(which, forEnroll, cb, opt_appIdHash, opt_logMsgUrl, opt_caller) {
};
/**
diff --git a/chromium/chrome/browser/resources/cryptotoken/gnubbymsgtypes.js b/chromium/chrome/browser/resources/cryptotoken/gnubbymsgtypes.js
deleted file mode 100644
index 8695d0698ac..00000000000
--- a/chromium/chrome/browser/resources/cryptotoken/gnubbymsgtypes.js
+++ /dev/null
@@ -1,46 +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.
-
-/**
- * @fileoverview This provides the different message types for the gnubby
- * operations.
- */
-
-var GnubbyMsgTypes = {};
-
-/**
- * Enroll request message type.
- * @const
- */
-GnubbyMsgTypes.ENROLL_WEB_REQUEST = 'enroll_web_request';
-
-/**
- * Enroll reply message type.
- * @const
- */
-GnubbyMsgTypes.ENROLL_WEB_REPLY = 'enroll_web_reply';
-
-/**
- * Enroll notification message type.
- * @const
- */
-GnubbyMsgTypes.ENROLL_WEB_NOTIFICATION = 'enroll_web_notification';
-
-/**
- * Sign request message type.
- * @const
- */
-GnubbyMsgTypes.SIGN_WEB_REQUEST = 'sign_web_request';
-
-/**
- * Sign reply message type.
- * @const
- */
-GnubbyMsgTypes.SIGN_WEB_REPLY = 'sign_web_reply';
-
-/**
- * Sign notification message type.
- * @const
- */
-GnubbyMsgTypes.SIGN_WEB_NOTIFICATION = 'sign_web_notification';
diff --git a/chromium/chrome/browser/resources/cryptotoken/hidgnubbydevice.js b/chromium/chrome/browser/resources/cryptotoken/hidgnubbydevice.js
index 1ad59d12895..80c40c00b16 100644
--- a/chromium/chrome/browser/resources/cryptotoken/hidgnubbydevice.js
+++ b/chromium/chrome/browser/resources/cryptotoken/hidgnubbydevice.js
@@ -416,8 +416,9 @@ HidGnubbyDevice.HID_VID_PIDS = [
/**
* @param {function(Array)} cb Enumeration callback
+ * @param {GnubbyEnumerationTypes=} opt_type Which type of enumeration to do.
*/
-HidGnubbyDevice.enumerate = function(cb) {
+HidGnubbyDevice.enumerate = function(cb, opt_type) {
/**
* One pass using getDevices, and one for each of the hardcoded vid/pids.
* @const
@@ -452,13 +453,24 @@ HidGnubbyDevice.enumerate = function(cb) {
}
}
- // Pass 1: usagePage-based enumeration.
- chrome.hid.getDevices({filters: [{usagePage: 0xf1d0}]},
- enumerated.bind(null, true));
- // Pass 2: vid/pid-based enumeration, for legacy devices.
- 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));
+ // 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.)
+ if (opt_type == GnubbyEnumerationTypes.VID_PID) {
+ enumerated(true, []);
+ } else {
+ chrome.hid.getDevices({filters: [{usagePage: 0xf1d0}]},
+ enumerated.bind(null, true));
+ }
+ // Pass 2: vid/pid-based enumeration, for legacy devices. If FIDO devices
+ // are asked for, "implement" this pass by providing it the empty list.
+ if (opt_type == GnubbyEnumerationTypes.FIDO_U2F) {
+ 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));
+ }
}
};
diff --git a/chromium/chrome/browser/resources/cryptotoken/manifest.json b/chromium/chrome/browser/resources/cryptotoken/manifest.json
index 0ba3a03bc5b..6e4c46df243 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.31",
+ "version": "0.9.38",
"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/singlesigner.js b/chromium/chrome/browser/resources/cryptotoken/singlesigner.js
index 445f96d698e..b76cc991fc2 100644
--- a/chromium/chrome/browser/resources/cryptotoken/singlesigner.js
+++ b/chromium/chrome/browser/resources/cryptotoken/singlesigner.js
@@ -74,6 +74,9 @@ function SingleGnubbySigner(gnubbyId, forEnroll, completeCb, timer,
/** @private {!Object<string, number>} */
this.cachedError_ = [];
+
+ /** @private {(function()|undefined)} */
+ this.openCanceller_;
}
/** @enum {number} */
@@ -107,6 +110,11 @@ SingleGnubbySigner.prototype.getDeviceId = function() {
* Closes this signer's gnubby, if it's held.
*/
SingleGnubbySigner.prototype.close = function() {
+ if (this.state_ == SingleGnubbySigner.State.OPENING) {
+ if (this.openCanceller_)
+ this.openCanceller_();
+ }
+
if (!this.gnubby_) return;
this.state_ = SingleGnubbySigner.State.CLOSING;
this.gnubby_.closeWhenIdle(this.closed_.bind(this));
@@ -185,12 +193,13 @@ SingleGnubbySigner.prototype.open_ = function() {
}
if (this.state_ == SingleGnubbySigner.State.INIT) {
this.state_ = SingleGnubbySigner.State.OPENING;
- DEVICE_FACTORY_REGISTRY.getGnubbyFactory().openGnubby(
+ this.openCanceller_ = DEVICE_FACTORY_REGISTRY.getGnubbyFactory().openGnubby(
this.gnubbyId_,
this.forEnroll_,
this.openCallback_.bind(this),
appIdHash,
- this.logMsgUrl_);
+ this.logMsgUrl_,
+ 'singlesigner.js:SingleGnubbySigner.prototype.open_');
}
};
@@ -233,11 +242,13 @@ SingleGnubbySigner.prototype.openCallback_ = function(rc, gnubby) {
var self = this;
window.setTimeout(function() {
if (self.gnubby_) {
- DEVICE_FACTORY_REGISTRY.getGnubbyFactory().openGnubby(
+ this.openCanceller_ = DEVICE_FACTORY_REGISTRY
+ .getGnubbyFactory().openGnubby(
self.gnubbyId_,
self.forEnroll_,
self.openCallback_.bind(self),
- self.logMsgUrl_);
+ self.logMsgUrl_,
+ 'singlesigner.js:SingleGnubbySigner.prototype.openCallback_');
}
}, SingleGnubbySigner.OPEN_DELAY_MILLIS);
} else {
diff --git a/chromium/chrome/browser/resources/cryptotoken/usbgnubbydevice.js b/chromium/chrome/browser/resources/cryptotoken/usbgnubbydevice.js
index 723d1252f23..e37f9b31e10 100644
--- a/chromium/chrome/browser/resources/cryptotoken/usbgnubbydevice.js
+++ b/chromium/chrome/browser/resources/cryptotoken/usbgnubbydevice.js
@@ -396,8 +396,16 @@ UsbGnubbyDevice.WINUSB_VID_PIDS = [
/**
* @param {function(Array)} cb Enumerate callback
+ * @param {GnubbyEnumerationTypes=} opt_type Which type of enumeration to do.
*/
-UsbGnubbyDevice.enumerate = function(cb) {
+UsbGnubbyDevice.enumerate = function(cb, opt_type) {
+ // UsbGnubbyDevices are all non-FIDO devices, so return an empty list if
+ // FIDO is what's wanted.
+ if (opt_type == GnubbyEnumerationTypes.FIDO_U2F) {
+ cb([]);
+ return;
+ }
+
var numEnumerated = 0;
var allDevs = [];
diff --git a/chromium/chrome/browser/resources/cryptotoken/usbgnubbyfactory.js b/chromium/chrome/browser/resources/cryptotoken/usbgnubbyfactory.js
index 9b110a6c53c..20c6410e5fd 100644
--- a/chromium/chrome/browser/resources/cryptotoken/usbgnubbyfactory.js
+++ b/chromium/chrome/browser/resources/cryptotoken/usbgnubbyfactory.js
@@ -27,12 +27,14 @@ function UsbGnubbyFactory(gnubbies) {
* @param {string=} opt_appIdHash The base64-encoded hash of the app id for
* which the gnubby being opened.
* @param {string=} opt_logMsgUrl The url to post log messages to.
+ * @param {string=} opt_caller Identifier for the caller.
+ * @return {undefined} no open canceller needed for this type of gnubby
* @override
*/
UsbGnubbyFactory.prototype.openGnubby =
- function(which, forEnroll, cb, opt_appIdHash, opt_logMsgUrl) {
+ function(which, forEnroll, cb, opt_appIdHash, opt_logMsgUrl, opt_caller) {
var gnubby = new Gnubby();
- gnubby.open(which, function(rc) {
+ gnubby.open(which, GnubbyEnumerationTypes.ANY, function(rc) {
if (rc) {
cb(rc, gnubby);
return;
@@ -40,7 +42,7 @@ UsbGnubbyFactory.prototype.openGnubby =
gnubby.sync(function(rc) {
cb(rc, gnubby);
});
- });
+ }, opt_caller);
};
/**
diff --git a/chromium/chrome/browser/resources/cryptotoken/webrequest.js b/chromium/chrome/browser/resources/cryptotoken/webrequest.js
index 0564559c233..6c77e3f3b7d 100644
--- a/chromium/chrome/browser/resources/cryptotoken/webrequest.js
+++ b/chromium/chrome/browser/resources/cryptotoken/webrequest.js
@@ -237,7 +237,7 @@ function sendResponseOnce(sentResponse, closeable, response, sendResponse) {
console.warn('sendResponse failed: ' + exception);
}
} else {
- console.warn(UTIL_fmt('Tried to reply more than once! Juan, FIX ME'));
+ console.warn(UTIL_fmt('Tried to reply more than once!'));
}
}
@@ -251,6 +251,8 @@ function sha256HashOfString(string) {
return s.digest();
}
+var UNUSED_CID_PUBKEY_VALUE = 'unused';
+
/**
* Normalizes the TLS channel ID value:
* 1. Converts semantically empty values (undefined, null, 0) to the empty
@@ -262,9 +264,9 @@ function sha256HashOfString(string) {
*/
function tlsChannelIdValue(opt_tlsChannelId) {
if (!opt_tlsChannelId) {
- // Case 1: Always set some value for TLS channel ID, even if it's the empty
+ // Case 1: Always set some value for TLS channel ID, even if it's the empty
// string: this browser definitely supports them.
- return '';
+ return UNUSED_CID_PUBKEY_VALUE;
}
if (typeof opt_tlsChannelId === 'string') {
try {
@@ -273,7 +275,7 @@ function tlsChannelIdValue(opt_tlsChannelId) {
// Case 1: The string value 'null' parses as the Javascript object null,
// so return an empty string: the browser definitely supports TLS
// channel id.
- return '';
+ return UNUSED_CID_PUBKEY_VALUE;
}
// Case 2: return the value as a JS object.
return /** @type {Object} */ (obj);
diff --git a/chromium/chrome/browser/resources/device_log_ui/device_log_ui.css b/chromium/chrome/browser/resources/device_log_ui/device_log_ui.css
index 3a8ea55aa53..76e1092eadf 100644
--- a/chromium/chrome/browser/resources/device_log_ui/device_log_ui.css
+++ b/chromium/chrome/browser/resources/device_log_ui/device_log_ui.css
@@ -99,7 +99,7 @@ body {
height: 14px;
margin-top: 2px;
padding: 0 4px 2px 4px;
- width: 50px;
+ width: 65px;
}
.log-type-login {
diff --git a/chromium/chrome/browser/resources/device_log_ui/device_log_ui.html b/chromium/chrome/browser/resources/device_log_ui/device_log_ui.html
index fbf99dfa2d8..17635afc445 100644
--- a/chromium/chrome/browser/resources/device_log_ui/device_log_ui.html
+++ b/chromium/chrome/browser/resources/device_log_ui/device_log_ui.html
@@ -46,6 +46,10 @@
<span i18n-content="logTypePowerText"></span>
</label>
<label>
+ <input id="log-type-bluetooth" type="checkbox">
+ <span i18n-content="logTypeBluetoothText"></span>
+ </label>
+ <label>
<input id="log-type-usb" type="checkbox">
<span i18n-content="logTypeUsbText"></span>
</label>
diff --git a/chromium/chrome/browser/resources/device_log_ui/device_log_ui.js b/chromium/chrome/browser/resources/device_log_ui/device_log_ui.js
index a562ed7eddb..acee79aa41d 100644
--- a/chromium/chrome/browser/resources/device_log_ui/device_log_ui.js
+++ b/chromium/chrome/browser/resources/device_log_ui/device_log_ui.js
@@ -95,7 +95,12 @@ var DeviceLogUI = (function() {
* @param {Object} data A JSON structure of event log entries.
*/
var getLogCallback = function(data) {
- createEventLog(JSON.parse(data));
+ try {
+ createEventLog(JSON.parse(data));
+ } catch(e) {
+ var container = $('log-container');
+ container.textContent = 'No log entries';
+ }
};
/**
diff --git a/chromium/chrome/browser/resources/downloads/OWNERS b/chromium/chrome/browser/resources/downloads/OWNERS
deleted file mode 100644
index cd46f8deb58..00000000000
--- a/chromium/chrome/browser/resources/downloads/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-asanka@chromium.org
-dbeam@chromium.org
diff --git a/chromium/chrome/browser/resources/downloads/compiled_resources.gyp b/chromium/chrome/browser/resources/downloads/compiled_resources.gyp
deleted file mode 100644
index 25184bdbd81..00000000000
--- a/chromium/chrome/browser/resources/downloads/compiled_resources.gyp
+++ /dev/null
@@ -1,33 +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.
-{
- 'targets': [
- {
- 'target_name': 'manager',
- 'variables': {
- 'depends': [
- '../../../../ui/webui/resources/js/action_link.js',
- '../../../../ui/webui/resources/js/assert.js',
- '../../../../ui/webui/resources/js/compiled_resources.gyp:load_time_data',
- '../../../../ui/webui/resources/js/cr.js',
- '../../../../ui/webui/resources/js/cr/ui.js',
- '../../../../ui/webui/resources/js/cr/ui/command.js',
- '../../../../ui/webui/resources/js/cr/ui/focus_grid.js',
- '../../../../ui/webui/resources/js/cr/ui/focus_row.js',
- '../../../../ui/webui/resources/js/event_tracker.js',
- '../../../../ui/webui/resources/js/util.js',
- 'constants.js',
- 'throttled_icon_loader.js',
- 'item_view.js',
- 'focus_row.js',
- ],
- 'externs': [
- '<(EXTERNS_DIR)/chrome_send.js',
- 'externs.js',
- ],
- },
- 'includes': ['../../../../third_party/closure_compiler/compile_js.gypi'],
- }
- ],
-}
diff --git a/chromium/chrome/browser/resources/downloads/constants.html b/chromium/chrome/browser/resources/downloads/constants.html
deleted file mode 100644
index 0ac6c26b9e5..00000000000
--- a/chromium/chrome/browser/resources/downloads/constants.html
+++ /dev/null
@@ -1,2 +0,0 @@
-<link rel="import" href="chrome://resources/html/cr.html">
-<script src="chrome://downloads/constants.js"></script>
diff --git a/chromium/chrome/browser/resources/downloads/constants.js b/chromium/chrome/browser/resources/downloads/constants.js
deleted file mode 100644
index b123be03919..00000000000
--- a/chromium/chrome/browser/resources/downloads/constants.js
+++ /dev/null
@@ -1,38 +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('downloads', function() {
- /**
- * Explains why a download is in DANGEROUS state.
- * @enum {string}
- */
- var DangerType = {
- NOT_DANGEROUS: 'NOT_DANGEROUS',
- DANGEROUS_FILE: 'DANGEROUS_FILE',
- DANGEROUS_URL: 'DANGEROUS_URL',
- DANGEROUS_CONTENT: 'DANGEROUS_CONTENT',
- UNCOMMON_CONTENT: 'UNCOMMON_CONTENT',
- DANGEROUS_HOST: 'DANGEROUS_HOST',
- POTENTIALLY_UNWANTED: 'POTENTIALLY_UNWANTED',
- };
-
- /**
- * The states a download can be in. These correspond to states defined in
- * DownloadsDOMHandler::CreateDownloadItemValue
- * @enum {string}
- */
- var States = {
- IN_PROGRESS: 'IN_PROGRESS',
- CANCELLED: 'CANCELLED',
- COMPLETE: 'COMPLETE',
- PAUSED: 'PAUSED',
- DANGEROUS: 'DANGEROUS',
- INTERRUPTED: 'INTERRUPTED',
- };
-
- return {
- DangerType: DangerType,
- States: States,
- };
-});
diff --git a/chromium/chrome/browser/resources/downloads/downloads.css b/chromium/chrome/browser/resources/downloads/downloads.css
deleted file mode 100644
index dd6bb7dcb47..00000000000
--- a/chromium/chrome/browser/resources/downloads/downloads.css
+++ /dev/null
@@ -1,163 +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 src="../search_header.css">
-
-#downloads-summary-text {
- font-weight: bold;
-}
-
-#download-actions {
- -webkit-margin-start: 16px;
-}
-
-#downloads-actions > * ~ * {
- -webkit-margin-start: 10px;
-}
-
-#downloads-display,
-#no-downloads-or-results {
- max-width: 740px;
- padding: 0 10px 34px;
-}
-
-.download {
- -webkit-margin-start: 114px;
- -webkit-padding-start: 52px;
- margin-bottom: 15px;
- position: relative;
-}
-
-.download,
-#no-downloads-or-results {
- margin-top: 6px;
-}
-
-.date-container {
- left: -110px;
- position: absolute;
- width: 110px;
-}
-
-html[dir=rtl] .date-container {
- left: auto;
- right: -110px;
-}
-
-.date-container .since {
- color: black;
-}
-
-.date-container .date {
- color: #666;
-}
-
-.download .icon {
- height: 32px;
- left: 9px;
- position: absolute;
- top: 2px;
- width: 32px;
-}
-
-html[dir=rtl] .icon {
- left: auto;
- right: 9px;
-}
-
-.download.otr > :-webkit-any(.safe, .dangerous) {
- -webkit-transition: opacity 150ms;
- background: url(../../../../ui/webui/resources/images/otr_icon_standalone.png)
- no-repeat right bottom;
- opacity: .66;
-}
-
-html[dir=rtl] .download.otr > :-webkit-any(.safe, .dangerous) {
- background-position: left bottom;
-}
-
-.download.otr > :-webkit-any(.safe, .dangerous):hover {
- opacity: 1;
-}
-
-.description.malware {
- color: rgb(196, 42, 23);
-}
-
-.progress {
- height: 48px;
- left: 0;
- position: absolute;
- top: -6px;
- width: 48px;
-}
-
-html[dir=rtl] .progress {
- left: auto;
- right: 0;
-}
-
-.progress.background {
- background: url(chrome://theme/IDR_DOWNLOAD_PROGRESS_BACKGROUND_32);
- background-size: 48px;
-}
-
-.title-area {
- align-items: baseline;
- display: flex;
-}
-
-.title-area > * {
- flex-shrink: 0;
-}
-
-.name,
-.src-url,
-.controls a,
-.description {
- -webkit-padding-end: 4px;
- -webkit-padding-start: 4px;
-}
-
-.name {
- -webkit-padding-end: 16px;
- display: inline-block;
- max-width: 450px;
- word-break: break-all;
-}
-
-.interrupted {
- color: red;
-}
-
-.download .status {
- color: #999;
- white-space: nowrap;
-}
-
-.download .src-url {
- color: rgb(85, 102, 221);
- display: inline-block;
- max-width: 500px;
- overflow: hidden;
- padding-bottom: 1px;
- padding-top: 4px;
- text-decoration: none;
- text-overflow: ellipsis;
- white-space: nowrap;
-}
-
-.controls a {
- -webkit-margin-end: 12px;
- color: #777;
-}
-
-.safe .controls a {
- display: inline;
-}
-
-#downloads-pagination {
- -webkit-margin-start: 18px;
- padding-top: 24px;
-}
diff --git a/chromium/chrome/browser/resources/downloads/downloads.html b/chromium/chrome/browser/resources/downloads/downloads.html
deleted file mode 100644
index 4349816fdd8..00000000000
--- a/chromium/chrome/browser/resources/downloads/downloads.html
+++ /dev/null
@@ -1,104 +0,0 @@
-<!doctype html>
-<html i18n-values="dir:textdirection;lang:language">
-<head>
- <meta charset="utf-8">
- <title i18n-content="title"></title>
- <link rel="stylesheet" href="chrome://resources/css/chrome_shared.css">
- <!-- This has to come after chrome_shared.css -->
- <link rel="stylesheet" href="downloads.css">
- <script src="chrome://resources/js/action_link.js"></script>
- <link rel="import" href="chrome://resources/html/assert.html">
- <link rel="import" href="chrome://resources/html/cr.html">
- <script src="chrome://resources/js/cr/ui.js"></script>
- <script src="chrome://resources/js/cr/ui/command.js"></script>
- <script src="chrome://resources/js/load_time_data.js"></script>
- <script src="chrome://resources/js/util.js"></script>
- <script src="chrome://resources/js/event_tracker.js"></script>
- <script src="chrome://resources/js/cr/ui/focus_row.js"></script>
- <script src="chrome://resources/js/cr/ui/focus_grid.js"></script>
- <link rel="import" href="chrome://downloads/constants.html">
- <link rel="import" href="chrome://downloads/throttled_icon_loader.html">
- <script src="chrome://downloads/item_view.js"></script>
- <script src="chrome://downloads/focus_row.js"></script>
- <script src="chrome://downloads/manager.js"></script>
-</head>
-<body>
- <header>
- <h1 i18n-content="downloads"></h1>
- <input id="term" type="search" tabindex=1
- i18n-values="placeholder:searchButton" autofocus incremental>
- </header>
- <div class="main">
- <div class="summary" id="downloads-summary">
- <span id="downloads-summary-text"></span>
- <span id="downloads-actions">
- <a is="action-link" id="open-downloads-folder"
- i18n-content="openDownloadsFolder"></a>
- <a is="action-link" id="clear-all" i18n-content="clearAll" hidden></a>
- </span>
- </div>
- <div id="downloads-display"></div>
- <div id="no-downloads-or-results"></div>
- </div>
- <command id="clear-all-command" shortcut="Alt-U+0043"><!-- Alt+C -->
-<if expr="is_macosx">
- <command id="undo-command" shortcut="Meta-U+005A"><!-- Command+Z -->
-</if>
-<if expr="not is_macosx">
- <command id="undo-command" shortcut="Ctrl-U+005A"><!-- Ctrl+Z -->
-</if>
- <div id="templates" hidden>
- <div class="download">
- <div class="date-container">
- <div class="since"></div>
- <div class="date"></div>
- </div>
- <div class="safe">
- <div class="progress background"></div>
- <canvas class="progress"></canvas>
- <img class="icon" alt="">
- <div class="title-area">
- <a is="action-link" class="name" focus-type="name"></a>
- <span class="name"></span>
- <span class="status"></span>
- </div>
- <div class="url-container">
- <a class="src-url" target="_blank" focus-type="url"></a>
- </div>
- <div class="controls">
- <a is="action-link" class="show" focus-type="show"
- i18n-content="controlShowInFolder"></a>
- <a class="retry" focus-type="retry" i18n-content="controlRetry"
- download></a>
- <a is="action-link" class="pause" focus-type="pause"
- i18n-content="controlPause"></a>
- <a is="action-link" class="resume" focus-type="resume"
- i18n-content="controlResume"></a>
- <a is="action-link" class="remove" focus-type="remove"
- i18n-content="controlRemoveFromList"></a>
- <a is="action-link" class="cancel" focus-type="cancel"
- i18n-content="controlCancel"></a>
- <span class="controlled-by"
- i18n-values=".innerHTML:controlByExtension"></span>
- </div>
- </div>
- <div class="dangerous">
- <img class="icon" alt="">
- <div class="description"></div>
- <div class="controls">
- <a is="action-link" class="restore" focus-type="save"
- i18n-content="dangerRestore"></a>
- <a is="action-link" class="remove" focus-type="discard"
- i18n-content="controlRemoveFromList"></a>
- </div>
- <button class="save" focus-type="save"
- i18n-content="dangerSave"></button>
- <button class="discard" focus-type="discard"
- i18n-content="dangerDiscard"></button>
- </div>
- </div>
- </div>
- <script src="chrome://downloads/strings.js"></script>
- <script src="chrome://resources/js/i18n_template.js"></script>
-</body>
-</html>
diff --git a/chromium/chrome/browser/resources/downloads/externs.js b/chromium/chrome/browser/resources/downloads/externs.js
deleted file mode 100644
index 65efb05f944..00000000000
--- a/chromium/chrome/browser/resources/downloads/externs.js
+++ /dev/null
@@ -1,36 +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.
-
-/**
- * @fileoverview Externs for objects sent from C++ to JS for chrome://downloads.
- * @externs
- */
-
-var downloads = {};
-
-/**
- * The type of the download object. The definition is based on
- * chrome/browser/ui/webui/downloads_dom_handler.cc:CreateDownloadItemValue()
- * @typedef {{by_ext_id: string,
- * by_ext_name: string,
- * danger_type: string,
- * date_string: string,
- * file_externally_removed: boolean,
- * file_name: string,
- * file_path: string,
- * file_url: string,
- * id: string,
- * last_reason_text: string,
- * otr: boolean,
- * percent: number,
- * progress_status_text: string,
- * resume: boolean,
- * retry: boolean,
- * since_string: string,
- * started: number,
- * state: string,
- * total: number,
- * url: string}}
- */
-downloads.Data;
diff --git a/chromium/chrome/browser/resources/downloads/focus_row.js b/chromium/chrome/browser/resources/downloads/focus_row.js
deleted file mode 100644
index fdebd6f4dee..00000000000
--- a/chromium/chrome/browser/resources/downloads/focus_row.js
+++ /dev/null
@@ -1,32 +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('downloads', function() {
- /**
- * @param {!Element} root
- * @param {?Node} boundary
- * @constructor
- * @extends {cr.ui.FocusRow}
- */
- function FocusRow(root, boundary) {
- cr.ui.FocusRow.call(this, root, boundary);
-
- assert(this.addItem('name', '[is="action-link"].name'));
- assert(this.addItem('url', '.src-url'));
- assert(this.addItem('show-retry', '.safe .controls .show'));
- assert(this.addItem('show-retry', '.retry'));
- assert(this.addItem('pause-resume', '.pause'));
- assert(this.addItem('pause-resume', '.resume'));
- assert(this.addItem('remove', '.remove'));
- assert(this.addItem('cancel', '.cancel'));
- assert(this.addItem('restore-save', '.restore'));
- assert(this.addItem('restore-save', '.save'));
- assert(this.addItem('remove-discard', '.remove'));
- assert(this.addItem('remove-discard', '.discard'));
- }
-
- FocusRow.prototype = {__proto__: cr.ui.FocusRow.prototype};
-
- return {FocusRow: FocusRow};
-});
diff --git a/chromium/chrome/browser/resources/downloads/item_view.js b/chromium/chrome/browser/resources/downloads/item_view.js
deleted file mode 100644
index f91d3fb1c08..00000000000
--- a/chromium/chrome/browser/resources/downloads/item_view.js
+++ /dev/null
@@ -1,395 +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('downloads', function() {
- /**
- * Creates and updates the DOM representation for a download.
- * @param {!downloads.ThrottledIconLoader} iconLoader
- * @constructor
- */
- function ItemView(iconLoader) {
- /** @private {!downloads.ThrottledIconLoader} */
- this.iconLoader_ = iconLoader;
-
- this.node = $('templates').querySelector('.download').cloneNode(true);
-
- this.safe_ = this.queryRequired_('.safe');
- this.since_ = this.queryRequired_('.since');
- this.dateContainer = this.queryRequired_('.date-container');
- this.date_ = this.queryRequired_('.date');
- this.save_ = this.queryRequired_('.save');
- this.backgroundProgress_ = this.queryRequired_('.progress.background');
- this.foregroundProgress_ = /** @type !HTMLCanvasElement */(
- this.queryRequired_('canvas.progress'));
- this.safeImg_ = /** @type !HTMLImageElement */(
- this.queryRequired_('.safe img'));
- this.fileName_ = this.queryRequired_('span.name');
- this.fileLink_ = this.queryRequired_('[is="action-link"].name');
- this.status_ = this.queryRequired_('.status');
- this.srcUrl_ = this.queryRequired_('.src-url');
- this.show_ = this.queryRequired_('.show');
- this.retry_ = this.queryRequired_('.retry');
- this.pause_ = this.queryRequired_('.pause');
- this.resume_ = this.queryRequired_('.resume');
- this.safeRemove_ = this.queryRequired_('.safe .remove');
- this.cancel_ = this.queryRequired_('.cancel');
- this.controlledBy_ = this.queryRequired_('.controlled-by');
-
- this.dangerous_ = this.queryRequired_('.dangerous');
- this.dangerImg_ = /** @type {!HTMLImageElement} */(
- this.queryRequired_('.dangerous img'));
- this.description_ = this.queryRequired_('.description');
- this.malwareControls_ = this.queryRequired_('.dangerous .controls');
- this.restore_ = this.queryRequired_('.restore');
- this.dangerRemove_ = this.queryRequired_('.dangerous .remove');
- this.save_ = this.queryRequired_('.save');
- this.discard_ = this.queryRequired_('.discard');
-
- // Event handlers (bound once on creation).
- this.safe_.ondragstart = this.onSafeDragstart_.bind(this);
- this.fileLink_.onclick = this.onFileLinkClick_.bind(this);
- this.show_.onclick = this.onShowClick_.bind(this);
- this.pause_.onclick = this.onPauseClick_.bind(this);
- this.resume_.onclick = this.onResumeClick_.bind(this);
- this.safeRemove_.onclick = this.onSafeRemoveClick_.bind(this);
- this.cancel_.onclick = this.onCancelClick_.bind(this);
- this.restore_.onclick = this.onRestoreClick_.bind(this);
- this.save_.onclick = this.onSaveClick_.bind(this);
- this.dangerRemove_.onclick = this.onDangerRemoveClick_.bind(this);
- this.discard_.onclick = this.onDiscardClick_.bind(this);
- }
-
- /** Progress meter constants. */
- ItemView.Progress = {
- /** @const {number} */
- START_ANGLE: -0.5 * Math.PI,
- /** @const {number} */
- SIDE: 48,
- };
-
- /** @const {number} */
- ItemView.Progress.HALF = ItemView.Progress.SIDE / 2;
-
- ItemView.computeDownloadProgress = function() {
- /**
- * @param {number} a Some float.
- * @param {number} b Some float.
- * @param {number=} opt_pct Percent of min(a,b).
- * @return {boolean} true if a is within opt_pct percent of b.
- */
- function floatEq(a, b, opt_pct) {
- return Math.abs(a - b) < (Math.min(a, b) * (opt_pct || 1.0) / 100.0);
- }
-
- if (floatEq(ItemView.Progress.scale, window.devicePixelRatio)) {
- // Zooming in or out multiple times then typing Ctrl+0 resets the zoom
- // level directly to 1x, which fires the matchMedia event multiple times.
- return;
- }
- var Progress = ItemView.Progress;
- Progress.scale = window.devicePixelRatio;
- Progress.width = Progress.SIDE * Progress.scale;
- Progress.height = Progress.SIDE * Progress.scale;
- Progress.radius = Progress.HALF * Progress.scale;
- Progress.centerX = Progress.HALF * Progress.scale;
- Progress.centerY = Progress.HALF * Progress.scale;
- };
- ItemView.computeDownloadProgress();
-
- // Listens for when device-pixel-ratio changes between any zoom level.
- [0.3, 0.4, 0.6, 0.7, 0.8, 0.95, 1.05, 1.2, 1.4, 1.6, 1.9, 2.2, 2.7, 3.5, 4.5].
- forEach(function(scale) {
- var media = '(-webkit-min-device-pixel-ratio:' + scale + ')';
- window.matchMedia(media).addListener(ItemView.computeDownloadProgress);
- });
-
- /**
- * @return {!HTMLImageElement} The correct <img> to show when an item is
- * progressing in the foreground.
- */
- ItemView.getForegroundProgressImage = function() {
- var x = window.devicePixelRatio >= 2 ? '2x' : '1x';
- ItemView.foregroundImages_ = ItemView.foregroundImages_ || {};
- if (!ItemView.foregroundImages_[x]) {
- ItemView.foregroundImages_[x] = new Image;
- var IMAGE_URL = 'chrome://theme/IDR_DOWNLOAD_PROGRESS_FOREGROUND_32';
- ItemView.foregroundImages_[x].src = IMAGE_URL + '@' + x;
- }
- return ItemView.foregroundImages_[x];
- };
-
- ItemView.prototype = {
- /** @param {!downloads.Data} data */
- update: function(data) {
- assert(!this.id_ || data.id == this.id_);
- this.id_ = data.id; // This is the only thing saved from |data|.
-
- this.node.classList.toggle('otr', data.otr);
-
- var dangerText = this.getDangerText_(data);
- this.dangerous_.hidden = !dangerText;
- this.safe_.hidden = !!dangerText;
-
- this.ensureTextIs_(this.since_, data.since_string);
- this.ensureTextIs_(this.date_, data.date_string);
-
- if (dangerText) {
- this.ensureTextIs_(this.description_, dangerText);
-
- var dangerType = data.danger_type;
- var dangerousFile = dangerType == downloads.DangerType.DANGEROUS_FILE;
- this.description_.classList.toggle('malware', !dangerousFile);
-
- var idr = dangerousFile ? 'IDR_WARNING' : 'IDR_SAFEBROWSING_WARNING';
- var iconUrl = 'chrome://theme/' + idr;
- this.iconLoader_.loadScaledIcon(this.dangerImg_, iconUrl);
-
- var showMalwareControls =
- dangerType == downloads.DangerType.DANGEROUS_CONTENT ||
- dangerType == downloads.DangerType.DANGEROUS_HOST ||
- dangerType == downloads.DangerType.DANGEROUS_URL ||
- dangerType == downloads.DangerType.POTENTIALLY_UNWANTED;
-
- this.malwareControls_.hidden = !showMalwareControls;
- this.discard_.hidden = showMalwareControls;
- this.save_.hidden = showMalwareControls;
- } else {
- var iconUrl = 'chrome://fileicon/' + encodeURIComponent(data.file_path);
- this.iconLoader_.loadScaledIcon(this.safeImg_, iconUrl);
-
- /** @const */ var isInProgress =
- data.state == downloads.States.IN_PROGRESS;
- this.node.classList.toggle('in-progress', isInProgress);
-
- /** @const */ var completelyOnDisk =
- data.state == downloads.States.COMPLETE &&
- !data.file_externally_removed;
-
- this.fileLink_.href = data.url;
- this.ensureTextIs_(this.fileLink_, data.file_name);
- this.fileLink_.hidden = !completelyOnDisk;
-
- /** @const */ var isInterrupted =
- data.state == downloads.States.INTERRUPTED;
- this.fileName_.classList.toggle('interrupted', isInterrupted);
- this.ensureTextIs_(this.fileName_, data.file_name);
- this.fileName_.hidden = completelyOnDisk;
-
- this.show_.hidden = !completelyOnDisk;
-
- this.retry_.href = data.url;
- this.retry_.hidden = !data.retry;
-
- this.pause_.hidden = !isInProgress;
-
- this.resume_.hidden = !data.resume;
-
- /** @const */ var isPaused = data.state == downloads.States.PAUSED;
- /** @const */ var showCancel = isPaused || isInProgress;
- this.cancel_.hidden = !showCancel;
-
- this.safeRemove_.hidden = showCancel ||
- !loadTimeData.getBoolean('allowDeletingHistory');
-
- /** @const */ var controlledByExtension = data.by_ext_id &&
- data.by_ext_name;
- this.controlledBy_.hidden = !controlledByExtension;
- if (controlledByExtension) {
- var link = this.controlledBy_.querySelector('a');
- link.href = 'chrome://extensions#' + data.by_ext_id;
- link.setAttribute('focus-type', 'controlled-by');
- link.textContent = data.by_ext_name;
- }
-
- this.ensureTextIs_(this.srcUrl_, data.url);
- this.srcUrl_.href = data.url;
- this.ensureTextIs_(this.status_, this.getStatusText_(data));
-
- this.foregroundProgress_.hidden = !isInProgress;
- this.backgroundProgress_.hidden = !isInProgress;
-
- if (isInProgress) {
- this.foregroundProgress_.width = ItemView.Progress.width;
- this.foregroundProgress_.height = ItemView.Progress.height;
-
- if (!this.progressContext_) {
- /** @private */
- this.progressContext_ = /** @type !CanvasRenderingContext2D */(
- this.foregroundProgress_.getContext('2d'));
- }
-
- var foregroundImage = ItemView.getForegroundProgressImage();
-
- // Draw a pie-slice for the progress.
- this.progressContext_.globalCompositeOperation = 'copy';
- this.progressContext_.drawImage(
- foregroundImage,
- 0, 0, // sx, sy
- foregroundImage.width,
- foregroundImage.height,
- 0, 0, // x, y
- ItemView.Progress.width, ItemView.Progress.height);
-
- this.progressContext_.globalCompositeOperation = 'destination-in';
- this.progressContext_.beginPath();
- this.progressContext_.moveTo(ItemView.Progress.centerX,
- ItemView.Progress.centerY);
-
- // Draw an arc CW for both RTL and LTR. http://crbug.com/13215
- this.progressContext_.arc(
- ItemView.Progress.centerX,
- ItemView.Progress.centerY,
- ItemView.Progress.radius,
- ItemView.Progress.START_ANGLE,
- ItemView.Progress.START_ANGLE + Math.PI * 0.02 * data.percent,
- false);
-
- this.progressContext_.lineTo(ItemView.Progress.centerX,
- ItemView.Progress.centerY);
- this.progressContext_.fill();
- this.progressContext_.closePath();
- }
- }
- },
-
- destroy: function() {
- if (this.node.parentNode)
- this.node.parentNode.removeChild(this.node);
- },
-
- /**
- * @param {string} selector A CSS selector (e.g. '.class-name').
- * @return {!Element} The element found by querying for |selector|.
- * @private
- */
- queryRequired_: function(selector) {
- return assert(this.node.querySelector(selector));
- },
-
- /**
- * Overwrite |el|'s textContent if it differs from |text|.
- * @param {!Element} el
- * @param {string} text
- * @private
- */
- ensureTextIs_: function(el, text) {
- if (el.textContent != text)
- el.textContent = text;
- },
-
- /**
- * @param {!downloads.Data} data
- * @return {string} Text describing the danger of a download. Empty if not
- * dangerous.
- */
- getDangerText_: function(data) {
- switch (data.danger_type) {
- case downloads.DangerType.DANGEROUS_FILE:
- return loadTimeData.getStringF('dangerFileDesc', data.file_name);
- case downloads.DangerType.DANGEROUS_URL:
- return loadTimeData.getString('dangerUrlDesc');
- case downloads.DangerType.DANGEROUS_CONTENT: // Fall through.
- case downloads.DangerType.DANGEROUS_HOST:
- return loadTimeData.getStringF('dangerContentDesc', data.file_name);
- case downloads.DangerType.UNCOMMON_CONTENT:
- return loadTimeData.getStringF('dangerUncommonDesc', data.file_name);
- case downloads.DangerType.POTENTIALLY_UNWANTED:
- return loadTimeData.getStringF('dangerSettingsDesc', data.file_name);
- default:
- return '';
- }
- },
-
- /**
- * @param {!downloads.Data} data
- * @return {string} User-visible status update text.
- * @private
- */
- getStatusText_: function(data) {
- switch (data.state) {
- case downloads.States.IN_PROGRESS:
- case downloads.States.PAUSED: // Fallthrough.
- assert(typeof data.progress_status_text == 'string');
- return data.progress_status_text;
- case downloads.States.CANCELLED:
- return loadTimeData.getString('statusCancelled');
- case downloads.States.DANGEROUS:
- break; // Intentionally hit assertNotReached(); at bottom.
- case downloads.States.INTERRUPTED:
- assert(typeof data.last_reason_text == 'string');
- return data.last_reason_text;
- case downloads.States.COMPLETE:
- return data.file_externally_removed ?
- loadTimeData.getString('statusRemoved') : '';
- }
- assertNotReached();
- return '';
- },
-
- /**
- * @private
- * @param {Event} e
- */
- onSafeDragstart_: function(e) {
- e.preventDefault();
- chrome.send('drag', [this.id_]);
- },
-
- /**
- * @param {Event} e
- * @private
- */
- onFileLinkClick_: function(e) {
- e.preventDefault();
- chrome.send('openFile', [this.id_]);
- },
-
- /** @private */
- onShowClick_: function() {
- chrome.send('show', [this.id_]);
- },
-
- /** @private */
- onPauseClick_: function() {
- chrome.send('pause', [this.id_]);
- },
-
- /** @private */
- onResumeClick_: function() {
- chrome.send('resume', [this.id_]);
- },
-
- /** @private */
- onSafeRemoveClick_: function() {
- chrome.send('remove', [this.id_]);
- },
-
- /** @private */
- onCancelClick_: function() {
- chrome.send('cancel', [this.id_]);
- },
-
- /** @private */
- onRestoreClick_: function() {
- this.onSaveClick_();
- },
-
- /** @private */
- onSaveClick_: function() {
- chrome.send('saveDangerous', [this.id_]);
- },
-
- /** @private */
- onDangerRemoveClick_: function() {
- this.onDiscardClick_();
- },
-
- /** @private */
- onDiscardClick_: function() {
- chrome.send('discardDangerous', [this.id_]);
- },
- };
-
- return {ItemView: ItemView};
-});
diff --git a/chromium/chrome/browser/resources/downloads/manager.js b/chromium/chrome/browser/resources/downloads/manager.js
deleted file mode 100644
index 7f91b615332..00000000000
--- a/chromium/chrome/browser/resources/downloads/manager.js
+++ /dev/null
@@ -1,256 +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('downloads', function() {
- /**
- * Class to own and manage download items.
- * @constructor
- */
- function Manager() {}
-
- cr.addSingletonGetter(Manager);
-
- Manager.prototype = {
- /** @private {string} */
- searchText_: '',
-
- /**
- * Sets the search text, updates related UIs, and tells the browser.
- * @param {string} searchText Text we're searching for.
- * @private
- */
- setSearchText_: function(searchText) {
- this.searchText_ = searchText;
-
- $('downloads-summary-text').textContent = this.searchText_ ?
- loadTimeData.getStringF('searchResultsFor', this.searchText_) : '';
-
- // Split quoted terms (e.g., 'The "lazy" dog' => ['The', 'lazy', 'dog']).
- function trim(s) { return s.trim(); }
- chrome.send('getDownloads', searchText.split(/"([^"]*)"/).map(trim));
- },
-
- /**
- * @return {number} A guess at how many items could be visible at once.
- * @private
- */
- guesstimateNumberOfVisibleItems_: function() {
- var headerHeight = document.querySelector('header').offsetHeight;
- var summaryHeight = $('downloads-summary').offsetHeight;
- var nonItemSpace = headerHeight + summaryHeight;
- return Math.floor((window.innerHeight - nonItemSpace) / 46) + 1;
- },
-
- /**
- * Called when all items need to be updated.
- * @param {!Array<!downloads.Data>} list A list of new download data.
- * @private
- */
- updateAll_: function(list) {
- var oldIdMap = this.idMap_ || {};
-
- /** @private {!Object<!downloads.ItemView>} */
- this.idMap_ = {};
-
- /** @private {!Array<!downloads.ItemView>} */
- this.items_ = [];
-
- if (!this.iconLoader_) {
- var guesstimate = Math.max(this.guesstimateNumberOfVisibleItems_(), 1);
- /** @private {downloads.ThrottledIconLoader} */
- this.iconLoader_ = new downloads.ThrottledIconLoader(guesstimate);
- }
-
- for (var i = 0; i < list.length; ++i) {
- var data = list[i];
- var id = data.id;
-
- // Re-use old items when possible (saves work, preserves focus).
- var item = oldIdMap[id] || new downloads.ItemView(this.iconLoader_);
-
- this.idMap_[id] = item; // Associated by ID for fast lookup.
- this.items_.push(item); // Add to sorted list for order.
-
- // Render |item| but don't actually add to the DOM yet. |this.items_|
- // must be fully created to be able to find the right spot to insert.
- item.update(data);
-
- // Collapse redundant dates.
- var prev = list[i - 1];
- item.dateContainer.hidden =
- prev && prev.date_string == data.date_string;
-
- delete oldIdMap[id];
- }
-
- // Remove stale, previously rendered items from the DOM.
- for (var id in oldIdMap) {
- var oldNode = oldIdMap[id].node;
- if (oldNode.parentNode)
- oldNode.parentNode.removeChild(oldNode);
- delete oldIdMap[id];
- }
-
- for (var i = 0; i < this.items_.length; ++i) {
- var item = this.items_[i];
- if (item.node.parentNode) // Already in the DOM; skip.
- continue;
-
- var before = null;
- // Find the next rendered item after this one, and insert before it.
- for (var j = i + 1; !before && j < this.items_.length; ++j) {
- if (this.items_[j].node.parentNode)
- before = this.items_[j].node;
- }
- // If |before| is null, |item| will just get added at the end.
- this.node_.insertBefore(item.node, before);
- }
-
- var noDownloadsOrResults = $('no-downloads-or-results');
- noDownloadsOrResults.textContent = loadTimeData.getString(
- this.searchText_ ? 'noSearchResults' : 'noDownloads');
-
- var hasDownloads = this.size_() > 0;
- this.node_.hidden = !hasDownloads;
- noDownloadsOrResults.hidden = hasDownloads;
-
- if (loadTimeData.getBoolean('allowDeletingHistory'))
- $('clear-all').hidden = !hasDownloads || this.searchText_.length > 0;
-
- this.rebuildFocusGrid_();
- },
-
- /**
- * @param {!downloads.Data} data Info about the item to update.
- * @private
- */
- updateItem_: function(data) {
- var activeElement = document.activeElement;
-
- var item = this.idMap_[data.id];
- item.update(data);
-
- if (item.node.contains(activeElement) &&
- !cr.ui.FocusRow.isFocusable(activeElement)) {
- var focusRow = this.focusGrid_.getRowForRoot(item.node);
- focusRow.getEquivalentElement(activeElement).focus();
- }
- },
-
- /**
- * Rebuild the focusGrid_ using the elements that each download will have.
- * @private
- */
- rebuildFocusGrid_: function() {
- var activeElement = document.activeElement;
-
- /** @private {!cr.ui.FocusGrid} */
- this.focusGrid_ = this.focusGrid_ || new cr.ui.FocusGrid();
- this.focusGrid_.destroy();
-
- this.items_.forEach(function(item) {
- var focusRow = new downloads.FocusRow(item.node, this.node_);
-
- this.focusGrid_.addRow(focusRow);
-
- if (item.node.contains(activeElement) &&
- !cr.ui.FocusRow.isFocusable(activeElement)) {
- focusRow.getEquivalentElement(activeElement).focus();
- }
- }, this);
-
- this.focusGrid_.ensureRowActive();
- },
-
- /**
- * @return {number} The number of downloads shown on the page.
- * @private
- */
- size_: function() {
- return this.items_.length;
- },
-
- /** @private */
- clearAll_: function() {
- if (loadTimeData.getBoolean('allowDeletingHistory')) {
- chrome.send('clearAll');
- this.setSearchText_('');
- }
- },
-
- /** @private */
- onLoad_: function() {
- this.node_ = $('downloads-display');
-
- $('clear-all').onclick = function() {
- this.clearAll_();
- }.bind(this);
-
- $('open-downloads-folder').onclick = function() {
- chrome.send('openDownloadsFolder');
- };
-
- $('term').onsearch = function(e) {
- this.setSearchText_($('term').value);
- }.bind(this);
-
- cr.ui.decorate('command', cr.ui.Command);
- document.addEventListener('canExecute', this.onCanExecute_.bind(this));
- document.addEventListener('command', this.onCommand_.bind(this));
-
- this.setSearchText_('');
- },
-
- /**
- * @param {Event} e
- * @private
- */
- onCanExecute_: function(e) {
- e = /** @type {cr.ui.CanExecuteEvent} */(e);
- switch (e.command.id) {
- case 'undo-command':
- e.canExecute = document.activeElement != $('term');
- break;
- case 'clear-all-command':
- e.canExecute = true;
- break;
- }
- },
-
- /**
- * @param {Event} e
- * @private
- */
- onCommand_: function(e) {
- if (e.command.id == 'undo-command')
- chrome.send('undo');
- else if (e.command.id == 'clear-all-command')
- this.clearAll_();
- },
- };
-
- Manager.updateAll = function(list) {
- Manager.getInstance().updateAll_(list);
- };
-
- Manager.updateItem = function(item) {
- Manager.getInstance().updateItem_(item);
- };
-
- Manager.setSearchText = function(searchText) {
- Manager.getInstance().setSearchText_(searchText);
- };
-
- Manager.onLoad = function() {
- Manager.getInstance().onLoad_();
- };
-
- Manager.size = function() {
- return Manager.getInstance().size_();
- };
-
- return {Manager: Manager};
-});
-
-window.addEventListener('DOMContentLoaded', downloads.Manager.onLoad);
diff --git a/chromium/chrome/browser/resources/downloads/throttled_icon_loader.js b/chromium/chrome/browser/resources/downloads/throttled_icon_loader.js
deleted file mode 100644
index 5a10024e480..00000000000
--- a/chromium/chrome/browser/resources/downloads/throttled_icon_loader.js
+++ /dev/null
@@ -1,61 +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.
-
-/** @typedef {{img: HTMLImageElement, url: string}} */
-var LoadIconRequest;
-
-cr.define('downloads', function() {
- /**
- * @param {number} maxAllowed The maximum number of simultaneous downloads
- * allowed.
- * @constructor
- */
- function ThrottledIconLoader(maxAllowed) {
- assert(maxAllowed > 0);
-
- /** @private {number} */
- this.maxAllowed_ = maxAllowed;
-
- /** @private {!Array<!LoadIconRequest>} */
- this.requests_ = [];
- }
-
- ThrottledIconLoader.prototype = {
- /** @private {number} */
- loading_: 0,
-
- /**
- * Load the provided |url| into |img.src| after appending ?scale=.
- * @param {!HTMLImageElement} img An <img> to show the loaded image in.
- * @param {string} url A remote image URL to load.
- */
- loadScaledIcon: function(img, url) {
- var scaledUrl = url + '?scale=' + window.devicePixelRatio + 'x';
- if (img.src == scaledUrl)
- return;
-
- this.requests_.push({img: img, url: scaledUrl});
- this.loadNextIcon_();
- },
-
- /** @private */
- loadNextIcon_: function() {
- if (this.loading_ > this.maxAllowed_ || !this.requests_.length)
- return;
-
- var request = this.requests_.shift();
- var img = request.img;
-
- img.onabort = img.onerror = img.onload = function() {
- this.loading_--;
- this.loadNextIcon_();
- }.bind(this);
-
- this.loading_++;
- img.src = request.url;
- },
- };
-
- return {ThrottledIconLoader: ThrottledIconLoader};
-});
diff --git a/chromium/chrome/browser/resources/engagement/engagement_table.css b/chromium/chrome/browser/resources/engagement/engagement_table.css
deleted file mode 100644
index cb6a00889fc..00000000000
--- a/chromium/chrome/browser/resources/engagement/engagement_table.css
+++ /dev/null
@@ -1,36 +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. */
-
-table,
-table td,
-table th {
- border: 1px solid #777;
- border-collapse: collapse;
- padding-left: 4px;
- padding-right: 4px;
-}
-
-table th {
- background: rgb(224, 236, 255);
- cursor: pointer;
- padding-bottom: 4px;
- padding-top: 4px;
- white-space: nowrap;
-}
-
-.origin-cell {
- min-width: 500px;
-}
-
-table tr:hover {
- background: rgb(255, 255, 187);
-}
-
-.sort-column::after {
- content: 'â–²';
-}
-
-:host([sort-reverse]) .sort-column::after {
- content: 'â–¼';
-}
diff --git a/chromium/chrome/browser/resources/engagement/engagement_table.html b/chromium/chrome/browser/resources/engagement/engagement_table.html
deleted file mode 100644
index 3b667e8f6e8..00000000000
--- a/chromium/chrome/browser/resources/engagement/engagement_table.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
-
-<dom-module id="engagement-table">
- <link rel="import" type="css" href="engagement_table.css">
- <template>
- <table>
- <thead>
- <tr>
- <th on-tap="handleSortColumnTap" sort-key="origin">
- Origin
- </th>
- <th on-tap="handleSortColumnTap" sort-key="score" class="sort-column">
- Points
- </th>
- </tr>
- </thead>
- <tbody>
- <template id="engagement-table-items" is="dom-repeat"
- items="{{engagementInfo}}" as="info"
- sort="[[getTableSortFunction_(sortKey_, sortReverse)]]">
- <tr>
- <td class="origin-cell">{{info.origin}}</td>
- <td>{{info.score}}</td>
- </tr>
- </template>
- </tbody>
- </table>
- </template>
-</dom-module>
-<script src="engagement_table.js"></script>
diff --git a/chromium/chrome/browser/resources/engagement/engagement_table.js b/chromium/chrome/browser/resources/engagement/engagement_table.js
deleted file mode 100644
index 976fbe975f0..00000000000
--- a/chromium/chrome/browser/resources/engagement/engagement_table.js
+++ /dev/null
@@ -1,107 +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.
-
-'use strict';
-
-/**
- * Strips a scheme from an origin.
- * @param {string} origin
- * @return {string} The host of the given origin.
- */
-function stripScheme(origin) {
- return new URL(origin).host;
-}
-
-Polymer({
- is: 'engagement-table',
- properties: {
- /**
- * A list of engagement info objects.
- * @type !Array<!SiteEngagementInfo>
- */
- engagementInfo: {type: Array, value: function() { return []; } },
-
- /**
- * The table's current sort key.
- * @type {string}
- * @private
- */
- sortKey_: {type: String, value: 'score'},
-
- /**
- * Whether the table is in reverse sorting order.
- * @type {boolean}
- * @private
- */
- sortReverse: {type: Boolean, value: true, reflectToAttribute: true},
- },
-
- /**
- * @param {Event} e
- */
- handleSortColumnTap: function(e) {
- this.sortTable_(e.currentTarget);
- e.preventDefault();
- },
-
- /**
- * Sorts the engagement table based on the provided sort column header. Sort
- * columns have a 'sort-key' attribute that is a property name of a
- * SiteEngagementInfo.
- * @param {HTMLElement} th The column to sort by.
- * @private
- */
- sortTable_: function(th) {
- // Remove the old sort indicator column.
- var sortColumn = this.$$('.sort-column');
- if (sortColumn)
- sortColumn.className = '';
-
- // Updating these properties recomputes the template sort function.
- var newSortKey = th.getAttribute('sort-key');
- if (this.sortKey_)
- this.sortReverse = (newSortKey == this.sortKey_) && !this.sortReverse;
-
- this.sortKey_ = newSortKey;
-
- // Specify the new sort indicator column.
- th.className = 'sort-column';
- },
-
- /**
- * Returns a sorting function for SiteEngagementInfo objects that sorts based
- * on sortKey.
- * @param {string} sortKey The name of the property to sort by.
- * @param {boolean} reverse Whether the sort should be in reverse order.
- * @return {function} A comparator for SiteEngagementInfos.
- * @private
- */
- getTableSortFunction_: function(sortKey, reverse) {
- return function(a, b) {
- return (reverse ? -1 : 1) *
- this.compareTableItem_(sortKey, a, b);
- }.bind(this);
- },
-
- /**
- * Compares two SiteEngagementInfo objects based on the sortKey.
- * @param {string} sortKey The name of the property to sort by.
- * @return {number} A negative number if |a| should be ordered before |b|, a
- * positive number otherwise.
- * @private
- */
- compareTableItem_: function(sortKey, a, b) {
- var val1 = a[sortKey];
- var val2 = b[sortKey];
-
- if (sortKey == 'origin')
- return stripScheme(val1) > stripScheme(val2) ? 1 : -1;
-
- if (sortKey == 'score')
- return val1 - val2;
-
- assertNotReached('Unsupported sort key: ' + sortKey);
- return 0;
- },
-});
diff --git a/chromium/chrome/browser/resources/engagement/site_engagement.html b/chromium/chrome/browser/resources/engagement/site_engagement.html
index 3d659b251f4..0125240b611 100644
--- a/chromium/chrome/browser/resources/engagement/site_engagement.html
+++ b/chromium/chrome/browser/resources/engagement/site_engagement.html
@@ -2,15 +2,86 @@
<head>
<title>Site Engagement</title>
<meta charset="utf-8">
- <!-- Must be before any other scripts or Polymer imports. -->
- <script src="chrome://resources/js/polymer_config.js"></script>
- <link rel="import" href="engagement_table.html">
<link rel="stylesheet" href="chrome://resources/css/text_defaults.css">
<script src="chrome://resources/js/util.js"></script>
<script src="chrome://site-engagement/site_engagement.js"></script>
+ <style>
+ body {
+ font-family: 'Roboto', 'Noto', sans-serif;
+ font-size: 14px;
+ }
+
+ table {
+ border-collapse: collapse;
+ }
+
+ table td,
+ table th {
+ border: 1px solid #777;
+ padding-left: 4px;
+ padding-right: 4px;
+ }
+
+ table th {
+ background: rgb(224, 236, 255);
+ cursor: pointer;
+ padding-bottom: 4px;
+ padding-top: 4px;
+ white-space: nowrap;
+ }
+
+ .engagement-bar {
+ background-color: black;
+ height: 2px;
+ }
+
+ .engagement-bar-cell {
+ border: none;
+ }
+
+ .origin-cell {
+ min-width: 500px;
+ }
+
+ .score-cell {
+ text-align: right;
+ }
+
+ .score-input {
+ background-color: transparent;
+ border: none;
+ text-align: right;
+ width: 40px;
+ }
+
+ table tr:hover {
+ background: rgb(255, 255, 187);
+ }
+
+ th.sort-column::after {
+ content: 'â–²';
+ }
+
+ th[sort-reverse].sort-column::after {
+ content: 'â–¼';
+ }
+ </style>
</head>
<body>
<h1>Site Engagement</h1>
- <engagement-table id="engagement-table"></engagement-table>
+ <table>
+ <thead>
+ <tr id="engagement-table-header">
+ <th sort-key="origin">
+ Origin
+ </th>
+ <th sort-key="score" class="sort-column" sort-reverse>
+ Points
+ </th>
+ </tr>
+ </thead>
+ <tbody id="engagement-table-body">
+ </tbody>
+ </table>
</body>
</html>
diff --git a/chromium/chrome/browser/resources/engagement/site_engagement.js b/chromium/chrome/browser/resources/engagement/site_engagement.js
index 38451293f51..0992b9ece11 100644
--- a/chromium/chrome/browser/resources/engagement/site_engagement.js
+++ b/chromium/chrome/browser/resources/engagement/site_engagement.js
@@ -7,7 +7,7 @@
define('main', [
'mojo/public/js/connection',
'chrome/browser/ui/webui/engagement/site_engagement.mojom',
- 'content/public/renderer/service_provider',
+ 'content/public/renderer/frame_service_registry',
], function(connection, siteEngagementMojom, serviceProvider) {
return function() {
var uiHandler = connection.bindHandleToProxy(
@@ -15,18 +15,141 @@ define('main', [
siteEngagementMojom.SiteEngagementUIHandler.name),
siteEngagementMojom.SiteEngagementUIHandler);
- var updateEngagementTable = function() {
+ var engagementTableBody = $('engagement-table-body');
+ var updateInterval = null;
+ var info = null;
+ var sortKey = 'score';
+ var sortReverse = true;
+
+ // Set table header sort handlers.
+ var engagementTableHeader = $('engagement-table-header');
+ var headers = engagementTableHeader.children;
+ for (var i = 0; i < headers.length; i++) {
+ headers[i].addEventListener('click', function(e) {
+ var newSortKey = e.target.getAttribute('sort-key');
+ if (sortKey == newSortKey) {
+ sortReverse = !sortReverse;
+ } else {
+ sortKey = newSortKey;
+ sortReverse = false;
+ }
+ var oldSortColumn = document.querySelector('.sort-column');
+ oldSortColumn.classList.remove('sort-column');
+ e.target.classList.add('sort-column');
+ if (sortReverse)
+ e.target.setAttribute('sort-reverse', '');
+ else
+ e.target.removeAttribute('sort-reverse');
+ renderTable();
+ });
+ }
+
+ /**
+ * Creates a single row in the engagement table.
+ * @param {SiteEngagementInfo} info The info to create the row from.
+ * @return {HTMLElement}
+ */
+ function createRow(info) {
+ var originCell = createElementWithClassName('td', 'origin-cell');
+ originCell.textContent = info.origin;
+
+ var scoreInput = createElementWithClassName('input', 'score-input');
+ scoreInput.addEventListener(
+ 'change', handleScoreChange.bind(undefined, info.origin));
+ scoreInput.value = info.score;
+
+ var scoreCell = createElementWithClassName('td', 'score-cell');
+ scoreCell.appendChild(scoreInput);
+
+ var engagementBar = createElementWithClassName('div', 'engagement-bar');
+ engagementBar.style.width = (info.score * 4) + 'px';
+
+ var engagementBarCell =
+ createElementWithClassName('td', 'engagement-bar-cell');
+ engagementBarCell.appendChild(engagementBar);
+
+ var row = document.createElement('tr');
+ row.appendChild(originCell);
+ row.appendChild(scoreCell);
+ row.appendChild(engagementBarCell);
+ return row;
+ }
+
+ /**
+ * Sets the engagement score when a score input is changed. Also resets the
+ * update interval.
+ * @param {string} origin The origin of the engagement score to set.
+ * @param {Event} e
+ */
+ function handleScoreChange(origin, e) {
+ uiHandler.setSiteEngagementScoreForOrigin(origin, e.target.value);
+ clearInterval(updateInterval);
+ updateInterval = setInterval(updateEngagementTable, 5000);
+ }
+
+ /**
+ * Remove all rows from the engagement table.
+ */
+ function clearTable() {
+ engagementTableBody.innerHTML = '';
+ }
+
+ /**
+ * Sort the engagement info based on |sortKey| and |sortReverse|.
+ */
+ function sortInfo() {
+ info.sort(function(a, b) {
+ return (sortReverse ? -1 : 1) *
+ compareTableItem(sortKey, a, b);
+ });
+ }
+
+ /**
+ * Compares two SiteEngagementInfo objects based on |sortKey|.
+ * @param {string} sortKey The name of the property to sort by.
+ * @return {number} A negative number if |a| should be ordered before |b|, a
+ * positive number otherwise.
+ */
+ function compareTableItem(sortKey, a, b) {
+ var val1 = a[sortKey];
+ var val2 = b[sortKey];
+
+ // Compare the hosts of the origin ignoring schemes.
+ if (sortKey == 'origin')
+ return new URL(val1).host > new URL(val2).host ? 1 : -1;
+
+ if (sortKey == 'score')
+ return val1 - val2;
+
+ assertNotReached('Unsupported sort key: ' + sortKey);
+ return 0;
+ }
+
+ /**
+ * Regenerates the engagement table from |info|.
+ */
+ function renderTable() {
+ clearTable();
+ sortInfo();
+ // Round each score to 2 decimal places.
+ info.forEach(function(info) {
+ info.score = Number(Math.round(info.score * 100) / 100);
+ engagementTableBody.appendChild(createRow(info));
+ });
+ }
+
+ /**
+ * Retrieve site engagement info and render the engagement table.
+ */
+ function updateEngagementTable() {
// Populate engagement table.
uiHandler.getSiteEngagementInfo().then(function(response) {
- // Round each score to 2 decimal places.
- response.info.forEach(function(x) {
- x.score = Number(Math.round(x.score * 100) / 100);
- });
- $('engagement-table').engagementInfo = response.info;
+ info = response.info;
+ renderTable(info);
});
-
- setTimeout(updateEngagementTable, 2000);
};
+
updateEngagementTable();
+ updateInterval = setInterval(updateEngagementTable, 5000);
};
});
diff --git a/chromium/chrome/browser/resources/extensions/compiled_resources.gyp b/chromium/chrome/browser/resources/extensions/compiled_resources.gyp
index 7779b4e4666..b5730d709ed 100644
--- a/chromium/chrome/browser/resources/extensions/compiled_resources.gyp
+++ b/chromium/chrome/browser/resources/extensions/compiled_resources.gyp
@@ -28,6 +28,7 @@
'../../../../ui/webui/resources/js/cr/ui/overlay.js',
'../../../../ui/webui/resources/js/event_tracker.js',
'../../../../ui/webui/resources/js/load_time_data.js',
+ '../../../../ui/webui/resources/js/promise_resolver.js',
'../../../../ui/webui/resources/js/util.js',
'focus_row.js',
],
diff --git a/chromium/chrome/browser/resources/extensions/extension_commands_overlay.html b/chromium/chrome/browser/resources/extensions/extension_commands_overlay.html
index 086ba453a5a..ad6c24839fe 100644
--- a/chromium/chrome/browser/resources/extensions/extension_commands_overlay.html
+++ b/chromium/chrome/browser/resources/extensions/extension_commands_overlay.html
@@ -5,19 +5,20 @@
-->
<div id="extension-commands-overlay" class="page">
<div class="close-button"></div>
- <h1 i18n-content="extensionCommandsOverlay"></h1>
+ <h1>$i18n{extensionCommandsOverlay}</h1>
<div class="content-area">
<div id="extension-command-list"
class="empty-extension-commands-list"></div>
<div id="no-commands" hidden>
- <span id="no-extensions-commands-message"
- i18n-content="extensionCommandsEmpty"></span>
+ <span id="no-extensions-commands-message">
+ $i18n{extensionCommandsEmpty}
+ </span>
</div>
</div>
<div class="action-area">
<div class="action-area-right">
<div class="button-strip">
- <button id="extension-commands-dismiss" i18n-content="ok"></button>
+ <button id="extension-commands-dismiss">$i18n{ok}</button>
</div>
</div>
</div>
diff --git a/chromium/chrome/browser/resources/extensions/extension_error.html b/chromium/chrome/browser/resources/extensions/extension_error.html
index 01589bf8c44..ad294bb4854 100644
--- a/chromium/chrome/browser/resources/extensions/extension_error.html
+++ b/chromium/chrome/browser/resources/extensions/extension_error.html
@@ -6,13 +6,13 @@ in the LICENSE file.
<div id="template-collection-extension-error" hidden>
<div class="extension-error-list">
<div class="extension-error-list-heading">
- <span i18n-content="extensionErrorHeading"></span>
- <a id="extension-error-list-clear" is="action-link"
- i18n-content="extensionErrorClearAll"></a>
+ <span>$i18n{extensionErrorHeading}</span>
+ <a id="extension-error-list-clear" is="action-link">
+ $i18n{extensionErrorClearAll}
+ </a>
</div>
<ul class="extension-error-list-contents"></ul>
- <span id="no-errors-span" i18n-content="extensionErrorNoErrors" hidden>
- </span>
+ <span id="no-errors-span" hidden>$i18n{extensionErrorNoErrors}</span>
</div>
<li class="extension-error-metadata">
<p class="extension-error-message" tabindex="0"></p>
diff --git a/chromium/chrome/browser/resources/extensions/extension_error.js b/chromium/chrome/browser/resources/extensions/extension_error.js
index 7853a157dd5..5606e928e61 100644
--- a/chromium/chrome/browser/resources/extensions/extension_error.js
+++ b/chromium/chrome/browser/resources/extensions/extension_error.js
@@ -146,7 +146,7 @@ cr.define('extensions', function() {
/**
* @param {!Element} root
- * @param {?Node} boundary
+ * @param {?Element} boundary
* @constructor
* @extends {cr.ui.FocusRow}
*/
diff --git a/chromium/chrome/browser/resources/extensions/extension_error_overlay.html b/chromium/chrome/browser/resources/extensions/extension_error_overlay.html
index ce95cc11bb3..2becd7ce9dd 100644
--- a/chromium/chrome/browser/resources/extensions/extension_error_overlay.html
+++ b/chromium/chrome/browser/resources/extensions/extension_error_overlay.html
@@ -7,11 +7,11 @@ in the LICENSE file.
<div id="template-collection-extension-error-overlay" hidden>
<div class="extension-error-overlay-runtime-content">
<div class="extension-error-overlay-context">
- <span i18n-content="extensionErrorOverlayContextUrl"></span>
+ <span>$i18n{extensionErrorOverlayContextUrl}</span>
<span class="extension-error-overlay-context-url"></span>
</div>
<details class="extension-error-overlay-stack-trace">
- <summary i18n-content="extensionErrorOverlayStackTrace"></summary>
+ <summary>$i18n{extensionErrorOverlayStackTrace}</summary>
<ul class="extension-error-overlay-stack-trace-list"></ul>
</details>
</div>
@@ -27,11 +27,11 @@ in the LICENSE file.
<div class="action-area">
<div class="action-area-right">
<div class="button-strip">
- <button id="extension-error-overlay-dismiss"
- i18n-content="extensionErrorOverlayDone">
+ <button id="extension-error-overlay-dismiss">
+ $i18n{extensionErrorOverlayDone}
</button>
- <button id="extension-error-overlay-devtools-button"
- i18n-content="extensionErrorOverlayLaunchDevtools" hidden>
+ <button id="extension-error-overlay-devtools-button" hidden>
+ $i18n{extensionErrorOverlayLaunchDevtools}
</button>
</div>
</div>
diff --git a/chromium/chrome/browser/resources/extensions/extension_error_overlay.js b/chromium/chrome/browser/resources/extensions/extension_error_overlay.js
index 3acfef97b6d..244a45e53c6 100644
--- a/chromium/chrome/browser/resources/extensions/extension_error_overlay.js
+++ b/chromium/chrome/browser/resources/extensions/extension_error_overlay.js
@@ -383,8 +383,6 @@ cr.define('extensions', function() {
/**
* Sets the active error for the overlay.
* @param {?(ManifestError|RuntimeError)} error The error to make active.
- * TODO(dbeam): add URL externs and re-enable typechecking in this method.
- * @suppress {missingProperties}
* @private
*/
setActiveError_: function(error) {
diff --git a/chromium/chrome/browser/resources/extensions/extension_list.js b/chromium/chrome/browser/resources/extensions/extension_list.js
index c59e3857daa..7adab1e3d30 100644
--- a/chromium/chrome/browser/resources/extensions/extension_list.js
+++ b/chromium/chrome/browser/resources/extensions/extension_list.js
@@ -698,7 +698,7 @@ cr.define('extensions', function() {
var isUnpacked =
extension.location == chrome.developerPrivate.Location.UNPACKED;
// The 'Reload' link.
- this.updateVisibility_(wrapper, '.reload-link', isUnpacked);
+ this.updateVisibility_(wrapper, '.reload-link', isActive && isUnpacked);
// The 'Launch' link.
this.updateVisibility_(
diff --git a/chromium/chrome/browser/resources/extensions/extension_load_error.html b/chromium/chrome/browser/resources/extensions/extension_load_error.html
index 9aed931ce17..8823bfbfea7 100644
--- a/chromium/chrome/browser/resources/extensions/extension_load_error.html
+++ b/chromium/chrome/browser/resources/extensions/extension_load_error.html
@@ -5,21 +5,23 @@ Use of this source code is governed by a BSD-style license that can be found
in the LICENSE file.
-->
<div id="extension-load-error" hidden>
- <h2 i18n-content="extensionLoadErrorHeading">Extension Load Error</h2>
+ <h2>$i18n{extensionLoadErrorHeading}</h2>
<div id="extension-load-error-message">
- <span i18n-content="extensionLoadErrorMessage"></span>
+ <span>$i18n{extensionLoadErrorMessage}</span>
<span id="extension-load-error-path"></span>
</div>
<span id="extension-load-error-reason"></span>
<div id="extension-load-error-manifest" class="extension-code"></div>
<div id="extension-load-error-controls">
- <button id="extension-load-error-retry-button"
- i18n-content="extensionLoadErrorRetry"></button>
- <button id="extension-load-error-give-up-button"
- i18n-content="extensionLoadErrorGiveUp"></button>
+ <button id="extension-load-error-retry-button">
+ $i18n{extensionLoadErrorRetry}
+ </button>
+ <button id="extension-load-error-give-up-button">
+ $i18n{extensionLoadErrorGiveUp}
+ </button>
</div>
<div id="extension-load-error-additional" hidden>
- <span i18n-content="extensionLoadAdditionalFailures"></span>
+ <span>$i18n{extensionLoadAdditionalFailures}</span>
<ul></ul>
</div>
</div>
diff --git a/chromium/chrome/browser/resources/extensions/extensions.html b/chromium/chrome/browser/resources/extensions/extensions.html
index 155714e11e5..39ab5fa223e 100644
--- a/chromium/chrome/browser/resources/extensions/extensions.html
+++ b/chromium/chrome/browser/resources/extensions/extensions.html
@@ -65,60 +65,64 @@
<include src="chromeos/kiosk_app_disable_bailout_confirm.html">
</if>
<div id="drop-target-overlay" class="page">
- <div i18n-content="extensionSettingsInstallDropTarget"></div>
+ <div>$i18n{extensionSettingsInstallDropTarget}</div>
</div>
</div>
<div class="page" id="extension-settings">
<header id="page-header">
- <h1 i18n-content="extensionSettings"></h1>
+ <h1>$i18n{extensionSettings}</h1>
<div id="header-controls" class="header-extras">
<div id="dev-toggle" class="checkbox">
<label>
<input id="toggle-dev-on" type="checkbox">
- <span i18n-content="extensionSettingsDeveloperMode"></span>
+ <span>$i18n{extensionSettingsDeveloperMode}</span>
</label>
</div>
</div>
<div class="page-banner profile-is-supervised-banner">
<div class="page-banner-gradient">
- <span class="page-banner-text"
- i18n-content="extensionSettingsSupervisedUser"></span>
+ <span class="page-banner-text">
+ $i18n{extensionSettingsSupervisedUser}
+ </span>
</div>
</div>
</header>
<div id="loading-spinner">
<div class="inline-spinner"></div>
- <span i18n-content="loading"></span>
+ <span>$i18n{loading}</span>
</div>
<div id="dev-controls" hidden>
<div class="button-container">
- <button id="load-unpacked"
- i18n-content="extensionSettingsLoadUnpackedButton"></button>
- <button id="pack-extension"
- i18n-content="extensionSettingsPackButton"></button>
+ <button id="load-unpacked">
+ $i18n{extensionSettingsLoadUnpackedButton}
+ </button>
+ <button id="pack-extension">
+ $i18n{extensionSettingsPackButton}
+ </button>
<if expr="chromeos">
- <button id="add-kiosk-app"
- i18n-content="addKioskAppButton" hidden></button>
+ <button id="add-kiosk-app" hidden>$i18n{addKioskAppButton}</button>
</if>
<div id="dev-controls-spacer"></div>
- <button id="update-extensions-now"
- i18n-content="extensionSettingsUpdateButton"></button>
+ <button id="update-extensions-now">
+ $i18n{extensionSettingsUpdateButton}
+ </button>
</div>
</div>
<include src="extension_load_error.html">
<div id="extension-list-wrapper" hidden>
<div id="footer-section">
<a target="_blank" class="more-extensions-link"
- i18n-values="href:extensionSettingsGetMoreExtensionsUrl"
- i18n-content="extensionSettingsGetMoreExtensions"></a>
- <a is="action-link" class="extension-commands-config"
- i18n-content="extensionSettingsCommandsLink" hidden></a>
+ i18n-values="href:extensionSettingsGetMoreExtensionsUrl">
+ $i18n{extensionSettingsGetMoreExtensions}
+ </a>
+ <a is="action-link" class="extension-commands-config" hidden>
+ $i18n{extensionSettingsCommandsLink}
+ </a>
</div>
</div>
<div id="no-extensions" hidden>
- <span id="no-extensions-message"
- i18n-content="extensionSettingsNoExtensions"></span>
+ <span id="no-extensions-message">$i18n{extensionSettingsNoExtensions}</span>
<span id="suggest-gallery" class="more-extensions-link"
i18n-values=".innerHTML:extensionSettingsSuggestGallery">
</span>
@@ -137,93 +141,94 @@
<span class="extension-version"></span>
</div>
<p class="corrupt-install-message"
- i18n-content="extensionSettingsCorruptInstall" hidden></p>
+ hidden>$i18n{extensionSettingsCorruptInstall}</p>
<p class="extension-description"></p>
<div class="action-links">
- <a is="action-link" class="permissions-link"
- i18n-content="extensionSettingsPermissions"></a>
- <a is="action-link" class="options-button"
- i18n-content="extensionSettingsOptions" hidden></a>
- <a class="options-link"
- i18n-content="extensionSettingsOptions" hidden></a>
+ <a is="action-link" class="permissions-link">
+ $i18n{extensionSettingsPermissions}
+ </a>
+ <a is="action-link" class="options-button" hidden>
+ $i18n{extensionSettingsOptions}
+ </a>
+ <a class="options-link" hidden>$i18n{extensionSettingsOptions}</a>
<a class="site-link" target="_parent" hidden></a>
- <a is="action-link" class="launch-link"
- i18n-content="extensionSettingsLaunch" hidden></a>
- <a is="action-link" role="button" class="reload-link"
- i18n-content="extensionSettingsReloadUnpacked" hidden></a>
+ <a is="action-link" class="launch-link" hidden>
+ $i18n{extensionSettingsLaunch}
+ </a>
+ <a is="action-link" role="button" class="reload-link" hidden>
+ $i18n{extensionSettingsReloadUnpacked}
+ </a>
<a is="action-link" role="button" class="errors-link">
<img class="extension-error-icon"></img>
- <span i18n-content="extensionErrorHeading"></span>
+ <span>$i18n{extensionErrorHeading}</span>
</a>
</div>
<div class="permanent-warnings">
<div class="extension-warnings" hidden>
- <span i18n-content="extensionSettingsWarningsTitle"></span>
+ <span>$i18n{extensionSettingsWarningsTitle}</span>
<ul></ul>
</div>
<div class="suspicious-install-message" hidden>
- <span i18n-content="extensionSettingsSuspiciousInstall"></span>
- <a target="_blank" class="learn-more-link"
- i18n-values="href:extensionSettingsSuspiciousInstallHelpUrl"
- i18n-content="extensionSettingsLearnMore"
- href="#">
+ <span>$i18n{extensionSettingsSuspiciousInstall}</span>
+ <a target="_blank" class="learn-more-link" href="#"
+ i18n-values="href:extensionSettingsSuspiciousInstallHelpUrl">
+ $i18n{extensionSettingsLearnMore}
</a>
</div>
</div>
<div class="dependent-extensions-message" hidden>
- <span i18n-content="extensionSettingsDependentExtensions"></span>
+ <span>$i18n{extensionSettingsDependentExtensions}</span>
<ul></ul>
</div>
<div class="developer-extras">
<div>
- <span i18n-content="extensionSettingsExtensionId"></span>
+ <span>$i18n{extensionSettingsExtensionId}</span>
<span class="extension-id"></span>
</div>
<div class="load-path" hidden>
- <span i18n-content="extensionSettingsExtensionPath"></span>
+ <span>$i18n{extensionSettingsExtensionPath}</span>
<a is="action-link"></a>
</div>
- <div class="managed-message"
- i18n-content="extensionSettingsPolicyControlled" hidden>
+ <div class="managed-message" hidden>
+ $i18n{extensionSettingsPolicyControlled}
</div>
- <div class="update-required-message"
- i18n-content="extensionSettingsUpdateRequiredBePolicy" hidden>
+ <div class="update-required-message" hidden>
+ $i18n{extensionSettingsUpdateRequiredBePolicy}
</div>
<div class="active-views" hidden>
- <span i18n-content="extensionSettingsInspectViews"></span>
+ <span>$i18n{extensionSettingsInspectViews}</span>
<a is="action-link"></a>
</div>
<div class="install-warnings" hidden>
- <span i18n-content="extensionSettingsInstallWarnings"></span>
+ <span>$i18n{extensionSettingsInstallWarnings}</span>
<ul></ul>
</div>
</div>
<div class="optional-controls">
<button class="show-button"
- i18n-content="extensionSettingsShowButton" hidden></button>
+ hidden>$i18n{extensionSettingsShowButton}</button>
<div class="checkbox">
<label class="incognito-control">
<input type="checkbox">
- <span i18n-content="extensionSettingsEnableIncognito"></span>
+ <span>$i18n{extensionSettingsEnableIncognito}</span>
</label>
</div>
<div class="checkbox error-collection-control" hidden>
<label>
<input type="checkbox">
- <span i18n-content="extensionSettingsEnableErrorCollection">
- </span>
+ <span>$i18n{extensionSettingsEnableErrorCollection}</span>
</label>
</div>
<div class="checkbox all-urls-control" hidden>
<label>
<input type="checkbox">
- <span i18n-content="extensionSettingsAllowOnAllUrls"></span>
+ <span>$i18n{extensionSettingsAllowOnAllUrls}</span>
</label>
</div>
<div class="checkbox file-access-control" hidden>
<label>
<input type="checkbox">
- <span i18n-content="extensionSettingsAllowFileAccess"></span>
+ <span>$i18n{extensionSettingsAllowFileAccess}</span>
</label>
</div>
</div>
@@ -232,17 +237,18 @@
</div>
</div>
<div class="enable-controls">
- <a is="action-link" role="button" class="terminated-reload-link"
- i18n-content="extensionSettingsReloadTerminated" hidden></a>
+ <a is="action-link" role="button" class="terminated-reload-link" hidden>
+ $i18n{extensionSettingsReloadTerminated}
+ </a>
<a is="action-link" role="button" class="corrupted-repair-button"
- i18n-content="extensionSettingsRepairCorrupted" hidden></a>
+ hidden>
+ $i18n{extensionSettingsRepairCorrupted}
+ </a>
<div class="checkbox enable-checkbox" hidden><label>
<input type="checkbox">
<span class="enable-checkbox-text">
- <span class="enabled-text" i18n-content="extensionSettingsEnabled">
- </span>
- <span class="enable-text" i18n-content="extensionSettingsEnable">
- </span>
+ <span class="enabled-text">$i18n{extensionSettingsEnabled}</span>
+ <span class="enable-text">$i18n{extensionSettingsEnable}</span>
</span>
</label>
<span class="location-text"></span>
@@ -255,7 +261,7 @@
<span class="dep-extension-title"></span>
<ul>
<li>
- <span i18n-content="extensionSettingsExtensionId"></span>
+ <span>$i18n{extensionSettingsExtensionId}</span>
<span class="dep-extension-id"></span>
</li>
</ul>
diff --git a/chromium/chrome/browser/resources/extensions/focus_row.js b/chromium/chrome/browser/resources/extensions/focus_row.js
index 6e9b078f302..6022f3993d9 100644
--- a/chromium/chrome/browser/resources/extensions/focus_row.js
+++ b/chromium/chrome/browser/resources/extensions/focus_row.js
@@ -5,7 +5,7 @@
cr.define('extensions', function() {
/**
* @param {!Element} root
- * @param {Node} boundary
+ * @param {?Element} boundary
* @constructor
* @extends {cr.ui.FocusRow}
*/
diff --git a/chromium/chrome/browser/resources/extensions/pack_extension_overlay.html b/chromium/chrome/browser/resources/extensions/pack_extension_overlay.html
index be2394c69d3..65572b515d7 100644
--- a/chromium/chrome/browser/resources/extensions/pack_extension_overlay.html
+++ b/chromium/chrome/browser/resources/extensions/pack_extension_overlay.html
@@ -1,32 +1,32 @@
<div id="pack-extension-overlay" class="page">
<div class="close-button"></div>
- <h1 i18n-content="packExtensionOverlay"></h1>
+ <h1>$i18n{packExtensionOverlay}</h1>
<div id="cbd-content-area" class="content-area">
- <div class="pack-extension-heading" i18n-content="packExtensionHeading">
- </div>
+ <div class="pack-extension-heading">$i18n{packExtensionHeading}</div>
<div class="pack-extension-text-boxes">
- <label i18n-content="packExtensionRootDir"
- for="extension-root-dir"></label>
- <input class="pack-extension-text-area"
- id="extension-root-dir" type="text">
- <button id="browse-extension-dir"
- i18n-content="packExtensionBrowseButton"></button>
+ <label for="extension-root-dir">$i18n{packExtensionRootDir}</label>
+ <input class="pack-extension-text-area" id="extension-root-dir"
+ type="text">
+ <button id="browse-extension-dir">
+ $i18n{packExtensionBrowseButton}
+ </button>
</div>
<div class="pack-extension-text-boxes">
- <label i18n-content="packExtensionPrivateKey" for="extension-private-key">
- </label>
- <input class="pack-extension-text-area"
- id="extension-private-key" type="text">
- <button id="browse-private-key"
- i18n-content="packExtensionBrowseButton"></button>
+ <label for="extension-private-key">$i18n{packExtensionPrivateKey}</label>
+ <input class="pack-extension-text-area" id="extension-private-key"
+ type="text">
+ <button id="browse-private-key">
+ $i18n{packExtensionBrowseButton}
+ </button>
</div>
</div>
<div class="action-area">
<div class="action-area-right">
<div class="button-strip">
- <button id="pack-extension-dismiss" i18n-content="cancel"></button>
- <button id="pack-extension-commit"
- i18n-content="packExtensionCommit"></button>
+ <button id="pack-extension-dismiss">$i18n{cancel}</button>
+ <button id="pack-extension-commit">
+ $i18n{packExtensionCommit}
+ </button>
</div>
</div>
</div>
diff --git a/chromium/chrome/browser/resources/feedback/css/feedback.css b/chromium/chrome/browser/resources/feedback/css/feedback.css
index 0e09874bba3..7270cf6d879 100644
--- a/chromium/chrome/browser/resources/feedback/css/feedback.css
+++ b/chromium/chrome/browser/resources/feedback/css/feedback.css
@@ -16,6 +16,10 @@ body {
width: 100%;
}
+[hidden] {
+ display: none !important;
+}
+
.title-bar {
-webkit-align-items: center;
-webkit-app-region: drag;
diff --git a/chromium/chrome/browser/resources/feedback/js/event_handler.js b/chromium/chrome/browser/resources/feedback/js/event_handler.js
index 315be255a64..3776ecd641c 100644
--- a/chromium/chrome/browser/resources/feedback/js/event_handler.js
+++ b/chromium/chrome/browser/resources/feedback/js/event_handler.js
@@ -13,7 +13,11 @@ var FEEDBACK_WIDTH = 500;
*/
var FEEDBACK_HEIGHT = 585;
-var initialFeedbackInfo = null;
+/**
+ * @type {string}
+ * @const
+ */
+var FEEDBACK_DEFAULT_WINDOW_ID = 'default_window';
// To generate a hashed extension ID, use a sha-256 hash, all in lower case.
// Example:
@@ -75,6 +79,117 @@ var whitelistedExtensionIds = [
'3BC3740BFC58F06088B300274B4CFBEA20136342', // http://crbug.com/541769
];
+/**
+ * Used to generate unique IDs for FeedbackRequest objects.
+ * @type {number}
+ */
+var lastUsedId = 0;
+
+/**
+ * A FeedbackRequest object represents a unique feedback report, requested by an
+ * instance of the feedback window. It contains the system information specific
+ * to this report, the full feedbackInfo, and callbacks to send the report upon
+ * request.
+ */
+class FeedbackRequest {
+ constructor(feedbackInfo) {
+ this.id_ = ++lastUsedId;
+ this.feedbackInfo_ = feedbackInfo;
+ this.onSystemInfoReadyCallback_ = null;
+ this.isSystemInfoReady_ = false;
+ this.reportIsBeingSent_ = false;
+ this.isRequestCanceled_ = false;
+ this.useSystemInfo_ = false;
+ }
+
+ /**
+ * Called when the system information is sent from the C++ side.
+ * @param {Object} sysInfo The received system information.
+ */
+ getSystemInformationCallback(sysInfo) {
+ if (this.isRequestCanceled_) {
+ // If the window had been closed before the system information was
+ // received, we skip the rest of the operations and return immediately.
+ return;
+ }
+
+ this.isSystemInfoReady_ = true;
+
+ // Combine the newly received system information with whatever system
+ // information we have in the feedback info (if any).
+ if (this.feedbackInfo_.systemInformation) {
+ this.feedbackInfo_.systemInformation =
+ this.feedbackInfo_.systemInformation.concat(sysInfo);
+ } else {
+ this.feedbackInfo_.systemInformation = sysInfo;
+ }
+
+ if (this.onSystemInfoReadyCallback_ != null) {
+ this.onSystemInfoReadyCallback_();
+ this.onSystemInfoReadyCallback_ = null;
+ }
+ }
+
+ /**
+ * Retrieves the system information for this request object.
+ * @param {function()} callback Invoked to notify the listener that the system
+ * information has been received.
+ */
+ getSystemInformation(callback) {
+ if (this.isSystemInfoReady_) {
+ callback();
+ return;
+ }
+
+ this.onSystemInfoReadyCallback_ = callback;
+ // The C++ side must reply to the callback specific to this object.
+ var boundCallback = this.getSystemInformationCallback.bind(this);
+ chrome.feedbackPrivate.getSystemInformation(boundCallback);
+ }
+
+ /**
+ * Sends the feedback report represented by the object, either now if system
+ * information is ready, or later once it is.
+ * @param {boolean} useSystemInfo True if the user would like the system
+ * information to be sent with the report.
+ */
+ sendReport(useSystemInfo) {
+ this.reportIsBeingSent_ = true;
+ this.useSystemInfo_ = useSystemInfo;
+ if (useSystemInfo && !this.isSystemInfoReady_) {
+ this.onSystemInfoReadyCallback_ = this.sendReportNow;
+ return;
+ }
+
+ this.sendReportNow();
+ }
+
+ /**
+ * Sends the report immediately and removes this object once the report is
+ * sent.
+ */
+ sendReportNow() {
+ if (!this.useSystemInfo_) {
+ // Clear the system information if the user doesn't want it to be sent.
+ this.feedbackInfo_.systemInformation = null;
+ }
+
+ /** @const */ var ID = this.id_;
+ chrome.feedbackPrivate.sendFeedback(this.feedbackInfo_,
+ function(result) {
+ console.log('Feedback: Report sent for request with ID ' + ID);
+ });
+ }
+
+ /**
+ * Handles the event when the feedback UI window corresponding to this
+ * FeedbackRequest instance is closed.
+ */
+ onWindowClosed() {
+ if (!this.reportIsBeingSent_)
+ this.isRequestCanceled_ = true;
+ }
+};
/**
* Function to determine whether or not a given extension id is whitelisted to
@@ -109,13 +224,10 @@ function senderWhitelisted(id, startFeedbackCallback, feedbackInfo) {
* @param {function(Object)} sendResponse Callback for sending a response.
*/
function feedbackReadyHandler(request, sender, sendResponse) {
- if (request.ready) {
- chrome.runtime.sendMessage(
- {sentFromEventPage: true, data: initialFeedbackInfo});
- }
+ if (request.ready)
+ chrome.runtime.sendMessage({sentFromEventPage: true});
}
-
/**
* Callback which gets notified if another extension is requesting feedback.
* @param {Object} request The message request object.
@@ -132,20 +244,44 @@ function requestFeedbackHandler(request, sender, sendResponse) {
* @param {Object} feedbackInfo Object containing any initial feedback info.
*/
function startFeedbackUI(feedbackInfo) {
- initialFeedbackInfo = feedbackInfo;
- var win = chrome.app.window.get('default_window');
+ var win = chrome.app.window.get(FEEDBACK_DEFAULT_WINDOW_ID);
if (win) {
win.show();
return;
}
chrome.app.window.create('html/default.html', {
frame: 'none',
- id: 'default_window',
+ id: FEEDBACK_DEFAULT_WINDOW_ID,
width: FEEDBACK_WIDTH,
height: FEEDBACK_HEIGHT,
hidden: true,
resizable: false },
- function(appWindow) {});
+ function(appWindow) {
+ var request = new FeedbackRequest(feedbackInfo);
+
+ // The feedbackInfo member of the new window should refer to the one in
+ // its corresponding FeedbackRequest object to avoid copying and
+ // duplicatations.
+ appWindow.contentWindow.feedbackInfo = request.feedbackInfo_;
+
+ // Define some functions for the new window so that it can call back
+ // into here.
+
+ // Define a function for the new window to get the system information.
+ appWindow.contentWindow.getSystemInformation = function(callback) {
+ request.getSystemInformation(callback);
+ };
+
+ // Define a function to request sending the feedback report.
+ appWindow.contentWindow.sendFeedbackReport = function(useSystemInfo) {
+ request.sendReport(useSystemInfo);
+ };
+
+ // Observe when the window is closed.
+ appWindow.onClosed.addListener(function() {
+ request.onWindowClosed();
+ });
+ });
}
chrome.runtime.onMessage.addListener(feedbackReadyHandler);
diff --git a/chromium/chrome/browser/resources/feedback/js/feedback.js b/chromium/chrome/browser/resources/feedback/js/feedback.js
index b903be5eef6..065081e1da1 100644
--- a/chromium/chrome/browser/resources/feedback/js/feedback.js
+++ b/chromium/chrome/browser/resources/feedback/js/feedback.js
@@ -7,6 +7,7 @@
*/
var FEEDBACK_LANDING_PAGE =
'https://support.google.com/chrome/go/feedback_confirmation';
+
/** @type {number}
* @const
*/
@@ -17,12 +18,19 @@ var MAX_ATTACH_FILE_SIZE = 3 * 1024 * 1024;
* @const
*/
var FEEDBACK_MIN_WIDTH = 500;
+
/**
* @type {number}
* @const
*/
var FEEDBACK_MIN_HEIGHT = 585;
+/**
+ * @type {number}
+ * @const
+ */
+var FEEDBACK_MIN_HEIGHT_LOGIN = 482;
+
/** @type {number}
* @const
*/
@@ -43,14 +51,31 @@ var SYSINFO_WINDOW_ID = 'sysinfo_window';
*/
var STATS_WINDOW_ID = 'stats_window';
+/**
+ * Feedback flow defined in feedback_private.idl.
+ * @enum {string}
+ */
+var FeedbackFlow = {
+ REGULAR: 'regular', // Flow in a regular user session.
+ LOGIN: 'login' // Flow on the login screen.
+};
+
var attachedFileBlob = null;
var lastReader = null;
-var feedbackInfo = null;
-var systemInfo = null;
-
+/**
+ * Determines whether the system information associated with this instance of
+ * the feedback window has been received.
+ * @type {boolean}
+ */
var isSystemInfoReady = false;
-var onSystemInfoReadyCallback = null;
+
+/**
+ * The callback used by the sys_info_page to receive the event that the system
+ * information is ready.
+ * @type {function(sysInfo)}
+ */
+var sysInfoPageOnSysInfoReadyCallback = null;
/**
* Reads the selected file when the user selects a file.
@@ -139,8 +164,7 @@ function sendReport() {
var useSystemInfo = false;
var useHistograms = false;
if ($('sys-info-checkbox') != null &&
- $('sys-info-checkbox').checked &&
- systemInfo != null) {
+ $('sys-info-checkbox').checked) {
// Send histograms along with system info.
useSystemInfo = useHistograms = true;
}
@@ -151,28 +175,19 @@ function sendReport() {
}
</if>
- if (useSystemInfo) {
- if (feedbackInfo.systemInformation != null) {
- // Concatenate sysinfo if we had any initial system information
- // sent with the feedback request event.
- feedbackInfo.systemInformation =
- feedbackInfo.systemInformation.concat(systemInfo);
- } else {
- feedbackInfo.systemInformation = systemInfo;
- }
- }
-
feedbackInfo.sendHistograms = useHistograms;
// If the user doesn't want to send the screenshot.
if (!$('screenshot-checkbox').checked)
feedbackInfo.screenshot = null;
- chrome.feedbackPrivate.sendFeedback(feedbackInfo, function(result) {
+ // Request sending the report, show the landing page (if allowed), and close
+ // this window right away. The FeedbackRequest object that represents this
+ // report will take care of sending the report in the background.
+ sendFeedbackReport(useSystemInfo);
+ if (feedbackInfo.flow != FeedbackFlow.LOGIN)
window.open(FEEDBACK_LANDING_PAGE, '_blank');
- window.close();
- });
-
+ window.close();
return true;
}
@@ -229,21 +244,26 @@ function resizeAppWindow() {
// style.margin - the variable seems to not exist.
var height = $('title-bar').scrollHeight +
$('content-pane').scrollHeight + CONTENT_MARGIN_HEIGHT;
- if (height < FEEDBACK_MIN_HEIGHT)
- height = FEEDBACK_MIN_HEIGHT;
+
+ var minHeight = FEEDBACK_MIN_HEIGHT;
+ if (feedbackInfo.flow == FeedbackFlow.LOGIN)
+ minHeight = FEEDBACK_MIN_HEIGHT_LOGIN;
+ height = Math.max(height, minHeight);
chrome.app.window.current().resizeTo(width, height);
}
/**
- * @return {Object} the full anonymized system information we got from the
- * system as well as the extra-app added data.
+ * A callback to be invoked when the background page of this extension receives
+ * the system information.
*/
-function getFullSystemInformation() {
- var sysInfo = feedbackInfo.systemInformation;
- if (systemInfo != null)
- sysInfo = sysInfo.concat(systemInfo);
- return sysInfo;
+function onSystemInformation() {
+ isSystemInfoReady = true;
+ // In case the sys_info_page needs to be notified by this event, do so.
+ if (sysInfoPageOnSysInfoReadyCallback != null) {
+ sysInfoPageOnSysInfoReadyCallback(feedbackInfo.systemInformation);
+ sysInfoPageOnSysInfoReadyCallback = null;
+ }
}
/**
@@ -261,7 +281,9 @@ function initialize() {
// Add listener to receive the feedback info object.
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
if (request.sentFromEventPage) {
- feedbackInfo = request.data;
+ if (!feedbackInfo.flow)
+ feedbackInfo.flow = FeedbackFlow.REGULAR;
+
$('description-text').textContent = feedbackInfo.description;
if (feedbackInfo.pageUrl)
$('page-url-text').value = feedbackInfo.pageUrl;
@@ -285,12 +307,9 @@ function initialize() {
$('user-email-text').value = email;
});
- chrome.feedbackPrivate.getSystemInformation(function(sysInfo) {
- systemInfo = sysInfo;
- isSystemInfoReady = true;
- if (onSystemInfoReadyCallback != null)
- onSystemInfoReadyCallback(getFullSystemInformation());
- });
+ // Initiate getting the system info.
+ isSystemInfoReady = false;
+ getSystemInformation(onSystemInformation);
// An extension called us with an attached file.
if (feedbackInfo.attachedFile) {
@@ -301,6 +320,13 @@ function initialize() {
$('attach-file').hidden = true;
}
+ // No URL and file attachment for login screen feedback.
+ if (feedbackInfo.flow == FeedbackFlow.LOGIN) {
+ $('page-url').hidden = true;
+ $('attach-file-container').hidden = true;
+ $('attach-file-note').hidden = true;
+ }
+
<if expr="chromeos">
if (feedbackInfo.traceId && ($('performance-info-area'))) {
$('performance-info-area').hidden = false;
@@ -318,7 +344,7 @@ function initialize() {
// Opens a new window showing the full anonymized system+app
// information.
$('sys-info-url').onclick = function() {
- var win = chrome.app.window.get('sys-info-window');
+ var win = chrome.app.window.get(SYSINFO_WINDOW_ID);
if (win) {
win.show();
return;
@@ -326,22 +352,26 @@ function initialize() {
chrome.app.window.create(
'/html/sys_info.html', {
frame: 'chrome',
- id: 'sys-info-window',
+ id: SYSINFO_WINDOW_ID,
width: 600,
height: 400,
hidden: false,
resizable: true
}, function(appWindow) {
- // Define two functions for the newly created window so that it
- // can retrieve its needed data.
+ // Define functions for the newly created window.
+
+ // Gets the full system information for the new window.
appWindow.contentWindow.getFullSystemInfo =
- function(onSysInfoReady) {
+ function(callback) {
if (isSystemInfoReady) {
- onSysInfoReady(getFullSystemInformation());
+ callback(feedbackInfo.systemInformation);
return;
}
- onSystemInfoReadyCallback = onSysInfoReady;
+
+ sysInfoPageOnSysInfoReadyCallback = callback;
};
+
+ // Returns the loadTimeData for the new window.
appWindow.contentWindow.getLoadTimeData = function() {
return loadTimeData;
};
diff --git a/chromium/chrome/browser/resources/gaia_auth_host/authenticator.js b/chromium/chrome/browser/resources/gaia_auth_host/authenticator.js
index 2407ffa3582..4159df30217 100644
--- a/chromium/chrome/browser/resources/gaia_auth_host/authenticator.js
+++ b/chromium/chrome/browser/resources/gaia_auth_host/authenticator.js
@@ -31,6 +31,7 @@ cr.define('cr.login', function() {
var GAPS_COOKIE = 'GAPS';
var SERVICE_ID = 'chromeoslogin';
var EMBEDDED_SETUP_CHROMEOS_ENDPOINT = 'embedded/setup/chromeos';
+ var SAML_REDIRECTION_PATH = 'samlredirect';
/**
* The source URL parameter for the constrained signin flow.
@@ -138,6 +139,7 @@ cr.define('cr.login', function() {
this.gapsCookie_ = null;
this.gapsCookieSent_ = false;
this.newGapsCookie_ = null;
+ this.readyFired_ = false;
this.useEafe_ = false;
this.clientId_ = null;
@@ -189,7 +191,7 @@ cr.define('cr.login', function() {
* Reinitializes authentication parameters so that a failed login attempt
* would not result in an infinite loop.
*/
- Authenticator.prototype.clearCredentials_ = function() {
+ Authenticator.prototype.resetStates_ = function() {
this.email_ = null;
this.gaiaId_ = null;
this.password_ = null;
@@ -197,6 +199,7 @@ cr.define('cr.login', function() {
this.gapsCookie_ = null;
this.gapsCookieSent_ = false;
this.newGapsCookie_ = null;
+ this.readyFired_ = false;
this.chooseWhatToSync_ = false;
this.skipForNow_ = false;
this.sessionIndex_ = null;
@@ -212,7 +215,7 @@ cr.define('cr.login', function() {
*/
Authenticator.prototype.load = function(authMode, data) {
this.authMode = authMode;
- this.clearCredentials_();
+ this.resetStates_();
// gaiaUrl parameter is used for testing. Once defined, it is never changed.
this.idpOrigin_ = data.gaiaUrl || IDP_ORIGIN;
this.continueUrl_ = data.continueUrl || CONTINUE_URL;
@@ -259,11 +262,23 @@ cr.define('cr.login', function() {
* Reloads the authenticator component.
*/
Authenticator.prototype.reload = function() {
- this.clearCredentials_();
+ this.resetStates_();
this.webview_.src = this.reloadUrl_;
};
Authenticator.prototype.constructInitialFrameUrl_ = function(data) {
+ if (data.doSamlRedirect) {
+ var url = this.idpOrigin_ + SAML_REDIRECTION_PATH;
+ url = appendParam(url, 'domain', data.enterpriseDomain);
+ url = appendParam(url, 'continue', data.gaiaUrl +
+ 'o/oauth2/programmatic_auth?hl=' + data.hl +
+ '&scope=https%3A%2F%2Fwww.google.com%2Faccounts%2FOAuthLogin&' +
+ 'client_id=' + encodeURIComponent(data.clientId) +
+ '&access_type=offline');
+
+ return url;
+ }
+
var path = data.gaiaPath;
if (!path && this.isNewGaiaFlow)
path = EMBEDDED_SETUP_CHROMEOS_ENDPOINT;
@@ -311,6 +326,18 @@ cr.define('cr.login', function() {
};
/**
+ * Dispatches the 'ready' event if it hasn't been dispatched already for the
+ * current content.
+ * @private
+ */
+ Authenticator.prototype.fireReadyEvent_ = function() {
+ if (!this.readyFired_) {
+ this.dispatchEvent(new Event('ready'));
+ this.readyFired_ = true;
+ }
+ };
+
+ /**
* Invoked when a main frame request in the webview has completed.
* @private
*/
@@ -659,7 +686,7 @@ cr.define('cr.login', function() {
gapsCookie: this.newGapsCookie_ || this.gapsCookie_ || '',
}
}));
- this.clearCredentials_();
+ this.resetStates_();
};
/**
@@ -684,6 +711,8 @@ cr.define('cr.login', function() {
this.authDomain = this.samlHandler_.authDomain;
this.authFlow = AuthFlow.SAML;
+
+ this.fireReadyEvent_();
};
/**
@@ -724,7 +753,7 @@ cr.define('cr.login', function() {
this.webview_.contentWindow.postMessage(msg, currentUrl);
- this.dispatchEvent(new Event('ready'));
+ this.fireReadyEvent_();
// Focus webview after dispatching event when webview is already visible.
this.webview_.focus();
}
diff --git a/chromium/chrome/browser/resources/help/compiled_resources.gyp b/chromium/chrome/browser/resources/help/compiled_resources.gyp
index 53f39ed86cc..1f1c0e710b7 100644
--- a/chromium/chrome/browser/resources/help/compiled_resources.gyp
+++ b/chromium/chrome/browser/resources/help/compiled_resources.gyp
@@ -19,6 +19,7 @@
'../../../../ui/webui/resources/js/cr/ui/page_manager/page.js',
'../../../../ui/webui/resources/js/cr/ui/page_manager/page_manager.js',
'../../../../ui/webui/resources/js/event_tracker.js',
+ '../../../../ui/webui/resources/js/promise_resolver.js',
'../../../../ui/webui/resources/js/util.js',
'../../../../chrome/browser/resources/help/channel_change_page.js',
'../../../../chrome/browser/resources/help/help_page.js',
diff --git a/chromium/chrome/browser/resources/help/help_content.css b/chromium/chrome/browser/resources/help/help_content.css
index 4f09ff20131..6084217a376 100644
--- a/chromium/chrome/browser/resources/help/help_content.css
+++ b/chromium/chrome/browser/resources/help/help_content.css
@@ -91,6 +91,11 @@
background-size: 18px;
}
+#controlled-feature-icon {
+ background-image: url(../../../../ui/webui/resources/images/business.svg);
+ background-size: 18px;
+}
+
#update-status-message-container {
display: inline-block;
vertical-align: middle;
diff --git a/chromium/chrome/browser/resources/help/help_content.html b/chromium/chrome/browser/resources/help/help_content.html
index 0e032aa4e0e..79b90935de7 100644
--- a/chromium/chrome/browser/resources/help/help_content.html
+++ b/chromium/chrome/browser/resources/help/help_content.html
@@ -53,6 +53,7 @@
</button>
<button id="request-update" i18n-content="updateButton">
</button>
+ <div id="controlled-feature-icon" class="help-page-icon" hidden></div>
</if>
</div>
</if>
diff --git a/chromium/chrome/browser/resources/help/help_page.js b/chromium/chrome/browser/resources/help/help_page.js
index 4269098fc15..e4a6afa23af 100644
--- a/chromium/chrome/browser/resources/help/help_page.js
+++ b/chromium/chrome/browser/resources/help/help_page.js
@@ -8,7 +8,7 @@ cr.define('help', function() {
/**
* Encapsulated handling of the About page. Called 'help' internally to avoid
- * confusion with generic AboutUI (about:memory, about:sandbox, etc.).
+ * confusion with generic AboutUI (about:version, about:sandbox, etc.).
*/
function HelpPage() {
var id = loadTimeData.valueExists('aboutOverlayTabTitle') ?
@@ -56,7 +56,13 @@ cr.define('help', function() {
* True if user is allowed to change channels, false otherwise.
* @private
*/
- can_change_channel_: false,
+ canChangeChannel_: false,
+
+ /**
+ * True if we have never checked for available updates.
+ * @private
+ */
+ haveNeverCheckedForUpdates_: true,
/** @override */
initializePage: function() {
@@ -160,6 +166,20 @@ cr.define('help', function() {
$('regulatory-label').onload = function() {
$('regulatory-label-container').hidden = false;
};
+
+ $('controlled-feature-icon').onclick = function(e) {
+ var content = /** @type {HTMLElement} */(
+ document.createElement('div'));
+ content.textContent =
+ loadTimeData.getString('updateDisabledByPolicy');
+ var bubble = new cr.ui.AutoCloseBubble;
+ bubble.id = 'controlled-feature-bubble';
+ bubble.anchorNode = $('controlled-feature-icon');
+ bubble.domSibling = $('controlled-feature-icon');
+ bubble.arrowLocation = cr.ui.ArrowLocation.TOP_END;
+ bubble.content = content;
+ bubble.show();
+ };
}
var logo = $('product-logo');
@@ -269,7 +289,17 @@ cr.define('help', function() {
* @private
*/
setUpdateStatus_: function(status, message) {
+ var oldStatus = this.status_;
this.status_ = status;
+
+ if (oldStatus != status && oldStatus == 'disabled_by_admin') {
+ // If the auto update policy was recently re-enabled, then we'll
+ // re-enable the 'request-update' button.
+ this.haveNeverCheckedForUpdates_ = true;
+ }
+
+ if (status == 'checking')
+ this.haveNeverCheckedForUpdates_ = false;
this.message_ = message;
this.updateUI_();
@@ -333,14 +363,15 @@ cr.define('help', function() {
this.setUpdateImage_('failed');
$('update-status-message').innerHTML = message;
} else if (status == 'disabled_by_admin') {
+ // This is the general behavior for non-chromeos.
this.setUpdateImage_('disabled-by-admin');
$('update-status-message').innerHTML = message;
}
if (cr.isChromeOS) {
- $('change-channel').disabled = !this.can_change_channel_ ||
+ $('change-channel').disabled = !this.canChangeChannel_ ||
status == 'nearly_updated';
- $('channel-change-disallowed-icon').hidden = this.can_change_channel_;
+ $('channel-change-disallowed-icon').hidden = this.canChangeChannel_;
}
// Following invariant must be established at the end of this function:
@@ -356,13 +387,19 @@ cr.define('help', function() {
}
if (cr.isChromeOS) {
- // Only enable the update button if it hasn't been used yet or the
- // status isn't 'updated'.
- if (!$('request-update').disabled || status != 'updated') {
- // Disable the button if an update is already in progress.
- $('request-update').disabled =
- ['checking', 'updating', 'nearly_updated'].indexOf(status) > -1;
- }
+ // Re-enable the update button if we are in a stale 'updated' status or
+ // update has failed, and disable it if there's an update in progress or
+ // updates are disabled by policy.
+ $('request-update').disabled =
+ !((this.haveNeverCheckedForUpdates_ && status == 'updated') ||
+ status == 'failed');
+ // If updates are disabled by policy, unhide the
+ // controlled-feature-icon.
+ $('controlled-feature-icon').hidden = (status != 'disabled_by_admin');
+ // If updates are no longer disabled by policy and the tooltip bubble
+ // is present, we hide it.
+ if (status != 'disabled_by_admin' && $('controlled-feature-bubble'))
+ $('controlled-feature-bubble').hide();
}
var container = $('update-status-container');
@@ -373,8 +410,10 @@ cr.define('help', function() {
if (cr.isChromeOS) {
// Assume the "updated" status is stale if we haven't checked yet.
- if (status == 'updated' && !$('request-update').disabled)
+ if (status == 'updated' && this.haveNeverCheckedForUpdates_ ||
+ status == 'disabled_by_admin') {
container.hidden = true;
+ }
// Hide the request update button if auto-updating is disabled or
// a relaunch button is showing.
@@ -522,7 +561,7 @@ cr.define('help', function() {
*/
updateEnableReleaseChannel_: function(enabled) {
this.updateChannelChangerContainerVisibility_(enabled);
- this.can_change_channel_ = enabled;
+ this.canChangeChannel_ = enabled;
this.updateUI_();
},
diff --git a/chromium/chrome/browser/resources/history/compiled_resources.gyp b/chromium/chrome/browser/resources/history/compiled_resources.gyp
deleted file mode 100644
index 9934bd0e18d..00000000000
--- a/chromium/chrome/browser/resources/history/compiled_resources.gyp
+++ /dev/null
@@ -1,35 +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.
-{
- 'targets': [
- {
- 'target_name': 'history',
- 'variables': {
- 'depends': [
- '../../../../ui/webui/resources/js/action_link.js',
- '../../../../ui/webui/resources/js/assert.js',
- '../../../../ui/webui/resources/js/cr.js',
- '../../../../ui/webui/resources/js/cr/ui.js',
- '../../../../ui/webui/resources/js/cr/ui/alert_overlay.js',
- '../../../../ui/webui/resources/js/cr/ui/command.js',
- '../../../../ui/webui/resources/js/cr/ui/focus_grid.js',
- '../../../../ui/webui/resources/js/cr/ui/focus_manager.js',
- '../../../../ui/webui/resources/js/cr/ui/focus_outline_manager.js',
- '../../../../ui/webui/resources/js/cr/ui/focus_row.js',
- '../../../../ui/webui/resources/js/cr/ui/menu.js',
- '../../../../ui/webui/resources/js/cr/ui/menu_button.js',
- '../../../../ui/webui/resources/js/cr/ui/menu_item.js',
- '../../../../ui/webui/resources/js/cr/ui/overlay.js',
- '../../../../ui/webui/resources/js/cr/ui/position_util.js',
- '../../../../ui/webui/resources/js/event_tracker.js',
- '../../../../ui/webui/resources/js/compiled_resources.gyp:load_time_data',
- '../../../../ui/webui/resources/js/util.js',
- 'history_focus_manager.js',
- ],
- 'externs': ['<(EXTERNS_DIR)/chrome_send.js'],
- },
- 'includes': ['../../../../third_party/closure_compiler/compile_js.gypi'],
- }
- ],
-}
diff --git a/chromium/chrome/browser/resources/downloads/compiled_resources2.gyp b/chromium/chrome/browser/resources/history/compiled_resources2.gyp
index 4777352a9ff..6efe6a888b7 100644
--- a/chromium/chrome/browser/resources/downloads/compiled_resources2.gyp
+++ b/chromium/chrome/browser/resources/history/compiled_resources2.gyp
@@ -1,63 +1,46 @@
-# Copyright 2014 The Chromium Authors. All rights reserved.
+# 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': 'constants',
- 'dependencies': ['<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr'],
- 'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
- },
- {
'target_name': 'externs',
- 'includes': ['../../../../third_party/closure_compiler/externs_js.gypi'],
+ 'includes': ['../../../../third_party/closure_compiler/include_js.gypi'],
},
{
- 'target_name': 'item_view',
+ 'target_name': 'history_focus_manager',
'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',
- 'constants',
- 'throttled_icon_loader',
- 'externs',
+ '<(DEPTH)/ui/webui/resources/js/cr/ui/compiled_resources2.gyp:focus_manager',
],
'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
},
{
- 'target_name': 'focus_row',
+ 'target_name': 'history',
'dependencies': [
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:action_link',
'<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:assert',
'<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
- '<(DEPTH)/ui/webui/resources/js/cr/ui/compiled_resources2.gyp:focus_row',
- 'item_view',
- ],
- 'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
- },
- {
- 'target_name': 'manager',
- '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',
'<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:event_tracker',
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:load_time_data',
'<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:util',
'<(DEPTH)/ui/webui/resources/js/cr/compiled_resources2.gyp:ui',
+ '<(DEPTH)/ui/webui/resources/js/cr/ui/compiled_resources2.gyp:alert_overlay',
'<(DEPTH)/ui/webui/resources/js/cr/ui/compiled_resources2.gyp:command',
'<(DEPTH)/ui/webui/resources/js/cr/ui/compiled_resources2.gyp:focus_grid',
- 'constants',
- 'throttled_icon_loader',
- 'item_view',
- 'focus_row',
+ '<(DEPTH)/ui/webui/resources/js/cr/ui/compiled_resources2.gyp:focus_outline_manager',
+ '<(DEPTH)/ui/webui/resources/js/cr/ui/compiled_resources2.gyp:focus_row',
+ '<(DEPTH)/ui/webui/resources/js/cr/ui/compiled_resources2.gyp:menu',
+ '<(DEPTH)/ui/webui/resources/js/cr/ui/compiled_resources2.gyp:menu_button',
+ '<(DEPTH)/ui/webui/resources/js/cr/ui/compiled_resources2.gyp:menu_item',
+ '<(DEPTH)/ui/webui/resources/js/cr/ui/compiled_resources2.gyp:overlay',
+ '<(DEPTH)/ui/webui/resources/js/cr/ui/compiled_resources2.gyp:position_util',
+ 'history_focus_manager',
'<(EXTERNS_GYP):chrome_send',
'externs',
],
'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
},
- {
- 'target_name': 'throttled_icon_loader',
- '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/history/externs.js b/chromium/chrome/browser/resources/history/externs.js
new file mode 100644
index 00000000000..9a4712d9ab5
--- /dev/null
+++ b/chromium/chrome/browser/resources/history/externs.js
@@ -0,0 +1,67 @@
+// 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 Externs for objects sent from C++ to chrome://history.
+ * @externs
+ */
+
+/**
+ * The type of the history result object. The definition is based on
+ * chrome/browser/ui/webui/browsing_history_handler.cc:
+ * BrowsingHistoryHandler::HistoryEntry::ToValue()
+ * @typedef {{allTimestamps: Array<number>,
+ * blockedVisit: boolean,
+ * dateRelativeDay: string,
+ * dateShort: string,
+ * dateTimeOfDay: string,
+ * deviceName: string,
+ * deviceType: string,
+ * domain: string,
+ * fallbackFaviconText: string,
+ * hostFilteringBehavior: number,
+ * snippet: string,
+ * starred: boolean,
+ * time: number,
+ * title: string,
+ * url: string}}
+ */
+var HistoryEntry;
+
+/**
+ * The type of the history results info object. The definition is based on
+ * chrome/browser/ui/webui/browsing_history_handler.cc:
+ * BrowsingHistoryHandler::QueryComplete()
+ * @typedef {{finished: boolean,
+ * hasSyncedResults: boolean,
+ * queryEndTime: string,
+ * queryStartTime: string,
+ * term: string}}
+ */
+var HistoryQuery;
+
+/**
+ * The type of the foreign session info object. This definition is based on
+ * chrome/browser/ui/webui/foreign_session_handler.cc:
+ * @typedef {{collapsed: boolean,
+ * deviceType: string,
+ * name: string,
+ * modifiedTime: string,
+ * tag: string,
+ * timestamp: number,
+ * windows: Array}}
+ */
+var ForeignSession;
+
+/**
+ * The type of the foreign session tab object. This definition is based on
+ * chrome/browser/ui/webui/foreign_session_handler.cc:
+ * @typedef {{direction: string,
+ * sessionId: number,
+ * timestamp: number,
+ * title: string,
+ * type: string,
+ * url: string}}
+ */
+var ForeignSessionTab;
diff --git a/chromium/chrome/browser/resources/history/history.css b/chromium/chrome/browser/resources/history/history.css
index f3d432b3f6d..810aa55ae98 100644
--- a/chromium/chrome/browser/resources/history/history.css
+++ b/chromium/chrome/browser/resources/history/history.css
@@ -38,15 +38,23 @@ html[dir='rtl'] #notification-bar {
float: left;
}
-#notification-bar.alone {
+#top-container.overflow #notification-bar {
float: left;
margin-top: 12px;
}
-html[dir='rtl'] #notification-bar.alone {
+html[dir='rtl'] #top-container.overflow #notification-bar {
float: right;
}
+#notification-bar span {
+ display: block;
+}
+
+#notification-bar span + span {
+ margin: 1em 0;
+}
+
#filter-controls,
#top-container,
#results-display,
@@ -73,6 +81,10 @@ html[dir='rtl'] #editing-controls {
float: right;
}
+#top-container.overflow #editing-controls {
+ float: none;
+}
+
#editing-controls button:first-of-type {
-webkit-margin-start: 0;
}
@@ -334,12 +346,6 @@ html[dir='rtl'] .number-visits {
margin-top: 1px;
}
-html[dir='rtl'] .entry .title,
-html[dir='rtl'] .site-domain {
- /* Put the favicon on the right. */
- background-position-x: right;
-}
-
.entry .time {
color: rgb(151, 156, 160);
max-width: 90px;
@@ -447,38 +453,29 @@ html[dir='rtl'] .site-domain {
white-space: nowrap;
}
-.entry .visit-entry,
-.site-domain {
- /* Make room for the favicon. */
- -webkit-padding-start: 16px;
-}
-
-.entry .visit-entry,
-.site-domain,
-.blocked-indicator {
- /* Control the favicon appearance. */
- background-position-y: center;
- background-repeat: no-repeat;
- background-size: 16px;
-}
-
-html[dir='rtl'] .entry .visit-entry,
-html[dir='rtl'] .site-domain,
-html[dir='rtl'] .blocked-indicator {
- background-position-x: right;
-}
-
/* TODO(sergiu): If this is the final icon replace it with a separate resource.
*/
.entry .blocked-indicator {
- -webkit-padding-start: 20px; /* 16px for favicon, 4px for <a> padding. */
- background-image: url(../ssl/images/roadblock.png);
+ -webkit-padding-start: 4px; /* For <a> padding. */
}
.blocked-indicator .title {
color: rgb(151, 156, 160);
}
+.blocked-icon {
+ background-image: url(../ssl/images/roadblock.png)
+}
+
+.favicon {
+ background-position-y: center;
+ background-repeat: no-repeat;
+ background-size: 16px;
+ flex-shrink: 0;
+ height: 16px;
+ width: 16px;
+}
+
.site-domain button:hover {
text-decoration: none;
}
diff --git a/chromium/chrome/browser/resources/history/history.js b/chromium/chrome/browser/resources/history/history.js
index 3ea486d1f9a..1fac5042896 100644
--- a/chromium/chrome/browser/resources/history/history.js
+++ b/chromium/chrome/browser/resources/history/history.js
@@ -46,39 +46,6 @@ var SupervisedUserFilteringBehavior = {
};
/**
- * The type of the history result object. The definition is based on
- * chrome/browser/ui/webui/history_ui.cc:
- * BrowsingHistoryHandler::HistoryEntry::ToValue()
- * @typedef {{allTimestamps: Array<number>,
- * blockedVisit: (boolean|undefined),
- * dateRelativeDay: (string|undefined),
- * dateShort: string,
- * dateTimeOfDay: (string|undefined),
- * deviceName: string,
- * deviceType: string,
- * domain: string,
- * hostFilteringBehavior: (number|undefined),
- * snippet: (string|undefined),
- * starred: boolean,
- * time: number,
- * title: string,
- * url: string}}
- */
-var HistoryEntry;
-
-/**
- * The type of the history results info object. The definition is based on
- * chrome/browser/ui/webui/history_ui.cc:
- * BrowsingHistoryHandler::QueryComplete()
- * @typedef {{finished: boolean,
- * hasSyncedResults: (boolean|undefined),
- * queryEndTime: string,
- * queryStartTime: string,
- * term: string}}
- */
-var HistoryQuery;
-
-/**
* Returns true if the mobile (non-desktop) version is being shown.
* @return {boolean} true if the mobile version is being shown.
*/
@@ -125,6 +92,7 @@ function Visit(result, continued, model) {
this.url_ = result.url;
this.domain_ = result.domain;
this.starred_ = result.starred;
+ this.fallbackFaviconText_ = result.fallbackFaviconText;
// These identify the name and type of the device on which this visit
// occurred. They will be empty if the visit occurred on the current device.
@@ -144,19 +112,19 @@ function Visit(result, continued, model) {
// See comment in BrowsingHistoryHandler::QueryComplete - we won't always
// get all of these.
- this.dateRelativeDay = result.dateRelativeDay || '';
- this.dateTimeOfDay = result.dateTimeOfDay || '';
- this.dateShort = result.dateShort || '';
+ this.dateRelativeDay = result.dateRelativeDay;
+ this.dateTimeOfDay = result.dateTimeOfDay;
+ this.dateShort = result.dateShort;
// Shows the filtering behavior for that host (only used for supervised
// users).
// A value of |SupervisedUserFilteringBehavior.ALLOW| is not displayed so it
// is used as the default value.
this.hostFilteringBehavior = SupervisedUserFilteringBehavior.ALLOW;
- if (typeof result.hostFilteringBehavior != 'undefined')
+ if (result.hostFilteringBehavior)
this.hostFilteringBehavior = result.hostFilteringBehavior;
- this.blockedVisit = result.blockedVisit || false;
+ this.blockedVisit = result.blockedVisit;
// Whether this is the continuation of a previous day.
this.continued = continued;
@@ -252,6 +220,15 @@ Visit.prototype.getResultDOM = function(propertyBag) {
entryBox.appendChild(bookmarkSection);
+ if (addTitleFavicon || this.blockedVisit) {
+ var faviconSection = createElementWithClassName('div', 'favicon');
+ if (this.blockedVisit)
+ faviconSection.classList.add('blocked-icon');
+ else
+ this.loadFavicon_(faviconSection);
+ entryBox.appendChild(faviconSection);
+ }
+
var visitEntryWrapper = /** @type {HTMLElement} */(
entryBox.appendChild(document.createElement('div')));
if (addTitleFavicon || this.blockedVisit)
@@ -263,9 +240,6 @@ Visit.prototype.getResultDOM = function(propertyBag) {
var title = visitEntryWrapper.appendChild(
this.getTitleDOM_(isSearchResult));
- if (addTitleFavicon)
- this.addFaviconToElement_(visitEntryWrapper);
-
if (focusless)
title.querySelector('a').tabIndex = -1;
@@ -394,7 +368,7 @@ Object.defineProperty(Visit.prototype, 'dropDown', {
Visit.prototype.addHighlightedText_ = function(node, content, highlightText) {
var i = 0;
if (highlightText) {
- var re = new RegExp(Visit.pregQuote_(highlightText), 'gim');
+ var re = new RegExp(quoteString(highlightText), 'gim');
var match;
while (match = re.exec(content)) {
if (match.index > i)
@@ -473,15 +447,42 @@ Visit.prototype.getVisitAttemptDOM_ = function() {
};
/**
- * Set the favicon for an element.
- * @param {Element} el The DOM element to which to add the icon.
+ * Load the favicon for an element.
+ * @param {Element} faviconDiv The DOM element for which to load the icon.
+ * @private
+ */
+Visit.prototype.loadFavicon_ = function(faviconDiv) {
+ if (cr.isAndroid) {
+ // On Android, if a large icon is unavailable, an HTML/CSS fallback favicon
+ // is generated because Android does not yet support text drawing in native.
+
+ // Check whether a fallback favicon needs to be generated.
+ var desiredPixelSize = 32 * window.devicePixelRatio;
+ var img = new Image();
+ img.onload = this.onLargeFaviconLoadedAndroid_.bind(this, faviconDiv);
+ img.src = 'chrome://large-icon/' + desiredPixelSize + '/' + this.url_;
+ } else {
+ faviconDiv.style.backgroundImage = getFaviconImageSet(this.url_);
+ }
+};
+
+/**
+ * Called when the chrome://large-icon image has finished loading.
+ * @param {Element} faviconDiv The DOM element to add the favicon to.
+ * @param {Event} event The onload event.
* @private
*/
-Visit.prototype.addFaviconToElement_ = function(el) {
- var url = isMobileVersion() ?
- getFaviconImageSet(this.url_, 32, 'touch-icon') :
- getFaviconImageSet(this.url_);
- el.style.backgroundImage = url;
+Visit.prototype.onLargeFaviconLoadedAndroid_ = function(faviconDiv, event) {
+ // The loaded image should either:
+ // - Have the desired size.
+ // OR
+ // - Be 1x1 px with the background color for the fallback icon.
+ var loadedImg = event.target;
+ if (loadedImg.width == 1) {
+ faviconDiv.classList.add('fallback-favicon');
+ faviconDiv.textContent = this.fallbackFaviconText_;
+ }
+ faviconDiv.style.backgroundImage = url(loadedImg.src);
};
/**
@@ -535,18 +536,6 @@ Visit.prototype.removeEntryFromHistory_ = function(e) {
e.preventDefault();
};
-// Visit, private, static: ----------------------------------------------------
-
-/**
- * Quote a string so it can be used in a regular expression.
- * @param {string} str The source string.
- * @return {string} The escaped string.
- * @private
- */
-Visit.pregQuote_ = function(str) {
- return str.replace(/([\\\.\+\*\?\[\^\]\$\(\)\{\}\=\!\<\>\|\:])/g, '\\$1');
-};
-
///////////////////////////////////////////////////////////////////////////////
// HistoryModel:
@@ -655,12 +644,6 @@ HistoryModel.prototype.addResults = function(info, results) {
lastDay = thisDay;
}
- if (loadTimeData.getBoolean('isUserSignedIn')) {
- var message = loadTimeData.getString(
- info.hasSyncedResults ? 'hasSyncedResults' : 'noSyncedResults');
- this.view_.showNotification(message);
- }
-
this.updateSearch_();
};
@@ -893,7 +876,7 @@ HistoryModel.prototype.getGroupByDomain = function() {
/**
* Provides an implementation for a single column grid.
* @param {!Element} root
- * @param {Node} boundary
+ * @param {?Element} boundary
* @constructor
* @extends {cr.ui.FocusRow}
*/
@@ -1178,6 +1161,31 @@ HistoryView.prototype.showNotification = function(innerHTML, isWarning) {
};
/**
+ * Shows a notification about whether there are any synced results, and whether
+ * there are other forms of browsing history on the server.
+ * @param {boolean} hasSyncedResults Whether there are synced results.
+ * @param {boolean} includeOtherFormsOfBrowsingHistory Whether to include
+ * a sentence about the existence of other forms of browsing history.
+ */
+HistoryView.prototype.showWebHistoryNotification = function(
+ hasSyncedResults, includeOtherFormsOfBrowsingHistory) {
+ var message = '';
+
+ if (loadTimeData.getBoolean('isUserSignedIn')) {
+ message += '<span>' + loadTimeData.getString(
+ hasSyncedResults ? 'hasSyncedResults' : 'noSyncedResults') + '</span>';
+ }
+
+ if (includeOtherFormsOfBrowsingHistory) {
+ message += ' ' /* A whitespace to separate <span>s. */ + '<span>' +
+ loadTimeData.getString('otherFormsOfBrowsingHistory') + '</span>';
+ }
+
+ if (message)
+ this.showNotification(message, false /* isWarning */);
+};
+
+/**
* @param {Visit} visit The visit about to be removed from this view.
*/
HistoryView.prototype.onBeforeRemove = function(visit) {
@@ -1285,19 +1293,19 @@ HistoryView.prototype.onEntryRemoved = function() {
*/
HistoryView.prototype.positionNotificationBar = function() {
var bar = $('notification-bar');
+ var container = $('top-container');
- // If the bar does not fit beside the editing controls, put it into the
- // overflow state.
- if (bar.getBoundingClientRect().top >=
- $('editing-controls').getBoundingClientRect().bottom) {
- bar.classList.add('alone');
- } else {
- bar.classList.remove('alone');
- }
+ // If the bar does not fit beside the editing controls, or if it contains
+ // more than one message, put it into the overflow state.
+ var shouldOverflow =
+ (bar.getBoundingClientRect().top >=
+ $('editing-controls').getBoundingClientRect().bottom) ||
+ bar.childElementCount > 1;
+ container.classList.toggle('overflow', shouldOverflow);
};
/**
- * @param {Element} el An element to look for.
+ * @param {!Element} el An element to look for.
* @return {boolean} Whether |el| is in |this.focusGrid_|.
*/
HistoryView.prototype.isInFocusGrid = function(el) {
@@ -1374,6 +1382,8 @@ HistoryView.prototype.getGroupedVisitsDOM_ = function(
var siteArrow = siteDomainRow.appendChild(
createElementWithClassName('div', 'site-domain-arrow'));
+ var siteFavicon = siteDomainRow.appendChild(
+ createElementWithClassName('div', 'favicon'));
var siteDomain = siteDomainRow.appendChild(
createElementWithClassName('div', 'site-domain'));
var siteDomainLink = siteDomain.appendChild(new ActionLink);
@@ -1385,7 +1395,7 @@ HistoryView.prototype.getGroupedVisitsDOM_ = function(
domainVisits.length);
siteDomain.appendChild(numberOfVisits);
- domainVisits[0].addFaviconToElement_(siteDomain);
+ domainVisits[0].loadFavicon_(siteFavicon);
siteDomainWrapper.addEventListener(
'click', this.toggleGroupedVisits_.bind(this));
@@ -2355,6 +2365,19 @@ function historyResult(info, results) {
}
/**
+ * Called by the history backend after receiving results and after discovering
+ * the existence of other forms of browsing history.
+ * @param {boolean} hasSyncedResults Whether there are synced results.
+ * @param {boolean} includeOtherFormsOfBrowsingHistory Whether to include
+ * a sentence about the existence of other forms of browsing history.
+ */
+function showNotification(
+ hasSyncedResults, includeOtherFormsOfBrowsingHistory) {
+ historyView.showWebHistoryNotification(
+ hasSyncedResults, includeOtherFormsOfBrowsingHistory);
+}
+
+/**
* Called by the history backend when history removal is successful.
*/
function deleteComplete() {
diff --git a/chromium/chrome/browser/resources/history/history_mobile.css b/chromium/chrome/browser/resources/history/history_mobile.css
index 4a4bfbfb021..2e4bf38f440 100644
--- a/chromium/chrome/browser/resources/history/history_mobile.css
+++ b/chromium/chrome/browser/resources/history/history_mobile.css
@@ -13,6 +13,7 @@ html {
}
body {
+ background-color: rgba(0, 0, 0, .05);
color: rgb(76, 76, 76);
font-size: initial;
height: 100%;
@@ -32,6 +33,7 @@ body {
}
h1 {
+ color: rgb(34, 34, 34);
font-weight: bold;
margin-bottom: 12px;
}
@@ -87,9 +89,20 @@ html[dir='rtl'] #search-field {
background-position: right 16px center;
}
-#notification-bar.alone {
+#notification-bar {
+ color: rgb(138, 138, 138);
+ font-size: 14px;
+ line-height: 1.5;
+}
+
+#notification-bar span {
+ /* On desktop, notification spans are displayed as separate paragraphs.
+ On mobile, join them into a single paragraph. */
+ display: inline;
+}
+
+#top-container.overflow #notification-bar {
float: none;
- font-size: 75%;
margin: 0;
padding-bottom: 0;
padding-top: 0;
@@ -123,6 +136,10 @@ button.remove-entry:active {
opacity: 1.0;
}
+.entry {
+ background-color: white;
+}
+
.entry-box {
margin-bottom: 0;
margin-top: 0;
@@ -196,8 +213,7 @@ input {
.entry .visit-entry {
-webkit-flex: auto;
-webkit-flex-flow: column;
- -webkit-padding-start: 48px;
- background-size: 32px;
+ -webkit-padding-start: 16px;
line-height: 1.3;
}
@@ -221,6 +237,19 @@ input {
display: inline;
}
+.favicon {
+ background-size: 32px;
+ height: 32px;
+ width: 32px;
+}
+
+.fallback-favicon {
+ border-radius: 2px;
+ color: white;
+ font: bold 20px/32px sans-serif;
+ text-align: center;
+}
+
.entry .domain {
font-size: 14px;
}
diff --git a/chromium/chrome/browser/resources/inline_login/inline_login.css b/chromium/chrome/browser/resources/inline_login/inline_login.css
index 0c8c5f20e04..c0cf004d4dc 100644
--- a/chromium/chrome/browser/resources/inline_login/inline_login.css
+++ b/chromium/chrome/browser/resources/inline_login/inline_login.css
@@ -33,3 +33,14 @@ body,
#contents:not(.loading) #spinner-container {
display: none;
}
+
+#navigation-button {
+ color: white;
+ position: absolute;
+ top: 0;
+ visibility: hidden;
+}
+
+#navigation-button.enabled {
+ visibility: visible;
+}
diff --git a/chromium/chrome/browser/resources/inline_login/inline_login.js b/chromium/chrome/browser/resources/inline_login/inline_login.js
index 80398495e6b..7e67cbc0728 100644
--- a/chromium/chrome/browser/resources/inline_login/inline_login.js
+++ b/chromium/chrome/browser/resources/inline_login/inline_login.js
@@ -53,6 +53,7 @@ cr.define('inline.login', function() {
* Initialize the UI.
*/
function initialize() {
+ $('navigation-button').addEventListener('click', navigationButtonClicked);
authExtHost = new cr.login.GaiaAuthHost('signin-frame');
authExtHost.addEventListener('dropLink', onDropLink);
authExtHost.addEventListener('ready', onAuthReady);
@@ -105,13 +106,36 @@ cr.define('inline.login', function() {
return authReadyFired;
}
+ function showBackButton() {
+
+ $('navigation-button').icon =
+ isRTL() ? 'icons:arrow-forward' : 'icons:arrow-back';
+
+ $('navigation-button').setAttribute(
+ 'aria-label', loadTimeData.getString('accessibleBackButtonLabel'));
+ }
+
+ function showCloseButton() {
+ $('navigation-button').icon = 'icons:close';
+ $('navigation-button').classList.add('enabled');
+ $('navigation-button').setAttribute(
+ 'aria-label', loadTimeData.getString('accessibleCloseButtonLabel'));
+ }
+
+ function navigationButtonClicked() {
+ chrome.send('navigationButtonClicked');
+ }
+
return {
+ closeDialog: closeDialog,
getAuthExtHost: getAuthExtHost,
- isAuthReady: isAuthReady,
+ handleOAuth2TokenFailure: handleOAuth2TokenFailure,
initialize: initialize,
+ isAuthReady: isAuthReady,
loadAuthExtension: loadAuthExtension,
- closeDialog: closeDialog,
- handleOAuth2TokenFailure: handleOAuth2TokenFailure
+ navigationButtonClicked: navigationButtonClicked,
+ showBackButton: showBackButton,
+ showCloseButton: showCloseButton
};
});
diff --git a/chromium/chrome/browser/resources/inline_login/new_inline_login.html b/chromium/chrome/browser/resources/inline_login/new_inline_login.html
index 2acb5c5944f..bf65d14131d 100644
--- a/chromium/chrome/browser/resources/inline_login/new_inline_login.html
+++ b/chromium/chrome/browser/resources/inline_login/new_inline_login.html
@@ -2,6 +2,8 @@
<html i18n-values="dir:textdirection;lang:language">
<head>
<title i18n-content="title"></title>
+ <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/iron-icons/iron-icons.html">
<link rel="stylesheet" href="chrome://resources/css/text_defaults.css">
<link rel="stylesheet" href="chrome://resources/css/spinner.css">
<link rel="stylesheet" href="chrome://chrome-signin/inline_login.css">
@@ -20,6 +22,8 @@
<div class="spinner"></div>
</div>
</div>
+ <paper-icon-button id="navigation-button"
+ icon="icons:close"></paper-icon-button>
<script src="chrome://resources/js/i18n_template.js"></script>
</body>
</html>
diff --git a/chromium/chrome/browser/resources/input_ime/OWNERS b/chromium/chrome/browser/resources/input_ime/OWNERS
new file mode 100644
index 00000000000..4235129a1e4
--- /dev/null
+++ b/chromium/chrome/browser/resources/input_ime/OWNERS
@@ -0,0 +1,2 @@
+shuchen@chromium.org
+azurewei@chromium.org
diff --git a/chromium/chrome/browser/resources/input_ime/ime_window_close.png b/chromium/chrome/browser/resources/input_ime/ime_window_close.png
new file mode 100644
index 00000000000..0010118ca99
--- /dev/null
+++ b/chromium/chrome/browser/resources/input_ime/ime_window_close.png
Binary files differ
diff --git a/chromium/chrome/browser/resources/input_ime/ime_window_close_click.png b/chromium/chrome/browser/resources/input_ime/ime_window_close_click.png
new file mode 100644
index 00000000000..a954503b6d3
--- /dev/null
+++ b/chromium/chrome/browser/resources/input_ime/ime_window_close_click.png
Binary files differ
diff --git a/chromium/chrome/browser/resources/input_ime/ime_window_close_hover.png b/chromium/chrome/browser/resources/input_ime/ime_window_close_hover.png
new file mode 100644
index 00000000000..a954503b6d3
--- /dev/null
+++ b/chromium/chrome/browser/resources/input_ime/ime_window_close_hover.png
Binary files differ
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 98ebea550ab..5a7350ac7e2 100644
--- a/chromium/chrome/browser/resources/local_ntp/most_visited_single.js
+++ b/chromium/chrome/browser/resources/local_ntp/most_visited_single.js
@@ -271,15 +271,7 @@ var showTiles = function() {
tiles = document.createElement('div');
if (impressionUrl) {
- if (navigator.sendBeacon) {
- navigator.sendBeacon(impressionUrl);
- } else {
- // if sendBeacon is not enabled, we fallback to "a ping".
- var a = document.createElement('a');
- a.href = '#';
- a.ping = impressionUrl;
- a.click();
- }
+ navigator.sendBeacon(impressionUrl);
impressionUrl = null;
}
};
@@ -327,6 +319,17 @@ var blacklistTile = function(tile) {
/**
+ * Returns whether the given URL has a known, safe scheme.
+ * @param {string} url URL to check.
+ */
+var isSchemeAllowed = function(url) {
+ return url.startsWith('http://') || url.startsWith('https://') ||
+ url.startsWith('ftp://') || url.startsWith('file://') ||
+ url.startsWith('chrome-extension://');
+};
+
+
+/**
* Renders a MostVisited tile to the DOM.
* @param {object} data Object containing rid, url, title, favicon, thumbnail.
* data is null if you want to construct an empty tile.
@@ -343,31 +346,25 @@ var renderTile = function(data) {
tile.className = 'mv-tile';
tile.setAttribute('data-tid', data.tid);
- var tooltip = queryArgs['removeTooltip'] || '';
var html = [];
if (!USE_ICONS) {
html.push('<div class="mv-favicon"></div>');
}
html.push('<div class="mv-title"></div><div class="mv-thumb"></div>');
- html.push('<div title="' + tooltip + '" class="mv-x"></div>');
+ html.push('<div class="mv-x"></div>');
tile.innerHTML = html.join('');
+ tile.lastElementChild.title = queryArgs['removeTooltip'] || '';
- tile.href = data.url;
+ if (isSchemeAllowed(data.url)) {
+ tile.href = data.url;
+ }
tile.title = data.title;
if (data.impressionUrl) {
impressionUrl = data.impressionUrl;
}
if (data.pingUrl) {
tile.addEventListener('click', function(ev) {
- if (navigator.sendBeacon) {
- navigator.sendBeacon(data.pingUrl);
- } else {
- // if sendBeacon is not enabled, we fallback to "a ping".
- var a = document.createElement('a');
- a.href = '#';
- a.ping = data.pingUrl;
- a.click();
- }
+ navigator.sendBeacon(data.pingUrl);
});
}
// For local suggestions, we use navigateContentWindow instead of the default
@@ -379,7 +376,7 @@ var renderTile = function(data) {
ev.button == 1, // MIDDLE BUTTON
ev.altKey, ev.ctrlKey, ev.metaKey, ev.shiftKey);
- window.chrome.embeddedSearch.newTabPage.navigateContentWindow(this.href,
+ window.chrome.embeddedSearch.newTabPage.navigateContentWindow(data.rid,
disp);
});
}
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 9c00c58ae14..d0338ab1501 100644
--- a/chromium/chrome/browser/resources/local_ntp/most_visited_util.js
+++ b/chromium/chrome/browser/resources/local_ntp/most_visited_util.js
@@ -165,9 +165,10 @@ function createMostVisitedLink(params, href, title, text, direction, provider) {
provider || '');
}
- if (!isServerSuggestion) {
+ if ('rid' in params) {
e.preventDefault();
- ntpApiHandle.navigateContentWindow(href, getDispositionFromEvent(e));
+ ntpApiHandle.navigateContentWindow(params.rid,
+ getDispositionFromEvent(e));
}
// Else follow <a> normally, so transition type would be LINK.
};
diff --git a/chromium/chrome/browser/resources/md_downloads/compiled_resources.gyp b/chromium/chrome/browser/resources/md_downloads/compiled_resources.gyp
deleted file mode 100644
index 89a982f5363..00000000000
--- a/chromium/chrome/browser/resources/md_downloads/compiled_resources.gyp
+++ /dev/null
@@ -1,40 +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.
-{
- 'targets': [
- {
- 'target_name': 'manager',
- 'variables': {
- 'depends': [
- '../../../../ui/webui/resources/cr_elements/cr_search_field/cr_search_field.js',
- '../../../../ui/webui/resources/js/action_link.js',
- '../../../../ui/webui/resources/js/assert.js',
- '../../../../ui/webui/resources/js/compiled_resources.gyp:load_time_data',
- '../../../../ui/webui/resources/js/cr.js',
- '../../../../ui/webui/resources/js/event_tracker.js',
- '../../../../ui/webui/resources/js/cr/ui.js',
- '../../../../ui/webui/resources/js/cr/ui/command.js',
- '../../../../ui/webui/resources/js/util.js',
- '../../../../third_party/polymer/v1_0/components-chromium/iron-a11y-keys-behavior/iron-a11y-keys-behavior-extracted.js',
- '../../../../third_party/polymer/v1_0/components-chromium/iron-behaviors/iron-button-state-extracted.js',
- '../../../../third_party/polymer/v1_0/components-chromium/iron-behaviors/iron-control-state-extracted.js',
- '../../../../third_party/polymer/v1_0/components-chromium/iron-list/iron-list-extracted.js',
- '../../../../third_party/polymer/v1_0/components-chromium/iron-resizable-behavior/iron-resizable-behavior-extracted.js',
- '../../../../third_party/polymer/v1_0/components-chromium/paper-behaviors/paper-inky-focus-behavior-extracted.js',
- '../../../../third_party/polymer/v1_0/components-chromium/paper-behaviors/paper-ripple-behavior-extracted.js',
- '../../../../third_party/polymer/v1_0/components-chromium/paper-ripple/paper-ripple-extracted.js',
- 'action_service.js',
- 'constants.js',
- 'item.js',
- 'toolbar.js',
- ],
- 'externs': [
- '<(EXTERNS_DIR)/chrome_send.js',
- 'externs.js',
- ],
- },
- 'includes': ['../../../../third_party/closure_compiler/compile_js.gypi'],
- }
- ],
-}
diff --git a/chromium/chrome/browser/resources/md_downloads/compiled_resources2.gyp b/chromium/chrome/browser/resources/md_downloads/compiled_resources2.gyp
index bc280d8fe32..f4498cfabc5 100644
--- a/chromium/chrome/browser/resources/md_downloads/compiled_resources2.gyp
+++ b/chromium/chrome/browser/resources/md_downloads/compiled_resources2.gyp
@@ -19,14 +19,14 @@
},
{
'target_name': 'externs',
- 'includes': ['../../../../third_party/closure_compiler/externs_js.gypi'],
+ 'includes': ['../../../../third_party/closure_compiler/include_js.gypi'],
},
{
'target_name': 'item',
'dependencies': [
- # TODO(dbeam): create compiled_resources2.gyp files for Polymer.
'<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
'<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:load_time_data',
+ '<(DEPTH)/third_party/polymer/v1_0/components-chromium/paper-behaviors/compiled_resources2.gyp:paper-inky-focus-behavior-extracted',
'constants',
'action_service',
'externs',
@@ -41,11 +41,12 @@
'<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:util',
'<(DEPTH)/ui/webui/resources/js/cr/compiled_resources2.gyp:ui',
'<(DEPTH)/ui/webui/resources/js/cr/ui/compiled_resources2.gyp:command',
+ '<(DEPTH)/third_party/polymer/v1_0/components-chromium/iron-list/compiled_resources2.gyp:iron-list-extracted',
'action_service',
'item',
'toolbar',
'<(EXTERNS_GYP):chrome_send',
- '../downloads/compiled_resources2.gyp:externs',
+ 'externs',
],
'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
},
diff --git a/chromium/chrome/browser/resources/md_downloads/crisper.js b/chromium/chrome/browser/resources/md_downloads/crisper.js
index 4741e55d1f7..efa2abf0e12 100644
--- a/chromium/chrome/browser/resources/md_downloads/crisper.js
+++ b/chromium/chrome/browser/resources/md_downloads/crisper.js
@@ -1,11 +1,38 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
+// 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.
-if (typeof Polymer == 'undefined')
- Polymer = {dom: 'shadow'};
-else
- console.error('Polymer is already defined.');
+/**
+ * @fileoverview PromiseResolver is a helper class that allows creating a
+ * Promise that will be fulfilled (resolved or rejected) some time later.
+ *
+ * Example:
+ * var resolver = new PromiseResolver();
+ * resolver.promise.then(function(result) {
+ * console.log('resolved with', result);
+ * });
+ * ...
+ * ...
+ * resolver.resolve({hello: 'world'});
+ */
+
+/**
+ * @constructor @struct
+ * @template T
+ */
+function PromiseResolver() {
+ /** @type {function(T): void} */
+ this.resolve;
+
+ /** @type {function(*=): void} */
+ this.reject;
+
+ /** @type {!Promise<T>} */
+ this.promise = new Promise(function(resolve, reject) {
+ this.resolve = resolve;
+ this.reject = reject;
+ }.bind(this));
+};
// 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.
@@ -17,8 +44,11 @@ else
*/
var global = this;
+/** @typedef {{eventName: string, uid: number}} */
+var WebUIListener;
+
/** Platform, package, object property, and Event support. **/
-var cr = function() {
+var cr = cr || function() {
'use strict';
/**
@@ -30,6 +60,8 @@ var cr = function() {
* @param {*=} opt_object The object to expose at the end of the path.
* @param {Object=} opt_objectToExportTo The object to add the path to;
* default is {@code global}.
+ * @return {!Object} The last object exported (i.e. exportPath('cr.ui')
+ * returns a reference to the ui property of window.cr).
* @private
*/
function exportPath(name, opt_object, opt_objectToExportTo) {
@@ -47,7 +79,7 @@ var cr = function() {
}
}
return cur;
- };
+ }
/**
* Fires a property change event on the target.
@@ -321,56 +353,62 @@ var cr = function() {
}
/**
- * The mapping used by the sendWithCallback mechanism to tie the callback
- * supplied to an invocation of sendWithCallback with the WebUI response
- * sent by the browser in response to the chrome.send call. The mapping is
- * from ID to callback function; the ID is generated by sendWithCallback and
- * is unique across all invocations of said method.
- * @type {!Object<Function>}
+ * The mapping used by the sendWithPromise mechanism to tie the Promise
+ * returned to callers with the corresponding WebUI response. The mapping is
+ * from ID to the PromiseResolver helper; the ID is generated by
+ * sendWithPromise and is unique across all invocations of said method.
+ * @type {!Object<!PromiseResolver>}
*/
- var chromeSendCallbackMap = Object.create(null);
+ var chromeSendResolverMap = {};
/**
* The named method the WebUI handler calls directly in response to a
- * chrome.send call that expects a callback. The handler requires no knowledge
+ * chrome.send call that expects a response. The handler requires no knowledge
* of the specific name of this method, as the name is passed to the handler
* as the first argument in the arguments list of chrome.send. The handler
* must pass the ID, also sent via the chrome.send arguments list, as the
* first argument of the JS invocation; additionally, the handler may
- * supply any number of other arguments that will be forwarded to the
- * callback.
- * @param {string} id The unique ID identifying the callback method this
- * response is tied to.
+ * supply any number of other arguments that will be included in the response.
+ * @param {string} id The unique ID identifying the Promise this response is
+ * tied to.
+ * @param {boolean} isSuccess Whether the request was successful.
+ * @param {*} response The response as sent from C++.
*/
- function webUIResponse(id) {
- chromeSendCallbackMap[id].apply(
- null, Array.prototype.slice.call(arguments, 1));
- delete chromeSendCallbackMap[id];
+ function webUIResponse(id, isSuccess, response) {
+ var resolver = chromeSendResolverMap[id];
+ delete chromeSendResolverMap[id];
+
+ if (isSuccess)
+ resolver.resolve(response);
+ else
+ resolver.reject(response);
}
/**
- * A variation of chrome.send which allows the client to receive a direct
- * callback without requiring the handler to have specific knowledge of any
- * JS internal method names or state. The callback will be removed from the
- * mapping once it has fired.
+ * A variation of chrome.send, suitable for messages that expect a single
+ * response from C++.
* @param {string} methodName The name of the WebUI handler API.
- * @param {Array|undefined} args Arguments for the method call sent to the
- * WebUI handler. Pass undefined if no args should be sent to the handler.
- * @param {Function} callback A callback function which is called (indirectly)
- * by the WebUI handler.
+ * @param {...*} var_args Varibale number of arguments to be forwarded to the
+ * C++ call.
+ * @return {!Promise}
*/
- function sendWithCallback(methodName, args, callback) {
- var id = methodName + createUid();
- chromeSendCallbackMap[id] = callback;
- chrome.send(methodName, ['cr.webUIResponse', id].concat(args || []));
+ function sendWithPromise(methodName, var_args) {
+ var args = Array.prototype.slice.call(arguments, 1);
+ var promiseResolver = new PromiseResolver();
+ var id = methodName + '_' + createUid();
+ chromeSendResolverMap[id] = promiseResolver;
+ chrome.send(methodName, [id].concat(args));
+ return promiseResolver.promise;
}
/**
- * A registry of callbacks keyed by event name. Used by addWebUIListener to
- * register listeners.
- * @type {!Object<Array<Function>>}
+ * A map of maps associating event names with listeners. The 2nd level map
+ * associates a listener ID with the callback function, such that individual
+ * listeners can be removed from an event without affecting other listeners of
+ * the same event.
+ * @type {!Object<!Object<!Function>>}
*/
- var webUIListenerMap = Object.create(null);
+ var webUIListenerMap = {};
/**
* The named method the WebUI handler calls directly when an event occurs.
@@ -378,26 +416,52 @@ var cr = function() {
* of the JS invocation; additionally, the handler may supply any number of
* other arguments that will be forwarded to the listener callbacks.
* @param {string} event The name of the event that has occurred.
+ * @param {...*} var_args Additional arguments passed from C++.
*/
- function webUIListenerCallback(event) {
- var listenerCallbacks = webUIListenerMap[event];
- for (var i = 0; i < listenerCallbacks.length; i++) {
- var callback = listenerCallbacks[i];
- callback.apply(null, Array.prototype.slice.call(arguments, 1));
+ function webUIListenerCallback(event, var_args) {
+ var eventListenersMap = webUIListenerMap[event];
+ if (!eventListenersMap) {
+ // C++ event sent for an event that has no listeners.
+ // TODO(dpapad): Should a warning be displayed here?
+ return;
+ }
+
+ var args = Array.prototype.slice.call(arguments, 1);
+ for (var listenerId in eventListenersMap) {
+ eventListenersMap[listenerId].apply(null, args);
}
}
/**
* Registers a listener for an event fired from WebUI handlers. Any number of
* listeners may register for a single event.
- * @param {string} event The event to listen to.
- * @param {Function} callback The callback run when the event is fired.
+ * @param {string} eventName The event to listen to.
+ * @param {!Function} callback The callback run when the event is fired.
+ * @return {!WebUIListener} An object to be used for removing a listener via
+ * cr.removeWebUIListener. Should be treated as read-only.
*/
- function addWebUIListener(event, callback) {
- if (event in webUIListenerMap)
- webUIListenerMap[event].push(callback);
- else
- webUIListenerMap[event] = [callback];
+ function addWebUIListener(eventName, callback) {
+ webUIListenerMap[eventName] = webUIListenerMap[eventName] || {};
+ var uid = createUid();
+ webUIListenerMap[eventName][uid] = callback;
+ return {eventName: eventName, uid: uid};
+ }
+
+ /**
+ * Removes a listener. Does nothing if the specified listener is not found.
+ * @param {!WebUIListener} listener The listener to be removed (as returned by
+ * addWebUIListener).
+ * @return {boolean} Whether the given listener was found and actually
+ * removed.
+ */
+ function removeWebUIListener(listener) {
+ var listenerExists = webUIListenerMap[listener.eventName] &&
+ webUIListenerMap[listener.eventName][listener.uid];
+ if (listenerExists) {
+ delete webUIListenerMap[listener.eventName][listener.uid];
+ return true;
+ }
+ return false;
}
return {
@@ -410,12 +474,15 @@ var cr = function() {
exportPath: exportPath,
getUid: getUid,
makePublic: makePublic,
- webUIResponse: webUIResponse,
- sendWithCallback: sendWithCallback,
- webUIListenerCallback: webUIListenerCallback,
- addWebUIListener: addWebUIListener,
PropertyKind: PropertyKind,
+ // C++ <-> JS communication related methods.
+ addWebUIListener: addWebUIListener,
+ removeWebUIListener: removeWebUIListener,
+ sendWithPromise: sendWithPromise,
+ webUIListenerCallback: webUIListenerCallback,
+ webUIResponse: webUIResponse,
+
get doc() {
return document;
},
@@ -439,6 +506,11 @@ var cr = function() {
get isLinux() {
return /Linux/.test(navigator.userAgent);
},
+
+ /** Whether this is on Android. */
+ get isAndroid() {
+ return /Android/.test(navigator.userAgent);
+ }
};
}();
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
@@ -990,12 +1062,25 @@ cr.define('cr.ui', function() {
// <include src="../../../../ui/webui/resources/js/assert.js">
/**
- * Alias for document.getElementById.
+ * Alias for document.getElementById. Found elements must be HTMLElements.
* @param {string} id The ID of the element to find.
* @return {HTMLElement} The found element or null if not found.
*/
function $(id) {
- return document.getElementById(id);
+ var el = document.getElementById(id);
+ return el ? assertInstanceof(el, HTMLElement) : null;
+}
+
+// TODO(devlin): This should return SVGElement, but closure compiler is missing
+// those externs.
+/**
+ * Alias for document.getElementById. Found elements must be SVGElements.
+ * @param {string} id The ID of the element to find.
+ * @return {Element} The found element or null if not found.
+ */
+function getSVGElement(id) {
+ var el = document.getElementById(id);
+ return el ? assertInstanceof(el, Element) : null;
}
/**
@@ -1018,25 +1103,6 @@ function announceAccessibleMessage(msg) {
}
/**
- * Calls chrome.send with a callback and restores the original afterwards.
- * @param {string} name The name of the message to send.
- * @param {!Array} params The parameters to send.
- * @param {string} callbackName The name of the function that the backend calls.
- * @param {!Function} callback The function to call.
- */
-function chromeSend(name, params, callbackName, callback) {
- var old = global[callbackName];
- global[callbackName] = function() {
- // restore
- global[callbackName] = old;
-
- var args = Array.prototype.slice.call(arguments);
- return callback.apply(global, args);
- };
- chrome.send(name, params);
-}
-
-/**
* Returns the scale factors supported by this platform for webui
* resources.
* @return {Array} The supported scale factors.
@@ -1365,10 +1431,19 @@ function createElementWithClassName(type, className) {
* or when no paint happens during the animation). This function sets up
* a timer and emulate the event if it is not fired when the timer expires.
* @param {!HTMLElement} el The element to watch for webkitTransitionEnd.
- * @param {number} timeOut The maximum wait time in milliseconds for the
- * webkitTransitionEnd to happen.
+ * @param {number=} opt_timeOut The maximum wait time in milliseconds for the
+ * webkitTransitionEnd to happen. If not specified, it is fetched from |el|
+ * using the transitionDuration style value.
*/
-function ensureTransitionEndEvent(el, timeOut) {
+function ensureTransitionEndEvent(el, opt_timeOut) {
+ if (opt_timeOut === undefined) {
+ var style = getComputedStyle(el);
+ opt_timeOut = parseFloat(style.transitionDuration) * 1000;
+
+ // Give an additional 50ms buffer for the animation to complete.
+ opt_timeOut += 50;
+ }
+
var fired = false;
el.addEventListener('webkitTransitionEnd', function f(e) {
el.removeEventListener('webkitTransitionEnd', f);
@@ -1377,7 +1452,7 @@ function ensureTransitionEndEvent(el, timeOut) {
window.setTimeout(function() {
if (!fired)
cr.dispatchSimpleEvent(el, 'webkitTransitionEnd', true);
- }, timeOut);
+ }, opt_timeOut);
}
/**
@@ -1446,7654 +1521,29 @@ function elide(original, maxLength) {
if (original.length <= maxLength)
return original;
return original.substring(0, maxLength - 1) + '\u2026';
-};
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-/**
- * @fileoverview Assertion support.
- */
-
-/**
- * Verify |condition| is truthy and return |condition| if so.
- * @template T
- * @param {T} condition A condition to check for truthiness. Note that this
- * may be used to test whether a value is defined or not, and we don't want
- * to force a cast to Boolean.
- * @param {string=} opt_message A message to show on failure.
- * @return {T} A non-null |condition|.
- */
-function assert(condition, opt_message) {
- if (!condition) {
- var message = 'Assertion failed';
- if (opt_message)
- message = message + ': ' + opt_message;
- var error = new Error(message);
- var global = function() { return this; }();
- if (global.traceAssertionsForTesting)
- console.warn(error.stack);
- throw error;
- }
- return condition;
}
/**
- * Call this from places in the code that should never be reached.
- *
- * For example, handling all the values of enum with a switch() like this:
- *
- * function getValueFromEnum(enum) {
- * switch (enum) {
- * case ENUM_FIRST_OF_TWO:
- * return first
- * case ENUM_LAST_OF_TWO:
- * return last;
- * }
- * assertNotReached();
- * return document;
- * }
- *
- * This code should only be hit in the case of serious programmer error or
- * unexpected input.
- *
- * @param {string=} opt_message A message to show when this is hit.
+ * Quote a string so it can be used in a regular expression.
+ * @param {string} str The source string.
+ * @return {string} The escaped string.
*/
-function assertNotReached(opt_message) {
- assert(false, opt_message || 'Unreachable code hit');
-}
-
-/**
- * @param {*} value The value to check.
- * @param {function(new: T, ...)} type A user-defined constructor.
- * @param {string=} opt_message A message to show when this is hit.
- * @return {T}
- * @template T
- */
-function assertInstanceof(value, type, opt_message) {
- assert(value instanceof type,
- opt_message || value + ' is not a[n] ' + (type.name || typeof type));
- return value;
-};
-// 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() {
- /**
- * @param {string} chromeSendName
- * @return {function(string):void} A chrome.send() callback with curried name.
- */
- function chromeSendWithId(chromeSendName) {
- return function(id) { chrome.send(chromeSendName, [id]); };
- }
-
- /** @constructor */
- function ActionService() {
- /** @private {Array<string>} */
- this.searchTerms_ = [];
- }
-
- /**
- * @param {string} s
- * @return {string} |s| without whitespace at the beginning or end.
- */
- function trim(s) { return s.trim(); }
-
- /**
- * @param {string|undefined} value
- * @return {boolean} Whether |value| is truthy.
- */
- function truthy(value) { return !!value; }
-
- /**
- * @param {string} searchText Input typed by the user into a search box.
- * @return {Array<string>} A list of terms extracted from |searchText|.
- */
- ActionService.splitTerms = function(searchText) {
- // Split quoted terms (e.g., 'The "lazy" dog' => ['The', 'lazy', 'dog']).
- return searchText.split(/"([^"]*)"/).map(trim).filter(truthy);
- };
-
- ActionService.prototype = {
- /** @param {string} id ID of the download to cancel. */
- cancel: chromeSendWithId('cancel'),
-
- /** Instructs the browser to clear all finished downloads. */
- clearAll: function() {
- if (loadTimeData.getBoolean('allowDeletingHistory')) {
- chrome.send('clearAll');
- this.search('');
- }
- },
-
- /** @param {string} id ID of the dangerous download to discard. */
- discardDangerous: chromeSendWithId('discardDangerous'),
-
- /** @param {string} url URL of a file to download. */
- download: function(url) {
- var a = document.createElement('a');
- a.href = url;
- a.setAttribute('download', '');
- a.click();
- },
-
- /** @param {string} id ID of the download that the user started dragging. */
- drag: chromeSendWithId('drag'),
-
- /** Loads more downloads with the current search terms. */
- loadMore: function() {
- chrome.send('getDownloads', this.searchTerms_);
- },
-
- /**
- * @return {boolean} Whether the user is currently searching for downloads
- * (i.e. has a non-empty search term).
- */
- isSearching: function() {
- return this.searchTerms_.length > 0;
- },
-
- /** Opens the current local destination for downloads. */
- openDownloadsFolder: chrome.send.bind(chrome, 'openDownloadsFolder'),
-
- /**
- * @param {string} id ID of the download to run locally on the user's box.
- */
- openFile: chromeSendWithId('openFile'),
-
- /** @param {string} id ID the of the progressing download to pause. */
- pause: chromeSendWithId('pause'),
-
- /** @param {string} id ID of the finished download to remove. */
- remove: chromeSendWithId('remove'),
-
- /** @param {string} id ID of the paused download to resume. */
- resume: chromeSendWithId('resume'),
-
- /**
- * @param {string} id ID of the dangerous download to save despite
- * warnings.
- */
- saveDangerous: chromeSendWithId('saveDangerous'),
-
- /** @param {string} searchText What to search for. */
- search: function(searchText) {
- var searchTerms = ActionService.splitTerms(searchText);
- var sameTerms = searchTerms.length == this.searchTerms_.length;
-
- for (var i = 0; sameTerms && i < searchTerms.length; ++i) {
- if (searchTerms[i] != this.searchTerms_[i])
- sameTerms = false;
- }
-
- if (sameTerms)
- return;
-
- this.searchTerms_ = searchTerms;
- this.loadMore();
- },
-
- /**
- * Shows the local folder a finished download resides in.
- * @param {string} id ID of the download to show.
- */
- show: chromeSendWithId('show'),
-
- /** Undo download removal. */
- undo: chrome.send.bind(chrome, 'undo'),
- };
-
- cr.addSingletonGetter(ActionService);
-
- return {ActionService: ActionService};
-});
-// 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() {
- /**
- * Explains why a download is in DANGEROUS state.
- * @enum {string}
- */
- var DangerType = {
- NOT_DANGEROUS: 'NOT_DANGEROUS',
- DANGEROUS_FILE: 'DANGEROUS_FILE',
- DANGEROUS_URL: 'DANGEROUS_URL',
- DANGEROUS_CONTENT: 'DANGEROUS_CONTENT',
- UNCOMMON_CONTENT: 'UNCOMMON_CONTENT',
- DANGEROUS_HOST: 'DANGEROUS_HOST',
- POTENTIALLY_UNWANTED: 'POTENTIALLY_UNWANTED',
- };
-
- /**
- * The states a download can be in. These correspond to states defined in
- * DownloadsDOMHandler::CreateDownloadItemValue
- * @enum {string}
- */
- var States = {
- IN_PROGRESS: 'IN_PROGRESS',
- CANCELLED: 'CANCELLED',
- COMPLETE: 'COMPLETE',
- PAUSED: 'PAUSED',
- DANGEROUS: 'DANGEROUS',
- INTERRUPTED: 'INTERRUPTED',
- };
-
- return {
- DangerType: DangerType,
- States: States,
- };
-});
-// 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.
-
-// Action links are elements that are used to perform an in-page navigation or
-// action (e.g. showing a dialog).
-//
-// They look like normal anchor (<a>) tags as their text color is blue. However,
-// they're subtly different as they're not initially underlined (giving users a
-// clue that underlined links navigate while action links don't).
-//
-// Action links look very similar to normal links when hovered (hand cursor,
-// underlined). This gives the user an idea that clicking this link will do
-// something similar to navigation but in the same page.
-//
-// They can be created in JavaScript like this:
-//
-// var link = document.createElement('a', 'action-link'); // Note second arg.
-//
-// or with a constructor like this:
-//
-// var link = new ActionLink();
-//
-// They can be used easily from HTML as well, like so:
-//
-// <a is="action-link">Click me!</a>
-//
-// NOTE: <action-link> and document.createElement('action-link') don't work.
-
-/**
- * @constructor
- * @extends {HTMLAnchorElement}
- */
-var ActionLink = document.registerElement('action-link', {
- prototype: {
- __proto__: HTMLAnchorElement.prototype,
-
- /** @this {ActionLink} */
- createdCallback: function() {
- // Action links can start disabled (e.g. <a is="action-link" disabled>).
- this.tabIndex = this.disabled ? -1 : 0;
-
- if (!this.hasAttribute('role'))
- this.setAttribute('role', 'link');
-
- this.addEventListener('keydown', function(e) {
- if (!this.disabled && e.keyIdentifier == 'Enter') {
- // Schedule a click asynchronously because other 'keydown' handlers
- // may still run later (e.g. document.addEventListener('keydown')).
- // Specifically options dialogs break when this timeout isn't here.
- // NOTE: this affects the "trusted" state of the ensuing click. I
- // haven't found anything that breaks because of this (yet).
- 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() {
- // This handlers strives to match the behavior of <a href="...">.
-
- // While the mouse is down, prevent text selection from dragging.
- document.addEventListener('selectstart', preventDefault);
- document.addEventListener('mouseup', removePreventDefault);
-
- // If focus started via mouse press, don't show an outline.
- if (document.activeElement != this)
- this.classList.add('no-outline');
- });
-
- this.addEventListener('blur', function() {
- this.classList.remove('no-outline');
- });
- },
-
- /** @type {boolean} */
- 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');
- },
-
- /** @override */
- setAttribute: function(attr, val) {
- if (attr.toLowerCase() == 'disabled')
- this.disabled = true;
- else
- HTMLAnchorElement.prototype.setAttribute.apply(this, arguments);
- },
-
- /** @override */
- removeAttribute: function(attr) {
- if (attr.toLowerCase() == 'disabled')
- this.disabled = false;
- else
- HTMLAnchorElement.prototype.removeAttribute.apply(this, arguments);
- },
- },
-
- extends: 'a',
-});
-// Copyright 2014 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-!function(a,b){b["true"]=a;var c={},d={},e={},f=null;!function(a){function b(a){if("number"==typeof a)return a;var b={};for(var c in a)b[c]=a[c];return b}function c(){this._delay=0,this._endDelay=0,this._fill="none",this._iterationStart=0,this._iterations=1,this._duration=0,this._playbackRate=1,this._direction="normal",this._easing="linear"}function d(b,d){var e=new c;return d&&(e.fill="both",e.duration="auto"),"number"!=typeof b||isNaN(b)?void 0!==b&&Object.getOwnPropertyNames(b).forEach(function(c){if("auto"!=b[c]){if(("number"==typeof e[c]||"duration"==c)&&("number"!=typeof b[c]||isNaN(b[c])))return;if("fill"==c&&-1==s.indexOf(b[c]))return;if("direction"==c&&-1==t.indexOf(b[c]))return;if("playbackRate"==c&&1!==b[c]&&a.isDeprecated("AnimationEffectTiming.playbackRate","2014-11-28","Use Animation.playbackRate instead."))return;e[c]=b[c]}}):e.duration=b,e}function e(a){return"number"==typeof a&&(a=isNaN(a)?{duration:0}:{duration:a}),a}function f(b,c){b=a.numericTimingToObject(b);var e=d(b,c);return e._easing=i(e.easing),e}function g(a,b,c,d){return 0>a||a>1||0>c||c>1?B:function(e){function f(a,b,c){return 3*a*(1-c)*(1-c)*c+3*b*(1-c)*c*c+c*c*c}if(0==e||1==e)return e;for(var g=0,h=1;;){var i=(g+h)/2,j=f(a,c,i);if(Math.abs(e-j)<.001)return f(b,d,i);e>j?g=i:h=i}}}function h(a,b){return function(c){if(c>=1)return 1;var d=1/a;return c+=b*d,c-c%d}}function i(a){var b=z.exec(a);if(b)return g.apply(this,b.slice(1).map(Number));var c=A.exec(a);if(c)return h(Number(c[1]),{start:u,middle:v,end:w}[c[2]]);var d=x[a];return d?d:B}function j(a){return Math.abs(k(a)/a.playbackRate)}function k(a){return a.duration*a.iterations}function l(a,b,c){return null==b?C:b<c.delay?D:b>=c.delay+a?E:F}function m(a,b,c,d,e){switch(d){case D:return"backwards"==b||"both"==b?0:null;case F:return c-e;case E:return"forwards"==b||"both"==b?a:null;case C:return null}}function n(a,b,c,d){return(d.playbackRate<0?b-a:b)*d.playbackRate+c}function o(a,b,c,d,e){return 1/0===c||c===-1/0||c-d==b&&e.iterations&&(e.iterations+e.iterationStart)%1==0?a:c%a}function p(a,b,c,d){return 0===c?0:b==a?d.iterationStart+d.iterations-1:Math.floor(c/a)}function q(a,b,c,d){var e=a%2>=1,f="normal"==d.direction||d.direction==(e?"alternate-reverse":"alternate"),g=f?c:b-c,h=g/b;return b*d.easing(h)}function r(a,b,c){var d=l(a,b,c),e=m(a,c.fill,b,d,c.delay);if(null===e)return null;if(0===a)return d===D?0:1;var f=c.iterationStart*c.duration,g=n(a,e,f,c),h=o(c.duration,k(c),g,f,c),i=p(c.duration,h,g,c);return q(i,c.duration,h,c)/c.duration}var s="backwards|forwards|both|none".split("|"),t="reverse|alternate|alternate-reverse".split("|");c.prototype={_setMember:function(b,c){this["_"+b]=c,this._effect&&(this._effect._timingInput[b]=c,this._effect._timing=a.normalizeTimingInput(a.normalizeTimingInput(this._effect._timingInput)),this._effect.activeDuration=a.calculateActiveDuration(this._effect._timing),this._effect._animation&&this._effect._animation._rebuildUnderlyingAnimation())},get playbackRate(){return this._playbackRate},set delay(a){this._setMember("delay",a)},get delay(){return this._delay},set endDelay(a){this._setMember("endDelay",a)},get endDelay(){return this._endDelay},set fill(a){this._setMember("fill",a)},get fill(){return this._fill},set iterationStart(a){this._setMember("iterationStart",a)},get iterationStart(){return this._iterationStart},set duration(a){this._setMember("duration",a)},get duration(){return this._duration},set direction(a){this._setMember("direction",a)},get direction(){return this._direction},set easing(a){this._setMember("easing",a)},get easing(){return this._easing},set iterations(a){this._setMember("iterations",a)},get iterations(){return this._iterations}};var u=1,v=.5,w=0,x={ease:g(.25,.1,.25,1),"ease-in":g(.42,0,1,1),"ease-out":g(0,0,.58,1),"ease-in-out":g(.42,0,.58,1),"step-start":h(1,u),"step-middle":h(1,v),"step-end":h(1,w)},y="\\s*(-?\\d+\\.?\\d*|-?\\.\\d+)\\s*",z=new RegExp("cubic-bezier\\("+y+","+y+","+y+","+y+"\\)"),A=/steps\(\s*(\d+)\s*,\s*(start|middle|end)\s*\)/,B=function(a){return a},C=0,D=1,E=2,F=3;a.cloneTimingInput=b,a.makeTiming=d,a.numericTimingToObject=e,a.normalizeTimingInput=f,a.calculateActiveDuration=j,a.calculateTimeFraction=r,a.calculatePhase=l,a.toTimingFunction=i}(c,f),function(a){function b(a,b){return a in h?h[a][b]||b:b}function c(a,c,d){var g=e[a];if(g){f.style[a]=c;for(var h in g){var i=g[h],j=f.style[i];d[i]=b(i,j)}}else d[a]=b(a,c)}function d(b){function d(){var a=e.length;null==e[a-1].offset&&(e[a-1].offset=1),a>1&&null==e[0].offset&&(e[0].offset=0);for(var b=0,c=e[0].offset,d=1;a>d;d++){var f=e[d].offset;if(null!=f){for(var g=1;d-b>g;g++)e[b+g].offset=c+(f-c)*g/(d-b);b=d,c=f}}}if(!Array.isArray(b)&&null!==b)throw new TypeError("Keyframes must be null or an array of keyframes");if(null==b)return[];for(var e=b.map(function(b){var d={};for(var e in b){var f=b[e];if("offset"==e){if(null!=f&&(f=Number(f),!isFinite(f)))throw new TypeError("keyframe offsets must be numbers.")}else{if("composite"==e)throw{type:DOMException.NOT_SUPPORTED_ERR,name:"NotSupportedError",message:"add compositing is not supported"};f="easing"==e?a.toTimingFunction(f):""+f}c(e,f,d)}return void 0==d.offset&&(d.offset=null),void 0==d.easing&&(d.easing=a.toTimingFunction("linear")),d}),f=!0,g=-1/0,h=0;h<e.length;h++){var i=e[h].offset;if(null!=i){if(g>i)throw{code:DOMException.INVALID_MODIFICATION_ERR,name:"InvalidModificationError",message:"Keyframes are not loosely sorted by offset. Sort or specify offsets."};g=i}else f=!1}return e=e.filter(function(a){return a.offset>=0&&a.offset<=1}),f||d(),e}var e={background:["backgroundImage","backgroundPosition","backgroundSize","backgroundRepeat","backgroundAttachment","backgroundOrigin","backgroundClip","backgroundColor"],border:["borderTopColor","borderTopStyle","borderTopWidth","borderRightColor","borderRightStyle","borderRightWidth","borderBottomColor","borderBottomStyle","borderBottomWidth","borderLeftColor","borderLeftStyle","borderLeftWidth"],borderBottom:["borderBottomWidth","borderBottomStyle","borderBottomColor"],borderColor:["borderTopColor","borderRightColor","borderBottomColor","borderLeftColor"],borderLeft:["borderLeftWidth","borderLeftStyle","borderLeftColor"],borderRadius:["borderTopLeftRadius","borderTopRightRadius","borderBottomRightRadius","borderBottomLeftRadius"],borderRight:["borderRightWidth","borderRightStyle","borderRightColor"],borderTop:["borderTopWidth","borderTopStyle","borderTopColor"],borderWidth:["borderTopWidth","borderRightWidth","borderBottomWidth","borderLeftWidth"],flex:["flexGrow","flexShrink","flexBasis"],font:["fontFamily","fontSize","fontStyle","fontVariant","fontWeight","lineHeight"],margin:["marginTop","marginRight","marginBottom","marginLeft"],outline:["outlineColor","outlineStyle","outlineWidth"],padding:["paddingTop","paddingRight","paddingBottom","paddingLeft"]},f=document.createElementNS("http://www.w3.org/1999/xhtml","div"),g={thin:"1px",medium:"3px",thick:"5px"},h={borderBottomWidth:g,borderLeftWidth:g,borderRightWidth:g,borderTopWidth:g,fontSize:{"xx-small":"60%","x-small":"75%",small:"89%",medium:"100%",large:"120%","x-large":"150%","xx-large":"200%"},fontWeight:{normal:"400",bold:"700"},outlineWidth:g,textShadow:{none:"0px 0px 0px transparent"},boxShadow:{none:"0px 0px 0px 0px transparent"}};a.normalizeKeyframes=d}(c,f),function(a){var b={};a.isDeprecated=function(a,c,d,e){var f=e?"are":"is",g=new Date,h=new Date(c);return h.setMonth(h.getMonth()+3),h>g?(a in b||console.warn("Web Animations: "+a+" "+f+" deprecated and will stop working on "+h.toDateString()+". "+d),b[a]=!0,!1):!0},a.deprecated=function(b,c,d,e){var f=e?"are":"is";if(a.isDeprecated(b,c,d,e))throw new Error(b+" "+f+" no longer supported. "+d)}}(c),function(){if(document.documentElement.animate){var a=document.documentElement.animate([],0),b=!0;if(a&&(b=!1,"play|currentTime|pause|reverse|playbackRate|cancel|finish|startTime|playState".split("|").forEach(function(c){void 0===a[c]&&(b=!0)})),!b)return}!function(a,b){function c(a){for(var b={},c=0;c<a.length;c++)for(var d in a[c])if("offset"!=d&&"easing"!=d&&"composite"!=d){var e={offset:a[c].offset,easing:a[c].easing,value:a[c][d]};b[d]=b[d]||[],b[d].push(e)}for(var f in b){var g=b[f];if(0!=g[0].offset||1!=g[g.length-1].offset)throw{type:DOMException.NOT_SUPPORTED_ERR,name:"NotSupportedError",message:"Partial keyframes are not supported"}}return b}function d(a){var c=[];for(var d in a)for(var e=a[d],f=0;f<e.length-1;f++){var g=e[f].offset,h=e[f+1].offset,i=e[f].value,j=e[f+1].value;g==h&&(1==h?i=j:j=i),c.push({startTime:g,endTime:h,easing:e[f].easing,property:d,interpolation:b.propertyInterpolation(d,i,j)})}return c.sort(function(a,b){return a.startTime-b.startTime}),c}b.convertEffectInput=function(e){var f=a.normalizeKeyframes(e),g=c(f),h=d(g);return function(a,c){if(null!=c)h.filter(function(a){return 0>=c&&0==a.startTime||c>=1&&1==a.endTime||c>=a.startTime&&c<=a.endTime}).forEach(function(d){var e=c-d.startTime,f=d.endTime-d.startTime,g=0==f?0:d.easing(e/f);b.apply(a,d.property,d.interpolation(g))});else for(var d in g)"offset"!=d&&"easing"!=d&&"composite"!=d&&b.clear(a,d)}}}(c,d,f),function(a){function b(a,b,c){e[c]=e[c]||[],e[c].push([a,b])}function c(a,c,d){for(var e=0;e<d.length;e++){var f=d[e];b(a,c,f),/-/.test(f)&&b(a,c,f.replace(/-(.)/g,function(a,b){return b.toUpperCase()}))}}function d(b,c,d){if("initial"==c||"initial"==d){var g=b.replace(/-(.)/g,function(a,b){return b.toUpperCase()});"initial"==c&&(c=f[g]),"initial"==d&&(d=f[g])}for(var h=c==d?[]:e[b],i=0;h&&i<h.length;i++){var j=h[i][0](c),k=h[i][0](d);if(void 0!==j&&void 0!==k){var l=h[i][1](j,k);if(l){var m=a.Interpolation.apply(null,l);return function(a){return 0==a?c:1==a?d:m(a)}}}}return a.Interpolation(!1,!0,function(a){return a?d:c})}var e={};a.addPropertiesHandler=c;var f={backgroundColor:"transparent",backgroundPosition:"0% 0%",borderBottomColor:"currentColor",borderBottomLeftRadius:"0px",borderBottomRightRadius:"0px",borderBottomWidth:"3px",borderLeftColor:"currentColor",borderLeftWidth:"3px",borderRightColor:"currentColor",borderRightWidth:"3px",borderSpacing:"2px",borderTopColor:"currentColor",borderTopLeftRadius:"0px",borderTopRightRadius:"0px",borderTopWidth:"3px",bottom:"auto",clip:"rect(0px, 0px, 0px, 0px)",color:"black",fontSize:"100%",fontWeight:"400",height:"auto",left:"auto",letterSpacing:"normal",lineHeight:"120%",marginBottom:"0px",marginLeft:"0px",marginRight:"0px",marginTop:"0px",maxHeight:"none",maxWidth:"none",minHeight:"0px",minWidth:"0px",opacity:"1.0",outlineColor:"invert",outlineOffset:"0px",outlineWidth:"3px",paddingBottom:"0px",paddingLeft:"0px",paddingRight:"0px",paddingTop:"0px",right:"auto",textIndent:"0px",textShadow:"0px 0px 0px transparent",top:"auto",transform:"",verticalAlign:"0px",visibility:"visible",width:"auto",wordSpacing:"normal",zIndex:"auto"};a.propertyInterpolation=d}(d,f),function(a,b){function c(b){var c=a.calculateActiveDuration(b),d=function(d){return a.calculateTimeFraction(c,d,b)};return d._totalDuration=b.delay+c+b.endDelay,d._isCurrent=function(d){var e=a.calculatePhase(c,d,b);return e===PhaseActive||e===PhaseBefore},d}b.KeyframeEffect=function(d,e,f){var g,h=c(a.normalizeTimingInput(f)),i=b.convertEffectInput(e),j=function(){i(d,g)};return j._update=function(a){return g=h(a),null!==g},j._clear=function(){i(d,null)},j._hasSameTarget=function(a){return d===a},j._isCurrent=h._isCurrent,j._totalDuration=h._totalDuration,j},b.NullEffect=function(a){var b=function(){a&&(a(),a=null)};return b._update=function(){return null},b._totalDuration=0,b._isCurrent=function(){return!1},b._hasSameTarget=function(){return!1},b}}(c,d,f),function(a){a.apply=function(b,c,d){b.style[a.propertyName(c)]=d},a.clear=function(b,c){b.style[a.propertyName(c)]=""}}(d,f),function(a){window.Element.prototype.animate=function(b,c){return a.timeline._play(a.KeyframeEffect(this,b,c))}}(d),function(a){function b(a,c,d){if("number"==typeof a&&"number"==typeof c)return a*(1-d)+c*d;if("boolean"==typeof a&&"boolean"==typeof c)return.5>d?a:c;if(a.length==c.length){for(var e=[],f=0;f<a.length;f++)e.push(b(a[f],c[f],d));return e}throw"Mismatched interpolation arguments "+a+":"+c}a.Interpolation=function(a,c,d){return function(e){return d(b(a,c,e))}}}(d,f),function(a,b){a.sequenceNumber=0;var c=function(a,b,c){this.target=a,this.currentTime=b,this.timelineTime=c,this.type="finish",this.bubbles=!1,this.cancelable=!1,this.currentTarget=a,this.defaultPrevented=!1,this.eventPhase=Event.AT_TARGET,this.timeStamp=Date.now()};b.Animation=function(b){this._sequenceNumber=a.sequenceNumber++,this._currentTime=0,this._startTime=null,this._paused=!1,this._playbackRate=1,this._inTimeline=!0,this._finishedFlag=!1,this.onfinish=null,this._finishHandlers=[],this._effect=b,this._inEffect=this._effect._update(0),this._idle=!0,this._currentTimePending=!1},b.Animation.prototype={_ensureAlive:function(){this._inEffect=this._effect._update(this.playbackRate<0&&0===this.currentTime?-1:this.currentTime),this._inTimeline||!this._inEffect&&this._finishedFlag||(this._inTimeline=!0,b.timeline._animations.push(this))},_tickCurrentTime:function(a,b){a!=this._currentTime&&(this._currentTime=a,this._isFinished&&!b&&(this._currentTime=this._playbackRate>0?this._totalDuration:0),this._ensureAlive())},get currentTime(){return this._idle||this._currentTimePending?null:this._currentTime},set currentTime(a){a=+a,isNaN(a)||(b.restart(),this._paused||null==this._startTime||(this._startTime=this._timeline.currentTime-a/this._playbackRate),this._currentTimePending=!1,this._currentTime!=a&&(this._tickCurrentTime(a,!0),b.invalidateEffects()))},get startTime(){return this._startTime},set startTime(a){a=+a,isNaN(a)||this._paused||this._idle||(this._startTime=a,this._tickCurrentTime((this._timeline.currentTime-this._startTime)*this.playbackRate),b.invalidateEffects())},get playbackRate(){return this._playbackRate},set playbackRate(a){if(a!=this._playbackRate){var b=this.currentTime;this._playbackRate=a,this._startTime=null,"paused"!=this.playState&&"idle"!=this.playState&&this.play(),null!=b&&(this.currentTime=b)}},get _isFinished(){return!this._idle&&(this._playbackRate>0&&this._currentTime>=this._totalDuration||this._playbackRate<0&&this._currentTime<=0)},get _totalDuration(){return this._effect._totalDuration},get playState(){return this._idle?"idle":null==this._startTime&&!this._paused&&0!=this.playbackRate||this._currentTimePending?"pending":this._paused?"paused":this._isFinished?"finished":"running"},play:function(){this._paused=!1,(this._isFinished||this._idle)&&(this._currentTime=this._playbackRate>0?0:this._totalDuration,this._startTime=null,b.invalidateEffects()),this._finishedFlag=!1,b.restart(),this._idle=!1,this._ensureAlive()},pause:function(){this._isFinished||this._paused||this._idle||(this._currentTimePending=!0),this._startTime=null,this._paused=!0},finish:function(){this._idle||(this.currentTime=this._playbackRate>0?this._totalDuration:0,this._startTime=this._totalDuration-this.currentTime,this._currentTimePending=!1)},cancel:function(){this._inEffect&&(this._inEffect=!1,this._idle=!0,this.currentTime=0,this._startTime=null,this._effect._update(null),b.invalidateEffects(),b.restart())},reverse:function(){this.playbackRate*=-1,this.play()},addEventListener:function(a,b){"function"==typeof b&&"finish"==a&&this._finishHandlers.push(b)},removeEventListener:function(a,b){if("finish"==a){var c=this._finishHandlers.indexOf(b);c>=0&&this._finishHandlers.splice(c,1)}},_fireEvents:function(a){var b=this._isFinished;if((b||this._idle)&&!this._finishedFlag){var d=new c(this,this._currentTime,a),e=this._finishHandlers.concat(this.onfinish?[this.onfinish]:[]);setTimeout(function(){e.forEach(function(a){a.call(d.target,d)})},0)}this._finishedFlag=b},_tick:function(a){return this._idle||this._paused||(null==this._startTime?this.startTime=a-this._currentTime/this.playbackRate:this._isFinished||this._tickCurrentTime((a-this._startTime)*this.playbackRate)),this._currentTimePending=!1,this._fireEvents(a),!this._idle&&(this._inEffect||!this._finishedFlag)}}}(c,d,f),function(a,b){function c(a){var b=i;i=[],a<s.currentTime&&(a=s.currentTime),g(a),b.forEach(function(b){b[1](a)}),o&&g(a),f(),l=void 0}function d(a,b){return a._sequenceNumber-b._sequenceNumber}function e(){this._animations=[],this.currentTime=window.performance&&performance.now?performance.now():0}function f(){p.forEach(function(a){a()}),p.length=0}function g(a){n=!1;var c=b.timeline;c.currentTime=a,c._animations.sort(d),m=!1;var e=c._animations;c._animations=[];var f=[],g=[];e=e.filter(function(b){return b._inTimeline=b._tick(a),b._inEffect?g.push(b._effect):f.push(b._effect),b._isFinished||b._paused||b._idle||(m=!0),b._inTimeline}),p.push.apply(p,f),p.push.apply(p,g),c._animations.push.apply(c._animations,e),o=!1,m&&requestAnimationFrame(function(){})}var h=window.requestAnimationFrame,i=[],j=0;window.requestAnimationFrame=function(a){var b=j++;return 0==i.length&&h(c),i.push([b,a]),b},window.cancelAnimationFrame=function(a){i.forEach(function(b){b[0]==a&&(b[1]=function(){})})},e.prototype={_play:function(c){c._timing=a.normalizeTimingInput(c.timing);var d=new b.Animation(c);return d._idle=!1,d._timeline=this,this._animations.push(d),b.restart(),b.invalidateEffects(),d}};var k,l=void 0,k=function(){return void 0==l&&(l=performance.now()),l},m=!1,n=!1;b.restart=function(){return m||(m=!0,requestAnimationFrame(function(){}),n=!0),n};var o=!1;b.invalidateEffects=function(){o=!0};var p=[],q=1e3/60,r=window.getComputedStyle;Object.defineProperty(window,"getComputedStyle",{configurable:!0,enumerable:!0,value:function(){if(o){var a=k();a-s.currentTime>0&&(s.currentTime+=q*(Math.floor((a-s.currentTime)/q)+1)),g(s.currentTime)}return f(),r.apply(this,arguments)}});var s=new e;b.timeline=s}(c,d,f),function(a){function b(a,b){var c=a.exec(b);return c?(c=a.ignoreCase?c[0].toLowerCase():c[0],[c,b.substr(c.length)]):void 0}function c(a,b){b=b.replace(/^\s*/,"");var c=a(b);return c?[c[0],c[1].replace(/^\s*/,"")]:void 0}function d(a,d,e){a=c.bind(null,a);for(var f=[];;){var g=a(e);if(!g)return[f,e];if(f.push(g[0]),e=g[1],g=b(d,e),!g||""==g[1])return[f,e];e=g[1]}}function e(a,b){for(var c=0,d=0;d<b.length&&(!/\s|,/.test(b[d])||0!=c);d++)if("("==b[d])c++;else if(")"==b[d]&&(c--,0==c&&d++,0>=c))break;var e=a(b.substr(0,d));return void 0==e?void 0:[e,b.substr(d)]}function f(a,b){for(var c=a,d=b;c&&d;)c>d?c%=d:d%=c;return c=a*b/(c+d)}function g(a){return function(b){var c=a(b);return c&&(c[0]=void 0),c}}function h(a,b){return function(c){var d=a(c);return d?d:[b,c]}}function i(b,c){for(var d=[],e=0;e<b.length;e++){var f=a.consumeTrimmed(b[e],c);if(!f||""==f[0])return;void 0!==f[0]&&d.push(f[0]),c=f[1]}return""==c?d:void 0}function j(a,b,c,d,e){for(var g=[],h=[],i=[],j=f(d.length,e.length),k=0;j>k;k++){var l=b(d[k%d.length],e[k%e.length]);if(!l)return;g.push(l[0]),h.push(l[1]),i.push(l[2])}return[g,h,function(b){var d=b.map(function(a,b){return i[b](a)}).join(c);return a?a(d):d}]}function k(a,b,c){for(var d=[],e=[],f=[],g=0,h=0;h<c.length;h++)if("function"==typeof c[h]){var i=c[h](a[g],b[g++]);d.push(i[0]),e.push(i[1]),f.push(i[2])}else!function(a){d.push(!1),e.push(!1),f.push(function(){return c[a]})}(h);return[d,e,function(a){for(var b="",c=0;c<a.length;c++)b+=f[c](a[c]);return b}]}a.consumeToken=b,a.consumeTrimmed=c,a.consumeRepeated=d,a.consumeParenthesised=e,a.ignore=g,a.optional=h,a.consumeList=i,a.mergeNestedRepeated=j.bind(null,null),a.mergeWrappedNestedRepeated=j,a.mergeList=k}(d),function(a){function b(b){function c(b){var c=a.consumeToken(/^inset/i,b);if(c)return d.inset=!0,c;var c=a.consumeLengthOrPercent(b);if(c)return d.lengths.push(c[0]),c;var c=a.consumeColor(b);return c?(d.color=c[0],c):void 0}var d={inset:!1,lengths:[],color:null},e=a.consumeRepeated(c,/^/,b);return e&&e[0].length?[d,e[1]]:void 0}function c(c){var d=a.consumeRepeated(b,/^,/,c);return d&&""==d[1]?d[0]:void 0}function d(b,c){for(;b.lengths.length<Math.max(b.lengths.length,c.lengths.length);)b.lengths.push({px:0});for(;c.lengths.length<Math.max(b.lengths.length,c.lengths.length);)c.lengths.push({px:0});if(b.inset==c.inset&&!!b.color==!!c.color){for(var d,e=[],f=[[],0],g=[[],0],h=0;h<b.lengths.length;h++){var i=a.mergeDimensions(b.lengths[h],c.lengths[h],2==h);f[0].push(i[0]),g[0].push(i[1]),e.push(i[2])}if(b.color&&c.color){var j=a.mergeColors(b.color,c.color);f[1]=j[0],g[1]=j[1],d=j[2]}return[f,g,function(a){for(var c=b.inset?"inset ":" ",f=0;f<e.length;f++)c+=e[f](a[0][f])+" ";return d&&(c+=d(a[1])),c}]}}function e(b,c,d,e){function f(a){return{inset:a,color:[0,0,0,0],lengths:[{px:0},{px:0},{px:0},{px:0}]}}for(var g=[],h=[],i=0;i<d.length||i<e.length;i++){var j=d[i]||f(e[i].inset),k=e[i]||f(d[i].inset);g.push(j),h.push(k)}return a.mergeNestedRepeated(b,c,g,h)}var f=e.bind(null,d,", ");a.addPropertiesHandler(c,f,["box-shadow","text-shadow"])}(d),function(a){function b(a){return a.toFixed(3).replace(".000","")}function c(a,b,c){return Math.min(b,Math.max(a,c))}function d(a){return/^\s*[-+]?(\d*\.)?\d+\s*$/.test(a)?Number(a):void 0}function e(a,c){return[a,c,b]}function f(a,b){return 0!=a?h(0,1/0)(a,b):void 0}function g(a,b){return[a,b,function(a){return Math.round(c(1,1/0,a))}]}function h(a,d){return function(e,f){return[e,f,function(e){return b(c(a,d,e))}]}}function i(a,b){return[a,b,Math.round]}a.clamp=c,a.addPropertiesHandler(d,h(0,1/0),["border-image-width","line-height"]),a.addPropertiesHandler(d,h(0,1),["opacity","shape-image-threshold"]),a.addPropertiesHandler(d,f,["flex-grow","flex-shrink"]),a.addPropertiesHandler(d,g,["orphans","widows"]),a.addPropertiesHandler(d,i,["z-index"]),a.parseNumber=d,a.mergeNumbers=e,a.numberToString=b}(d,f),function(a){function b(a,b){return"visible"==a||"visible"==b?[0,1,function(c){return 0>=c?a:c>=1?b:"visible"}]:void 0}a.addPropertiesHandler(String,b,["visibility"])}(d),function(a){function b(a){a=a.trim(),e.fillStyle="#000",e.fillStyle=a;var b=e.fillStyle;if(e.fillStyle="#fff",e.fillStyle=a,b==e.fillStyle){e.fillRect(0,0,1,1);var c=e.getImageData(0,0,1,1).data;e.clearRect(0,0,1,1);var d=c[3]/255;return[c[0]*d,c[1]*d,c[2]*d,d]}}function c(b,c){return[b,c,function(b){function c(a){return Math.max(0,Math.min(255,a))}if(b[3])for(var d=0;3>d;d++)b[d]=Math.round(c(b[d]/b[3]));return b[3]=a.numberToString(a.clamp(0,1,b[3])),"rgba("+b.join(",")+")"}]}var d=document.createElementNS("http://www.w3.org/1999/xhtml","canvas");d.width=d.height=1;var e=d.getContext("2d");a.addPropertiesHandler(b,c,["background-color","border-bottom-color","border-left-color","border-right-color","border-top-color","color","outline-color","text-decoration-color"]),a.consumeColor=a.consumeParenthesised.bind(null,b),a.mergeColors=c}(d,f),function(a,b){function c(a,b){if(b=b.trim().toLowerCase(),"0"==b&&"px".search(a)>=0)return{px:0};if(/^[^(]*$|^calc/.test(b)){b=b.replace(/calc\(/g,"(");var c={};b=b.replace(a,function(a){return c[a]=null,"U"+a});for(var d="U("+a.source+")",e=b.replace(/[-+]?(\d*\.)?\d+/g,"N").replace(new RegExp("N"+d,"g"),"D").replace(/\s[+-]\s/g,"O").replace(/\s/g,""),f=[/N\*(D)/g,/(N|D)[*/]N/g,/(N|D)O\1/g,/\((N|D)\)/g],g=0;g<f.length;)f[g].test(e)?(e=e.replace(f[g],"$1"),g=0):g++;if("D"==e){for(var h in c){var i=eval(b.replace(new RegExp("U"+h,"g"),"").replace(new RegExp(d,"g"),"*0"));if(!isFinite(i))return;c[h]=i}return c}}}function d(a,b){return e(a,b,!0)}function e(b,c,d){var e,f=[];for(e in b)f.push(e);for(e in c)f.indexOf(e)<0&&f.push(e);return b=f.map(function(a){return b[a]||0}),c=f.map(function(a){return c[a]||0}),[b,c,function(b){var c=b.map(function(c,e){return 1==b.length&&d&&(c=Math.max(c,0)),a.numberToString(c)+f[e]}).join(" + ");return b.length>1?"calc("+c+")":c}]}var f="px|em|ex|ch|rem|vw|vh|vmin|vmax|cm|mm|in|pt|pc",g=c.bind(null,new RegExp(f,"g")),h=c.bind(null,new RegExp(f+"|%","g")),i=c.bind(null,/deg|rad|grad|turn/g);a.parseLength=g,a.parseLengthOrPercent=h,a.consumeLengthOrPercent=a.consumeParenthesised.bind(null,h),a.parseAngle=i,a.mergeDimensions=e;var j=a.consumeParenthesised.bind(null,g),k=a.consumeRepeated.bind(void 0,j,/^/),l=a.consumeRepeated.bind(void 0,k,/^,/);a.consumeSizePairList=l;var m=function(a){var b=l(a);return b&&""==b[1]?b[0]:void 0},n=a.mergeNestedRepeated.bind(void 0,d," "),o=a.mergeNestedRepeated.bind(void 0,n,",");a.mergeNonNegativeSizePair=n,a.addPropertiesHandler(m,o,["background-size"]),a.addPropertiesHandler(h,d,["border-bottom-width","border-image-width","border-left-width","border-right-width","border-top-width","flex-basis","font-size","height","line-height","max-height","max-width","outline-width","width"]),a.addPropertiesHandler(h,e,["border-bottom-left-radius","border-bottom-right-radius","border-top-left-radius","border-top-right-radius","bottom","left","letter-spacing","margin-bottom","margin-left","margin-right","margin-top","min-height","min-width","outline-offset","padding-bottom","padding-left","padding-right","padding-top","perspective","right","shape-margin","text-indent","top","vertical-align","word-spacing"])}(d,f),function(a){function b(b){return a.consumeLengthOrPercent(b)||a.consumeToken(/^auto/,b)}function c(c){var d=a.consumeList([a.ignore(a.consumeToken.bind(null,/^rect/)),a.ignore(a.consumeToken.bind(null,/^\(/)),a.consumeRepeated.bind(null,b,/^,/),a.ignore(a.consumeToken.bind(null,/^\)/))],c);return d&&4==d[0].length?d[0]:void 0}function d(b,c){return"auto"==b||"auto"==c?[!0,!1,function(d){var e=d?b:c;if("auto"==e)return"auto";var f=a.mergeDimensions(e,e);return f[2](f[0])}]:a.mergeDimensions(b,c)}function e(a){return"rect("+a+")"}var f=a.mergeWrappedNestedRepeated.bind(null,e,d,", ");a.parseBox=c,a.mergeBoxes=f,a.addPropertiesHandler(c,f,["clip"])}(d,f),function(a){function b(a){return function(b){var c=0;return a.map(function(a){return a===j?b[c++]:a})}}function c(a){return a}function d(b){if(b=b.toLowerCase().trim(),"none"==b)return[];for(var c,d=/\s*(\w+)\(([^)]*)\)/g,e=[],f=0;c=d.exec(b);){if(c.index!=f)return;f=c.index+c[0].length;var g=c[1],h=m[g];if(!h)return;var i=c[2].split(","),j=h[0];if(j.length<i.length)return;for(var n=[],o=0;o<j.length;o++){var p,q=i[o],r=j[o];if(p=q?{A:function(b){return"0"==b.trim()?l:a.parseAngle(b)},N:a.parseNumber,T:a.parseLengthOrPercent,L:a.parseLength}[r.toUpperCase()](q):{a:l,n:n[0],t:k}[r],void 0===p)return;n.push(p)}if(e.push({t:g,d:n}),d.lastIndex==b.length)return e}}function e(a){return a.toFixed(6).replace(".000000","")}function f(b,c){if(b.decompositionPair!==c){b.decompositionPair=c;var d=a.makeMatrixDecomposition(b)}if(c.decompositionPair!==b){c.decompositionPair=b;var f=a.makeMatrixDecomposition(c)}return null==d[0]||null==f[0]?[[!1],[!0],function(a){return a?c[0].d:b[0].d}]:(d[0].push(0),f[0].push(1),[d,f,function(b){var c=a.quat(d[0][3],f[0][3],b[5]),g=a.composeMatrix(b[0],b[1],b[2],c,b[4]),h=g.map(e).join(",");return h}])}function g(a){return a.replace(/[xy]/,"")}function h(a){return a.replace(/(x|y|z|3d)?$/,"3d")}function i(b,c){var d=a.makeMatrixDecomposition&&!0,e=!1;if(!b.length||!c.length){b.length||(e=!0,b=c,c=[]);for(var i=0;i<b.length;i++){var j=b[i].t,k=b[i].d,l="scale"==j.substr(0,5)?1:0;c.push({t:j,d:k.map(function(a){if("number"==typeof a)return l;var b={};for(var c in a)b[c]=l;return b})})}}var n=function(a,b){return"perspective"==a&&"perspective"==b||("matrix"==a||"matrix3d"==a)&&("matrix"==b||"matrix3d"==b)},o=[],p=[],q=[];if(b.length!=c.length){if(!d)return;var r=f(b,c);o=[r[0]],p=[r[1]],q=[["matrix",[r[2]]]]}else for(var i=0;i<b.length;i++){var j,s=b[i].t,t=c[i].t,u=b[i].d,v=c[i].d,w=m[s],x=m[t];if(n(s,t)){if(!d)return;var r=f([b[i]],[c[i]]);o.push(r[0]),p.push(r[1]),q.push(["matrix",[r[2]]])}else{if(s==t)j=s;else if(w[2]&&x[2]&&g(s)==g(t))j=g(s),u=w[2](u),v=x[2](v);else{if(!w[1]||!x[1]||h(s)!=h(t)){if(!d)return;var r=f(b,c);o=[r[0]],p=[r[1]],q=[["matrix",[r[2]]]];break}j=h(s),u=w[1](u),v=x[1](v)}for(var y=[],z=[],A=[],B=0;B<u.length;B++){var C="number"==typeof u[B]?a.mergeNumbers:a.mergeDimensions,r=C(u[B],v[B]);y[B]=r[0],z[B]=r[1],A.push(r[2])}o.push(y),p.push(z),q.push([j,A])}}if(e){var D=o;o=p,p=D}return[o,p,function(a){return a.map(function(a,b){var c=a.map(function(a,c){return q[b][1][c](a)}).join(",");return"matrix"==q[b][0]&&16==c.split(",").length&&(q[b][0]="matrix3d"),q[b][0]+"("+c+")"}).join(" ")}]}var j=null,k={px:0},l={deg:0},m={matrix:["NNNNNN",[j,j,0,0,j,j,0,0,0,0,1,0,j,j,0,1],c],matrix3d:["NNNNNNNNNNNNNNNN",c],rotate:["A"],rotatex:["A"],rotatey:["A"],rotatez:["A"],rotate3d:["NNNA"],perspective:["L"],scale:["Nn",b([j,j,1]),c],scalex:["N",b([j,1,1]),b([j,1])],scaley:["N",b([1,j,1]),b([1,j])],scalez:["N",b([1,1,j])],scale3d:["NNN",c],skew:["Aa",null,c],skewx:["A",null,b([j,l])],skewy:["A",null,b([l,j])],translate:["Tt",b([j,j,k]),c],translatex:["T",b([j,k,k]),b([j,k])],translatey:["T",b([k,j,k]),b([k,j])],translatez:["L",b([k,k,j])],translate3d:["TTL",c]};a.addPropertiesHandler(d,i,["transform"])}(d,f),function(a){function b(a,b){b.concat([a]).forEach(function(b){b in document.documentElement.style&&(c[a]=b)})}var c={};b("transform",["webkitTransform","msTransform"]),b("transformOrigin",["webkitTransformOrigin"]),b("perspective",["webkitPerspective"]),b("perspectiveOrigin",["webkitPerspectiveOrigin"]),a.propertyName=function(a){return c[a]||a}}(d,f)}(),!function(a,b){function c(a){var b=window.document.timeline;b.currentTime=a,b._discardAnimations(),0==b._animations.length?e=!1:requestAnimationFrame(c)}var d=window.requestAnimationFrame;window.requestAnimationFrame=function(a){return d(function(b){window.document.timeline._updateAnimationsPromises(),a(b),window.document.timeline._updateAnimationsPromises()})},b.AnimationTimeline=function(){this._animations=[],this.currentTime=void 0},b.AnimationTimeline.prototype={getAnimations:function(){return this._discardAnimations(),this._animations.slice()},_updateAnimationsPromises:function(){b.animationsWithPromises=b.animationsWithPromises.filter(function(a){return a._updatePromises()})},_discardAnimations:function(){this._updateAnimationsPromises(),this._animations=this._animations.filter(function(a){return"finished"!=a.playState&&"idle"!=a.playState})},_play:function(a){var c=new b.Animation(a,this);return this._animations.push(c),b.restartWebAnimationsNextTick(),c._updatePromises(),c._animation.play(),c._updatePromises(),c},play:function(a){return a&&a.remove(),this._play(a)}};var e=!1;b.restartWebAnimationsNextTick=function(){e||(e=!0,requestAnimationFrame(c))};var f=new b.AnimationTimeline;b.timeline=f;try{Object.defineProperty(window.document,"timeline",{configurable:!0,get:function(){return f}})}catch(g){}try{window.document.timeline=f}catch(g){}}(c,e,f),function(a,b){b.animationsWithPromises=[],b.Animation=function(b,c){if(this.effect=b,b&&(b._animation=this),!c)throw new Error("Animation with null timeline is not supported");this._timeline=c,this._sequenceNumber=a.sequenceNumber++,this._holdTime=0,this._paused=!1,this._isGroup=!1,this._animation=null,this._childAnimations=[],this._callback=null,this._oldPlayState="idle",this._rebuildUnderlyingAnimation(),this._animation.cancel(),this._updatePromises()},b.Animation.prototype={_updatePromises:function(){var a=this._oldPlayState,b=this.playState;return this._readyPromise&&b!==a&&("idle"==b?(this._rejectReadyPromise(),this._readyPromise=void 0):"pending"==a?this._resolveReadyPromise():"pending"==b&&(this._readyPromise=void 0)),this._finishedPromise&&b!==a&&("idle"==b?(this._rejectFinishedPromise(),this._finishedPromise=void 0):"finished"==b?this._resolveFinishedPromise():"finished"==a&&(this._finishedPromise=void 0)),this._oldPlayState=this.playState,this._readyPromise||this._finishedPromise},_rebuildUnderlyingAnimation:function(){this._updatePromises();var a,c,d,e,f=this._animation?!0:!1;f&&(a=this.playbackRate,c=this._paused,d=this.startTime,e=this.currentTime,this._animation.cancel(),this._animation._wrapper=null,this._animation=null),(!this.effect||this.effect instanceof window.KeyframeEffect)&&(this._animation=b.newUnderlyingAnimationForKeyframeEffect(this.effect),b.bindAnimationForKeyframeEffect(this)),(this.effect instanceof window.SequenceEffect||this.effect instanceof window.GroupEffect)&&(this._animation=b.newUnderlyingAnimationForGroup(this.effect),b.bindAnimationForGroup(this)),this.effect&&this.effect._onsample&&b.bindAnimationForCustomEffect(this),f&&(1!=a&&(this.playbackRate=a),null!==d?this.startTime=d:null!==e?this.currentTime=e:null!==this._holdTime&&(this.currentTime=this._holdTime),c&&this.pause()),this._updatePromises()
-},_updateChildren:function(){if(this.effect&&"idle"!=this.playState){var a=this.effect._timing.delay;this._childAnimations.forEach(function(c){this._arrangeChildren(c,a),this.effect instanceof window.SequenceEffect&&(a+=b.groupChildDuration(c.effect))}.bind(this))}},_setExternalAnimation:function(a){if(this.effect&&this._isGroup)for(var b=0;b<this.effect.children.length;b++)this.effect.children[b]._animation=a,this._childAnimations[b]._setExternalAnimation(a)},_constructChildAnimations:function(){if(this.effect&&this._isGroup){var a=this.effect._timing.delay;this._removeChildAnimations(),this.effect.children.forEach(function(c){var d=window.document.timeline._play(c);this._childAnimations.push(d),d.playbackRate=this.playbackRate,this._paused&&d.pause(),c._animation=this.effect._animation,this._arrangeChildren(d,a),this.effect instanceof window.SequenceEffect&&(a+=b.groupChildDuration(c))}.bind(this))}},_arrangeChildren:function(a,b){null===this.startTime?a.currentTime=this.currentTime-b/this.playbackRate:a.startTime!==this.startTime+b/this.playbackRate&&(a.startTime=this.startTime+b/this.playbackRate)},get timeline(){return this._timeline},get playState(){return this._animation?this._animation.playState:"idle"},get finished(){return window.Promise?(this._finishedPromise||(-1==b.animationsWithPromises.indexOf(this)&&b.animationsWithPromises.push(this),this._finishedPromise=new Promise(function(a,b){this._resolveFinishedPromise=function(){a(this)},this._rejectFinishedPromise=function(){b({type:DOMException.ABORT_ERR,name:"AbortError"})}}.bind(this)),"finished"==this.playState&&this._resolveFinishedPromise()),this._finishedPromise):(console.warn("Animation Promises require JavaScript Promise constructor"),null)},get ready(){return window.Promise?(this._readyPromise||(-1==b.animationsWithPromises.indexOf(this)&&b.animationsWithPromises.push(this),this._readyPromise=new Promise(function(a,b){this._resolveReadyPromise=function(){a(this)},this._rejectReadyPromise=function(){b({type:DOMException.ABORT_ERR,name:"AbortError"})}}.bind(this)),"pending"!==this.playState&&this._resolveReadyPromise()),this._readyPromise):(console.warn("Animation Promises require JavaScript Promise constructor"),null)},get onfinish(){return this._onfinish},set onfinish(a){"function"==typeof a?(this._onfinish=a,this._animation.onfinish=function(b){b.target=this,a.call(this,b)}.bind(this)):(this._animation.onfinish=a,this.onfinish=this._animation.onfinish)},get currentTime(){this._updatePromises();var a=this._animation.currentTime;return this._updatePromises(),a},set currentTime(a){this._updatePromises(),this._animation.currentTime=isFinite(a)?a:Math.sign(a)*Number.MAX_VALUE,this._register(),this._forEachChild(function(b,c){b.currentTime=a-c}),this._updatePromises()},get startTime(){return this._animation.startTime},set startTime(a){this._updatePromises(),this._animation.startTime=isFinite(a)?a:Math.sign(a)*Number.MAX_VALUE,this._register(),this._forEachChild(function(b,c){b.startTime=a+c}),this._updatePromises()},get playbackRate(){return this._animation.playbackRate},set playbackRate(a){this._updatePromises();var b=this.currentTime;this._animation.playbackRate=a,this._forEachChild(function(b){b.playbackRate=a}),"paused"!=this.playState&&"idle"!=this.playState&&this.play(),null!==b&&(this.currentTime=b),this._updatePromises()},play:function(){this._updatePromises(),this._paused=!1,this._animation.play(),-1==this._timeline._animations.indexOf(this)&&this._timeline._animations.push(this),this._register(),b.awaitStartTime(this),this._forEachChild(function(a){var b=a.currentTime;a.play(),a.currentTime=b}),this._updatePromises()},pause:function(){this._updatePromises(),this.currentTime&&(this._holdTime=this.currentTime),this._animation.pause(),this._register(),this._forEachChild(function(a){a.pause()}),this._paused=!0,this._updatePromises()},finish:function(){this._updatePromises(),this._animation.finish(),this._register(),this._updatePromises()},cancel:function(){this._updatePromises(),this._animation.cancel(),this._register(),this._removeChildAnimations(),this._updatePromises()},reverse:function(){this._updatePromises();var a=this.currentTime;this._animation.reverse(),this._forEachChild(function(a){a.reverse()}),null!==a&&(this.currentTime=a),this._updatePromises()},addEventListener:function(a,b){var c=b;"function"==typeof b&&(c=function(a){a.target=this,b.call(this,a)}.bind(this),b._wrapper=c),this._animation.addEventListener(a,c)},removeEventListener:function(a,b){this._animation.removeEventListener(a,b&&b._wrapper||b)},_removeChildAnimations:function(){for(;this._childAnimations.length;)this._childAnimations.pop().cancel()},_forEachChild:function(b){var c=0;if(this.effect.children&&this._childAnimations.length<this.effect.children.length&&this._constructChildAnimations(),this._childAnimations.forEach(function(a){b.call(this,a,c),this.effect instanceof window.SequenceEffect&&(c+=a.effect.activeDuration)}.bind(this)),"pending"!=this.playState){var d=this.effect._timing,e=this.currentTime;null!==e&&(e=a.calculateTimeFraction(a.calculateActiveDuration(d),e,d)),(null==e||isNaN(e))&&this._removeChildAnimations()}}},window.Animation=b.Animation}(c,e,f),function(a,b){function c(b){this._frames=a.normalizeKeyframes(b)}function d(){for(var a=!1;h.length;){var b=h.shift();b._updateChildren(),a=!0}return a}var e=function(a){if(a._animation=void 0,a instanceof window.SequenceEffect||a instanceof window.GroupEffect)for(var b=0;b<a.children.length;b++)e(a.children[b])};b.removeMulti=function(a){for(var b=[],c=0;c<a.length;c++){var d=a[c];d._parent?(-1==b.indexOf(d._parent)&&b.push(d._parent),d._parent.children.splice(d._parent.children.indexOf(d),1),d._parent=null,e(d)):d._animation&&d._animation.effect==d&&(d._animation.cancel(),d._animation.effect=new KeyframeEffect(null,[]),d._animation._callback&&(d._animation._callback._animation=null),d._animation._rebuildUnderlyingAnimation(),e(d))}for(c=0;c<b.length;c++)b[c]._rebuild()},b.KeyframeEffect=function(b,d,e){return this.target=b,this._parent=null,e=a.numericTimingToObject(e),this._timingInput=a.cloneTimingInput(e),this._timing=a.normalizeTimingInput(e),this.timing=a.makeTiming(e,!1,this),this.timing._effect=this,"function"==typeof d?(a.deprecated("Custom KeyframeEffect","2015-06-22","Use KeyframeEffect.onsample instead."),this._normalizedKeyframes=d):this._normalizedKeyframes=new c(d),this._keyframes=d,this.activeDuration=a.calculateActiveDuration(this._timing),this},b.KeyframeEffect.prototype={getFrames:function(){return"function"==typeof this._normalizedKeyframes?this._normalizedKeyframes:this._normalizedKeyframes._frames},set onsample(a){if("function"==typeof this.getFrames())throw new Error("Setting onsample on custom effect KeyframeEffect is not supported.");this._onsample=a,this._animation&&this._animation._rebuildUnderlyingAnimation()},get parent(){return this._parent},clone:function(){if("function"==typeof this.getFrames())throw new Error("Cloning custom effects is not supported.");var b=new KeyframeEffect(this.target,[],a.cloneTimingInput(this._timingInput));return b._normalizedKeyframes=this._normalizedKeyframes,b._keyframes=this._keyframes,b},remove:function(){b.removeMulti([this])}};var f=Element.prototype.animate;Element.prototype.animate=function(a,c){return b.timeline._play(new b.KeyframeEffect(this,a,c))};var g=document.createElementNS("http://www.w3.org/1999/xhtml","div");b.newUnderlyingAnimationForKeyframeEffect=function(a){if(a){var b=a.target||g,c=a._keyframes;"function"==typeof c&&(c=[]);var d=a._timingInput}else var b=g,c=[],d=0;return f.apply(b,[c,d])},b.bindAnimationForKeyframeEffect=function(a){a.effect&&"function"==typeof a.effect._normalizedKeyframes&&b.bindAnimationForCustomEffect(a)};var h=[];b.awaitStartTime=function(a){null===a.startTime&&a._isGroup&&(0==h.length&&requestAnimationFrame(d),h.push(a))};var i=window.getComputedStyle;Object.defineProperty(window,"getComputedStyle",{configurable:!0,enumerable:!0,value:function(){window.document.timeline._updateAnimationsPromises();var a=i.apply(this,arguments);return d()&&(a=i.apply(this,arguments)),window.document.timeline._updateAnimationsPromises(),a}}),window.KeyframeEffect=b.KeyframeEffect,window.Element.prototype.getAnimations=function(){return document.timeline.getAnimations().filter(function(a){return null!==a.effect&&a.effect.target==this}.bind(this))}}(c,e,f),function(a,b){function c(a){a._registered||(a._registered=!0,f.push(a),g||(g=!0,requestAnimationFrame(d)))}function d(){var a=f;f=[],a.sort(function(a,b){return a._sequenceNumber-b._sequenceNumber}),a=a.filter(function(a){a();var b=a._animation?a._animation.playState:"idle";return"running"!=b&&"pending"!=b&&(a._registered=!1),a._registered}),f.push.apply(f,a),f.length?(g=!0,requestAnimationFrame(d)):g=!1}var e=(document.createElementNS("http://www.w3.org/1999/xhtml","div"),0);b.bindAnimationForCustomEffect=function(b){var d,f=b.effect.target,g="function"==typeof b.effect.getFrames();d=g?b.effect.getFrames():b.effect._onsample;var h=b.effect.timing,i=null;h=a.normalizeTimingInput(h);var j=function(){var c=j._animation?j._animation.currentTime:null;null!==c&&(c=a.calculateTimeFraction(a.calculateActiveDuration(h),c,h),isNaN(c)&&(c=null)),c!==i&&(g?d(c,f,b.effect):d(c,b.effect,b.effect._animation)),i=c};j._animation=b,j._registered=!1,j._sequenceNumber=e++,b._callback=j,c(j)};var f=[],g=!1;b.Animation.prototype._register=function(){this._callback&&c(this._callback)}}(c,e,f),function(a,b){function c(a){return a._timing.delay+a.activeDuration+a._timing.endDelay}function d(b,c){this._parent=null,this.children=b||[],this._reparent(this.children),c=a.numericTimingToObject(c),this._timingInput=a.cloneTimingInput(c),this._timing=a.normalizeTimingInput(c,!0),this.timing=a.makeTiming(c,!0,this),this.timing._effect=this,"auto"===this._timing.duration&&(this._timing.duration=this.activeDuration)}window.SequenceEffect=function(){d.apply(this,arguments)},window.GroupEffect=function(){d.apply(this,arguments)},d.prototype={_isAncestor:function(a){for(var b=this;null!==b;){if(b==a)return!0;b=b._parent}return!1},_rebuild:function(){for(var a=this;a;)"auto"===a.timing.duration&&(a._timing.duration=a.activeDuration),a=a._parent;this._animation&&this._animation._rebuildUnderlyingAnimation()},_reparent:function(a){b.removeMulti(a);for(var c=0;c<a.length;c++)a[c]._parent=this},_putChild:function(a,b){for(var c=b?"Cannot append an ancestor or self":"Cannot prepend an ancestor or self",d=0;d<a.length;d++)if(this._isAncestor(a[d]))throw{type:DOMException.HIERARCHY_REQUEST_ERR,name:"HierarchyRequestError",message:c};for(var d=0;d<a.length;d++)b?this.children.push(a[d]):this.children.unshift(a[d]);this._reparent(a),this._rebuild()},append:function(){this._putChild(arguments,!0)},prepend:function(){this._putChild(arguments,!1)},get parent(){return this._parent},get firstChild(){return this.children.length?this.children[0]:null},get lastChild(){return this.children.length?this.children[this.children.length-1]:null},clone:function(){for(var b=a.cloneTimingInput(this._timingInput),c=[],d=0;d<this.children.length;d++)c.push(this.children[d].clone());return this instanceof GroupEffect?new GroupEffect(c,b):new SequenceEffect(c,b)},remove:function(){b.removeMulti([this])}},window.SequenceEffect.prototype=Object.create(d.prototype),Object.defineProperty(window.SequenceEffect.prototype,"activeDuration",{get:function(){var a=0;return this.children.forEach(function(b){a+=c(b)}),Math.max(a,0)}}),window.GroupEffect.prototype=Object.create(d.prototype),Object.defineProperty(window.GroupEffect.prototype,"activeDuration",{get:function(){var a=0;return this.children.forEach(function(b){a=Math.max(a,c(b))}),a}}),b.newUnderlyingAnimationForGroup=function(c){var d,e=null,f=function(b){var c=d._wrapper;return c&&"pending"!=c.playState&&c.effect?null==b?void c._removeChildAnimations():0==b&&c.playbackRate<0&&(e||(e=a.normalizeTimingInput(c.effect.timing)),b=a.calculateTimeFraction(a.calculateActiveDuration(e),-1,e),isNaN(b)||null==b)?(c._forEachChild(function(a){a.currentTime=-1}),void c._removeChildAnimations()):void 0:void 0},g=new KeyframeEffect(null,[],c._timing);return g.onsample=f,d=b.timeline._play(g)},b.bindAnimationForGroup=function(a){a._animation._wrapper=a,a._isGroup=!0,b.awaitStartTime(a),a._constructChildAnimations(),a._setExternalAnimation(a)},b.groupChildDuration=c}(c,e,f)}({},function(){return this}());
-// 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 src="../../../../ui/webui/resources/js/i18n_template_no_process.js">
-
-i18nTemplate.process(document, loadTimeData);
-(function () {
-function resolve() {
-document.body.removeAttribute('unresolved');
-}
-if (window.WebComponents) {
-addEventListener('WebComponentsReady', resolve);
-} else {
-if (document.readyState === 'interactive' || document.readyState === 'complete') {
-resolve();
-} else {
-addEventListener('DOMContentLoaded', resolve);
-}
-}
-}());
-window.Polymer = {
-Settings: function () {
-var user = window.Polymer || {};
-var parts = location.search.slice(1).split('&');
-for (var i = 0, o; i < parts.length && (o = parts[i]); i++) {
-o = o.split('=');
-o[0] && (user[o[0]] = o[1] || true);
-}
-var wantShadow = user.dom === 'shadow';
-var hasShadow = Boolean(Element.prototype.createShadowRoot);
-var nativeShadow = hasShadow && !window.ShadowDOMPolyfill;
-var useShadow = wantShadow && hasShadow;
-var hasNativeImports = Boolean('import' in document.createElement('link'));
-var useNativeImports = hasNativeImports;
-var useNativeCustomElements = !window.CustomElements || window.CustomElements.useNative;
-return {
-wantShadow: wantShadow,
-hasShadow: hasShadow,
-nativeShadow: nativeShadow,
-useShadow: useShadow,
-useNativeShadow: useShadow && nativeShadow,
-useNativeImports: useNativeImports,
-useNativeCustomElements: useNativeCustomElements
-};
-}()
-};
-(function () {
-var userPolymer = window.Polymer;
-window.Polymer = function (prototype) {
-if (typeof prototype === 'function') {
-prototype = prototype.prototype;
-}
-if (!prototype) {
-prototype = {};
-}
-var factory = desugar(prototype);
-prototype = factory.prototype;
-var options = { prototype: prototype };
-if (prototype.extends) {
-options.extends = prototype.extends;
-}
-Polymer.telemetry._registrate(prototype);
-document.registerElement(prototype.is, options);
-return factory;
-};
-var desugar = function (prototype) {
-var base = Polymer.Base;
-if (prototype.extends) {
-base = Polymer.Base._getExtendedPrototype(prototype.extends);
-}
-prototype = Polymer.Base.chainObject(prototype, base);
-prototype.registerCallback();
-return prototype.constructor;
-};
-window.Polymer = Polymer;
-if (userPolymer) {
-for (var i in userPolymer) {
-Polymer[i] = userPolymer[i];
-}
-}
-Polymer.Class = desugar;
-}());
-Polymer.telemetry = {
-registrations: [],
-_regLog: function (prototype) {
-console.log('[' + prototype.is + ']: registered');
-},
-_registrate: function (prototype) {
-this.registrations.push(prototype);
-Polymer.log && this._regLog(prototype);
-},
-dumpRegistrations: function () {
-this.registrations.forEach(this._regLog);
-}
-};
-Object.defineProperty(window, 'currentImport', {
-enumerable: true,
-configurable: true,
-get: function () {
-return (document._currentScript || document.currentScript).ownerDocument;
-}
-});
-Polymer.RenderStatus = {
-_ready: false,
-_callbacks: [],
-whenReady: function (cb) {
-if (this._ready) {
-cb();
-} else {
-this._callbacks.push(cb);
-}
-},
-_makeReady: function () {
-this._ready = true;
-for (var i = 0; i < this._callbacks.length; i++) {
-this._callbacks[i]();
-}
-this._callbacks = [];
-},
-_catchFirstRender: function () {
-requestAnimationFrame(function () {
-Polymer.RenderStatus._makeReady();
-});
-},
-_afterNextRenderQueue: [],
-_waitingNextRender: false,
-afterNextRender: function (element, fn, args) {
-this._watchNextRender();
-this._afterNextRenderQueue.push([
-element,
-fn,
-args
-]);
-},
-_watchNextRender: function () {
-if (!this._waitingNextRender) {
-this._waitingNextRender = true;
-var fn = function () {
-Polymer.RenderStatus._flushNextRender();
-};
-if (!this._ready) {
-this.whenReady(fn);
-} else {
-requestAnimationFrame(fn);
-}
-}
-},
-_flushNextRender: function () {
-var self = this;
-setTimeout(function () {
-self._flushRenderCallbacks(self._afterNextRenderQueue);
-self._afterNextRenderQueue = [];
-self._waitingNextRender = false;
-});
-},
-_flushRenderCallbacks: function (callbacks) {
-for (var i = 0, h; i < callbacks.length; i++) {
-h = callbacks[i];
-h[1].apply(h[0], h[2] || Polymer.nar);
-}
-;
-}
-};
-if (window.HTMLImports) {
-HTMLImports.whenReady(function () {
-Polymer.RenderStatus._catchFirstRender();
-});
-} else {
-Polymer.RenderStatus._catchFirstRender();
-}
-Polymer.ImportStatus = Polymer.RenderStatus;
-Polymer.ImportStatus.whenLoaded = Polymer.ImportStatus.whenReady;
-Polymer.Base = {
-__isPolymerInstance__: true,
-_addFeature: function (feature) {
-this.extend(this, feature);
-},
-registerCallback: function () {
-this._desugarBehaviors();
-this._doBehavior('beforeRegister');
-this._registerFeatures();
-this._doBehavior('registered');
-},
-createdCallback: function () {
-Polymer.telemetry.instanceCount++;
-this.root = this;
-this._doBehavior('created');
-this._initFeatures();
-},
-attachedCallback: function () {
-var self = this;
-Polymer.RenderStatus.whenReady(function () {
-self.isAttached = true;
-self._doBehavior('attached');
-});
-},
-detachedCallback: function () {
-this.isAttached = false;
-this._doBehavior('detached');
-},
-attributeChangedCallback: function (name, oldValue, newValue) {
-this._attributeChangedImpl(name);
-this._doBehavior('attributeChanged', [
-name,
-oldValue,
-newValue
-]);
-},
-_attributeChangedImpl: function (name) {
-this._setAttributeToProperty(this, name);
-},
-extend: function (prototype, api) {
-if (prototype && api) {
-var n$ = Object.getOwnPropertyNames(api);
-for (var i = 0, n; i < n$.length && (n = n$[i]); i++) {
-this.copyOwnProperty(n, api, prototype);
-}
-}
-return prototype || api;
-},
-mixin: function (target, source) {
-for (var i in source) {
-target[i] = source[i];
-}
-return target;
-},
-copyOwnProperty: function (name, source, target) {
-var pd = Object.getOwnPropertyDescriptor(source, name);
-if (pd) {
-Object.defineProperty(target, name, pd);
-}
-},
-_log: console.log.apply.bind(console.log, console),
-_warn: console.warn.apply.bind(console.warn, console),
-_error: console.error.apply.bind(console.error, console),
-_logf: function () {
-return this._logPrefix.concat([this.is]).concat(Array.prototype.slice.call(arguments, 0));
-}
-};
-Polymer.Base._logPrefix = function () {
-var color = window.chrome || /firefox/i.test(navigator.userAgent);
-return color ? [
-'%c[%s::%s]:',
-'font-weight: bold; background-color:#EEEE00;'
-] : ['[%s::%s]:'];
-}();
-Polymer.Base.chainObject = function (object, inherited) {
-if (object && inherited && object !== inherited) {
-if (!Object.__proto__) {
-object = Polymer.Base.extend(Object.create(inherited), object);
-}
-object.__proto__ = inherited;
-}
-return object;
-};
-Polymer.Base = Polymer.Base.chainObject(Polymer.Base, HTMLElement.prototype);
-if (window.CustomElements) {
-Polymer.instanceof = CustomElements.instanceof;
-} else {
-Polymer.instanceof = function (obj, ctor) {
-return obj instanceof ctor;
-};
-}
-Polymer.isInstance = function (obj) {
-return Boolean(obj && obj.__isPolymerInstance__);
-};
-Polymer.telemetry.instanceCount = 0;
-(function () {
-var modules = {};
-var lcModules = {};
-var findModule = function (id) {
-return modules[id] || lcModules[id.toLowerCase()];
-};
-var DomModule = function () {
-return document.createElement('dom-module');
-};
-DomModule.prototype = Object.create(HTMLElement.prototype);
-Polymer.Base.extend(DomModule.prototype, {
-constructor: DomModule,
-createdCallback: function () {
-this.register();
-},
-register: function (id) {
-var id = id || this.id || this.getAttribute('name') || this.getAttribute('is');
-if (id) {
-this.id = id;
-modules[id] = this;
-lcModules[id.toLowerCase()] = this;
-}
-},
-import: function (id, selector) {
-if (id) {
-var m = findModule(id);
-if (!m) {
-forceDomModulesUpgrade();
-m = findModule(id);
-}
-if (m && selector) {
-m = m.querySelector(selector);
-}
-return m;
-}
-}
-});
-var cePolyfill = window.CustomElements && !CustomElements.useNative;
-document.registerElement('dom-module', DomModule);
-function forceDomModulesUpgrade() {
-if (cePolyfill) {
-var script = document._currentScript || document.currentScript;
-var doc = script && script.ownerDocument || document;
-var modules = doc.querySelectorAll('dom-module');
-for (var i = modules.length - 1, m; i >= 0 && (m = modules[i]); i--) {
-if (m.__upgraded__) {
-return;
-} else {
-CustomElements.upgrade(m);
-}
-}
-}
-}
-}());
-Polymer.Base._addFeature({
-_prepIs: function () {
-if (!this.is) {
-var module = (document._currentScript || document.currentScript).parentNode;
-if (module.localName === 'dom-module') {
-var id = module.id || module.getAttribute('name') || module.getAttribute('is');
-this.is = id;
-}
-}
-if (this.is) {
-this.is = this.is.toLowerCase();
-}
-}
-});
-Polymer.Base._addFeature({
-behaviors: [],
-_desugarBehaviors: function () {
-if (this.behaviors.length) {
-this.behaviors = this._desugarSomeBehaviors(this.behaviors);
-}
-},
-_desugarSomeBehaviors: function (behaviors) {
-behaviors = this._flattenBehaviorsList(behaviors);
-for (var i = behaviors.length - 1; i >= 0; i--) {
-this._mixinBehavior(behaviors[i]);
-}
-return behaviors;
-},
-_flattenBehaviorsList: function (behaviors) {
-var flat = [];
-for (var i = 0; i < behaviors.length; i++) {
-var b = behaviors[i];
-if (b instanceof Array) {
-flat = flat.concat(this._flattenBehaviorsList(b));
-} else if (b) {
-flat.push(b);
-} else {
-this._warn(this._logf('_flattenBehaviorsList', 'behavior is null, check for missing or 404 import'));
-}
-}
-return flat;
-},
-_mixinBehavior: function (b) {
-var n$ = Object.getOwnPropertyNames(b);
-for (var i = 0, n; i < n$.length && (n = n$[i]); i++) {
-if (!Polymer.Base._behaviorProperties[n] && !this.hasOwnProperty(n)) {
-this.copyOwnProperty(n, b, this);
-}
-}
-},
-_prepBehaviors: function () {
-this._prepFlattenedBehaviors(this.behaviors);
-},
-_prepFlattenedBehaviors: function (behaviors) {
-for (var i = 0, l = behaviors.length; i < l; i++) {
-this._prepBehavior(behaviors[i]);
-}
-this._prepBehavior(this);
-},
-_doBehavior: function (name, args) {
-for (var i = 0; i < this.behaviors.length; i++) {
-this._invokeBehavior(this.behaviors[i], name, args);
-}
-this._invokeBehavior(this, name, args);
-},
-_invokeBehavior: function (b, name, args) {
-var fn = b[name];
-if (fn) {
-fn.apply(this, args || Polymer.nar);
-}
-},
-_marshalBehaviors: function () {
-for (var i = 0; i < this.behaviors.length; i++) {
-this._marshalBehavior(this.behaviors[i]);
-}
-this._marshalBehavior(this);
-}
-});
-Polymer.Base._behaviorProperties = {
-hostAttributes: true,
-registered: true,
-properties: true,
-observers: true,
-listeners: true,
-created: true,
-attached: true,
-detached: true,
-attributeChanged: true,
-ready: true
-};
-Polymer.Base._addFeature({
-_getExtendedPrototype: function (tag) {
-return this._getExtendedNativePrototype(tag);
-},
-_nativePrototypes: {},
-_getExtendedNativePrototype: function (tag) {
-var p = this._nativePrototypes[tag];
-if (!p) {
-var np = this.getNativePrototype(tag);
-p = this.extend(Object.create(np), Polymer.Base);
-this._nativePrototypes[tag] = p;
-}
-return p;
-},
-getNativePrototype: function (tag) {
-return Object.getPrototypeOf(document.createElement(tag));
-}
-});
-Polymer.Base._addFeature({
-_prepConstructor: function () {
-this._factoryArgs = this.extends ? [
-this.extends,
-this.is
-] : [this.is];
-var ctor = function () {
-return this._factory(arguments);
-};
-if (this.hasOwnProperty('extends')) {
-ctor.extends = this.extends;
-}
-Object.defineProperty(this, 'constructor', {
-value: ctor,
-writable: true,
-configurable: true
-});
-ctor.prototype = this;
-},
-_factory: function (args) {
-var elt = document.createElement.apply(document, this._factoryArgs);
-if (this.factoryImpl) {
-this.factoryImpl.apply(elt, args);
-}
-return elt;
-}
-});
-Polymer.nob = Object.create(null);
-Polymer.Base._addFeature({
-properties: {},
-getPropertyInfo: function (property) {
-var info = this._getPropertyInfo(property, this.properties);
-if (!info) {
-for (var i = 0; i < this.behaviors.length; i++) {
-info = this._getPropertyInfo(property, this.behaviors[i].properties);
-if (info) {
-return info;
-}
-}
-;
-}
-return info || Polymer.nob;
-},
-_getPropertyInfo: function (property, properties) {
-var p = properties && properties[property];
-if (typeof p === 'function') {
-p = properties[property] = { type: p };
-}
-if (p) {
-p.defined = true;
-}
-return p;
-},
-_prepPropertyInfo: function () {
-this._propertyInfo = {};
-for (var i = 0, p; i < this.behaviors.length; i++) {
-this._addPropertyInfo(this._propertyInfo, this.behaviors[i].properties);
-}
-this._addPropertyInfo(this._propertyInfo, this.properties);
-this._addPropertyInfo(this._propertyInfo, this._propertyEffects);
-},
-_addPropertyInfo: function (target, source) {
-if (source) {
-var t, s;
-for (var i in source) {
-t = target[i];
-s = source[i];
-if (i[0] === '_' && !s.readOnly) {
-continue;
-}
-if (!target[i]) {
-target[i] = {
-type: typeof s === 'function' ? s : s.type,
-readOnly: s.readOnly,
-attribute: Polymer.CaseMap.camelToDashCase(i)
-};
-} else {
-if (!t.type) {
-t.type = s.type;
-}
-if (!t.readOnly) {
-t.readOnly = s.readOnly;
-}
-}
-}
-}
-}
-});
-Polymer.CaseMap = {
-_caseMap: {},
-dashToCamelCase: function (dash) {
-var mapped = Polymer.CaseMap._caseMap[dash];
-if (mapped) {
-return mapped;
-}
-if (dash.indexOf('-') < 0) {
-return Polymer.CaseMap._caseMap[dash] = dash;
-}
-return Polymer.CaseMap._caseMap[dash] = dash.replace(/-([a-z])/g, function (m) {
-return m[1].toUpperCase();
-});
-},
-camelToDashCase: function (camel) {
-var mapped = Polymer.CaseMap._caseMap[camel];
-if (mapped) {
-return mapped;
-}
-return Polymer.CaseMap._caseMap[camel] = camel.replace(/([a-z][A-Z])/g, function (g) {
-return g[0] + '-' + g[1].toLowerCase();
-});
-}
-};
-Polymer.Base._addFeature({
-_addHostAttributes: function (attributes) {
-if (!this._aggregatedAttributes) {
-this._aggregatedAttributes = {};
-}
-if (attributes) {
-this.mixin(this._aggregatedAttributes, attributes);
-}
-},
-_marshalHostAttributes: function () {
-if (this._aggregatedAttributes) {
-this._applyAttributes(this, this._aggregatedAttributes);
-}
-},
-_applyAttributes: function (node, attr$) {
-for (var n in attr$) {
-if (!this.hasAttribute(n) && n !== 'class') {
-var v = attr$[n];
-this.serializeValueToAttribute(v, n, this);
-}
-}
-},
-_marshalAttributes: function () {
-this._takeAttributesToModel(this);
-},
-_takeAttributesToModel: function (model) {
-if (this.hasAttributes()) {
-for (var i in this._propertyInfo) {
-var info = this._propertyInfo[i];
-if (this.hasAttribute(info.attribute)) {
-this._setAttributeToProperty(model, info.attribute, i, info);
-}
-}
-}
-},
-_setAttributeToProperty: function (model, attribute, property, info) {
-if (!this._serializing) {
-var property = property || Polymer.CaseMap.dashToCamelCase(attribute);
-info = info || this._propertyInfo && this._propertyInfo[property];
-if (info && !info.readOnly) {
-var v = this.getAttribute(attribute);
-model[property] = this.deserialize(v, info.type);
-}
-}
-},
-_serializing: false,
-reflectPropertyToAttribute: function (property, attribute, value) {
-this._serializing = true;
-value = value === undefined ? this[property] : value;
-this.serializeValueToAttribute(value, attribute || Polymer.CaseMap.camelToDashCase(property));
-this._serializing = false;
-},
-serializeValueToAttribute: function (value, attribute, node) {
-var str = this.serialize(value);
-node = node || this;
-if (str === undefined) {
-node.removeAttribute(attribute);
-} else {
-node.setAttribute(attribute, str);
-}
-},
-deserialize: function (value, type) {
-switch (type) {
-case Number:
-value = Number(value);
-break;
-case Boolean:
-value = value !== null;
-break;
-case Object:
-try {
-value = JSON.parse(value);
-} catch (x) {
-}
-break;
-case Array:
-try {
-value = JSON.parse(value);
-} catch (x) {
-value = null;
-console.warn('Polymer::Attributes: couldn`t decode Array as JSON');
-}
-break;
-case Date:
-value = new Date(value);
-break;
-case String:
-default:
-break;
-}
-return value;
-},
-serialize: function (value) {
-switch (typeof value) {
-case 'boolean':
-return value ? '' : undefined;
-case 'object':
-if (value instanceof Date) {
-return value;
-} else if (value) {
-try {
-return JSON.stringify(value);
-} catch (x) {
-return '';
-}
-}
-default:
-return value != null ? value : undefined;
-}
-}
-});
-Polymer.Base._addFeature({
-_setupDebouncers: function () {
-this._debouncers = {};
-},
-debounce: function (jobName, callback, wait) {
-return this._debouncers[jobName] = Polymer.Debounce.call(this, this._debouncers[jobName], callback, wait);
-},
-isDebouncerActive: function (jobName) {
-var debouncer = this._debouncers[jobName];
-return debouncer && debouncer.finish;
-},
-flushDebouncer: function (jobName) {
-var debouncer = this._debouncers[jobName];
-if (debouncer) {
-debouncer.complete();
-}
-},
-cancelDebouncer: function (jobName) {
-var debouncer = this._debouncers[jobName];
-if (debouncer) {
-debouncer.stop();
-}
-}
-});
-Polymer.version = '1.2.3';
-Polymer.Base._addFeature({
-_registerFeatures: function () {
-this._prepIs();
-this._prepBehaviors();
-this._prepConstructor();
-this._prepPropertyInfo();
-},
-_prepBehavior: function (b) {
-this._addHostAttributes(b.hostAttributes);
-},
-_marshalBehavior: function (b) {
-},
-_initFeatures: function () {
-this._marshalHostAttributes();
-this._setupDebouncers();
-this._marshalBehaviors();
-}
-});
-Polymer.Base._addFeature({
-_prepTemplate: function () {
-if (this._template === undefined) {
-this._template = Polymer.DomModule.import(this.is, 'template');
-}
-if (this._template && this._template.hasAttribute('is')) {
-this._warn(this._logf('_prepTemplate', 'top-level Polymer template ' + 'must not be a type-extension, found', this._template, 'Move inside simple <template>.'));
-}
-if (this._template && !this._template.content && window.HTMLTemplateElement && HTMLTemplateElement.decorate) {
-HTMLTemplateElement.decorate(this._template);
-}
-},
-_stampTemplate: function () {
-if (this._template) {
-this.root = this.instanceTemplate(this._template);
-}
-},
-instanceTemplate: function (template) {
-var dom = document.importNode(template._content || template.content, true);
-return dom;
-}
-});
-(function () {
-var baseAttachedCallback = Polymer.Base.attachedCallback;
-Polymer.Base._addFeature({
-_hostStack: [],
-ready: function () {
-},
-_registerHost: function (host) {
-this.dataHost = host = host || Polymer.Base._hostStack[Polymer.Base._hostStack.length - 1];
-if (host && host._clients) {
-host._clients.push(this);
-}
-},
-_beginHosting: function () {
-Polymer.Base._hostStack.push(this);
-if (!this._clients) {
-this._clients = [];
-}
-},
-_endHosting: function () {
-Polymer.Base._hostStack.pop();
-},
-_tryReady: function () {
-if (this._canReady()) {
-this._ready();
-}
-},
-_canReady: function () {
-return !this.dataHost || this.dataHost._clientsReadied;
-},
-_ready: function () {
-this._beforeClientsReady();
-if (this._template) {
-this._setupRoot();
-this._readyClients();
-}
-this._clientsReadied = true;
-this._clients = null;
-this._afterClientsReady();
-this._readySelf();
-},
-_readyClients: function () {
-this._beginDistribute();
-var c$ = this._clients;
-if (c$) {
-for (var i = 0, l = c$.length, c; i < l && (c = c$[i]); i++) {
-c._ready();
-}
-}
-this._finishDistribute();
-},
-_readySelf: function () {
-this._doBehavior('ready');
-this._readied = true;
-if (this._attachedPending) {
-this._attachedPending = false;
-this.attachedCallback();
-}
-},
-_beforeClientsReady: function () {
-},
-_afterClientsReady: function () {
-},
-_beforeAttached: function () {
-},
-attachedCallback: function () {
-if (this._readied) {
-this._beforeAttached();
-baseAttachedCallback.call(this);
-} else {
-this._attachedPending = true;
-}
-}
-});
-}());
-Polymer.ArraySplice = function () {
-function newSplice(index, removed, addedCount) {
-return {
-index: index,
-removed: removed,
-addedCount: addedCount
-};
-}
-var EDIT_LEAVE = 0;
-var EDIT_UPDATE = 1;
-var EDIT_ADD = 2;
-var EDIT_DELETE = 3;
-function ArraySplice() {
-}
-ArraySplice.prototype = {
-calcEditDistances: function (current, currentStart, currentEnd, old, oldStart, oldEnd) {
-var rowCount = oldEnd - oldStart + 1;
-var columnCount = currentEnd - currentStart + 1;
-var distances = new Array(rowCount);
-for (var i = 0; i < rowCount; i++) {
-distances[i] = new Array(columnCount);
-distances[i][0] = i;
-}
-for (var j = 0; j < columnCount; j++)
-distances[0][j] = j;
-for (var i = 1; i < rowCount; i++) {
-for (var j = 1; j < columnCount; j++) {
-if (this.equals(current[currentStart + j - 1], old[oldStart + i - 1]))
-distances[i][j] = distances[i - 1][j - 1];
-else {
-var north = distances[i - 1][j] + 1;
-var west = distances[i][j - 1] + 1;
-distances[i][j] = north < west ? north : west;
-}
-}
-}
-return distances;
-},
-spliceOperationsFromEditDistances: function (distances) {
-var i = distances.length - 1;
-var j = distances[0].length - 1;
-var current = distances[i][j];
-var edits = [];
-while (i > 0 || j > 0) {
-if (i == 0) {
-edits.push(EDIT_ADD);
-j--;
-continue;
-}
-if (j == 0) {
-edits.push(EDIT_DELETE);
-i--;
-continue;
-}
-var northWest = distances[i - 1][j - 1];
-var west = distances[i - 1][j];
-var north = distances[i][j - 1];
-var min;
-if (west < north)
-min = west < northWest ? west : northWest;
-else
-min = north < northWest ? north : northWest;
-if (min == northWest) {
-if (northWest == current) {
-edits.push(EDIT_LEAVE);
-} else {
-edits.push(EDIT_UPDATE);
-current = northWest;
-}
-i--;
-j--;
-} else if (min == west) {
-edits.push(EDIT_DELETE);
-i--;
-current = west;
-} else {
-edits.push(EDIT_ADD);
-j--;
-current = north;
-}
-}
-edits.reverse();
-return edits;
-},
-calcSplices: function (current, currentStart, currentEnd, old, oldStart, oldEnd) {
-var prefixCount = 0;
-var suffixCount = 0;
-var minLength = Math.min(currentEnd - currentStart, oldEnd - oldStart);
-if (currentStart == 0 && oldStart == 0)
-prefixCount = this.sharedPrefix(current, old, minLength);
-if (currentEnd == current.length && oldEnd == old.length)
-suffixCount = this.sharedSuffix(current, old, minLength - prefixCount);
-currentStart += prefixCount;
-oldStart += prefixCount;
-currentEnd -= suffixCount;
-oldEnd -= suffixCount;
-if (currentEnd - currentStart == 0 && oldEnd - oldStart == 0)
-return [];
-if (currentStart == currentEnd) {
-var splice = newSplice(currentStart, [], 0);
-while (oldStart < oldEnd)
-splice.removed.push(old[oldStart++]);
-return [splice];
-} else if (oldStart == oldEnd)
-return [newSplice(currentStart, [], currentEnd - currentStart)];
-var ops = this.spliceOperationsFromEditDistances(this.calcEditDistances(current, currentStart, currentEnd, old, oldStart, oldEnd));
-var splice = undefined;
-var splices = [];
-var index = currentStart;
-var oldIndex = oldStart;
-for (var i = 0; i < ops.length; i++) {
-switch (ops[i]) {
-case EDIT_LEAVE:
-if (splice) {
-splices.push(splice);
-splice = undefined;
-}
-index++;
-oldIndex++;
-break;
-case EDIT_UPDATE:
-if (!splice)
-splice = newSplice(index, [], 0);
-splice.addedCount++;
-index++;
-splice.removed.push(old[oldIndex]);
-oldIndex++;
-break;
-case EDIT_ADD:
-if (!splice)
-splice = newSplice(index, [], 0);
-splice.addedCount++;
-index++;
-break;
-case EDIT_DELETE:
-if (!splice)
-splice = newSplice(index, [], 0);
-splice.removed.push(old[oldIndex]);
-oldIndex++;
-break;
-}
-}
-if (splice) {
-splices.push(splice);
-}
-return splices;
-},
-sharedPrefix: function (current, old, searchLength) {
-for (var i = 0; i < searchLength; i++)
-if (!this.equals(current[i], old[i]))
-return i;
-return searchLength;
-},
-sharedSuffix: function (current, old, searchLength) {
-var index1 = current.length;
-var index2 = old.length;
-var count = 0;
-while (count < searchLength && this.equals(current[--index1], old[--index2]))
-count++;
-return count;
-},
-calculateSplices: function (current, previous) {
-return this.calcSplices(current, 0, current.length, previous, 0, previous.length);
-},
-equals: function (currentValue, previousValue) {
-return currentValue === previousValue;
-}
-};
-return new ArraySplice();
-}();
-Polymer.domInnerHTML = function () {
-var escapeAttrRegExp = /[&\u00A0"]/g;
-var escapeDataRegExp = /[&\u00A0<>]/g;
-function escapeReplace(c) {
-switch (c) {
-case '&':
-return '&amp;';
-case '<':
-return '&lt;';
-case '>':
-return '&gt;';
-case '"':
-return '&quot;';
-case '\xA0':
-return '&nbsp;';
-}
-}
-function escapeAttr(s) {
-return s.replace(escapeAttrRegExp, escapeReplace);
-}
-function escapeData(s) {
-return s.replace(escapeDataRegExp, escapeReplace);
-}
-function makeSet(arr) {
-var set = {};
-for (var i = 0; i < arr.length; i++) {
-set[arr[i]] = true;
-}
-return set;
-}
-var voidElements = makeSet([
-'area',
-'base',
-'br',
-'col',
-'command',
-'embed',
-'hr',
-'img',
-'input',
-'keygen',
-'link',
-'meta',
-'param',
-'source',
-'track',
-'wbr'
-]);
-var plaintextParents = makeSet([
-'style',
-'script',
-'xmp',
-'iframe',
-'noembed',
-'noframes',
-'plaintext',
-'noscript'
-]);
-function getOuterHTML(node, parentNode, composed) {
-switch (node.nodeType) {
-case Node.ELEMENT_NODE:
-var tagName = node.localName;
-var s = '<' + tagName;
-var attrs = node.attributes;
-for (var i = 0, attr; attr = attrs[i]; i++) {
-s += ' ' + attr.name + '="' + escapeAttr(attr.value) + '"';
-}
-s += '>';
-if (voidElements[tagName]) {
-return s;
-}
-return s + getInnerHTML(node, composed) + '</' + tagName + '>';
-case Node.TEXT_NODE:
-var data = node.data;
-if (parentNode && plaintextParents[parentNode.localName]) {
-return data;
-}
-return escapeData(data);
-case Node.COMMENT_NODE:
-return '<!--' + node.data + '-->';
-default:
-console.error(node);
-throw new Error('not implemented');
-}
-}
-function getInnerHTML(node, composed) {
-if (node instanceof HTMLTemplateElement)
-node = node.content;
-var s = '';
-var c$ = Polymer.dom(node).childNodes;
-c$ = composed ? node._composedChildren : c$;
-for (var i = 0, l = c$.length, child; i < l && (child = c$[i]); i++) {
-s += getOuterHTML(child, node, composed);
-}
-return s;
-}
-return { getInnerHTML: getInnerHTML };
-}();
-Polymer.DomApi = function () {
-'use strict';
-var Settings = Polymer.Settings;
-var getInnerHTML = Polymer.domInnerHTML.getInnerHTML;
-var nativeInsertBefore = Element.prototype.insertBefore;
-var nativeRemoveChild = Element.prototype.removeChild;
-var nativeAppendChild = Element.prototype.appendChild;
-var nativeCloneNode = Element.prototype.cloneNode;
-var nativeImportNode = Document.prototype.importNode;
-var needsToWrap = Settings.hasShadow && !Settings.nativeShadow;
-var wrap = window.wrap ? window.wrap : function (node) {
-return node;
-};
-var DomApi = function (node) {
-this.node = needsToWrap ? wrap(node) : node;
-if (this.patch) {
-this.patch();
-}
-};
-DomApi.prototype = {
-flush: function () {
-Polymer.dom.flush();
-},
-deepContains: function (node) {
-if (this.node.contains(node)) {
-return true;
-}
-var n = node;
-var wrappedDocument = wrap(document);
-while (n && n !== wrappedDocument && n !== this.node) {
-n = Polymer.dom(n).parentNode || n.host;
-}
-return n === this.node;
-},
-_lazyDistribute: function (host) {
-if (host.shadyRoot && host.shadyRoot._distributionClean) {
-host.shadyRoot._distributionClean = false;
-Polymer.dom.addDebouncer(host.debounce('_distribute', host._distributeContent));
-}
-},
-appendChild: function (node) {
-return this._addNode(node);
-},
-insertBefore: function (node, ref_node) {
-return this._addNode(node, ref_node);
-},
-_addNode: function (node, ref_node) {
-this._removeNodeFromParent(node);
-var addedInsertionPoint;
-var root = this.getOwnerRoot();
-if (root) {
-addedInsertionPoint = this._maybeAddInsertionPoint(node, this.node);
-}
-if (this._nodeHasLogicalChildren(this.node)) {
-if (ref_node) {
-var children = this.childNodes;
-var index = children.indexOf(ref_node);
-if (index < 0) {
-throw Error('The ref_node to be inserted before is not a child ' + 'of this node');
-}
-}
-this._addLogicalInfo(node, this.node, index);
-}
-this._addNodeToHost(node);
-if (!this._maybeDistribute(node, this.node) && !this._tryRemoveUndistributedNode(node)) {
-if (ref_node) {
-ref_node = ref_node.localName === CONTENT ? this._firstComposedNode(ref_node) : ref_node;
-}
-var container = this.node._isShadyRoot ? this.node.host : this.node;
-addToComposedParent(container, node, ref_node);
-if (ref_node) {
-nativeInsertBefore.call(container, node, ref_node);
-} else {
-nativeAppendChild.call(container, node);
-}
-}
-if (addedInsertionPoint) {
-this._updateInsertionPoints(root.host);
-}
-this.notifyObserver();
-return node;
-},
-removeChild: function (node) {
-if (factory(node).parentNode !== this.node) {
-console.warn('The node to be removed is not a child of this node', node);
-}
-this._removeNodeFromHost(node);
-if (!this._maybeDistribute(node, this.node)) {
-var container = this.node._isShadyRoot ? this.node.host : this.node;
-if (container === node.parentNode) {
-removeFromComposedParent(container, node);
-nativeRemoveChild.call(container, node);
-}
-}
-this.notifyObserver();
-return node;
-},
-replaceChild: function (node, ref_node) {
-this.insertBefore(node, ref_node);
-this.removeChild(ref_node);
-return node;
-},
-_hasCachedOwnerRoot: function (node) {
-return Boolean(node._ownerShadyRoot !== undefined);
-},
-getOwnerRoot: function () {
-return this._ownerShadyRootForNode(this.node);
-},
-_ownerShadyRootForNode: function (node) {
-if (!node) {
-return;
-}
-if (node._ownerShadyRoot === undefined) {
-var root;
-if (node._isShadyRoot) {
-root = node;
-} else {
-var parent = Polymer.dom(node).parentNode;
-if (parent) {
-root = parent._isShadyRoot ? parent : this._ownerShadyRootForNode(parent);
-} else {
-root = null;
-}
-}
-node._ownerShadyRoot = root;
-}
-return node._ownerShadyRoot;
-},
-_maybeDistribute: function (node, parent) {
-var fragContent = node.nodeType === Node.DOCUMENT_FRAGMENT_NODE && !node.__noContent && Polymer.dom(node).querySelector(CONTENT);
-var wrappedContent = fragContent && Polymer.dom(fragContent).parentNode.nodeType !== Node.DOCUMENT_FRAGMENT_NODE;
-var hasContent = fragContent || node.localName === CONTENT;
-if (hasContent) {
-var root = this._ownerShadyRootForNode(parent);
-if (root) {
-var host = root.host;
-this._lazyDistribute(host);
-}
-}
-var parentNeedsDist = this._parentNeedsDistribution(parent);
-if (parentNeedsDist) {
-this._lazyDistribute(parent);
-}
-return parentNeedsDist || hasContent && !wrappedContent;
-},
-_maybeAddInsertionPoint: function (node, parent) {
-var added;
-if (node.nodeType === Node.DOCUMENT_FRAGMENT_NODE && !node.__noContent) {
-var c$ = factory(node).querySelectorAll(CONTENT);
-for (var i = 0, n, np, na; i < c$.length && (n = c$[i]); i++) {
-np = factory(n).parentNode;
-if (np === node) {
-np = parent;
-}
-na = this._maybeAddInsertionPoint(n, np);
-added = added || na;
-}
-} else if (node.localName === CONTENT) {
-saveLightChildrenIfNeeded(parent);
-saveLightChildrenIfNeeded(node);
-added = true;
-}
-return added;
-},
-_tryRemoveUndistributedNode: function (node) {
-if (this.node.shadyRoot) {
-var parent = getComposedParent(node);
-if (parent) {
-nativeRemoveChild.call(parent, node);
-}
-return true;
-}
-},
-_updateInsertionPoints: function (host) {
-var i$ = host.shadyRoot._insertionPoints = factory(host.shadyRoot).querySelectorAll(CONTENT);
-for (var i = 0, c; i < i$.length; i++) {
-c = i$[i];
-saveLightChildrenIfNeeded(c);
-saveLightChildrenIfNeeded(factory(c).parentNode);
-}
-},
-_nodeHasLogicalChildren: function (node) {
-return Boolean(node._lightChildren !== undefined);
-},
-_parentNeedsDistribution: function (parent) {
-return parent && parent.shadyRoot && hasInsertionPoint(parent.shadyRoot);
-},
-_removeNodeFromParent: function (node) {
-var parent = node._lightParent || node.parentNode;
-if (parent && hasDomApi(parent)) {
-factory(parent).notifyObserver();
-}
-this._removeNodeFromHost(node, true);
-},
-_removeNodeFromHost: function (node, ensureComposedRemoval) {
-var hostNeedsDist;
-var root;
-var parent = node._lightParent;
-if (parent) {
-factory(node)._distributeParent();
-root = this._ownerShadyRootForNode(node);
-if (root) {
-root.host._elementRemove(node);
-hostNeedsDist = this._removeDistributedChildren(root, node);
-}
-this._removeLogicalInfo(node, parent);
-}
-this._removeOwnerShadyRoot(node);
-if (root && hostNeedsDist) {
-this._updateInsertionPoints(root.host);
-this._lazyDistribute(root.host);
-} else if (ensureComposedRemoval) {
-removeFromComposedParent(getComposedParent(node), node);
-}
-},
-_removeDistributedChildren: function (root, container) {
-var hostNeedsDist;
-var ip$ = root._insertionPoints;
-for (var i = 0; i < ip$.length; i++) {
-var content = ip$[i];
-if (this._contains(container, content)) {
-var dc$ = factory(content).getDistributedNodes();
-for (var j = 0; j < dc$.length; j++) {
-hostNeedsDist = true;
-var node = dc$[j];
-var parent = node.parentNode;
-if (parent) {
-removeFromComposedParent(parent, node);
-nativeRemoveChild.call(parent, node);
-}
-}
-}
-}
-return hostNeedsDist;
-},
-_contains: function (container, node) {
-while (node) {
-if (node == container) {
-return true;
-}
-node = factory(node).parentNode;
-}
-},
-_addNodeToHost: function (node) {
-var root = this.getOwnerRoot();
-if (root) {
-root.host._elementAdd(node);
-}
-},
-_addLogicalInfo: function (node, container, index) {
-var children = factory(container).childNodes;
-index = index === undefined ? children.length : index;
-if (node.nodeType === Node.DOCUMENT_FRAGMENT_NODE) {
-var c$ = arrayCopyChildNodes(node);
-for (var i = 0, n; i < c$.length && (n = c$[i]); i++) {
-children.splice(index++, 0, n);
-n._lightParent = container;
-}
-} else {
-children.splice(index, 0, node);
-node._lightParent = container;
-}
-},
-_removeLogicalInfo: function (node, container) {
-var children = factory(container).childNodes;
-var index = children.indexOf(node);
-if (index < 0 || container !== node._lightParent) {
-throw Error('The node to be removed is not a child of this node');
-}
-children.splice(index, 1);
-node._lightParent = null;
-},
-_removeOwnerShadyRoot: function (node) {
-if (this._hasCachedOwnerRoot(node)) {
-var c$ = factory(node).childNodes;
-for (var i = 0, l = c$.length, n; i < l && (n = c$[i]); i++) {
-this._removeOwnerShadyRoot(n);
-}
-}
-node._ownerShadyRoot = undefined;
-},
-_firstComposedNode: function (content) {
-var n$ = factory(content).getDistributedNodes();
-for (var i = 0, l = n$.length, n, p$; i < l && (n = n$[i]); i++) {
-p$ = factory(n).getDestinationInsertionPoints();
-if (p$[p$.length - 1] === content) {
-return n;
-}
-}
-},
-querySelector: function (selector) {
-return this.querySelectorAll(selector)[0];
-},
-querySelectorAll: function (selector) {
-return this._query(function (n) {
-return matchesSelector.call(n, selector);
-}, this.node);
-},
-_query: function (matcher, node) {
-node = node || this.node;
-var list = [];
-this._queryElements(factory(node).childNodes, matcher, list);
-return list;
-},
-_queryElements: function (elements, matcher, list) {
-for (var i = 0, l = elements.length, c; i < l && (c = elements[i]); i++) {
-if (c.nodeType === Node.ELEMENT_NODE) {
-this._queryElement(c, matcher, list);
-}
-}
-},
-_queryElement: function (node, matcher, list) {
-if (matcher(node)) {
-list.push(node);
-}
-this._queryElements(factory(node).childNodes, matcher, list);
-},
-getDestinationInsertionPoints: function () {
-return this.node._destinationInsertionPoints || [];
-},
-getDistributedNodes: function () {
-return this.node._distributedNodes || [];
-},
-queryDistributedElements: function (selector) {
-var c$ = this.getEffectiveChildNodes();
-var list = [];
-for (var i = 0, l = c$.length, c; i < l && (c = c$[i]); i++) {
-if (c.nodeType === Node.ELEMENT_NODE && matchesSelector.call(c, selector)) {
-list.push(c);
-}
-}
-return list;
-},
-getEffectiveChildNodes: function () {
-var list = [];
-var c$ = this.childNodes;
-for (var i = 0, l = c$.length, c; i < l && (c = c$[i]); i++) {
-if (c.localName === CONTENT) {
-var d$ = factory(c).getDistributedNodes();
-for (var j = 0; j < d$.length; j++) {
-list.push(d$[j]);
-}
-} else {
-list.push(c);
-}
-}
-return list;
-},
-_clear: function () {
-while (this.childNodes.length) {
-this.removeChild(this.childNodes[0]);
-}
-},
-setAttribute: function (name, value) {
-this.node.setAttribute(name, value);
-this._distributeParent();
-},
-removeAttribute: function (name) {
-this.node.removeAttribute(name);
-this._distributeParent();
-},
-_distributeParent: function () {
-if (this._parentNeedsDistribution(this.parentNode)) {
-this._lazyDistribute(this.parentNode);
-}
-},
-cloneNode: function (deep) {
-var n = nativeCloneNode.call(this.node, false);
-if (deep) {
-var c$ = this.childNodes;
-var d = factory(n);
-for (var i = 0, nc; i < c$.length; i++) {
-nc = factory(c$[i]).cloneNode(true);
-d.appendChild(nc);
-}
-}
-return n;
-},
-importNode: function (externalNode, deep) {
-var doc = this.node instanceof Document ? this.node : this.node.ownerDocument;
-var n = nativeImportNode.call(doc, externalNode, false);
-if (deep) {
-var c$ = factory(externalNode).childNodes;
-var d = factory(n);
-for (var i = 0, nc; i < c$.length; i++) {
-nc = factory(doc).importNode(c$[i], true);
-d.appendChild(nc);
-}
-}
-return n;
-},
-observeNodes: function (callback) {
-if (callback) {
-if (!this.observer) {
-this.observer = this.node.localName === CONTENT ? new DomApi.DistributedNodesObserver(this) : new DomApi.EffectiveNodesObserver(this);
-}
-return this.observer.addListener(callback);
-}
-},
-unobserveNodes: function (handle) {
-if (this.observer) {
-this.observer.removeListener(handle);
-}
-},
-notifyObserver: function () {
-if (this.observer) {
-this.observer.notify();
-}
-}
-};
-if (!Settings.useShadow) {
-Object.defineProperties(DomApi.prototype, {
-childNodes: {
-get: function () {
-var c$ = getLightChildren(this.node);
-return Array.isArray(c$) ? c$ : arrayCopyChildNodes(this.node);
-},
-configurable: true
-},
-children: {
-get: function () {
-return Array.prototype.filter.call(this.childNodes, function (n) {
-return n.nodeType === Node.ELEMENT_NODE;
-});
-},
-configurable: true
-},
-parentNode: {
-get: function () {
-return this.node._lightParent || getComposedParent(this.node);
-},
-configurable: true
-},
-firstChild: {
-get: function () {
-return this.childNodes[0];
-},
-configurable: true
-},
-lastChild: {
-get: function () {
-var c$ = this.childNodes;
-return c$[c$.length - 1];
-},
-configurable: true
-},
-nextSibling: {
-get: function () {
-var c$ = this.parentNode && factory(this.parentNode).childNodes;
-if (c$) {
-return c$[Array.prototype.indexOf.call(c$, this.node) + 1];
-}
-},
-configurable: true
-},
-previousSibling: {
-get: function () {
-var c$ = this.parentNode && factory(this.parentNode).childNodes;
-if (c$) {
-return c$[Array.prototype.indexOf.call(c$, this.node) - 1];
-}
-},
-configurable: true
-},
-firstElementChild: {
-get: function () {
-return this.children[0];
-},
-configurable: true
-},
-lastElementChild: {
-get: function () {
-var c$ = this.children;
-return c$[c$.length - 1];
-},
-configurable: true
-},
-nextElementSibling: {
-get: function () {
-var c$ = this.parentNode && factory(this.parentNode).children;
-if (c$) {
-return c$[Array.prototype.indexOf.call(c$, this.node) + 1];
-}
-},
-configurable: true
-},
-previousElementSibling: {
-get: function () {
-var c$ = this.parentNode && factory(this.parentNode).children;
-if (c$) {
-return c$[Array.prototype.indexOf.call(c$, this.node) - 1];
-}
-},
-configurable: true
-},
-textContent: {
-get: function () {
-var nt = this.node.nodeType;
-if (nt === Node.TEXT_NODE || nt === Node.COMMENT_NODE) {
-return this.node.textContent;
-} else {
-var tc = [];
-for (var i = 0, cn = this.childNodes, c; c = cn[i]; i++) {
-if (c.nodeType !== Node.COMMENT_NODE) {
-tc.push(c.textContent);
-}
-}
-return tc.join('');
-}
-},
-set: function (text) {
-var nt = this.node.nodeType;
-if (nt === Node.TEXT_NODE || nt === Node.COMMENT_NODE) {
-this.node.textContent = text;
-} else {
-this._clear();
-if (text) {
-this.appendChild(document.createTextNode(text));
-}
-}
-},
-configurable: true
-},
-innerHTML: {
-get: function () {
-var nt = this.node.nodeType;
-if (nt === Node.TEXT_NODE || nt === Node.COMMENT_NODE) {
-return null;
-} else {
-return getInnerHTML(this.node);
-}
-},
-set: function (text) {
-var nt = this.node.nodeType;
-if (nt !== Node.TEXT_NODE || nt !== Node.COMMENT_NODE) {
-this._clear();
-var d = document.createElement('div');
-d.innerHTML = text;
-var c$ = arrayCopyChildNodes(d);
-for (var i = 0; i < c$.length; i++) {
-this.appendChild(c$[i]);
-}
-}
-},
-configurable: true
-}
-});
-DomApi.prototype._getComposedInnerHTML = function () {
-return getInnerHTML(this.node, true);
-};
-} else {
-var forwardMethods = function (m$) {
-for (var i = 0; i < m$.length; i++) {
-forwardMethod(m$[i]);
-}
-};
-var forwardMethod = function (method) {
-DomApi.prototype[method] = function () {
-return this.node[method].apply(this.node, arguments);
-};
-};
-forwardMethods([
-'cloneNode',
-'appendChild',
-'insertBefore',
-'removeChild',
-'replaceChild'
-]);
-DomApi.prototype.querySelectorAll = function (selector) {
-return arrayCopy(this.node.querySelectorAll(selector));
-};
-DomApi.prototype.getOwnerRoot = function () {
-var n = this.node;
-while (n) {
-if (n.nodeType === Node.DOCUMENT_FRAGMENT_NODE && n.host) {
-return n;
-}
-n = n.parentNode;
-}
-};
-DomApi.prototype.importNode = function (externalNode, deep) {
-var doc = this.node instanceof Document ? this.node : this.node.ownerDocument;
-return doc.importNode(externalNode, deep);
-};
-DomApi.prototype.getDestinationInsertionPoints = function () {
-var n$ = this.node.getDestinationInsertionPoints && this.node.getDestinationInsertionPoints();
-return n$ ? arrayCopy(n$) : [];
-};
-DomApi.prototype.getDistributedNodes = function () {
-var n$ = this.node.getDistributedNodes && this.node.getDistributedNodes();
-return n$ ? arrayCopy(n$) : [];
-};
-DomApi.prototype._distributeParent = function () {
-};
-Object.defineProperties(DomApi.prototype, {
-childNodes: {
-get: function () {
-return arrayCopyChildNodes(this.node);
-},
-configurable: true
-},
-children: {
-get: function () {
-return arrayCopyChildren(this.node);
-},
-configurable: true
-},
-textContent: {
-get: function () {
-return this.node.textContent;
-},
-set: function (value) {
-return this.node.textContent = value;
-},
-configurable: true
-},
-innerHTML: {
-get: function () {
-return this.node.innerHTML;
-},
-set: function (value) {
-return this.node.innerHTML = value;
-},
-configurable: true
-}
-});
-var forwardProperties = function (f$) {
-for (var i = 0; i < f$.length; i++) {
-forwardProperty(f$[i]);
-}
-};
-var forwardProperty = function (name) {
-Object.defineProperty(DomApi.prototype, name, {
-get: function () {
-return this.node[name];
-},
-configurable: true
-});
-};
-forwardProperties([
-'parentNode',
-'firstChild',
-'lastChild',
-'nextSibling',
-'previousSibling',
-'firstElementChild',
-'lastElementChild',
-'nextElementSibling',
-'previousElementSibling'
-]);
-}
-var CONTENT = 'content';
-function factory(node, patch) {
-node = node || document;
-if (!node.__domApi) {
-node.__domApi = new DomApi(node, patch);
-}
-return node.__domApi;
-}
-;
-function hasDomApi(node) {
-return Boolean(node.__domApi);
-}
-;
-Polymer.dom = function (obj, patch) {
-if (obj instanceof Event) {
-return Polymer.EventApi.factory(obj);
-} else {
-return factory(obj, patch);
-}
-};
-function getLightChildren(node) {
-var children = node._lightChildren;
-return children ? children : node.childNodes;
-}
-function getComposedChildren(node) {
-if (!node._composedChildren) {
-node._composedChildren = arrayCopyChildNodes(node);
-}
-return node._composedChildren;
-}
-function addToComposedParent(parent, node, ref_node) {
-var children = getComposedChildren(parent);
-var i = ref_node ? children.indexOf(ref_node) : -1;
-if (node.nodeType === Node.DOCUMENT_FRAGMENT_NODE) {
-var fragChildren = getComposedChildren(node);
-for (var j = 0; j < fragChildren.length; j++) {
-addNodeToComposedChildren(fragChildren[j], parent, children, i + j);
-}
-node._composedChildren = null;
-} else {
-addNodeToComposedChildren(node, parent, children, i);
-}
-}
-function getComposedParent(node) {
-return node.__patched ? node._composedParent : node.parentNode;
-}
-function addNodeToComposedChildren(node, parent, children, i) {
-node._composedParent = parent;
-children.splice(i >= 0 ? i : children.length, 0, node);
-}
-function removeFromComposedParent(parent, node) {
-node._composedParent = null;
-if (parent) {
-var children = getComposedChildren(parent);
-var i = children.indexOf(node);
-if (i >= 0) {
-children.splice(i, 1);
-}
-}
-}
-function saveLightChildrenIfNeeded(node) {
-if (!node._lightChildren) {
-var c$ = arrayCopyChildNodes(node);
-for (var i = 0, l = c$.length, child; i < l && (child = c$[i]); i++) {
-child._lightParent = child._lightParent || node;
-}
-node._lightChildren = c$;
-}
-}
-function arrayCopyChildNodes(parent) {
-var copy = [], i = 0;
-for (var n = parent.firstChild; n; n = n.nextSibling) {
-copy[i++] = n;
-}
-return copy;
-}
-function arrayCopyChildren(parent) {
-var copy = [], i = 0;
-for (var n = parent.firstElementChild; n; n = n.nextElementSibling) {
-copy[i++] = n;
-}
-return copy;
-}
-function arrayCopy(a$) {
-var l = a$.length;
-var copy = new Array(l);
-for (var i = 0; i < l; i++) {
-copy[i] = a$[i];
-}
-return copy;
-}
-function hasInsertionPoint(root) {
-return Boolean(root && root._insertionPoints.length);
-}
-var p = Element.prototype;
-var matchesSelector = p.matches || p.matchesSelector || p.mozMatchesSelector || p.msMatchesSelector || p.oMatchesSelector || p.webkitMatchesSelector;
-return {
-getLightChildren: getLightChildren,
-getComposedParent: getComposedParent,
-getComposedChildren: getComposedChildren,
-removeFromComposedParent: removeFromComposedParent,
-saveLightChildrenIfNeeded: saveLightChildrenIfNeeded,
-matchesSelector: matchesSelector,
-hasInsertionPoint: hasInsertionPoint,
-ctor: DomApi,
-factory: factory,
-hasDomApi: hasDomApi,
-arrayCopy: arrayCopy,
-arrayCopyChildNodes: arrayCopyChildNodes,
-arrayCopyChildren: arrayCopyChildren,
-wrap: wrap
-};
-}();
-Polymer.Base.extend(Polymer.dom, {
-_flushGuard: 0,
-_FLUSH_MAX: 100,
-_needsTakeRecords: !Polymer.Settings.useNativeCustomElements,
-_debouncers: [],
-_staticFlushList: [],
-_finishDebouncer: null,
-flush: function () {
-this._flushGuard = 0;
-this._prepareFlush();
-while (this._debouncers.length && this._flushGuard < this._FLUSH_MAX) {
-for (var i = 0; i < this._debouncers.length; i++) {
-this._debouncers[i].complete();
-}
-if (this._finishDebouncer) {
-this._finishDebouncer.complete();
-}
-this._prepareFlush();
-this._flushGuard++;
-}
-if (this._flushGuard >= this._FLUSH_MAX) {
-console.warn('Polymer.dom.flush aborted. Flush may not be complete.');
-}
-},
-_prepareFlush: function () {
-if (this._needsTakeRecords) {
-CustomElements.takeRecords();
-}
-for (var i = 0; i < this._staticFlushList.length; i++) {
-this._staticFlushList[i]();
-}
-},
-addStaticFlush: function (fn) {
-this._staticFlushList.push(fn);
-},
-removeStaticFlush: function (fn) {
-var i = this._staticFlushList.indexOf(fn);
-if (i >= 0) {
-this._staticFlushList.splice(i, 1);
-}
-},
-addDebouncer: function (debouncer) {
-this._debouncers.push(debouncer);
-this._finishDebouncer = Polymer.Debounce(this._finishDebouncer, this._finishFlush);
-},
-_finishFlush: function () {
-Polymer.dom._debouncers = [];
-}
-});
-Polymer.EventApi = function () {
-'use strict';
-var DomApi = Polymer.DomApi.ctor;
-var Settings = Polymer.Settings;
-DomApi.Event = function (event) {
-this.event = event;
-};
-if (Settings.useShadow) {
-DomApi.Event.prototype = {
-get rootTarget() {
-return this.event.path[0];
-},
-get localTarget() {
-return this.event.target;
-},
-get path() {
-return this.event.path;
-}
-};
-} else {
-DomApi.Event.prototype = {
-get rootTarget() {
-return this.event.target;
-},
-get localTarget() {
-var current = this.event.currentTarget;
-var currentRoot = current && Polymer.dom(current).getOwnerRoot();
-var p$ = this.path;
-for (var i = 0; i < p$.length; i++) {
-if (Polymer.dom(p$[i]).getOwnerRoot() === currentRoot) {
-return p$[i];
-}
-}
-},
-get path() {
-if (!this.event._path) {
-var path = [];
-var o = this.rootTarget;
-while (o) {
-path.push(o);
-o = Polymer.dom(o).parentNode || o.host;
-}
-path.push(window);
-this.event._path = path;
-}
-return this.event._path;
-}
-};
-}
-var factory = function (event) {
-if (!event.__eventApi) {
-event.__eventApi = new DomApi.Event(event);
-}
-return event.__eventApi;
-};
-return { factory: factory };
-}();
-(function () {
-'use strict';
-var DomApi = Polymer.DomApi.ctor;
-Object.defineProperty(DomApi.prototype, 'classList', {
-get: function () {
-if (!this._classList) {
-this._classList = new DomApi.ClassList(this);
-}
-return this._classList;
-},
-configurable: true
-});
-DomApi.ClassList = function (host) {
-this.domApi = host;
-this.node = host.node;
-};
-DomApi.ClassList.prototype = {
-add: function () {
-this.node.classList.add.apply(this.node.classList, arguments);
-this.domApi._distributeParent();
-},
-remove: function () {
-this.node.classList.remove.apply(this.node.classList, arguments);
-this.domApi._distributeParent();
-},
-toggle: function () {
-this.node.classList.toggle.apply(this.node.classList, arguments);
-this.domApi._distributeParent();
-},
-contains: function () {
-return this.node.classList.contains.apply(this.node.classList, arguments);
-}
-};
-}());
-(function () {
-'use strict';
-var DomApi = Polymer.DomApi.ctor;
-var Settings = Polymer.Settings;
-var hasDomApi = Polymer.DomApi.hasDomApi;
-DomApi.EffectiveNodesObserver = function (domApi) {
-this.domApi = domApi;
-this.node = this.domApi.node;
-this._listeners = [];
-};
-DomApi.EffectiveNodesObserver.prototype = {
-addListener: function (callback) {
-if (!this._isSetup) {
-this._setup();
-this._isSetup = true;
-}
-var listener = {
-fn: callback,
-_nodes: []
-};
-this._listeners.push(listener);
-this._scheduleNotify();
-return listener;
-},
-removeListener: function (handle) {
-var i = this._listeners.indexOf(handle);
-if (i >= 0) {
-this._listeners.splice(i, 1);
-handle._nodes = [];
-}
-if (!this._hasListeners()) {
-this._cleanup();
-this._isSetup = false;
-}
-},
-_setup: function () {
-this._observeContentElements(this.domApi.childNodes);
-},
-_cleanup: function () {
-this._unobserveContentElements(this.domApi.childNodes);
-},
-_hasListeners: function () {
-return Boolean(this._listeners.length);
-},
-_scheduleNotify: function () {
-if (this._debouncer) {
-this._debouncer.stop();
-}
-this._debouncer = Polymer.Debounce(this._debouncer, this._notify);
-this._debouncer.context = this;
-Polymer.dom.addDebouncer(this._debouncer);
-},
-notify: function () {
-if (this._hasListeners()) {
-this._scheduleNotify();
-}
-},
-_notify: function (mxns) {
-this._beforeCallListeners();
-this._callListeners();
-},
-_beforeCallListeners: function () {
-this._updateContentElements();
-},
-_updateContentElements: function () {
-this._observeContentElements(this.domApi.childNodes);
-},
-_observeContentElements: function (elements) {
-for (var i = 0, n; i < elements.length && (n = elements[i]); i++) {
-if (this._isContent(n)) {
-n.__observeNodesMap = n.__observeNodesMap || new WeakMap();
-if (!n.__observeNodesMap.has(this)) {
-n.__observeNodesMap.set(this, this._observeContent(n));
-}
-}
-}
-},
-_observeContent: function (content) {
-var self = this;
-var h = Polymer.dom(content).observeNodes(function () {
-self._scheduleNotify();
-});
-h._avoidChangeCalculation = true;
-return h;
-},
-_unobserveContentElements: function (elements) {
-for (var i = 0, n, h; i < elements.length && (n = elements[i]); i++) {
-if (this._isContent(n)) {
-h = n.__observeNodesMap.get(this);
-if (h) {
-Polymer.dom(n).unobserveNodes(h);
-n.__observeNodesMap.delete(this);
-}
-}
-}
-},
-_isContent: function (node) {
-return node.localName === 'content';
-},
-_callListeners: function () {
-var o$ = this._listeners;
-var nodes = this._getEffectiveNodes();
-for (var i = 0, o; i < o$.length && (o = o$[i]); i++) {
-var info = this._generateListenerInfo(o, nodes);
-if (info || o._alwaysNotify) {
-this._callListener(o, info);
-}
-}
-},
-_getEffectiveNodes: function () {
-return this.domApi.getEffectiveChildNodes();
-},
-_generateListenerInfo: function (listener, newNodes) {
-if (listener._avoidChangeCalculation) {
-return true;
-}
-var oldNodes = listener._nodes;
-var info = {
-target: this.node,
-addedNodes: [],
-removedNodes: []
-};
-var splices = Polymer.ArraySplice.calculateSplices(newNodes, oldNodes);
-for (var i = 0, s; i < splices.length && (s = splices[i]); i++) {
-for (var j = 0, n; j < s.removed.length && (n = s.removed[j]); j++) {
-info.removedNodes.push(n);
-}
-}
-for (var i = 0, s; i < splices.length && (s = splices[i]); i++) {
-for (var j = s.index; j < s.index + s.addedCount; j++) {
-info.addedNodes.push(newNodes[j]);
-}
-}
-listener._nodes = newNodes;
-if (info.addedNodes.length || info.removedNodes.length) {
-return info;
-}
-},
-_callListener: function (listener, info) {
-return listener.fn.call(this.node, info);
-},
-enableShadowAttributeTracking: function () {
-}
-};
-if (Settings.useShadow) {
-var baseSetup = DomApi.EffectiveNodesObserver.prototype._setup;
-var baseCleanup = DomApi.EffectiveNodesObserver.prototype._cleanup;
-var beforeCallListeners = DomApi.EffectiveNodesObserver.prototype._beforeCallListeners;
-Polymer.Base.extend(DomApi.EffectiveNodesObserver.prototype, {
-_setup: function () {
-if (!this._observer) {
-var self = this;
-this._mutationHandler = function (mxns) {
-if (mxns && mxns.length) {
-self._scheduleNotify();
-}
-};
-this._observer = new MutationObserver(this._mutationHandler);
-this._boundFlush = function () {
-self._flush();
-};
-Polymer.dom.addStaticFlush(this._boundFlush);
-this._observer.observe(this.node, { childList: true });
-}
-baseSetup.call(this);
-},
-_cleanup: function () {
-this._observer.disconnect();
-this._observer = null;
-this._mutationHandler = null;
-Polymer.dom.removeStaticFlush(this._boundFlush);
-baseCleanup.call(this);
-},
-_flush: function () {
-if (this._observer) {
-this._mutationHandler(this._observer.takeRecords());
-}
-},
-enableShadowAttributeTracking: function () {
-if (this._observer) {
-this._makeContentListenersAlwaysNotify();
-this._observer.disconnect();
-this._observer.observe(this.node, {
-childList: true,
-attributes: true,
-subtree: true
-});
-var root = this.domApi.getOwnerRoot();
-var host = root && root.host;
-if (host && Polymer.dom(host).observer) {
-Polymer.dom(host).observer.enableShadowAttributeTracking();
-}
-}
-},
-_makeContentListenersAlwaysNotify: function () {
-for (var i = 0, h; i < this._listeners.length; i++) {
-h = this._listeners[i];
-h._alwaysNotify = h._isContentListener;
-}
-}
-});
-}
-}());
-(function () {
-'use strict';
-var DomApi = Polymer.DomApi.ctor;
-var Settings = Polymer.Settings;
-DomApi.DistributedNodesObserver = function (domApi) {
-DomApi.EffectiveNodesObserver.call(this, domApi);
-};
-DomApi.DistributedNodesObserver.prototype = Object.create(DomApi.EffectiveNodesObserver.prototype);
-Polymer.Base.extend(DomApi.DistributedNodesObserver.prototype, {
-_setup: function () {
-},
-_cleanup: function () {
-},
-_beforeCallListeners: function () {
-},
-_getEffectiveNodes: function () {
-return this.domApi.getDistributedNodes();
-}
-});
-if (Settings.useShadow) {
-Polymer.Base.extend(DomApi.DistributedNodesObserver.prototype, {
-_setup: function () {
-if (!this._observer) {
-var root = this.domApi.getOwnerRoot();
-var host = root && root.host;
-if (host) {
-var self = this;
-this._observer = Polymer.dom(host).observeNodes(function () {
-self._scheduleNotify();
-});
-this._observer._isContentListener = true;
-if (this._hasAttrSelect()) {
-Polymer.dom(host).observer.enableShadowAttributeTracking();
-}
-}
-}
-},
-_hasAttrSelect: function () {
-var select = this.node.getAttribute('select');
-return select && select.match(/[[.]+/);
-},
-_cleanup: function () {
-var root = this.domApi.getOwnerRoot();
-var host = root && root.host;
-if (host) {
-Polymer.dom(host).unobserveNodes(this._observer);
-}
-this._observer = null;
-}
-});
-}
-}());
-(function () {
-var hasDomApi = Polymer.DomApi.hasDomApi;
-Polymer.Base._addFeature({
-_prepShady: function () {
-this._useContent = this._useContent || Boolean(this._template);
-},
-_poolContent: function () {
-if (this._useContent) {
-saveLightChildrenIfNeeded(this);
-}
-},
-_setupRoot: function () {
-if (this._useContent) {
-this._createLocalRoot();
-if (!this.dataHost) {
-upgradeLightChildren(this._lightChildren);
-}
-}
-},
-_createLocalRoot: function () {
-this.shadyRoot = this.root;
-this.shadyRoot._distributionClean = false;
-this.shadyRoot._hasDistributed = false;
-this.shadyRoot._isShadyRoot = true;
-this.shadyRoot._dirtyRoots = [];
-var i$ = this.shadyRoot._insertionPoints = !this._notes || this._notes._hasContent ? this.shadyRoot.querySelectorAll('content') : [];
-saveLightChildrenIfNeeded(this.shadyRoot);
-for (var i = 0, c; i < i$.length; i++) {
-c = i$[i];
-saveLightChildrenIfNeeded(c);
-saveLightChildrenIfNeeded(c.parentNode);
-}
-this.shadyRoot.host = this;
-},
-get domHost() {
-var root = Polymer.dom(this).getOwnerRoot();
-return root && root.host;
-},
-distributeContent: function (updateInsertionPoints) {
-if (this.shadyRoot) {
-var dom = Polymer.dom(this);
-if (updateInsertionPoints) {
-dom._updateInsertionPoints(this);
-}
-var host = getTopDistributingHost(this);
-dom._lazyDistribute(host);
-}
-},
-_distributeContent: function () {
-if (this._useContent && !this.shadyRoot._distributionClean) {
-this._beginDistribute();
-this._distributeDirtyRoots();
-this._finishDistribute();
-}
-},
-_beginDistribute: function () {
-if (this._useContent && hasInsertionPoint(this.shadyRoot)) {
-this._resetDistribution();
-this._distributePool(this.shadyRoot, this._collectPool());
-}
-},
-_distributeDirtyRoots: function () {
-var c$ = this.shadyRoot._dirtyRoots;
-for (var i = 0, l = c$.length, c; i < l && (c = c$[i]); i++) {
-c._distributeContent();
-}
-this.shadyRoot._dirtyRoots = [];
-},
-_finishDistribute: function () {
-if (this._useContent) {
-this.shadyRoot._distributionClean = true;
-if (hasInsertionPoint(this.shadyRoot)) {
-this._composeTree();
-notifyContentObservers(this.shadyRoot);
-} else {
-if (!this.shadyRoot._hasDistributed) {
-this.textContent = '';
-this._composedChildren = null;
-this.appendChild(this.shadyRoot);
-} else {
-var children = this._composeNode(this);
-this._updateChildNodes(this, children);
-}
-}
-if (!this.shadyRoot._hasDistributed) {
-notifyInitialDistribution(this);
-}
-this.shadyRoot._hasDistributed = true;
-}
-},
-elementMatches: function (selector, node) {
-node = node || this;
-return matchesSelector.call(node, selector);
-},
-_resetDistribution: function () {
-var children = getLightChildren(this);
-for (var i = 0; i < children.length; i++) {
-var child = children[i];
-if (child._destinationInsertionPoints) {
-child._destinationInsertionPoints = undefined;
-}
-if (isInsertionPoint(child)) {
-clearDistributedDestinationInsertionPoints(child);
-}
-}
-var root = this.shadyRoot;
-var p$ = root._insertionPoints;
-for (var j = 0; j < p$.length; j++) {
-p$[j]._distributedNodes = [];
-}
-},
-_collectPool: function () {
-var pool = [];
-var children = getLightChildren(this);
-for (var i = 0; i < children.length; i++) {
-var child = children[i];
-if (isInsertionPoint(child)) {
-pool.push.apply(pool, child._distributedNodes);
-} else {
-pool.push(child);
-}
-}
-return pool;
-},
-_distributePool: function (node, pool) {
-var p$ = node._insertionPoints;
-for (var i = 0, l = p$.length, p; i < l && (p = p$[i]); i++) {
-this._distributeInsertionPoint(p, pool);
-maybeRedistributeParent(p, this);
-}
-},
-_distributeInsertionPoint: function (content, pool) {
-var anyDistributed = false;
-for (var i = 0, l = pool.length, node; i < l; i++) {
-node = pool[i];
-if (!node) {
-continue;
-}
-if (this._matchesContentSelect(node, content)) {
-distributeNodeInto(node, content);
-pool[i] = undefined;
-anyDistributed = true;
-}
-}
-if (!anyDistributed) {
-var children = getLightChildren(content);
-for (var j = 0; j < children.length; j++) {
-distributeNodeInto(children[j], content);
-}
-}
-},
-_composeTree: function () {
-this._updateChildNodes(this, this._composeNode(this));
-var p$ = this.shadyRoot._insertionPoints;
-for (var i = 0, l = p$.length, p, parent; i < l && (p = p$[i]); i++) {
-parent = p._lightParent || p.parentNode;
-if (!parent._useContent && parent !== this && parent !== this.shadyRoot) {
-this._updateChildNodes(parent, this._composeNode(parent));
-}
-}
-},
-_composeNode: function (node) {
-var children = [];
-var c$ = getLightChildren(node.shadyRoot || node);
-for (var i = 0; i < c$.length; i++) {
-var child = c$[i];
-if (isInsertionPoint(child)) {
-var distributedNodes = child._distributedNodes;
-for (var j = 0; j < distributedNodes.length; j++) {
-var distributedNode = distributedNodes[j];
-if (isFinalDestination(child, distributedNode)) {
-children.push(distributedNode);
-}
-}
-} else {
-children.push(child);
-}
-}
-return children;
-},
-_updateChildNodes: function (container, children) {
-var composed = getComposedChildren(container);
-var splices = Polymer.ArraySplice.calculateSplices(children, composed);
-for (var i = 0, d = 0, s; i < splices.length && (s = splices[i]); i++) {
-for (var j = 0, n; j < s.removed.length && (n = s.removed[j]); j++) {
-if (getComposedParent(n) === container) {
-remove(n);
-}
-composed.splice(s.index + d, 1);
-}
-d -= s.addedCount;
-}
-for (var i = 0, s, next; i < splices.length && (s = splices[i]); i++) {
-next = composed[s.index];
-for (var j = s.index, n; j < s.index + s.addedCount; j++) {
-n = children[j];
-insertBefore(container, n, next);
-composed.splice(j, 0, n);
-}
-}
-ensureComposedParent(container, children);
-},
-_matchesContentSelect: function (node, contentElement) {
-var select = contentElement.getAttribute('select');
-if (!select) {
-return true;
-}
-select = select.trim();
-if (!select) {
-return true;
-}
-if (!(node instanceof Element)) {
-return false;
-}
-var validSelectors = /^(:not\()?[*.#[a-zA-Z_|]/;
-if (!validSelectors.test(select)) {
-return false;
-}
-return this.elementMatches(select, node);
-},
-_elementAdd: function () {
-},
-_elementRemove: function () {
-}
-});
-var saveLightChildrenIfNeeded = Polymer.DomApi.saveLightChildrenIfNeeded;
-var getLightChildren = Polymer.DomApi.getLightChildren;
-var matchesSelector = Polymer.DomApi.matchesSelector;
-var hasInsertionPoint = Polymer.DomApi.hasInsertionPoint;
-var getComposedChildren = Polymer.DomApi.getComposedChildren;
-var getComposedParent = Polymer.DomApi.getComposedParent;
-var removeFromComposedParent = Polymer.DomApi.removeFromComposedParent;
-function distributeNodeInto(child, insertionPoint) {
-insertionPoint._distributedNodes.push(child);
-var points = child._destinationInsertionPoints;
-if (!points) {
-child._destinationInsertionPoints = [insertionPoint];
-} else {
-points.push(insertionPoint);
-}
-}
-function clearDistributedDestinationInsertionPoints(content) {
-var e$ = content._distributedNodes;
-if (e$) {
-for (var i = 0; i < e$.length; i++) {
-var d = e$[i]._destinationInsertionPoints;
-if (d) {
-d.splice(d.indexOf(content) + 1, d.length);
-}
-}
-}
-}
-function maybeRedistributeParent(content, host) {
-var parent = content._lightParent;
-if (parent && parent.shadyRoot && hasInsertionPoint(parent.shadyRoot) && parent.shadyRoot._distributionClean) {
-parent.shadyRoot._distributionClean = false;
-host.shadyRoot._dirtyRoots.push(parent);
-}
-}
-function isFinalDestination(insertionPoint, node) {
-var points = node._destinationInsertionPoints;
-return points && points[points.length - 1] === insertionPoint;
-}
-function isInsertionPoint(node) {
-return node.localName == 'content';
-}
-var nativeInsertBefore = Element.prototype.insertBefore;
-var nativeRemoveChild = Element.prototype.removeChild;
-function insertBefore(parentNode, newChild, refChild) {
-var newChildParent = getComposedParent(newChild);
-if (newChildParent !== parentNode) {
-removeFromComposedParent(newChildParent, newChild);
-}
-remove(newChild);
-nativeInsertBefore.call(parentNode, newChild, refChild || null);
-newChild._composedParent = parentNode;
-}
-function remove(node) {
-var parentNode = getComposedParent(node);
-if (parentNode) {
-node._composedParent = null;
-nativeRemoveChild.call(parentNode, node);
-}
-}
-function ensureComposedParent(parent, children) {
-for (var i = 0, n; i < children.length; i++) {
-children[i]._composedParent = parent;
-}
-}
-function getTopDistributingHost(host) {
-while (host && hostNeedsRedistribution(host)) {
-host = host.domHost;
-}
-return host;
-}
-function hostNeedsRedistribution(host) {
-var c$ = Polymer.dom(host).children;
-for (var i = 0, c; i < c$.length; i++) {
-c = c$[i];
-if (c.localName === 'content') {
-return host.domHost;
-}
-}
-}
-function notifyContentObservers(root) {
-for (var i = 0, c; i < root._insertionPoints.length; i++) {
-c = root._insertionPoints[i];
-if (hasDomApi(c)) {
-Polymer.dom(c).notifyObserver();
-}
-}
-}
-function notifyInitialDistribution(host) {
-if (hasDomApi(host)) {
-Polymer.dom(host).notifyObserver();
-}
-}
-var needsUpgrade = window.CustomElements && !CustomElements.useNative;
-function upgradeLightChildren(children) {
-if (needsUpgrade && children) {
-for (var i = 0; i < children.length; i++) {
-CustomElements.upgrade(children[i]);
-}
-}
-}
-}());
-if (Polymer.Settings.useShadow) {
-Polymer.Base._addFeature({
-_poolContent: function () {
-},
-_beginDistribute: function () {
-},
-distributeContent: function () {
-},
-_distributeContent: function () {
-},
-_finishDistribute: function () {
-},
-_createLocalRoot: function () {
-this.createShadowRoot();
-this.shadowRoot.appendChild(this.root);
-this.root = this.shadowRoot;
-}
-});
-}
-Polymer.DomModule = document.createElement('dom-module');
-Polymer.Base._addFeature({
-_registerFeatures: function () {
-this._prepIs();
-this._prepBehaviors();
-this._prepConstructor();
-this._prepTemplate();
-this._prepShady();
-this._prepPropertyInfo();
-},
-_prepBehavior: function (b) {
-this._addHostAttributes(b.hostAttributes);
-},
-_initFeatures: function () {
-this._registerHost();
-if (this._template) {
-this._poolContent();
-this._beginHosting();
-this._stampTemplate();
-this._endHosting();
-}
-this._marshalHostAttributes();
-this._setupDebouncers();
-this._marshalBehaviors();
-this._tryReady();
-},
-_marshalBehavior: function (b) {
-}
-});
-Polymer.nar = [];
-Polymer.Annotations = {
-parseAnnotations: function (template) {
-var list = [];
-var content = template._content || template.content;
-this._parseNodeAnnotations(content, list, template.hasAttribute('strip-whitespace'));
-return list;
-},
-_parseNodeAnnotations: function (node, list, stripWhiteSpace) {
-return node.nodeType === Node.TEXT_NODE ? this._parseTextNodeAnnotation(node, list) : this._parseElementAnnotations(node, list, stripWhiteSpace);
-},
-_bindingRegex: /([^{[]*)(\{\{|\[\[)(?!\}\}|\]\])(.+?)(?:\]\]|\}\})/g,
-_parseBindings: function (text) {
-var re = this._bindingRegex;
-var parts = [];
-var m, lastIndex;
-while ((m = re.exec(text)) !== null) {
-if (m[1]) {
-parts.push({ literal: m[1] });
-}
-var mode = m[2][0];
-var value = m[3].trim();
-var negate = false;
-if (value[0] == '!') {
-negate = true;
-value = value.substring(1).trim();
-}
-var customEvent, notifyEvent, colon;
-if (mode == '{' && (colon = value.indexOf('::')) > 0) {
-notifyEvent = value.substring(colon + 2);
-value = value.substring(0, colon);
-customEvent = true;
-}
-parts.push({
-compoundIndex: parts.length,
-value: value,
-mode: mode,
-negate: negate,
-event: notifyEvent,
-customEvent: customEvent
-});
-lastIndex = re.lastIndex;
-}
-if (lastIndex && lastIndex < text.length) {
-var literal = text.substring(lastIndex);
-if (literal) {
-parts.push({ literal: literal });
-}
-}
-if (parts.length) {
-return parts;
-}
-},
-_literalFromParts: function (parts) {
-var s = '';
-for (var i = 0; i < parts.length; i++) {
-var literal = parts[i].literal;
-s += literal || '';
-}
-return s;
-},
-_parseTextNodeAnnotation: function (node, list) {
-var parts = this._parseBindings(node.textContent);
-if (parts) {
-node.textContent = this._literalFromParts(parts) || ' ';
-var annote = {
-bindings: [{
-kind: 'text',
-name: 'textContent',
-parts: parts,
-isCompound: parts.length !== 1
-}]
-};
-list.push(annote);
-return annote;
-}
-},
-_parseElementAnnotations: function (element, list, stripWhiteSpace) {
-var annote = {
-bindings: [],
-events: []
-};
-if (element.localName === 'content') {
-list._hasContent = true;
-}
-this._parseChildNodesAnnotations(element, annote, list, stripWhiteSpace);
-if (element.attributes) {
-this._parseNodeAttributeAnnotations(element, annote, list);
-if (this.prepElement) {
-this.prepElement(element);
-}
-}
-if (annote.bindings.length || annote.events.length || annote.id) {
-list.push(annote);
-}
-return annote;
-},
-_parseChildNodesAnnotations: function (root, annote, list, stripWhiteSpace) {
-if (root.firstChild) {
-var node = root.firstChild;
-var i = 0;
-while (node) {
-var next = node.nextSibling;
-if (node.localName === 'template' && !node.hasAttribute('preserve-content')) {
-this._parseTemplate(node, i, list, annote);
-}
-if (node.nodeType === Node.TEXT_NODE) {
-var n = next;
-while (n && n.nodeType === Node.TEXT_NODE) {
-node.textContent += n.textContent;
-next = n.nextSibling;
-root.removeChild(n);
-n = next;
-}
-if (stripWhiteSpace && !node.textContent.trim()) {
-root.removeChild(node);
-i--;
-}
-}
-if (node.parentNode) {
-var childAnnotation = this._parseNodeAnnotations(node, list, stripWhiteSpace);
-if (childAnnotation) {
-childAnnotation.parent = annote;
-childAnnotation.index = i;
-}
-}
-node = next;
-i++;
-}
-}
-},
-_parseTemplate: function (node, index, list, parent) {
-var content = document.createDocumentFragment();
-content._notes = this.parseAnnotations(node);
-content.appendChild(node.content);
-list.push({
-bindings: Polymer.nar,
-events: Polymer.nar,
-templateContent: content,
-parent: parent,
-index: index
-});
-},
-_parseNodeAttributeAnnotations: function (node, annotation) {
-var attrs = Array.prototype.slice.call(node.attributes);
-for (var i = attrs.length - 1, a; a = attrs[i]; i--) {
-var n = a.name;
-var v = a.value;
-var b;
-if (n.slice(0, 3) === 'on-') {
-node.removeAttribute(n);
-annotation.events.push({
-name: n.slice(3),
-value: v
-});
-} else if (b = this._parseNodeAttributeAnnotation(node, n, v)) {
-annotation.bindings.push(b);
-} else if (n === 'id') {
-annotation.id = v;
-}
-}
-},
-_parseNodeAttributeAnnotation: function (node, name, value) {
-var parts = this._parseBindings(value);
-if (parts) {
-var origName = name;
-var kind = 'property';
-if (name[name.length - 1] == '$') {
-name = name.slice(0, -1);
-kind = 'attribute';
-}
-var literal = this._literalFromParts(parts);
-if (literal && kind == 'attribute') {
-node.setAttribute(name, literal);
-}
-if (node.localName == 'input' && name == 'value') {
-node.setAttribute(origName, '');
-}
-node.removeAttribute(origName);
-if (kind === 'property') {
-name = Polymer.CaseMap.dashToCamelCase(name);
-}
-return {
-kind: kind,
-name: name,
-parts: parts,
-literal: literal,
-isCompound: parts.length !== 1
-};
-}
-},
-_localSubTree: function (node, host) {
-return node === host ? node.childNodes : node._lightChildren || node.childNodes;
-},
-findAnnotatedNode: function (root, annote) {
-var parent = annote.parent && Polymer.Annotations.findAnnotatedNode(root, annote.parent);
-return !parent ? root : Polymer.Annotations._localSubTree(parent, root)[annote.index];
-}
-};
-(function () {
-function resolveCss(cssText, ownerDocument) {
-return cssText.replace(CSS_URL_RX, function (m, pre, url, post) {
-return pre + '\'' + resolve(url.replace(/["']/g, ''), ownerDocument) + '\'' + post;
-});
-}
-function resolveAttrs(element, ownerDocument) {
-for (var name in URL_ATTRS) {
-var a$ = URL_ATTRS[name];
-for (var i = 0, l = a$.length, a, at, v; i < l && (a = a$[i]); i++) {
-if (name === '*' || element.localName === name) {
-at = element.attributes[a];
-v = at && at.value;
-if (v && v.search(BINDING_RX) < 0) {
-at.value = a === 'style' ? resolveCss(v, ownerDocument) : resolve(v, ownerDocument);
-}
-}
-}
-}
-}
-function resolve(url, ownerDocument) {
-if (url && url[0] === '#') {
-return url;
-}
-var resolver = getUrlResolver(ownerDocument);
-resolver.href = url;
-return resolver.href || url;
-}
-var tempDoc;
-var tempDocBase;
-function resolveUrl(url, baseUri) {
-if (!tempDoc) {
-tempDoc = document.implementation.createHTMLDocument('temp');
-tempDocBase = tempDoc.createElement('base');
-tempDoc.head.appendChild(tempDocBase);
-}
-tempDocBase.href = baseUri;
-return resolve(url, tempDoc);
-}
-function getUrlResolver(ownerDocument) {
-return ownerDocument.__urlResolver || (ownerDocument.__urlResolver = ownerDocument.createElement('a'));
-}
-var CSS_URL_RX = /(url\()([^)]*)(\))/g;
-var URL_ATTRS = {
-'*': [
-'href',
-'src',
-'style',
-'url'
-],
-form: ['action']
-};
-var BINDING_RX = /\{\{|\[\[/;
-Polymer.ResolveUrl = {
-resolveCss: resolveCss,
-resolveAttrs: resolveAttrs,
-resolveUrl: resolveUrl
-};
-}());
-Polymer.Base._addFeature({
-_prepAnnotations: function () {
-if (!this._template) {
-this._notes = [];
-} else {
-var self = this;
-Polymer.Annotations.prepElement = function (element) {
-self._prepElement(element);
-};
-if (this._template._content && this._template._content._notes) {
-this._notes = this._template._content._notes;
-} else {
-this._notes = Polymer.Annotations.parseAnnotations(this._template);
-}
-this._processAnnotations(this._notes);
-Polymer.Annotations.prepElement = null;
-}
-},
-_processAnnotations: function (notes) {
-for (var i = 0; i < notes.length; i++) {
-var note = notes[i];
-for (var j = 0; j < note.bindings.length; j++) {
-var b = note.bindings[j];
-for (var k = 0; k < b.parts.length; k++) {
-var p = b.parts[k];
-if (!p.literal) {
-p.signature = this._parseMethod(p.value);
-if (!p.signature) {
-p.model = this._modelForPath(p.value);
-}
-}
-}
-}
-if (note.templateContent) {
-this._processAnnotations(note.templateContent._notes);
-var pp = note.templateContent._parentProps = this._discoverTemplateParentProps(note.templateContent._notes);
-var bindings = [];
-for (var prop in pp) {
-bindings.push({
-index: note.index,
-kind: 'property',
-name: '_parent_' + prop,
-parts: [{
-mode: '{',
-model: prop,
-value: prop
-}]
-});
-}
-note.bindings = note.bindings.concat(bindings);
-}
-}
-},
-_discoverTemplateParentProps: function (notes) {
-var pp = {};
-for (var i = 0, n; i < notes.length && (n = notes[i]); i++) {
-for (var j = 0, b$ = n.bindings, b; j < b$.length && (b = b$[j]); j++) {
-for (var k = 0, p$ = b.parts, p; k < p$.length && (p = p$[k]); k++) {
-if (p.signature) {
-var args = p.signature.args;
-for (var kk = 0; kk < args.length; kk++) {
-pp[args[kk].model] = true;
-}
-} else {
-pp[p.model] = true;
-}
-}
-}
-if (n.templateContent) {
-var tpp = n.templateContent._parentProps;
-Polymer.Base.mixin(pp, tpp);
-}
-}
-return pp;
-},
-_prepElement: function (element) {
-Polymer.ResolveUrl.resolveAttrs(element, this._template.ownerDocument);
-},
-_findAnnotatedNode: Polymer.Annotations.findAnnotatedNode,
-_marshalAnnotationReferences: function () {
-if (this._template) {
-this._marshalIdNodes();
-this._marshalAnnotatedNodes();
-this._marshalAnnotatedListeners();
-}
-},
-_configureAnnotationReferences: function (config) {
-var notes = this._notes;
-var nodes = this._nodes;
-for (var i = 0; i < notes.length; i++) {
-var note = notes[i];
-var node = nodes[i];
-this._configureTemplateContent(note, node);
-this._configureCompoundBindings(note, node);
-}
-},
-_configureTemplateContent: function (note, node) {
-if (note.templateContent) {
-node._content = note.templateContent;
-}
-},
-_configureCompoundBindings: function (note, node) {
-var bindings = note.bindings;
-for (var i = 0; i < bindings.length; i++) {
-var binding = bindings[i];
-if (binding.isCompound) {
-var storage = node.__compoundStorage__ || (node.__compoundStorage__ = {});
-var parts = binding.parts;
-var literals = new Array(parts.length);
-for (var j = 0; j < parts.length; j++) {
-literals[j] = parts[j].literal;
-}
-var name = binding.name;
-storage[name] = literals;
-if (binding.literal && binding.kind == 'property') {
-if (node._configValue) {
-node._configValue(name, binding.literal);
-} else {
-node[name] = binding.literal;
-}
-}
-}
-}
-},
-_marshalIdNodes: function () {
-this.$ = {};
-for (var i = 0, l = this._notes.length, a; i < l && (a = this._notes[i]); i++) {
-if (a.id) {
-this.$[a.id] = this._findAnnotatedNode(this.root, a);
-}
-}
-},
-_marshalAnnotatedNodes: function () {
-if (this._notes && this._notes.length) {
-var r = new Array(this._notes.length);
-for (var i = 0; i < this._notes.length; i++) {
-r[i] = this._findAnnotatedNode(this.root, this._notes[i]);
-}
-this._nodes = r;
-}
-},
-_marshalAnnotatedListeners: function () {
-for (var i = 0, l = this._notes.length, a; i < l && (a = this._notes[i]); i++) {
-if (a.events && a.events.length) {
-var node = this._findAnnotatedNode(this.root, a);
-for (var j = 0, e$ = a.events, e; j < e$.length && (e = e$[j]); j++) {
-this.listen(node, e.name, e.value);
-}
-}
-}
-}
-});
-Polymer.Base._addFeature({
-listeners: {},
-_listenListeners: function (listeners) {
-var node, name, eventName;
-for (eventName in listeners) {
-if (eventName.indexOf('.') < 0) {
-node = this;
-name = eventName;
-} else {
-name = eventName.split('.');
-node = this.$[name[0]];
-name = name[1];
-}
-this.listen(node, name, listeners[eventName]);
-}
-},
-listen: function (node, eventName, methodName) {
-var handler = this._recallEventHandler(this, eventName, node, methodName);
-if (!handler) {
-handler = this._createEventHandler(node, eventName, methodName);
-}
-if (handler._listening) {
-return;
-}
-this._listen(node, eventName, handler);
-handler._listening = true;
-},
-_boundListenerKey: function (eventName, methodName) {
-return eventName + ':' + methodName;
-},
-_recordEventHandler: function (host, eventName, target, methodName, handler) {
-var hbl = host.__boundListeners;
-if (!hbl) {
-hbl = host.__boundListeners = new WeakMap();
-}
-var bl = hbl.get(target);
-if (!bl) {
-bl = {};
-hbl.set(target, bl);
-}
-var key = this._boundListenerKey(eventName, methodName);
-bl[key] = handler;
-},
-_recallEventHandler: function (host, eventName, target, methodName) {
-var hbl = host.__boundListeners;
-if (!hbl) {
-return;
-}
-var bl = hbl.get(target);
-if (!bl) {
-return;
-}
-var key = this._boundListenerKey(eventName, methodName);
-return bl[key];
-},
-_createEventHandler: function (node, eventName, methodName) {
-var host = this;
-var handler = function (e) {
-if (host[methodName]) {
-host[methodName](e, e.detail);
-} else {
-host._warn(host._logf('_createEventHandler', 'listener method `' + methodName + '` not defined'));
-}
-};
-handler._listening = false;
-this._recordEventHandler(host, eventName, node, methodName, handler);
-return handler;
-},
-unlisten: function (node, eventName, methodName) {
-var handler = this._recallEventHandler(this, eventName, node, methodName);
-if (handler) {
-this._unlisten(node, eventName, handler);
-handler._listening = false;
-}
-},
-_listen: function (node, eventName, handler) {
-node.addEventListener(eventName, handler);
-},
-_unlisten: function (node, eventName, handler) {
-node.removeEventListener(eventName, handler);
-}
-});
-(function () {
-'use strict';
-var wrap = Polymer.DomApi.wrap;
-var HAS_NATIVE_TA = typeof document.head.style.touchAction === 'string';
-var GESTURE_KEY = '__polymerGestures';
-var HANDLED_OBJ = '__polymerGesturesHandled';
-var TOUCH_ACTION = '__polymerGesturesTouchAction';
-var TAP_DISTANCE = 25;
-var TRACK_DISTANCE = 5;
-var TRACK_LENGTH = 2;
-var MOUSE_TIMEOUT = 2500;
-var MOUSE_EVENTS = [
-'mousedown',
-'mousemove',
-'mouseup',
-'click'
-];
-var MOUSE_WHICH_TO_BUTTONS = [
-0,
-1,
-4,
-2
-];
-var MOUSE_HAS_BUTTONS = function () {
-try {
-return new MouseEvent('test', { buttons: 1 }).buttons === 1;
-} catch (e) {
-return false;
-}
-}();
-var IS_TOUCH_ONLY = navigator.userAgent.match(/iP(?:[oa]d|hone)|Android/);
-var mouseCanceller = function (mouseEvent) {
-mouseEvent[HANDLED_OBJ] = { skip: true };
-if (mouseEvent.type === 'click') {
-var path = Polymer.dom(mouseEvent).path;
-for (var i = 0; i < path.length; i++) {
-if (path[i] === POINTERSTATE.mouse.target) {
-return;
-}
-}
-mouseEvent.preventDefault();
-mouseEvent.stopPropagation();
-}
-};
-function setupTeardownMouseCanceller(setup) {
-for (var i = 0, en; i < MOUSE_EVENTS.length; i++) {
-en = MOUSE_EVENTS[i];
-if (setup) {
-document.addEventListener(en, mouseCanceller, true);
-} else {
-document.removeEventListener(en, mouseCanceller, true);
-}
-}
-}
-function ignoreMouse() {
-if (IS_TOUCH_ONLY) {
-return;
-}
-if (!POINTERSTATE.mouse.mouseIgnoreJob) {
-setupTeardownMouseCanceller(true);
-}
-var unset = function () {
-setupTeardownMouseCanceller();
-POINTERSTATE.mouse.target = null;
-POINTERSTATE.mouse.mouseIgnoreJob = null;
-};
-POINTERSTATE.mouse.mouseIgnoreJob = Polymer.Debounce(POINTERSTATE.mouse.mouseIgnoreJob, unset, MOUSE_TIMEOUT);
-}
-function hasLeftMouseButton(ev) {
-var type = ev.type;
-if (MOUSE_EVENTS.indexOf(type) === -1) {
-return false;
-}
-if (type === 'mousemove') {
-var buttons = ev.buttons === undefined ? 1 : ev.buttons;
-if (ev instanceof window.MouseEvent && !MOUSE_HAS_BUTTONS) {
-buttons = MOUSE_WHICH_TO_BUTTONS[ev.which] || 0;
-}
-return Boolean(buttons & 1);
-} else {
-var button = ev.button === undefined ? 0 : ev.button;
-return button === 0;
-}
-}
-function isSyntheticClick(ev) {
-if (ev.type === 'click') {
-if (ev.detail === 0) {
-return true;
-}
-var t = Gestures.findOriginalTarget(ev);
-var bcr = t.getBoundingClientRect();
-var x = ev.pageX, y = ev.pageY;
-return !(x >= bcr.left && x <= bcr.right && (y >= bcr.top && y <= bcr.bottom));
-}
-return false;
-}
-var POINTERSTATE = {
-mouse: {
-target: null,
-mouseIgnoreJob: null
-},
-touch: {
-x: 0,
-y: 0,
-id: -1,
-scrollDecided: false
-}
-};
-function firstTouchAction(ev) {
-var path = Polymer.dom(ev).path;
-var ta = 'auto';
-for (var i = 0, n; i < path.length; i++) {
-n = path[i];
-if (n[TOUCH_ACTION]) {
-ta = n[TOUCH_ACTION];
-break;
-}
-}
-return ta;
-}
-function trackDocument(stateObj, movefn, upfn) {
-stateObj.movefn = movefn;
-stateObj.upfn = upfn;
-document.addEventListener('mousemove', movefn);
-document.addEventListener('mouseup', upfn);
-}
-function untrackDocument(stateObj) {
-document.removeEventListener('mousemove', stateObj.movefn);
-document.removeEventListener('mouseup', stateObj.upfn);
-}
-var Gestures = {
-gestures: {},
-recognizers: [],
-deepTargetFind: function (x, y) {
-var node = document.elementFromPoint(x, y);
-var next = node;
-while (next && next.shadowRoot) {
-next = next.shadowRoot.elementFromPoint(x, y);
-if (next) {
-node = next;
-}
-}
-return node;
-},
-findOriginalTarget: function (ev) {
-if (ev.path) {
-return ev.path[0];
-}
-return ev.target;
-},
-handleNative: function (ev) {
-var handled;
-var type = ev.type;
-var node = wrap(ev.currentTarget);
-var gobj = node[GESTURE_KEY];
-if (!gobj) {
-return;
-}
-var gs = gobj[type];
-if (!gs) {
-return;
-}
-if (!ev[HANDLED_OBJ]) {
-ev[HANDLED_OBJ] = {};
-if (type.slice(0, 5) === 'touch') {
-var t = ev.changedTouches[0];
-if (type === 'touchstart') {
-if (ev.touches.length === 1) {
-POINTERSTATE.touch.id = t.identifier;
-}
-}
-if (POINTERSTATE.touch.id !== t.identifier) {
-return;
-}
-if (!HAS_NATIVE_TA) {
-if (type === 'touchstart' || type === 'touchmove') {
-Gestures.handleTouchAction(ev);
-}
-}
-if (type === 'touchend') {
-POINTERSTATE.mouse.target = Polymer.dom(ev).rootTarget;
-ignoreMouse(true);
-}
-}
-}
-handled = ev[HANDLED_OBJ];
-if (handled.skip) {
-return;
-}
-var recognizers = Gestures.recognizers;
-for (var i = 0, r; i < recognizers.length; i++) {
-r = recognizers[i];
-if (gs[r.name] && !handled[r.name]) {
-if (r.flow && r.flow.start.indexOf(ev.type) > -1) {
-if (r.reset) {
-r.reset();
-}
-}
-}
-}
-for (var i = 0, r; i < recognizers.length; i++) {
-r = recognizers[i];
-if (gs[r.name] && !handled[r.name]) {
-handled[r.name] = true;
-r[type](ev);
-}
-}
-},
-handleTouchAction: function (ev) {
-var t = ev.changedTouches[0];
-var type = ev.type;
-if (type === 'touchstart') {
-POINTERSTATE.touch.x = t.clientX;
-POINTERSTATE.touch.y = t.clientY;
-POINTERSTATE.touch.scrollDecided = false;
-} else if (type === 'touchmove') {
-if (POINTERSTATE.touch.scrollDecided) {
-return;
-}
-POINTERSTATE.touch.scrollDecided = true;
-var ta = firstTouchAction(ev);
-var prevent = false;
-var dx = Math.abs(POINTERSTATE.touch.x - t.clientX);
-var dy = Math.abs(POINTERSTATE.touch.y - t.clientY);
-if (!ev.cancelable) {
-} else if (ta === 'none') {
-prevent = true;
-} else if (ta === 'pan-x') {
-prevent = dy > dx;
-} else if (ta === 'pan-y') {
-prevent = dx > dy;
-}
-if (prevent) {
-ev.preventDefault();
-} else {
-Gestures.prevent('track');
-}
-}
-},
-add: function (node, evType, handler) {
-node = wrap(node);
-var recognizer = this.gestures[evType];
-var deps = recognizer.deps;
-var name = recognizer.name;
-var gobj = node[GESTURE_KEY];
-if (!gobj) {
-node[GESTURE_KEY] = gobj = {};
-}
-for (var i = 0, dep, gd; i < deps.length; i++) {
-dep = deps[i];
-if (IS_TOUCH_ONLY && MOUSE_EVENTS.indexOf(dep) > -1) {
-continue;
-}
-gd = gobj[dep];
-if (!gd) {
-gobj[dep] = gd = { _count: 0 };
-}
-if (gd._count === 0) {
-node.addEventListener(dep, this.handleNative);
-}
-gd[name] = (gd[name] || 0) + 1;
-gd._count = (gd._count || 0) + 1;
-}
-node.addEventListener(evType, handler);
-if (recognizer.touchAction) {
-this.setTouchAction(node, recognizer.touchAction);
-}
-},
-remove: function (node, evType, handler) {
-node = wrap(node);
-var recognizer = this.gestures[evType];
-var deps = recognizer.deps;
-var name = recognizer.name;
-var gobj = node[GESTURE_KEY];
-if (gobj) {
-for (var i = 0, dep, gd; i < deps.length; i++) {
-dep = deps[i];
-gd = gobj[dep];
-if (gd && gd[name]) {
-gd[name] = (gd[name] || 1) - 1;
-gd._count = (gd._count || 1) - 1;
-if (gd._count === 0) {
-node.removeEventListener(dep, this.handleNative);
-}
-}
-}
-}
-node.removeEventListener(evType, handler);
-},
-register: function (recog) {
-this.recognizers.push(recog);
-for (var i = 0; i < recog.emits.length; i++) {
-this.gestures[recog.emits[i]] = recog;
-}
-},
-findRecognizerByEvent: function (evName) {
-for (var i = 0, r; i < this.recognizers.length; i++) {
-r = this.recognizers[i];
-for (var j = 0, n; j < r.emits.length; j++) {
-n = r.emits[j];
-if (n === evName) {
-return r;
-}
-}
-}
-return null;
-},
-setTouchAction: function (node, value) {
-if (HAS_NATIVE_TA) {
-node.style.touchAction = value;
-}
-node[TOUCH_ACTION] = value;
-},
-fire: function (target, type, detail) {
-var ev = Polymer.Base.fire(type, detail, {
-node: target,
-bubbles: true,
-cancelable: true
-});
-if (ev.defaultPrevented) {
-var se = detail.sourceEvent;
-if (se && se.preventDefault) {
-se.preventDefault();
-}
-}
-},
-prevent: function (evName) {
-var recognizer = this.findRecognizerByEvent(evName);
-if (recognizer.info) {
-recognizer.info.prevent = true;
-}
-}
-};
-Gestures.register({
-name: 'downup',
-deps: [
-'mousedown',
-'touchstart',
-'touchend'
-],
-flow: {
-start: [
-'mousedown',
-'touchstart'
-],
-end: [
-'mouseup',
-'touchend'
-]
-},
-emits: [
-'down',
-'up'
-],
-info: {
-movefn: function () {
-},
-upfn: function () {
-}
-},
-reset: function () {
-untrackDocument(this.info);
-},
-mousedown: function (e) {
-if (!hasLeftMouseButton(e)) {
-return;
-}
-var t = Gestures.findOriginalTarget(e);
-var self = this;
-var movefn = function movefn(e) {
-if (!hasLeftMouseButton(e)) {
-self.fire('up', t, e);
-untrackDocument(self.info);
-}
-};
-var upfn = function upfn(e) {
-if (hasLeftMouseButton(e)) {
-self.fire('up', t, e);
-}
-untrackDocument(self.info);
-};
-trackDocument(this.info, movefn, upfn);
-this.fire('down', t, e);
-},
-touchstart: function (e) {
-this.fire('down', Gestures.findOriginalTarget(e), e.changedTouches[0]);
-},
-touchend: function (e) {
-this.fire('up', Gestures.findOriginalTarget(e), e.changedTouches[0]);
-},
-fire: function (type, target, event) {
-var self = this;
-Gestures.fire(target, type, {
-x: event.clientX,
-y: event.clientY,
-sourceEvent: event,
-prevent: function (e) {
-return Gestures.prevent(e);
-}
-});
-}
-});
-Gestures.register({
-name: 'track',
-touchAction: 'none',
-deps: [
-'mousedown',
-'touchstart',
-'touchmove',
-'touchend'
-],
-flow: {
-start: [
-'mousedown',
-'touchstart'
-],
-end: [
-'mouseup',
-'touchend'
-]
-},
-emits: ['track'],
-info: {
-x: 0,
-y: 0,
-state: 'start',
-started: false,
-moves: [],
-addMove: function (move) {
-if (this.moves.length > TRACK_LENGTH) {
-this.moves.shift();
-}
-this.moves.push(move);
-},
-movefn: function () {
-},
-upfn: function () {
-},
-prevent: false
-},
-reset: function () {
-this.info.state = 'start';
-this.info.started = false;
-this.info.moves = [];
-this.info.x = 0;
-this.info.y = 0;
-this.info.prevent = false;
-untrackDocument(this.info);
-},
-hasMovedEnough: function (x, y) {
-if (this.info.prevent) {
-return false;
-}
-if (this.info.started) {
-return true;
-}
-var dx = Math.abs(this.info.x - x);
-var dy = Math.abs(this.info.y - y);
-return dx >= TRACK_DISTANCE || dy >= TRACK_DISTANCE;
-},
-mousedown: function (e) {
-if (!hasLeftMouseButton(e)) {
-return;
-}
-var t = Gestures.findOriginalTarget(e);
-var self = this;
-var movefn = function movefn(e) {
-var x = e.clientX, y = e.clientY;
-if (self.hasMovedEnough(x, y)) {
-self.info.state = self.info.started ? e.type === 'mouseup' ? 'end' : 'track' : 'start';
-self.info.addMove({
-x: x,
-y: y
-});
-if (!hasLeftMouseButton(e)) {
-self.info.state = 'end';
-untrackDocument(self.info);
-}
-self.fire(t, e);
-self.info.started = true;
-}
+function quoteString(str) {
+ return str.replace(/([\\\.\+\*\?\[\^\]\$\(\)\{\}\=\!\<\>\|\:])/g, '\\$1');
};
-var upfn = function upfn(e) {
-if (self.info.started) {
-Gestures.prevent('tap');
-movefn(e);
-}
-untrackDocument(self.info);
-};
-trackDocument(this.info, movefn, upfn);
-this.info.x = e.clientX;
-this.info.y = e.clientY;
-},
-touchstart: function (e) {
-var ct = e.changedTouches[0];
-this.info.x = ct.clientX;
-this.info.y = ct.clientY;
-},
-touchmove: function (e) {
-var t = Gestures.findOriginalTarget(e);
-var ct = e.changedTouches[0];
-var x = ct.clientX, y = ct.clientY;
-if (this.hasMovedEnough(x, y)) {
-this.info.addMove({
-x: x,
-y: y
-});
-this.fire(t, ct);
-this.info.state = 'track';
-this.info.started = true;
-}
-},
-touchend: function (e) {
-var t = Gestures.findOriginalTarget(e);
-var ct = e.changedTouches[0];
-if (this.info.started) {
-Gestures.prevent('tap');
-this.info.state = 'end';
-this.info.addMove({
-x: ct.clientX,
-y: ct.clientY
-});
-this.fire(t, ct);
-}
-},
-fire: function (target, touch) {
-var secondlast = this.info.moves[this.info.moves.length - 2];
-var lastmove = this.info.moves[this.info.moves.length - 1];
-var dx = lastmove.x - this.info.x;
-var dy = lastmove.y - this.info.y;
-var ddx, ddy = 0;
-if (secondlast) {
-ddx = lastmove.x - secondlast.x;
-ddy = lastmove.y - secondlast.y;
-}
-return Gestures.fire(target, 'track', {
-state: this.info.state,
-x: touch.clientX,
-y: touch.clientY,
-dx: dx,
-dy: dy,
-ddx: ddx,
-ddy: ddy,
-sourceEvent: touch,
-hover: function () {
-return Gestures.deepTargetFind(touch.clientX, touch.clientY);
-}
-});
-}
-});
-Gestures.register({
-name: 'tap',
-deps: [
-'mousedown',
-'click',
-'touchstart',
-'touchend'
-],
-flow: {
-start: [
-'mousedown',
-'touchstart'
-],
-end: [
-'click',
-'touchend'
-]
-},
-emits: ['tap'],
-info: {
-x: NaN,
-y: NaN,
-prevent: false
-},
-reset: function () {
-this.info.x = NaN;
-this.info.y = NaN;
-this.info.prevent = false;
-},
-save: function (e) {
-this.info.x = e.clientX;
-this.info.y = e.clientY;
-},
-mousedown: function (e) {
-if (hasLeftMouseButton(e)) {
-this.save(e);
-}
-},
-click: function (e) {
-if (hasLeftMouseButton(e)) {
-this.forward(e);
-}
-},
-touchstart: function (e) {
-this.save(e.changedTouches[0]);
-},
-touchend: function (e) {
-this.forward(e.changedTouches[0]);
-},
-forward: function (e) {
-var dx = Math.abs(e.clientX - this.info.x);
-var dy = Math.abs(e.clientY - this.info.y);
-var t = Gestures.findOriginalTarget(e);
-if (isNaN(dx) || isNaN(dy) || dx <= TAP_DISTANCE && dy <= TAP_DISTANCE || isSyntheticClick(e)) {
-if (!this.info.prevent) {
-Gestures.fire(t, 'tap', {
-x: e.clientX,
-y: e.clientY,
-sourceEvent: e
-});
-}
-}
-}
-});
-var DIRECTION_MAP = {
-x: 'pan-x',
-y: 'pan-y',
-none: 'none',
-all: 'auto'
-};
-Polymer.Base._addFeature({
-_listen: function (node, eventName, handler) {
-if (Gestures.gestures[eventName]) {
-Gestures.add(node, eventName, handler);
-} else {
-node.addEventListener(eventName, handler);
-}
-},
-_unlisten: function (node, eventName, handler) {
-if (Gestures.gestures[eventName]) {
-Gestures.remove(node, eventName, handler);
-} else {
-node.removeEventListener(eventName, handler);
-}
-},
-setScrollDirection: function (direction, node) {
-node = node || this;
-Gestures.setTouchAction(node, DIRECTION_MAP[direction] || 'auto');
-}
-});
-Polymer.Gestures = Gestures;
-}());
-Polymer.Async = {
-_currVal: 0,
-_lastVal: 0,
-_callbacks: [],
-_twiddleContent: 0,
-_twiddle: document.createTextNode(''),
-run: function (callback, waitTime) {
-if (waitTime > 0) {
-return ~setTimeout(callback, waitTime);
-} else {
-this._twiddle.textContent = this._twiddleContent++;
-this._callbacks.push(callback);
-return this._currVal++;
-}
-},
-cancel: function (handle) {
-if (handle < 0) {
-clearTimeout(~handle);
-} else {
-var idx = handle - this._lastVal;
-if (idx >= 0) {
-if (!this._callbacks[idx]) {
-throw 'invalid async handle: ' + handle;
-}
-this._callbacks[idx] = null;
-}
-}
-},
-_atEndOfMicrotask: function () {
-var len = this._callbacks.length;
-for (var i = 0; i < len; i++) {
-var cb = this._callbacks[i];
-if (cb) {
-try {
-cb();
-} catch (e) {
-i++;
-this._callbacks.splice(0, i);
-this._lastVal += i;
-this._twiddle.textContent = this._twiddleContent++;
-throw e;
-}
-}
-}
-this._callbacks.splice(0, len);
-this._lastVal += len;
-}
-};
-new window.MutationObserver(function () {
-Polymer.Async._atEndOfMicrotask();
-}).observe(Polymer.Async._twiddle, { characterData: true });
-Polymer.Debounce = function () {
-var Async = Polymer.Async;
-var Debouncer = function (context) {
-this.context = context;
-var self = this;
-this.boundComplete = function () {
-self.complete();
-};
-};
-Debouncer.prototype = {
-go: function (callback, wait) {
-var h;
-this.finish = function () {
-Async.cancel(h);
-};
-h = Async.run(this.boundComplete, wait);
-this.callback = callback;
-},
-stop: function () {
-if (this.finish) {
-this.finish();
-this.finish = null;
-}
-},
-complete: function () {
-if (this.finish) {
-this.stop();
-this.callback.call(this.context);
-}
-}
-};
-function debounce(debouncer, callback, wait) {
-if (debouncer) {
-debouncer.stop();
-} else {
-debouncer = new Debouncer(this);
-}
-debouncer.go(callback, wait);
-return debouncer;
-}
-return debounce;
-}();
-Polymer.Base._addFeature({
-$$: function (slctr) {
-return Polymer.dom(this.root).querySelector(slctr);
-},
-toggleClass: function (name, bool, node) {
-node = node || this;
-if (arguments.length == 1) {
-bool = !node.classList.contains(name);
-}
-if (bool) {
-Polymer.dom(node).classList.add(name);
-} else {
-Polymer.dom(node).classList.remove(name);
-}
-},
-toggleAttribute: function (name, bool, node) {
-node = node || this;
-if (arguments.length == 1) {
-bool = !node.hasAttribute(name);
-}
-if (bool) {
-Polymer.dom(node).setAttribute(name, '');
-} else {
-Polymer.dom(node).removeAttribute(name);
-}
-},
-classFollows: function (name, toElement, fromElement) {
-if (fromElement) {
-Polymer.dom(fromElement).classList.remove(name);
-}
-if (toElement) {
-Polymer.dom(toElement).classList.add(name);
-}
-},
-attributeFollows: function (name, toElement, fromElement) {
-if (fromElement) {
-Polymer.dom(fromElement).removeAttribute(name);
-}
-if (toElement) {
-Polymer.dom(toElement).setAttribute(name, '');
-}
-},
-getEffectiveChildNodes: function () {
-return Polymer.dom(this).getEffectiveChildNodes();
-},
-getEffectiveChildren: function () {
-var list = Polymer.dom(this).getEffectiveChildNodes();
-return list.filter(function (n) {
-return n.nodeType === Node.ELEMENT_NODE;
-});
-},
-getEffectiveTextContent: function () {
-var cn = this.getEffectiveChildNodes();
-var tc = [];
-for (var i = 0, c; c = cn[i]; i++) {
-if (c.nodeType !== Node.COMMENT_NODE) {
-tc.push(Polymer.dom(c).textContent);
-}
-}
-return tc.join('');
-},
-queryEffectiveChildren: function (slctr) {
-var e$ = Polymer.dom(this).queryDistributedElements(slctr);
-return e$ && e$[0];
-},
-queryAllEffectiveChildren: function (slctr) {
-return Polymer.dom(this).queryDistributedElements(slctr);
-},
-getContentChildNodes: function (slctr) {
-var content = Polymer.dom(this.root).querySelector(slctr || 'content');
-return content ? Polymer.dom(content).getDistributedNodes() : [];
-},
-getContentChildren: function (slctr) {
-return this.getContentChildNodes(slctr).filter(function (n) {
-return n.nodeType === Node.ELEMENT_NODE;
-});
-},
-fire: function (type, detail, options) {
-options = options || Polymer.nob;
-var node = options.node || this;
-var detail = detail === null || detail === undefined ? {} : detail;
-var bubbles = options.bubbles === undefined ? true : options.bubbles;
-var cancelable = Boolean(options.cancelable);
-var useCache = options._useCache;
-var event = this._getEvent(type, bubbles, cancelable, useCache);
-event.detail = detail;
-if (useCache) {
-this.__eventCache[type] = null;
-}
-node.dispatchEvent(event);
-if (useCache) {
-this.__eventCache[type] = event;
-}
-return event;
-},
-__eventCache: {},
-_getEvent: function (type, bubbles, cancelable, useCache) {
-var event = useCache && this.__eventCache[type];
-if (!event || (event.bubbles != bubbles || event.cancelable != cancelable)) {
-event = new Event(type, {
-bubbles: Boolean(bubbles),
-cancelable: cancelable
-});
-}
-return event;
-},
-async: function (callback, waitTime) {
-var self = this;
-return Polymer.Async.run(function () {
-callback.call(self);
-}, waitTime);
-},
-cancelAsync: function (handle) {
-Polymer.Async.cancel(handle);
-},
-arrayDelete: function (path, item) {
-var index;
-if (Array.isArray(path)) {
-index = path.indexOf(item);
-if (index >= 0) {
-return path.splice(index, 1);
-}
-} else {
-var arr = this._get(path);
-index = arr.indexOf(item);
-if (index >= 0) {
-return this.splice(path, index, 1);
-}
-}
-},
-transform: function (transform, node) {
-node = node || this;
-node.style.webkitTransform = transform;
-node.style.transform = transform;
-},
-translate3d: function (x, y, z, node) {
-node = node || this;
-this.transform('translate3d(' + x + ',' + y + ',' + z + ')', node);
-},
-importHref: function (href, onload, onerror) {
-var l = document.createElement('link');
-l.rel = 'import';
-l.href = href;
-var self = this;
-if (onload) {
-l.onload = function (e) {
-return onload.call(self, e);
-};
-}
-if (onerror) {
-l.onerror = function (e) {
-return onerror.call(self, e);
-};
-}
-document.head.appendChild(l);
-return l;
-},
-create: function (tag, props) {
-var elt = document.createElement(tag);
-if (props) {
-for (var n in props) {
-elt[n] = props[n];
-}
-}
-return elt;
-},
-isLightDescendant: function (node) {
-return this !== node && this.contains(node) && Polymer.dom(this).getOwnerRoot() === Polymer.dom(node).getOwnerRoot();
-},
-isLocalDescendant: function (node) {
-return this.root === Polymer.dom(node).getOwnerRoot();
-}
-});
-Polymer.Bind = {
-_dataEventCache: {},
-prepareModel: function (model) {
-Polymer.Base.mixin(model, this._modelApi);
-},
-_modelApi: {
-_notifyChange: function (source, event, value) {
-value = value === undefined ? this[source] : value;
-event = event || Polymer.CaseMap.camelToDashCase(source) + '-changed';
-this.fire(event, { value: value }, {
-bubbles: false,
-cancelable: false,
-_useCache: true
-});
-},
-_propertySetter: function (property, value, effects, fromAbove) {
-var old = this.__data__[property];
-if (old !== value && (old === old || value === value)) {
-this.__data__[property] = value;
-if (typeof value == 'object') {
-this._clearPath(property);
-}
-if (this._propertyChanged) {
-this._propertyChanged(property, value, old);
-}
-if (effects) {
-this._effectEffects(property, value, effects, old, fromAbove);
-}
-}
-return old;
-},
-__setProperty: function (property, value, quiet, node) {
-node = node || this;
-var effects = node._propertyEffects && node._propertyEffects[property];
-if (effects) {
-node._propertySetter(property, value, effects, quiet);
-} else {
-node[property] = value;
-}
-},
-_effectEffects: function (property, value, effects, old, fromAbove) {
-for (var i = 0, l = effects.length, fx; i < l && (fx = effects[i]); i++) {
-fx.fn.call(this, property, value, fx.effect, old, fromAbove);
-}
-},
-_clearPath: function (path) {
-for (var prop in this.__data__) {
-if (prop.indexOf(path + '.') === 0) {
-this.__data__[prop] = undefined;
-}
-}
-}
-},
-ensurePropertyEffects: function (model, property) {
-if (!model._propertyEffects) {
-model._propertyEffects = {};
-}
-var fx = model._propertyEffects[property];
-if (!fx) {
-fx = model._propertyEffects[property] = [];
-}
-return fx;
-},
-addPropertyEffect: function (model, property, kind, effect) {
-var fx = this.ensurePropertyEffects(model, property);
-var propEffect = {
-kind: kind,
-effect: effect,
-fn: Polymer.Bind['_' + kind + 'Effect']
-};
-fx.push(propEffect);
-return propEffect;
-},
-createBindings: function (model) {
-var fx$ = model._propertyEffects;
-if (fx$) {
-for (var n in fx$) {
-var fx = fx$[n];
-fx.sort(this._sortPropertyEffects);
-this._createAccessors(model, n, fx);
-}
-}
-},
-_sortPropertyEffects: function () {
-var EFFECT_ORDER = {
-'compute': 0,
-'annotation': 1,
-'computedAnnotation': 2,
-'reflect': 3,
-'notify': 4,
-'observer': 5,
-'complexObserver': 6,
-'function': 7
-};
-return function (a, b) {
-return EFFECT_ORDER[a.kind] - EFFECT_ORDER[b.kind];
-};
-}(),
-_createAccessors: function (model, property, effects) {
-var defun = {
-get: function () {
-return this.__data__[property];
-}
-};
-var setter = function (value) {
-this._propertySetter(property, value, effects);
-};
-var info = model.getPropertyInfo && model.getPropertyInfo(property);
-if (info && info.readOnly) {
-if (!info.computed) {
-model['_set' + this.upper(property)] = setter;
-}
-} else {
-defun.set = setter;
-}
-Object.defineProperty(model, property, defun);
-},
-upper: function (name) {
-return name[0].toUpperCase() + name.substring(1);
-},
-_addAnnotatedListener: function (model, index, property, path, event) {
-if (!model._bindListeners) {
-model._bindListeners = [];
-}
-var fn = this._notedListenerFactory(property, path, this._isStructured(path));
-var eventName = event || Polymer.CaseMap.camelToDashCase(property) + '-changed';
-model._bindListeners.push({
-index: index,
-property: property,
-path: path,
-changedFn: fn,
-event: eventName
-});
-},
-_isStructured: function (path) {
-return path.indexOf('.') > 0;
-},
-_isEventBogus: function (e, target) {
-return e.path && e.path[0] !== target;
-},
-_notedListenerFactory: function (property, path, isStructured) {
-return function (target, value, targetPath) {
-if (targetPath) {
-this._notifyPath(this._fixPath(path, property, targetPath), value);
-} else {
-value = target[property];
-if (!isStructured) {
-this[path] = value;
-} else {
-if (this.__data__[path] != value) {
-this.set(path, value);
-}
-}
-}
-};
-},
-prepareInstance: function (inst) {
-inst.__data__ = Object.create(null);
-},
-setupBindListeners: function (inst) {
-var b$ = inst._bindListeners;
-for (var i = 0, l = b$.length, info; i < l && (info = b$[i]); i++) {
-var node = inst._nodes[info.index];
-this._addNotifyListener(node, inst, info.event, info.changedFn);
-}
-;
-},
-_addNotifyListener: function (element, context, event, changedFn) {
-element.addEventListener(event, function (e) {
-return context._notifyListener(changedFn, e);
-});
-}
-};
-Polymer.Base.extend(Polymer.Bind, {
-_shouldAddListener: function (effect) {
-return effect.name && effect.kind != 'attribute' && effect.kind != 'text' && !effect.isCompound && effect.parts[0].mode === '{' && !effect.parts[0].negate;
-},
-_annotationEffect: function (source, value, effect) {
-if (source != effect.value) {
-value = this._get(effect.value);
-this.__data__[effect.value] = value;
-}
-var calc = effect.negate ? !value : value;
-if (!effect.customEvent || this._nodes[effect.index][effect.name] !== calc) {
-return this._applyEffectValue(effect, calc);
-}
-},
-_reflectEffect: function (source, value, effect) {
-this.reflectPropertyToAttribute(source, effect.attribute, value);
-},
-_notifyEffect: function (source, value, effect, old, fromAbove) {
-if (!fromAbove) {
-this._notifyChange(source, effect.event, value);
-}
-},
-_functionEffect: function (source, value, fn, old, fromAbove) {
-fn.call(this, source, value, old, fromAbove);
-},
-_observerEffect: function (source, value, effect, old) {
-var fn = this[effect.method];
-if (fn) {
-fn.call(this, value, old);
-} else {
-this._warn(this._logf('_observerEffect', 'observer method `' + effect.method + '` not defined'));
-}
-},
-_complexObserverEffect: function (source, value, effect) {
-var fn = this[effect.method];
-if (fn) {
-var args = Polymer.Bind._marshalArgs(this.__data__, effect, source, value);
-if (args) {
-fn.apply(this, args);
-}
-} else {
-this._warn(this._logf('_complexObserverEffect', 'observer method `' + effect.method + '` not defined'));
-}
-},
-_computeEffect: function (source, value, effect) {
-var args = Polymer.Bind._marshalArgs(this.__data__, effect, source, value);
-if (args) {
-var fn = this[effect.method];
-if (fn) {
-this.__setProperty(effect.name, fn.apply(this, args));
-} else {
-this._warn(this._logf('_computeEffect', 'compute method `' + effect.method + '` not defined'));
-}
-}
-},
-_annotatedComputationEffect: function (source, value, effect) {
-var computedHost = this._rootDataHost || this;
-var fn = computedHost[effect.method];
-if (fn) {
-var args = Polymer.Bind._marshalArgs(this.__data__, effect, source, value);
-if (args) {
-var computedvalue = fn.apply(computedHost, args);
-if (effect.negate) {
-computedvalue = !computedvalue;
-}
-this._applyEffectValue(effect, computedvalue);
-}
-} else {
-computedHost._warn(computedHost._logf('_annotatedComputationEffect', 'compute method `' + effect.method + '` not defined'));
-}
-},
-_marshalArgs: function (model, effect, path, value) {
-var values = [];
-var args = effect.args;
-for (var i = 0, l = args.length; i < l; i++) {
-var arg = args[i];
-var name = arg.name;
-var v;
-if (arg.literal) {
-v = arg.value;
-} else if (arg.structured) {
-v = Polymer.Base._get(name, model);
-} else {
-v = model[name];
-}
-if (args.length > 1 && v === undefined) {
-return;
-}
-if (arg.wildcard) {
-var baseChanged = name.indexOf(path + '.') === 0;
-var matches = effect.trigger.name.indexOf(name) === 0 && !baseChanged;
-values[i] = {
-path: matches ? path : name,
-value: matches ? value : v,
-base: v
-};
-} else {
-values[i] = v;
-}
-}
-return values;
-}
-});
-Polymer.Base._addFeature({
-_addPropertyEffect: function (property, kind, effect) {
-var prop = Polymer.Bind.addPropertyEffect(this, property, kind, effect);
-prop.pathFn = this['_' + prop.kind + 'PathEffect'];
-},
-_prepEffects: function () {
-Polymer.Bind.prepareModel(this);
-this._addAnnotationEffects(this._notes);
-},
-_prepBindings: function () {
-Polymer.Bind.createBindings(this);
-},
-_addPropertyEffects: function (properties) {
-if (properties) {
-for (var p in properties) {
-var prop = properties[p];
-if (prop.observer) {
-this._addObserverEffect(p, prop.observer);
-}
-if (prop.computed) {
-prop.readOnly = true;
-this._addComputedEffect(p, prop.computed);
-}
-if (prop.notify) {
-this._addPropertyEffect(p, 'notify', { event: Polymer.CaseMap.camelToDashCase(p) + '-changed' });
-}
-if (prop.reflectToAttribute) {
-this._addPropertyEffect(p, 'reflect', { attribute: Polymer.CaseMap.camelToDashCase(p) });
-}
-if (prop.readOnly) {
-Polymer.Bind.ensurePropertyEffects(this, p);
-}
-}
-}
-},
-_addComputedEffect: function (name, expression) {
-var sig = this._parseMethod(expression);
-for (var i = 0, arg; i < sig.args.length && (arg = sig.args[i]); i++) {
-this._addPropertyEffect(arg.model, 'compute', {
-method: sig.method,
-args: sig.args,
-trigger: arg,
-name: name
-});
-}
-},
-_addObserverEffect: function (property, observer) {
-this._addPropertyEffect(property, 'observer', {
-method: observer,
-property: property
-});
-},
-_addComplexObserverEffects: function (observers) {
-if (observers) {
-for (var i = 0, o; i < observers.length && (o = observers[i]); i++) {
-this._addComplexObserverEffect(o);
-}
-}
-},
-_addComplexObserverEffect: function (observer) {
-var sig = this._parseMethod(observer);
-for (var i = 0, arg; i < sig.args.length && (arg = sig.args[i]); i++) {
-this._addPropertyEffect(arg.model, 'complexObserver', {
-method: sig.method,
-args: sig.args,
-trigger: arg
-});
-}
-},
-_addAnnotationEffects: function (notes) {
-for (var i = 0, note; i < notes.length && (note = notes[i]); i++) {
-var b$ = note.bindings;
-for (var j = 0, binding; j < b$.length && (binding = b$[j]); j++) {
-this._addAnnotationEffect(binding, i);
-}
-}
-},
-_addAnnotationEffect: function (note, index) {
-if (Polymer.Bind._shouldAddListener(note)) {
-Polymer.Bind._addAnnotatedListener(this, index, note.name, note.parts[0].value, note.parts[0].event);
-}
-for (var i = 0; i < note.parts.length; i++) {
-var part = note.parts[i];
-if (part.signature) {
-this._addAnnotatedComputationEffect(note, part, index);
-} else if (!part.literal) {
-this._addPropertyEffect(part.model, 'annotation', {
-kind: note.kind,
-index: index,
-name: note.name,
-value: part.value,
-isCompound: note.isCompound,
-compoundIndex: part.compoundIndex,
-event: part.event,
-customEvent: part.customEvent,
-negate: part.negate
-});
-}
-}
-},
-_addAnnotatedComputationEffect: function (note, part, index) {
-var sig = part.signature;
-if (sig.static) {
-this.__addAnnotatedComputationEffect('__static__', index, note, part, null);
-} else {
-for (var i = 0, arg; i < sig.args.length && (arg = sig.args[i]); i++) {
-if (!arg.literal) {
-this.__addAnnotatedComputationEffect(arg.model, index, note, part, arg);
-}
-}
-}
-},
-__addAnnotatedComputationEffect: function (property, index, note, part, trigger) {
-this._addPropertyEffect(property, 'annotatedComputation', {
-index: index,
-isCompound: note.isCompound,
-compoundIndex: part.compoundIndex,
-kind: note.kind,
-name: note.name,
-negate: part.negate,
-method: part.signature.method,
-args: part.signature.args,
-trigger: trigger
-});
-},
-_parseMethod: function (expression) {
-var m = expression.match(/([^\s]+)\((.*)\)/);
-if (m) {
-var sig = {
-method: m[1],
-static: true
-};
-if (m[2].trim()) {
-var args = m[2].replace(/\\,/g, '&comma;').split(',');
-return this._parseArgs(args, sig);
-} else {
-sig.args = Polymer.nar;
-return sig;
-}
-}
-},
-_parseArgs: function (argList, sig) {
-sig.args = argList.map(function (rawArg) {
-var arg = this._parseArg(rawArg);
-if (!arg.literal) {
-sig.static = false;
-}
-return arg;
-}, this);
-return sig;
-},
-_parseArg: function (rawArg) {
-var arg = rawArg.trim().replace(/&comma;/g, ',').replace(/\\(.)/g, '$1');
-var a = {
-name: arg,
-model: this._modelForPath(arg)
-};
-var fc = arg[0];
-if (fc === '-') {
-fc = arg[1];
-}
-if (fc >= '0' && fc <= '9') {
-fc = '#';
-}
-switch (fc) {
-case '\'':
-case '"':
-a.value = arg.slice(1, -1);
-a.literal = true;
-break;
-case '#':
-a.value = Number(arg);
-a.literal = true;
-break;
-}
-if (!a.literal) {
-a.structured = arg.indexOf('.') > 0;
-if (a.structured) {
-a.wildcard = arg.slice(-2) == '.*';
-if (a.wildcard) {
-a.name = arg.slice(0, -2);
-}
-}
-}
-return a;
-},
-_marshalInstanceEffects: function () {
-Polymer.Bind.prepareInstance(this);
-if (this._bindListeners) {
-Polymer.Bind.setupBindListeners(this);
-}
-},
-_applyEffectValue: function (info, value) {
-var node = this._nodes[info.index];
-var property = info.name;
-if (info.isCompound) {
-var storage = node.__compoundStorage__[property];
-storage[info.compoundIndex] = value;
-value = storage.join('');
-}
-if (info.kind == 'attribute') {
-this.serializeValueToAttribute(value, property, node);
-} else {
-if (property === 'className') {
-value = this._scopeElementClass(node, value);
-}
-if (property === 'textContent' || node.localName == 'input' && property == 'value') {
-value = value == undefined ? '' : value;
-}
-var pinfo;
-if (!node._propertyInfo || !(pinfo = node._propertyInfo[property]) || !pinfo.readOnly) {
-this.__setProperty(property, value, true, node);
-}
-}
-},
-_executeStaticEffects: function () {
-if (this._propertyEffects && this._propertyEffects.__static__) {
-this._effectEffects('__static__', null, this._propertyEffects.__static__);
-}
-}
-});
-Polymer.Base._addFeature({
-_setupConfigure: function (initialConfig) {
-this._config = {};
-this._handlers = [];
-if (initialConfig) {
-for (var i in initialConfig) {
-if (initialConfig[i] !== undefined) {
-this._config[i] = initialConfig[i];
-}
-}
-}
-},
-_marshalAttributes: function () {
-this._takeAttributesToModel(this._config);
-},
-_attributeChangedImpl: function (name) {
-var model = this._clientsReadied ? this : this._config;
-this._setAttributeToProperty(model, name);
-},
-_configValue: function (name, value) {
-var info = this._propertyInfo[name];
-if (!info || !info.readOnly) {
-this._config[name] = value;
-}
-},
-_beforeClientsReady: function () {
-this._configure();
-},
-_configure: function () {
-this._configureAnnotationReferences();
-this._aboveConfig = this.mixin({}, this._config);
-var config = {};
-for (var i = 0; i < this.behaviors.length; i++) {
-this._configureProperties(this.behaviors[i].properties, config);
-}
-this._configureProperties(this.properties, config);
-this.mixin(config, this._aboveConfig);
-this._config = config;
-if (this._clients && this._clients.length) {
-this._distributeConfig(this._config);
-}
-},
-_configureProperties: function (properties, config) {
-for (var i in properties) {
-var c = properties[i];
-if (c.value !== undefined) {
-var value = c.value;
-if (typeof value == 'function') {
-value = value.call(this, this._config);
-}
-config[i] = value;
-}
-}
-},
-_distributeConfig: function (config) {
-var fx$ = this._propertyEffects;
-if (fx$) {
-for (var p in config) {
-var fx = fx$[p];
-if (fx) {
-for (var i = 0, l = fx.length, x; i < l && (x = fx[i]); i++) {
-if (x.kind === 'annotation' && !x.isCompound) {
-var node = this._nodes[x.effect.index];
-if (node._configValue) {
-var value = p === x.effect.value ? config[p] : this._get(x.effect.value, config);
-node._configValue(x.effect.name, value);
-}
-}
-}
-}
-}
-}
-},
-_afterClientsReady: function () {
-this._executeStaticEffects();
-this._applyConfig(this._config, this._aboveConfig);
-this._flushHandlers();
-},
-_applyConfig: function (config, aboveConfig) {
-for (var n in config) {
-if (this[n] === undefined) {
-this.__setProperty(n, config[n], n in aboveConfig);
-}
-}
-},
-_notifyListener: function (fn, e) {
-if (!Polymer.Bind._isEventBogus(e, e.target)) {
-var value, path;
-if (e.detail) {
-value = e.detail.value;
-path = e.detail.path;
-}
-if (!this._clientsReadied) {
-this._queueHandler([
-fn,
-e.target,
-value,
-path
-]);
-} else {
-return fn.call(this, e.target, value, path);
-}
-}
-},
-_queueHandler: function (args) {
-this._handlers.push(args);
-},
-_flushHandlers: function () {
-var h$ = this._handlers;
-for (var i = 0, l = h$.length, h; i < l && (h = h$[i]); i++) {
-h[0].call(this, h[1], h[2], h[3]);
-}
-this._handlers = [];
-}
-});
-(function () {
-'use strict';
-Polymer.Base._addFeature({
-notifyPath: function (path, value, fromAbove) {
-var info = {};
-this._get(path, this, info);
-this._notifyPath(info.path, value, fromAbove);
-},
-_notifyPath: function (path, value, fromAbove) {
-var old = this._propertySetter(path, value);
-if (old !== value && (old === old || value === value)) {
-this._pathEffector(path, value);
-if (!fromAbove) {
-this._notifyPathUp(path, value);
-}
-return true;
-}
-},
-_getPathParts: function (path) {
-if (Array.isArray(path)) {
-var parts = [];
-for (var i = 0; i < path.length; i++) {
-var args = path[i].toString().split('.');
-for (var j = 0; j < args.length; j++) {
-parts.push(args[j]);
-}
-}
-return parts;
-} else {
-return path.toString().split('.');
-}
-},
-set: function (path, value, root) {
-var prop = root || this;
-var parts = this._getPathParts(path);
-var array;
-var last = parts[parts.length - 1];
-if (parts.length > 1) {
-for (var i = 0; i < parts.length - 1; i++) {
-var part = parts[i];
-if (array && part[0] == '#') {
-prop = Polymer.Collection.get(array).getItem(part);
-} else {
-prop = prop[part];
-if (array && parseInt(part, 10) == part) {
-parts[i] = Polymer.Collection.get(array).getKey(prop);
-}
-}
-if (!prop) {
-return;
-}
-array = Array.isArray(prop) ? prop : null;
-}
-if (array) {
-var coll = Polymer.Collection.get(array);
-if (last[0] == '#') {
-var key = last;
-var old = coll.getItem(key);
-last = array.indexOf(old);
-coll.setItem(key, value);
-} else if (parseInt(last, 10) == last) {
-var old = prop[last];
-var key = coll.getKey(old);
-parts[i] = key;
-coll.setItem(key, value);
-}
-}
-prop[last] = value;
-if (!root) {
-this._notifyPath(parts.join('.'), value);
-}
-} else {
-prop[path] = value;
-}
-},
-get: function (path, root) {
-return this._get(path, root);
-},
-_get: function (path, root, info) {
-var prop = root || this;
-var parts = this._getPathParts(path);
-var array;
-for (var i = 0; i < parts.length; i++) {
-if (!prop) {
-return;
-}
-var part = parts[i];
-if (array && part[0] == '#') {
-prop = Polymer.Collection.get(array).getItem(part);
-} else {
-prop = prop[part];
-if (info && array && parseInt(part, 10) == part) {
-parts[i] = Polymer.Collection.get(array).getKey(prop);
-}
-}
-array = Array.isArray(prop) ? prop : null;
-}
-if (info) {
-info.path = parts.join('.');
-}
-return prop;
-},
-_pathEffector: function (path, value) {
-var model = this._modelForPath(path);
-var fx$ = this._propertyEffects && this._propertyEffects[model];
-if (fx$) {
-for (var i = 0, fx; i < fx$.length && (fx = fx$[i]); i++) {
-var fxFn = fx.pathFn;
-if (fxFn) {
-fxFn.call(this, path, value, fx.effect);
-}
-}
-}
-if (this._boundPaths) {
-this._notifyBoundPaths(path, value);
-}
-},
-_annotationPathEffect: function (path, value, effect) {
-if (effect.value === path || effect.value.indexOf(path + '.') === 0) {
-Polymer.Bind._annotationEffect.call(this, path, value, effect);
-} else if (path.indexOf(effect.value + '.') === 0 && !effect.negate) {
-var node = this._nodes[effect.index];
-if (node && node._notifyPath) {
-var p = this._fixPath(effect.name, effect.value, path);
-node._notifyPath(p, value, true);
-}
-}
-},
-_complexObserverPathEffect: function (path, value, effect) {
-if (this._pathMatchesEffect(path, effect)) {
-Polymer.Bind._complexObserverEffect.call(this, path, value, effect);
-}
-},
-_computePathEffect: function (path, value, effect) {
-if (this._pathMatchesEffect(path, effect)) {
-Polymer.Bind._computeEffect.call(this, path, value, effect);
-}
-},
-_annotatedComputationPathEffect: function (path, value, effect) {
-if (this._pathMatchesEffect(path, effect)) {
-Polymer.Bind._annotatedComputationEffect.call(this, path, value, effect);
-}
-},
-_pathMatchesEffect: function (path, effect) {
-var effectArg = effect.trigger.name;
-return effectArg == path || effectArg.indexOf(path + '.') === 0 || effect.trigger.wildcard && path.indexOf(effectArg) === 0;
-},
-linkPaths: function (to, from) {
-this._boundPaths = this._boundPaths || {};
-if (from) {
-this._boundPaths[to] = from;
-} else {
-this.unlinkPaths(to);
-}
-},
-unlinkPaths: function (path) {
-if (this._boundPaths) {
-delete this._boundPaths[path];
-}
-},
-_notifyBoundPaths: function (path, value) {
-for (var a in this._boundPaths) {
-var b = this._boundPaths[a];
-if (path.indexOf(a + '.') == 0) {
-this._notifyPath(this._fixPath(b, a, path), value);
-} else if (path.indexOf(b + '.') == 0) {
-this._notifyPath(this._fixPath(a, b, path), value);
-}
-}
-},
-_fixPath: function (property, root, path) {
-return property + path.slice(root.length);
-},
-_notifyPathUp: function (path, value) {
-var rootName = this._modelForPath(path);
-var dashCaseName = Polymer.CaseMap.camelToDashCase(rootName);
-var eventName = dashCaseName + this._EVENT_CHANGED;
-this.fire(eventName, {
-path: path,
-value: value
-}, {
-bubbles: false,
-_useCache: true
-});
-},
-_modelForPath: function (path) {
-var dot = path.indexOf('.');
-return dot < 0 ? path : path.slice(0, dot);
-},
-_EVENT_CHANGED: '-changed',
-notifySplices: function (path, splices) {
-var info = {};
-var array = this._get(path, this, info);
-this._notifySplices(array, info.path, splices);
-},
-_notifySplices: function (array, path, splices) {
-var change = {
-keySplices: Polymer.Collection.applySplices(array, splices),
-indexSplices: splices
-};
-if (!array.hasOwnProperty('splices')) {
-Object.defineProperty(array, 'splices', {
-configurable: true,
-writable: true
-});
-}
-array.splices = change;
-this._notifyPath(path + '.splices', change);
-this._notifyPath(path + '.length', array.length);
-change.keySplices = null;
-change.indexSplices = null;
-},
-_notifySplice: function (array, path, index, added, removed) {
-this._notifySplices(array, path, [{
-index: index,
-addedCount: added,
-removed: removed,
-object: array,
-type: 'splice'
-}]);
-},
-push: function (path) {
-var info = {};
-var array = this._get(path, this, info);
-var args = Array.prototype.slice.call(arguments, 1);
-var len = array.length;
-var ret = array.push.apply(array, args);
-if (args.length) {
-this._notifySplice(array, info.path, len, args.length, []);
-}
-return ret;
-},
-pop: function (path) {
-var info = {};
-var array = this._get(path, this, info);
-var hadLength = Boolean(array.length);
-var args = Array.prototype.slice.call(arguments, 1);
-var ret = array.pop.apply(array, args);
-if (hadLength) {
-this._notifySplice(array, info.path, array.length, 0, [ret]);
-}
-return ret;
-},
-splice: function (path, start, deleteCount) {
-var info = {};
-var array = this._get(path, this, info);
-if (start < 0) {
-start = array.length - Math.floor(-start);
-} else {
-start = Math.floor(start);
-}
-if (!start) {
-start = 0;
-}
-var args = Array.prototype.slice.call(arguments, 1);
-var ret = array.splice.apply(array, args);
-var addedCount = Math.max(args.length - 2, 0);
-if (addedCount || ret.length) {
-this._notifySplice(array, info.path, start, addedCount, ret);
-}
-return ret;
-},
-shift: function (path) {
-var info = {};
-var array = this._get(path, this, info);
-var hadLength = Boolean(array.length);
-var args = Array.prototype.slice.call(arguments, 1);
-var ret = array.shift.apply(array, args);
-if (hadLength) {
-this._notifySplice(array, info.path, 0, 0, [ret]);
-}
-return ret;
-},
-unshift: function (path) {
-var info = {};
-var array = this._get(path, this, info);
-var args = Array.prototype.slice.call(arguments, 1);
-var ret = array.unshift.apply(array, args);
-if (args.length) {
-this._notifySplice(array, info.path, 0, args.length, []);
-}
-return ret;
-},
-prepareModelNotifyPath: function (model) {
-this.mixin(model, {
-fire: Polymer.Base.fire,
-_getEvent: Polymer.Base._getEvent,
-__eventCache: Polymer.Base.__eventCache,
-notifyPath: Polymer.Base.notifyPath,
-_get: Polymer.Base._get,
-_EVENT_CHANGED: Polymer.Base._EVENT_CHANGED,
-_notifyPath: Polymer.Base._notifyPath,
-_notifyPathUp: Polymer.Base._notifyPathUp,
-_pathEffector: Polymer.Base._pathEffector,
-_annotationPathEffect: Polymer.Base._annotationPathEffect,
-_complexObserverPathEffect: Polymer.Base._complexObserverPathEffect,
-_annotatedComputationPathEffect: Polymer.Base._annotatedComputationPathEffect,
-_computePathEffect: Polymer.Base._computePathEffect,
-_modelForPath: Polymer.Base._modelForPath,
-_pathMatchesEffect: Polymer.Base._pathMatchesEffect,
-_notifyBoundPaths: Polymer.Base._notifyBoundPaths,
-_getPathParts: Polymer.Base._getPathParts
-});
-}
-});
-}());
-Polymer.Base._addFeature({
-resolveUrl: function (url) {
-var module = Polymer.DomModule.import(this.is);
-var root = '';
-if (module) {
-var assetPath = module.getAttribute('assetpath') || '';
-root = Polymer.ResolveUrl.resolveUrl(assetPath, module.ownerDocument.baseURI);
-}
-return Polymer.ResolveUrl.resolveUrl(url, root);
-}
-});
-Polymer.CssParse = function () {
-var api = {
-parse: function (text) {
-text = this._clean(text);
-return this._parseCss(this._lex(text), text);
-},
-_clean: function (cssText) {
-return cssText.replace(this._rx.comments, '').replace(this._rx.port, '');
-},
-_lex: function (text) {
-var root = {
-start: 0,
-end: text.length
-};
-var n = root;
-for (var i = 0, s = 0, l = text.length; i < l; i++) {
-switch (text[i]) {
-case this.OPEN_BRACE:
-if (!n.rules) {
-n.rules = [];
-}
-var p = n;
-var previous = p.rules[p.rules.length - 1];
-n = {
-start: i + 1,
-parent: p,
-previous: previous
-};
-p.rules.push(n);
-break;
-case this.CLOSE_BRACE:
-n.end = i + 1;
-n = n.parent || root;
-break;
-}
-}
-return root;
-},
-_parseCss: function (node, text) {
-var t = text.substring(node.start, node.end - 1);
-node.parsedCssText = node.cssText = t.trim();
-if (node.parent) {
-var ss = node.previous ? node.previous.end : node.parent.start;
-t = text.substring(ss, node.start - 1);
-t = this._expandUnicodeEscapes(t);
-t = t.replace(this._rx.multipleSpaces, ' ');
-t = t.substring(t.lastIndexOf(';') + 1);
-var s = node.parsedSelector = node.selector = t.trim();
-node.atRule = s.indexOf(this.AT_START) === 0;
-if (node.atRule) {
-if (s.indexOf(this.MEDIA_START) === 0) {
-node.type = this.types.MEDIA_RULE;
-} else if (s.match(this._rx.keyframesRule)) {
-node.type = this.types.KEYFRAMES_RULE;
-}
-} else {
-if (s.indexOf(this.VAR_START) === 0) {
-node.type = this.types.MIXIN_RULE;
-} else {
-node.type = this.types.STYLE_RULE;
-}
-}
-}
-var r$ = node.rules;
-if (r$) {
-for (var i = 0, l = r$.length, r; i < l && (r = r$[i]); i++) {
-this._parseCss(r, text);
-}
-}
-return node;
-},
-_expandUnicodeEscapes: function (s) {
-return s.replace(/\\([0-9a-f]{1,6})\s/gi, function () {
-var code = arguments[1], repeat = 6 - code.length;
-while (repeat--) {
-code = '0' + code;
-}
-return '\\' + code;
-});
-},
-stringify: function (node, preserveProperties, text) {
-text = text || '';
-var cssText = '';
-if (node.cssText || node.rules) {
-var r$ = node.rules;
-if (r$ && (preserveProperties || !this._hasMixinRules(r$))) {
-for (var i = 0, l = r$.length, r; i < l && (r = r$[i]); i++) {
-cssText = this.stringify(r, preserveProperties, cssText);
-}
-} else {
-cssText = preserveProperties ? node.cssText : this.removeCustomProps(node.cssText);
-cssText = cssText.trim();
-if (cssText) {
-cssText = ' ' + cssText + '\n';
-}
-}
-}
-if (cssText) {
-if (node.selector) {
-text += node.selector + ' ' + this.OPEN_BRACE + '\n';
-}
-text += cssText;
-if (node.selector) {
-text += this.CLOSE_BRACE + '\n\n';
-}
-}
-return text;
-},
-_hasMixinRules: function (rules) {
-return rules[0].selector.indexOf(this.VAR_START) === 0;
-},
-removeCustomProps: function (cssText) {
-return cssText;
-},
-removeCustomPropAssignment: function (cssText) {
-return cssText.replace(this._rx.customProp, '').replace(this._rx.mixinProp, '');
-},
-removeCustomPropApply: function (cssText) {
-return cssText.replace(this._rx.mixinApply, '').replace(this._rx.varApply, '');
-},
-types: {
-STYLE_RULE: 1,
-KEYFRAMES_RULE: 7,
-MEDIA_RULE: 4,
-MIXIN_RULE: 1000
-},
-OPEN_BRACE: '{',
-CLOSE_BRACE: '}',
-_rx: {
-comments: /\/\*[^*]*\*+([^\/*][^*]*\*+)*\//gim,
-port: /@import[^;]*;/gim,
-customProp: /(?:^|[\s;])--[^;{]*?:[^{};]*?(?:[;\n]|$)/gim,
-mixinProp: /(?:^|[\s;])?--[^;{]*?:[^{;]*?{[^}]*?}(?:[;\n]|$)?/gim,
-mixinApply: /@apply[\s]*\([^)]*?\)[\s]*(?:[;\n]|$)?/gim,
-varApply: /[^;:]*?:[^;]*?var\([^;]*\)(?:[;\n]|$)?/gim,
-keyframesRule: /^@[^\s]*keyframes/,
-multipleSpaces: /\s+/g
-},
-VAR_START: '--',
-MEDIA_START: '@media',
-AT_START: '@'
-};
-return api;
-}();
-Polymer.StyleUtil = function () {
-return {
-MODULE_STYLES_SELECTOR: 'style, link[rel=import][type~=css], template',
-INCLUDE_ATTR: 'include',
-toCssText: function (rules, callback, preserveProperties) {
-if (typeof rules === 'string') {
-rules = this.parser.parse(rules);
-}
-if (callback) {
-this.forEachStyleRule(rules, callback);
-}
-return this.parser.stringify(rules, preserveProperties);
-},
-forRulesInStyles: function (styles, callback) {
-if (styles) {
-for (var i = 0, l = styles.length, s; i < l && (s = styles[i]); i++) {
-this.forEachStyleRule(this.rulesForStyle(s), callback);
-}
-}
-},
-rulesForStyle: function (style) {
-if (!style.__cssRules && style.textContent) {
-style.__cssRules = this.parser.parse(style.textContent);
-}
-return style.__cssRules;
-},
-clearStyleRules: function (style) {
-style.__cssRules = null;
-},
-forEachStyleRule: function (node, callback) {
-if (!node) {
-return;
-}
-var s = node.parsedSelector;
-var skipRules = false;
-if (node.type === this.ruleTypes.STYLE_RULE) {
-callback(node);
-} else if (node.type === this.ruleTypes.KEYFRAMES_RULE || node.type === this.ruleTypes.MIXIN_RULE) {
-skipRules = true;
-}
-var r$ = node.rules;
-if (r$ && !skipRules) {
-for (var i = 0, l = r$.length, r; i < l && (r = r$[i]); i++) {
-this.forEachStyleRule(r, callback);
-}
-}
-},
-applyCss: function (cssText, moniker, target, afterNode) {
-var style = document.createElement('style');
-if (moniker) {
-style.setAttribute('scope', moniker);
-}
-style.textContent = cssText;
-target = target || document.head;
-if (!afterNode) {
-var n$ = target.querySelectorAll('style[scope]');
-afterNode = n$[n$.length - 1];
-}
-target.insertBefore(style, afterNode && afterNode.nextSibling || target.firstChild);
-return style;
-},
-cssFromModules: function (moduleIds, warnIfNotFound) {
-var modules = moduleIds.trim().split(' ');
-var cssText = '';
-for (var i = 0; i < modules.length; i++) {
-cssText += this.cssFromModule(modules[i], warnIfNotFound);
-}
-return cssText;
-},
-cssFromModule: function (moduleId, warnIfNotFound) {
-var m = Polymer.DomModule.import(moduleId);
-if (m && !m._cssText) {
-m._cssText = this.cssFromElement(m);
-}
-if (!m && warnIfNotFound) {
-console.warn('Could not find style data in module named', moduleId);
-}
-return m && m._cssText || '';
-},
-cssFromElement: function (element) {
-var cssText = '';
-var content = element.content || element;
-var e$ = Polymer.DomApi.arrayCopy(content.querySelectorAll(this.MODULE_STYLES_SELECTOR));
-for (var i = 0, e; i < e$.length; i++) {
-e = e$[i];
-if (e.localName === 'template') {
-cssText += this.cssFromElement(e);
-} else {
-if (e.localName === 'style') {
-var include = e.getAttribute(this.INCLUDE_ATTR);
-if (include) {
-cssText += this.cssFromModules(include, true);
-}
-e = e.__appliedElement || e;
-e.parentNode.removeChild(e);
-cssText += this.resolveCss(e.textContent, element.ownerDocument);
-} else if (e.import && e.import.body) {
-cssText += this.resolveCss(e.import.body.textContent, e.import);
-}
-}
-}
-return cssText;
-},
-resolveCss: Polymer.ResolveUrl.resolveCss,
-parser: Polymer.CssParse,
-ruleTypes: Polymer.CssParse.types
-};
-}();
-Polymer.StyleTransformer = function () {
-var nativeShadow = Polymer.Settings.useNativeShadow;
-var styleUtil = Polymer.StyleUtil;
-var api = {
-dom: function (node, scope, useAttr, shouldRemoveScope) {
-this._transformDom(node, scope || '', useAttr, shouldRemoveScope);
-},
-_transformDom: function (node, selector, useAttr, shouldRemoveScope) {
-if (node.setAttribute) {
-this.element(node, selector, useAttr, shouldRemoveScope);
-}
-var c$ = Polymer.dom(node).childNodes;
-for (var i = 0; i < c$.length; i++) {
-this._transformDom(c$[i], selector, useAttr, shouldRemoveScope);
-}
-},
-element: function (element, scope, useAttr, shouldRemoveScope) {
-if (useAttr) {
-if (shouldRemoveScope) {
-element.removeAttribute(SCOPE_NAME);
-} else {
-element.setAttribute(SCOPE_NAME, scope);
-}
-} else {
-if (scope) {
-if (element.classList) {
-if (shouldRemoveScope) {
-element.classList.remove(SCOPE_NAME);
-element.classList.remove(scope);
-} else {
-element.classList.add(SCOPE_NAME);
-element.classList.add(scope);
-}
-} else if (element.getAttribute) {
-var c = element.getAttribute(CLASS);
-if (shouldRemoveScope) {
-if (c) {
-element.setAttribute(CLASS, c.replace(SCOPE_NAME, '').replace(scope, ''));
-}
-} else {
-element.setAttribute(CLASS, c + (c ? ' ' : '') + SCOPE_NAME + ' ' + scope);
-}
-}
-}
-}
-},
-elementStyles: function (element, callback) {
-var styles = element._styles;
-var cssText = '';
-for (var i = 0, l = styles.length, s, text; i < l && (s = styles[i]); i++) {
-var rules = styleUtil.rulesForStyle(s);
-cssText += nativeShadow ? styleUtil.toCssText(rules, callback) : this.css(rules, element.is, element.extends, callback, element._scopeCssViaAttr) + '\n\n';
-}
-return cssText.trim();
-},
-css: function (rules, scope, ext, callback, useAttr) {
-var hostScope = this._calcHostScope(scope, ext);
-scope = this._calcElementScope(scope, useAttr);
-var self = this;
-return styleUtil.toCssText(rules, function (rule) {
-if (!rule.isScoped) {
-self.rule(rule, scope, hostScope);
-rule.isScoped = true;
-}
-if (callback) {
-callback(rule, scope, hostScope);
-}
-});
-},
-_calcElementScope: function (scope, useAttr) {
-if (scope) {
-return useAttr ? CSS_ATTR_PREFIX + scope + CSS_ATTR_SUFFIX : CSS_CLASS_PREFIX + scope;
-} else {
-return '';
-}
-},
-_calcHostScope: function (scope, ext) {
-return ext ? '[is=' + scope + ']' : scope;
-},
-rule: function (rule, scope, hostScope) {
-this._transformRule(rule, this._transformComplexSelector, scope, hostScope);
-},
-_transformRule: function (rule, transformer, scope, hostScope) {
-var p$ = rule.selector.split(COMPLEX_SELECTOR_SEP);
-for (var i = 0, l = p$.length, p; i < l && (p = p$[i]); i++) {
-p$[i] = transformer.call(this, p, scope, hostScope);
-}
-rule.selector = rule.transformedSelector = p$.join(COMPLEX_SELECTOR_SEP);
-},
-_transformComplexSelector: function (selector, scope, hostScope) {
-var stop = false;
-var hostContext = false;
-var self = this;
-selector = selector.replace(SIMPLE_SELECTOR_SEP, function (m, c, s) {
-if (!stop) {
-var info = self._transformCompoundSelector(s, c, scope, hostScope);
-stop = stop || info.stop;
-hostContext = hostContext || info.hostContext;
-c = info.combinator;
-s = info.value;
-} else {
-s = s.replace(SCOPE_JUMP, ' ');
-}
-return c + s;
-});
-if (hostContext) {
-selector = selector.replace(HOST_CONTEXT_PAREN, function (m, pre, paren, post) {
-return pre + paren + ' ' + hostScope + post + COMPLEX_SELECTOR_SEP + ' ' + pre + hostScope + paren + post;
-});
-}
-return selector;
-},
-_transformCompoundSelector: function (selector, combinator, scope, hostScope) {
-var jumpIndex = selector.search(SCOPE_JUMP);
-var hostContext = false;
-if (selector.indexOf(HOST_CONTEXT) >= 0) {
-hostContext = true;
-} else if (selector.indexOf(HOST) >= 0) {
-selector = selector.replace(HOST_PAREN, function (m, host, paren) {
-return hostScope + paren;
-});
-selector = selector.replace(HOST, hostScope);
-} else if (jumpIndex !== 0) {
-selector = scope ? this._transformSimpleSelector(selector, scope) : selector;
-}
-if (selector.indexOf(CONTENT) >= 0) {
-combinator = '';
-}
-var stop;
-if (jumpIndex >= 0) {
-selector = selector.replace(SCOPE_JUMP, ' ');
-stop = true;
-}
-return {
-value: selector,
-combinator: combinator,
-stop: stop,
-hostContext: hostContext
-};
-},
-_transformSimpleSelector: function (selector, scope) {
-var p$ = selector.split(PSEUDO_PREFIX);
-p$[0] += scope;
-return p$.join(PSEUDO_PREFIX);
-},
-documentRule: function (rule) {
-rule.selector = rule.parsedSelector;
-this.normalizeRootSelector(rule);
-if (!nativeShadow) {
-this._transformRule(rule, this._transformDocumentSelector);
-}
-},
-normalizeRootSelector: function (rule) {
-if (rule.selector === ROOT) {
-rule.selector = 'body';
-}
-},
-_transformDocumentSelector: function (selector) {
-return selector.match(SCOPE_JUMP) ? this._transformComplexSelector(selector, SCOPE_DOC_SELECTOR) : this._transformSimpleSelector(selector.trim(), SCOPE_DOC_SELECTOR);
-},
-SCOPE_NAME: 'style-scope'
-};
-var SCOPE_NAME = api.SCOPE_NAME;
-var SCOPE_DOC_SELECTOR = ':not([' + SCOPE_NAME + '])' + ':not(.' + SCOPE_NAME + ')';
-var COMPLEX_SELECTOR_SEP = ',';
-var SIMPLE_SELECTOR_SEP = /(^|[\s>+~]+)([^\s>+~]+)/g;
-var HOST = ':host';
-var ROOT = ':root';
-var HOST_PAREN = /(\:host)(?:\(((?:\([^)(]*\)|[^)(]*)+?)\))/g;
-var HOST_CONTEXT = ':host-context';
-var HOST_CONTEXT_PAREN = /(.*)(?:\:host-context)(?:\(((?:\([^)(]*\)|[^)(]*)+?)\))(.*)/;
-var CONTENT = '::content';
-var SCOPE_JUMP = /\:\:content|\:\:shadow|\/deep\//;
-var CSS_CLASS_PREFIX = '.';
-var CSS_ATTR_PREFIX = '[' + SCOPE_NAME + '~=';
-var CSS_ATTR_SUFFIX = ']';
-var PSEUDO_PREFIX = ':';
-var CLASS = 'class';
-return api;
-}();
-Polymer.StyleExtends = function () {
-var styleUtil = Polymer.StyleUtil;
-return {
-hasExtends: function (cssText) {
-return Boolean(cssText.match(this.rx.EXTEND));
-},
-transform: function (style) {
-var rules = styleUtil.rulesForStyle(style);
-var self = this;
-styleUtil.forEachStyleRule(rules, function (rule) {
-var map = self._mapRule(rule);
-if (rule.parent) {
-var m;
-while (m = self.rx.EXTEND.exec(rule.cssText)) {
-var extend = m[1];
-var extendor = self._findExtendor(extend, rule);
-if (extendor) {
-self._extendRule(rule, extendor);
-}
-}
-}
-rule.cssText = rule.cssText.replace(self.rx.EXTEND, '');
-});
-return styleUtil.toCssText(rules, function (rule) {
-if (rule.selector.match(self.rx.STRIP)) {
-rule.cssText = '';
-}
-}, true);
-},
-_mapRule: function (rule) {
-if (rule.parent) {
-var map = rule.parent.map || (rule.parent.map = {});
-var parts = rule.selector.split(',');
-for (var i = 0, p; i < parts.length; i++) {
-p = parts[i];
-map[p.trim()] = rule;
-}
-return map;
-}
-},
-_findExtendor: function (extend, rule) {
-return rule.parent && rule.parent.map && rule.parent.map[extend] || this._findExtendor(extend, rule.parent);
-},
-_extendRule: function (target, source) {
-if (target.parent !== source.parent) {
-this._cloneAndAddRuleToParent(source, target.parent);
-}
-target.extends = target.extends || [];
-target.extends.push(source);
-source.selector = source.selector.replace(this.rx.STRIP, '');
-source.selector = (source.selector && source.selector + ',\n') + target.selector;
-if (source.extends) {
-source.extends.forEach(function (e) {
-this._extendRule(target, e);
-}, this);
-}
-},
-_cloneAndAddRuleToParent: function (rule, parent) {
-rule = Object.create(rule);
-rule.parent = parent;
-if (rule.extends) {
-rule.extends = rule.extends.slice();
-}
-parent.rules.push(rule);
-},
-rx: {
-EXTEND: /@extends\(([^)]*)\)\s*?;/gim,
-STRIP: /%[^,]*$/
-}
-};
-}();
-(function () {
-var prepElement = Polymer.Base._prepElement;
-var nativeShadow = Polymer.Settings.useNativeShadow;
-var styleUtil = Polymer.StyleUtil;
-var styleTransformer = Polymer.StyleTransformer;
-var styleExtends = Polymer.StyleExtends;
-Polymer.Base._addFeature({
-_prepElement: function (element) {
-if (this._encapsulateStyle) {
-styleTransformer.element(element, this.is, this._scopeCssViaAttr);
-}
-prepElement.call(this, element);
-},
-_prepStyles: function () {
-if (this._encapsulateStyle === undefined) {
-this._encapsulateStyle = !nativeShadow && Boolean(this._template);
-}
-if (this._template) {
-this._styles = this._collectStyles();
-var cssText = styleTransformer.elementStyles(this);
-if (cssText) {
-var style = styleUtil.applyCss(cssText, this.is, nativeShadow ? this._template.content : null);
-if (!nativeShadow) {
-this._scopeStyle = style;
-}
-}
-} else {
-this._styles = [];
-}
-},
-_collectStyles: function () {
-var styles = [];
-var cssText = '', m$ = this.styleModules;
-if (m$) {
-for (var i = 0, l = m$.length, m; i < l && (m = m$[i]); i++) {
-cssText += styleUtil.cssFromModule(m);
-}
-}
-cssText += styleUtil.cssFromModule(this.is);
-var p = this._template && this._template.parentNode;
-if (this._template && (!p || p.id.toLowerCase() !== this.is)) {
-cssText += styleUtil.cssFromElement(this._template);
-}
-if (cssText) {
-var style = document.createElement('style');
-style.textContent = cssText;
-if (styleExtends.hasExtends(style.textContent)) {
-cssText = styleExtends.transform(style);
-}
-styles.push(style);
-}
-return styles;
-},
-_elementAdd: function (node) {
-if (this._encapsulateStyle) {
-if (node.__styleScoped) {
-node.__styleScoped = false;
-} else {
-styleTransformer.dom(node, this.is, this._scopeCssViaAttr);
-}
-}
-},
-_elementRemove: function (node) {
-if (this._encapsulateStyle) {
-styleTransformer.dom(node, this.is, this._scopeCssViaAttr, true);
-}
-},
-scopeSubtree: function (container, shouldObserve) {
-if (nativeShadow) {
-return;
-}
-var self = this;
-var scopify = function (node) {
-if (node.nodeType === Node.ELEMENT_NODE) {
-node.className = self._scopeElementClass(node, node.className);
-var n$ = node.querySelectorAll('*');
-for (var i = 0, n; i < n$.length && (n = n$[i]); i++) {
-n.className = self._scopeElementClass(n, n.className);
-}
-}
-};
-scopify(container);
-if (shouldObserve) {
-var mo = new MutationObserver(function (mxns) {
-for (var i = 0, m; i < mxns.length && (m = mxns[i]); i++) {
-if (m.addedNodes) {
-for (var j = 0; j < m.addedNodes.length; j++) {
-scopify(m.addedNodes[j]);
-}
-}
-}
-});
-mo.observe(container, {
-childList: true,
-subtree: true
-});
-return mo;
-}
-}
-});
-}());
-Polymer.StyleProperties = function () {
-'use strict';
-var nativeShadow = Polymer.Settings.useNativeShadow;
-var matchesSelector = Polymer.DomApi.matchesSelector;
-var styleUtil = Polymer.StyleUtil;
-var styleTransformer = Polymer.StyleTransformer;
-return {
-decorateStyles: function (styles) {
-var self = this, props = {};
-styleUtil.forRulesInStyles(styles, function (rule) {
-self.decorateRule(rule);
-self.collectPropertiesInCssText(rule.propertyInfo.cssText, props);
-});
-var names = [];
-for (var i in props) {
-names.push(i);
-}
-return names;
-},
-decorateRule: function (rule) {
-if (rule.propertyInfo) {
-return rule.propertyInfo;
-}
-var info = {}, properties = {};
-var hasProperties = this.collectProperties(rule, properties);
-if (hasProperties) {
-info.properties = properties;
-rule.rules = null;
-}
-info.cssText = this.collectCssText(rule);
-rule.propertyInfo = info;
-return info;
-},
-collectProperties: function (rule, properties) {
-var info = rule.propertyInfo;
-if (info) {
-if (info.properties) {
-Polymer.Base.mixin(properties, info.properties);
-return true;
-}
-} else {
-var m, rx = this.rx.VAR_ASSIGN;
-var cssText = rule.parsedCssText;
-var any;
-while (m = rx.exec(cssText)) {
-properties[m[1]] = (m[2] || m[3]).trim();
-any = true;
-}
-return any;
-}
-},
-collectCssText: function (rule) {
-var customCssText = '';
-var cssText = rule.parsedCssText;
-cssText = cssText.replace(this.rx.BRACKETED, '').replace(this.rx.VAR_ASSIGN, '');
-var parts = cssText.split(';');
-for (var i = 0, p; i < parts.length; i++) {
-p = parts[i];
-if (p.match(this.rx.MIXIN_MATCH) || p.match(this.rx.VAR_MATCH)) {
-customCssText += p + ';\n';
-}
-}
-return customCssText;
-},
-collectPropertiesInCssText: function (cssText, props) {
-var m;
-while (m = this.rx.VAR_CAPTURE.exec(cssText)) {
-props[m[1]] = true;
-var def = m[2];
-if (def && def.match(this.rx.IS_VAR)) {
-props[def] = true;
-}
-}
-},
-reify: function (props) {
-var names = Object.getOwnPropertyNames(props);
-for (var i = 0, n; i < names.length; i++) {
-n = names[i];
-props[n] = this.valueForProperty(props[n], props);
-}
-},
-valueForProperty: function (property, props) {
-if (property) {
-if (property.indexOf(';') >= 0) {
-property = this.valueForProperties(property, props);
-} else {
-var self = this;
-var fn = function (all, prefix, value, fallback) {
-var propertyValue = self.valueForProperty(props[value], props) || (props[fallback] ? self.valueForProperty(props[fallback], props) : fallback);
-return prefix + (propertyValue || '');
-};
-property = property.replace(this.rx.VAR_MATCH, fn);
-}
-}
-return property && property.trim() || '';
-},
-valueForProperties: function (property, props) {
-var parts = property.split(';');
-for (var i = 0, p, m; i < parts.length; i++) {
-if (p = parts[i]) {
-m = p.match(this.rx.MIXIN_MATCH);
-if (m) {
-p = this.valueForProperty(props[m[1]], props);
-} else {
-var pp = p.split(':');
-if (pp[1]) {
-pp[1] = pp[1].trim();
-pp[1] = this.valueForProperty(pp[1], props) || pp[1];
-}
-p = pp.join(':');
-}
-parts[i] = p && p.lastIndexOf(';') === p.length - 1 ? p.slice(0, -1) : p || '';
-}
-}
-return parts.filter(function (v) {
-return v;
-}).join(';');
-},
-applyProperties: function (rule, props) {
-var output = '';
-if (!rule.propertyInfo) {
-this.decorateRule(rule);
-}
-if (rule.propertyInfo.cssText) {
-output = this.valueForProperties(rule.propertyInfo.cssText, props);
-}
-rule.cssText = output;
-},
-propertyDataFromStyles: function (styles, element) {
-var props = {}, self = this;
-var o = [], i = 0;
-styleUtil.forRulesInStyles(styles, function (rule) {
-if (!rule.propertyInfo) {
-self.decorateRule(rule);
-}
-if (element && rule.propertyInfo.properties && matchesSelector.call(element, rule.transformedSelector || rule.parsedSelector)) {
-self.collectProperties(rule, props);
-addToBitMask(i, o);
-}
-i++;
-});
-return {
-properties: props,
-key: o
-};
-},
-scopePropertiesFromStyles: function (styles) {
-if (!styles._scopeStyleProperties) {
-styles._scopeStyleProperties = this.selectedPropertiesFromStyles(styles, this.SCOPE_SELECTORS);
-}
-return styles._scopeStyleProperties;
-},
-hostPropertiesFromStyles: function (styles) {
-if (!styles._hostStyleProperties) {
-styles._hostStyleProperties = this.selectedPropertiesFromStyles(styles, this.HOST_SELECTORS);
-}
-return styles._hostStyleProperties;
-},
-selectedPropertiesFromStyles: function (styles, selectors) {
-var props = {}, self = this;
-styleUtil.forRulesInStyles(styles, function (rule) {
-if (!rule.propertyInfo) {
-self.decorateRule(rule);
-}
-for (var i = 0; i < selectors.length; i++) {
-if (rule.parsedSelector === selectors[i]) {
-self.collectProperties(rule, props);
-return;
-}
-}
-});
-return props;
-},
-transformStyles: function (element, properties, scopeSelector) {
-var self = this;
-var hostSelector = styleTransformer._calcHostScope(element.is, element.extends);
-var rxHostSelector = element.extends ? '\\' + hostSelector.slice(0, -1) + '\\]' : hostSelector;
-var hostRx = new RegExp(this.rx.HOST_PREFIX + rxHostSelector + this.rx.HOST_SUFFIX);
-return styleTransformer.elementStyles(element, function (rule) {
-self.applyProperties(rule, properties);
-if (rule.cssText && !nativeShadow) {
-self._scopeSelector(rule, hostRx, hostSelector, element._scopeCssViaAttr, scopeSelector);
-}
-});
-},
-_scopeSelector: function (rule, hostRx, hostSelector, viaAttr, scopeId) {
-rule.transformedSelector = rule.transformedSelector || rule.selector;
-var selector = rule.transformedSelector;
-var scope = viaAttr ? '[' + styleTransformer.SCOPE_NAME + '~=' + scopeId + ']' : '.' + scopeId;
-var parts = selector.split(',');
-for (var i = 0, l = parts.length, p; i < l && (p = parts[i]); i++) {
-parts[i] = p.match(hostRx) ? p.replace(hostSelector, hostSelector + scope) : scope + ' ' + p;
-}
-rule.selector = parts.join(',');
-},
-applyElementScopeSelector: function (element, selector, old, viaAttr) {
-var c = viaAttr ? element.getAttribute(styleTransformer.SCOPE_NAME) : element.className;
-var v = old ? c.replace(old, selector) : (c ? c + ' ' : '') + this.XSCOPE_NAME + ' ' + selector;
-if (c !== v) {
-if (viaAttr) {
-element.setAttribute(styleTransformer.SCOPE_NAME, v);
-} else {
-element.className = v;
-}
-}
-},
-applyElementStyle: function (element, properties, selector, style) {
-var cssText = style ? style.textContent || '' : this.transformStyles(element, properties, selector);
-var s = element._customStyle;
-if (s && !nativeShadow && s !== style) {
-s._useCount--;
-if (s._useCount <= 0 && s.parentNode) {
-s.parentNode.removeChild(s);
-}
-}
-if (nativeShadow || (!style || !style.parentNode)) {
-if (nativeShadow && element._customStyle) {
-element._customStyle.textContent = cssText;
-style = element._customStyle;
-} else if (cssText) {
-style = styleUtil.applyCss(cssText, selector, nativeShadow ? element.root : null, element._scopeStyle);
-}
-}
-if (style) {
-style._useCount = style._useCount || 0;
-if (element._customStyle != style) {
-style._useCount++;
-}
-element._customStyle = style;
-}
-return style;
-},
-mixinCustomStyle: function (props, customStyle) {
-var v;
-for (var i in customStyle) {
-v = customStyle[i];
-if (v || v === 0) {
-props[i] = v;
-}
-}
-},
-rx: {
-VAR_ASSIGN: /(?:^|[;\s{]\s*)(--[\w-]*?)\s*:\s*(?:([^;{]*)|{([^}]*)})(?:(?=[;\s}])|$)/gi,
-MIXIN_MATCH: /(?:^|\W+)@apply[\s]*\(([^)]*)\)/i,
-VAR_MATCH: /(^|\W+)var\([\s]*([^,)]*)[\s]*,?[\s]*((?:[^,)]*)|(?:[^;]*\([^;)]*\)))[\s]*?\)/gi,
-VAR_CAPTURE: /\([\s]*(--[^,\s)]*)(?:,[\s]*(--[^,\s)]*))?(?:\)|,)/gi,
-IS_VAR: /^--/,
-BRACKETED: /\{[^}]*\}/g,
-HOST_PREFIX: '(?:^|[^.#[:])',
-HOST_SUFFIX: '($|[.:[\\s>+~])'
-},
-HOST_SELECTORS: [':host'],
-SCOPE_SELECTORS: [':root'],
-XSCOPE_NAME: 'x-scope'
-};
-function addToBitMask(n, bits) {
-var o = parseInt(n / 32);
-var v = 1 << n % 32;
-bits[o] = (bits[o] || 0) | v;
-}
-}();
-(function () {
-Polymer.StyleCache = function () {
-this.cache = {};
-};
-Polymer.StyleCache.prototype = {
-MAX: 100,
-store: function (is, data, keyValues, keyStyles) {
-data.keyValues = keyValues;
-data.styles = keyStyles;
-var s$ = this.cache[is] = this.cache[is] || [];
-s$.push(data);
-if (s$.length > this.MAX) {
-s$.shift();
-}
-},
-retrieve: function (is, keyValues, keyStyles) {
-var cache = this.cache[is];
-if (cache) {
-for (var i = cache.length - 1, data; i >= 0; i--) {
-data = cache[i];
-if (keyStyles === data.styles && this._objectsEqual(keyValues, data.keyValues)) {
-return data;
-}
-}
-}
-},
-clear: function () {
-this.cache = {};
-},
-_objectsEqual: function (target, source) {
-var t, s;
-for (var i in target) {
-t = target[i], s = source[i];
-if (!(typeof t === 'object' && t ? this._objectsStrictlyEqual(t, s) : t === s)) {
-return false;
-}
-}
-if (Array.isArray(target)) {
-return target.length === source.length;
-}
-return true;
-},
-_objectsStrictlyEqual: function (target, source) {
-return this._objectsEqual(target, source) && this._objectsEqual(source, target);
-}
-};
-}());
-Polymer.StyleDefaults = function () {
-var styleProperties = Polymer.StyleProperties;
-var styleUtil = Polymer.StyleUtil;
-var StyleCache = Polymer.StyleCache;
-var api = {
-_styles: [],
-_properties: null,
-customStyle: {},
-_styleCache: new StyleCache(),
-addStyle: function (style) {
-this._styles.push(style);
-this._properties = null;
-},
-get _styleProperties() {
-if (!this._properties) {
-styleProperties.decorateStyles(this._styles);
-this._styles._scopeStyleProperties = null;
-this._properties = styleProperties.scopePropertiesFromStyles(this._styles);
-styleProperties.mixinCustomStyle(this._properties, this.customStyle);
-styleProperties.reify(this._properties);
-}
-return this._properties;
-},
-_needsStyleProperties: function () {
-},
-_computeStyleProperties: function () {
-return this._styleProperties;
-},
-updateStyles: function (properties) {
-this._properties = null;
-if (properties) {
-Polymer.Base.mixin(this.customStyle, properties);
-}
-this._styleCache.clear();
-for (var i = 0, s; i < this._styles.length; i++) {
-s = this._styles[i];
-s = s.__importElement || s;
-s._apply();
-}
-}
-};
-return api;
-}();
-(function () {
-'use strict';
-var serializeValueToAttribute = Polymer.Base.serializeValueToAttribute;
-var propertyUtils = Polymer.StyleProperties;
-var styleTransformer = Polymer.StyleTransformer;
-var styleUtil = Polymer.StyleUtil;
-var styleDefaults = Polymer.StyleDefaults;
-var nativeShadow = Polymer.Settings.useNativeShadow;
-Polymer.Base._addFeature({
-_prepStyleProperties: function () {
-this._ownStylePropertyNames = this._styles ? propertyUtils.decorateStyles(this._styles) : null;
-},
-customStyle: null,
-getComputedStyleValue: function (property) {
-return this._styleProperties && this._styleProperties[property] || getComputedStyle(this).getPropertyValue(property);
-},
-_setupStyleProperties: function () {
-this.customStyle = {};
-},
-_needsStyleProperties: function () {
-return Boolean(this._ownStylePropertyNames && this._ownStylePropertyNames.length);
-},
-_beforeAttached: function () {
-if (!this._scopeSelector && this._needsStyleProperties()) {
-this._updateStyleProperties();
-}
-},
-_findStyleHost: function () {
-var e = this, root;
-while (root = Polymer.dom(e).getOwnerRoot()) {
-if (Polymer.isInstance(root.host)) {
-return root.host;
-}
-e = root.host;
-}
-return styleDefaults;
-},
-_updateStyleProperties: function () {
-var info, scope = this._findStyleHost();
-if (!scope._styleCache) {
-scope._styleCache = new Polymer.StyleCache();
-}
-var scopeData = propertyUtils.propertyDataFromStyles(scope._styles, this);
-scopeData.key.customStyle = this.customStyle;
-info = scope._styleCache.retrieve(this.is, scopeData.key, this._styles);
-var scopeCached = Boolean(info);
-if (scopeCached) {
-this._styleProperties = info._styleProperties;
-} else {
-this._computeStyleProperties(scopeData.properties);
-}
-this._computeOwnStyleProperties();
-if (!scopeCached) {
-info = styleCache.retrieve(this.is, this._ownStyleProperties, this._styles);
-}
-var globalCached = Boolean(info) && !scopeCached;
-var style = this._applyStyleProperties(info);
-if (!scopeCached) {
-style = style && nativeShadow ? style.cloneNode(true) : style;
-info = {
-style: style,
-_scopeSelector: this._scopeSelector,
-_styleProperties: this._styleProperties
-};
-scopeData.key.customStyle = {};
-this.mixin(scopeData.key.customStyle, this.customStyle);
-scope._styleCache.store(this.is, info, scopeData.key, this._styles);
-if (!globalCached) {
-styleCache.store(this.is, Object.create(info), this._ownStyleProperties, this._styles);
-}
-}
-},
-_computeStyleProperties: function (scopeProps) {
-var scope = this._findStyleHost();
-if (!scope._styleProperties) {
-scope._computeStyleProperties();
-}
-var props = Object.create(scope._styleProperties);
-this.mixin(props, propertyUtils.hostPropertiesFromStyles(this._styles));
-scopeProps = scopeProps || propertyUtils.propertyDataFromStyles(scope._styles, this).properties;
-this.mixin(props, scopeProps);
-this.mixin(props, propertyUtils.scopePropertiesFromStyles(this._styles));
-propertyUtils.mixinCustomStyle(props, this.customStyle);
-propertyUtils.reify(props);
-this._styleProperties = props;
-},
-_computeOwnStyleProperties: function () {
-var props = {};
-for (var i = 0, n; i < this._ownStylePropertyNames.length; i++) {
-n = this._ownStylePropertyNames[i];
-props[n] = this._styleProperties[n];
-}
-this._ownStyleProperties = props;
-},
-_scopeCount: 0,
-_applyStyleProperties: function (info) {
-var oldScopeSelector = this._scopeSelector;
-this._scopeSelector = info ? info._scopeSelector : this.is + '-' + this.__proto__._scopeCount++;
-var style = propertyUtils.applyElementStyle(this, this._styleProperties, this._scopeSelector, info && info.style);
-if (!nativeShadow) {
-propertyUtils.applyElementScopeSelector(this, this._scopeSelector, oldScopeSelector, this._scopeCssViaAttr);
-}
-return style;
-},
-serializeValueToAttribute: function (value, attribute, node) {
-node = node || this;
-if (attribute === 'class' && !nativeShadow) {
-var host = node === this ? this.domHost || this.dataHost : this;
-if (host) {
-value = host._scopeElementClass(node, value);
-}
-}
-node = this.shadyRoot && this.shadyRoot._hasDistributed ? Polymer.dom(node) : node;
-serializeValueToAttribute.call(this, value, attribute, node);
-},
-_scopeElementClass: function (element, selector) {
-if (!nativeShadow && !this._scopeCssViaAttr) {
-selector += (selector ? ' ' : '') + SCOPE_NAME + ' ' + this.is + (element._scopeSelector ? ' ' + XSCOPE_NAME + ' ' + element._scopeSelector : '');
-}
-return selector;
-},
-updateStyles: function (properties) {
-if (this.isAttached) {
-if (properties) {
-this.mixin(this.customStyle, properties);
-}
-if (this._needsStyleProperties()) {
-this._updateStyleProperties();
-} else {
-this._styleProperties = null;
-}
-if (this._styleCache) {
-this._styleCache.clear();
-}
-this._updateRootStyles();
-}
-},
-_updateRootStyles: function (root) {
-root = root || this.root;
-var c$ = Polymer.dom(root)._query(function (e) {
-return e.shadyRoot || e.shadowRoot;
-});
-for (var i = 0, l = c$.length, c; i < l && (c = c$[i]); i++) {
-if (c.updateStyles) {
-c.updateStyles();
-}
-}
-}
-});
-Polymer.updateStyles = function (properties) {
-styleDefaults.updateStyles(properties);
-Polymer.Base._updateRootStyles(document);
-};
-var styleCache = new Polymer.StyleCache();
-Polymer.customStyleCache = styleCache;
-var SCOPE_NAME = styleTransformer.SCOPE_NAME;
-var XSCOPE_NAME = propertyUtils.XSCOPE_NAME;
-}());
-Polymer.Base._addFeature({
-_registerFeatures: function () {
-this._prepIs();
-this._prepConstructor();
-this._prepTemplate();
-this._prepStyles();
-this._prepStyleProperties();
-this._prepAnnotations();
-this._prepEffects();
-this._prepBehaviors();
-this._prepPropertyInfo();
-this._prepBindings();
-this._prepShady();
-},
-_prepBehavior: function (b) {
-this._addPropertyEffects(b.properties);
-this._addComplexObserverEffects(b.observers);
-this._addHostAttributes(b.hostAttributes);
-},
-_initFeatures: function () {
-this._setupConfigure();
-this._setupStyleProperties();
-this._setupDebouncers();
-this._registerHost();
-if (this._template) {
-this._poolContent();
-this._beginHosting();
-this._stampTemplate();
-this._endHosting();
-this._marshalAnnotationReferences();
-}
-this._marshalInstanceEffects();
-this._marshalBehaviors();
-this._marshalHostAttributes();
-this._marshalAttributes();
-this._tryReady();
-},
-_marshalBehavior: function (b) {
-if (b.listeners) {
-this._listenListeners(b.listeners);
-}
-}
-});
-(function () {
-var nativeShadow = Polymer.Settings.useNativeShadow;
-var propertyUtils = Polymer.StyleProperties;
-var styleUtil = Polymer.StyleUtil;
-var cssParse = Polymer.CssParse;
-var styleDefaults = Polymer.StyleDefaults;
-var styleTransformer = Polymer.StyleTransformer;
-Polymer({
-is: 'custom-style',
-extends: 'style',
-_template: null,
-properties: { include: String },
-ready: function () {
-this._tryApply();
-},
-attached: function () {
-this._tryApply();
-},
-_tryApply: function () {
-if (!this._appliesToDocument) {
-if (this.parentNode && this.parentNode.localName !== 'dom-module') {
-this._appliesToDocument = true;
-var e = this.__appliedElement || this;
-styleDefaults.addStyle(e);
-if (e.textContent || this.include) {
-this._apply(true);
-} else {
-var self = this;
-var observer = new MutationObserver(function () {
-observer.disconnect();
-self._apply(true);
-});
-observer.observe(e, { childList: true });
-}
-}
-}
-},
-_apply: function (deferProperties) {
-var e = this.__appliedElement || this;
-if (this.include) {
-e.textContent = styleUtil.cssFromModules(this.include, true) + e.textContent;
-}
-if (e.textContent) {
-styleUtil.forEachStyleRule(styleUtil.rulesForStyle(e), function (rule) {
-styleTransformer.documentRule(rule);
-});
-var self = this;
-function fn() {
-self._applyCustomProperties(e);
-}
-if (this._pendingApplyProperties) {
-cancelAnimationFrame(this._pendingApplyProperties);
-this._pendingApplyProperties = null;
-}
-if (deferProperties) {
-this._pendingApplyProperties = requestAnimationFrame(fn);
-} else {
-fn();
-}
-}
-},
-_applyCustomProperties: function (element) {
-this._computeStyleProperties();
-var props = this._styleProperties;
-var rules = styleUtil.rulesForStyle(element);
-element.textContent = styleUtil.toCssText(rules, function (rule) {
-var css = rule.cssText = rule.parsedCssText;
-if (rule.propertyInfo && rule.propertyInfo.cssText) {
-css = cssParse.removeCustomPropAssignment(css);
-rule.cssText = propertyUtils.valueForProperties(css, props);
-}
-});
-}
-});
-}());
-Polymer.Templatizer = {
-properties: { __hideTemplateChildren__: { observer: '_showHideChildren' } },
-_instanceProps: Polymer.nob,
-_parentPropPrefix: '_parent_',
-templatize: function (template) {
-this._templatized = template;
-if (!template._content) {
-template._content = template.content;
-}
-if (template._content._ctor) {
-this.ctor = template._content._ctor;
-this._prepParentProperties(this.ctor.prototype, template);
-return;
-}
-var archetype = Object.create(Polymer.Base);
-this._customPrepAnnotations(archetype, template);
-this._prepParentProperties(archetype, template);
-archetype._prepEffects();
-this._customPrepEffects(archetype);
-archetype._prepBehaviors();
-archetype._prepPropertyInfo();
-archetype._prepBindings();
-archetype._notifyPathUp = this._notifyPathUpImpl;
-archetype._scopeElementClass = this._scopeElementClassImpl;
-archetype.listen = this._listenImpl;
-archetype._showHideChildren = this._showHideChildrenImpl;
-var _constructor = this._constructorImpl;
-var ctor = function TemplateInstance(model, host) {
-_constructor.call(this, model, host);
-};
-ctor.prototype = archetype;
-archetype.constructor = ctor;
-template._content._ctor = ctor;
-this.ctor = ctor;
-},
-_getRootDataHost: function () {
-return this.dataHost && this.dataHost._rootDataHost || this.dataHost;
-},
-_showHideChildrenImpl: function (hide) {
-var c = this._children;
-for (var i = 0; i < c.length; i++) {
-var n = c[i];
-if (Boolean(hide) != Boolean(n.__hideTemplateChildren__)) {
-if (n.nodeType === Node.TEXT_NODE) {
-if (hide) {
-n.__polymerTextContent__ = n.textContent;
-n.textContent = '';
-} else {
-n.textContent = n.__polymerTextContent__;
-}
-} else if (n.style) {
-if (hide) {
-n.__polymerDisplay__ = n.style.display;
-n.style.display = 'none';
-} else {
-n.style.display = n.__polymerDisplay__;
-}
-}
-}
-n.__hideTemplateChildren__ = hide;
-}
-},
-_debounceTemplate: function (fn) {
-Polymer.dom.addDebouncer(this.debounce('_debounceTemplate', fn));
-},
-_flushTemplates: function (debouncerExpired) {
-Polymer.dom.flush();
-},
-_customPrepEffects: function (archetype) {
-var parentProps = archetype._parentProps;
-for (var prop in parentProps) {
-archetype._addPropertyEffect(prop, 'function', this._createHostPropEffector(prop));
-}
-for (var prop in this._instanceProps) {
-archetype._addPropertyEffect(prop, 'function', this._createInstancePropEffector(prop));
-}
-},
-_customPrepAnnotations: function (archetype, template) {
-archetype._template = template;
-var c = template._content;
-if (!c._notes) {
-var rootDataHost = archetype._rootDataHost;
-if (rootDataHost) {
-Polymer.Annotations.prepElement = function () {
-rootDataHost._prepElement();
-};
-}
-c._notes = Polymer.Annotations.parseAnnotations(template);
-Polymer.Annotations.prepElement = null;
-this._processAnnotations(c._notes);
-}
-archetype._notes = c._notes;
-archetype._parentProps = c._parentProps;
-},
-_prepParentProperties: function (archetype, template) {
-var parentProps = this._parentProps = archetype._parentProps;
-if (this._forwardParentProp && parentProps) {
-var proto = archetype._parentPropProto;
-var prop;
-if (!proto) {
-for (prop in this._instanceProps) {
-delete parentProps[prop];
-}
-proto = archetype._parentPropProto = Object.create(null);
-if (template != this) {
-Polymer.Bind.prepareModel(proto);
-Polymer.Base.prepareModelNotifyPath(proto);
-}
-for (prop in parentProps) {
-var parentProp = this._parentPropPrefix + prop;
-var effects = [
-{
-kind: 'function',
-effect: this._createForwardPropEffector(prop),
-fn: Polymer.Bind._functionEffect
-},
-{
-kind: 'notify',
-fn: Polymer.Bind._notifyEffect,
-effect: { event: Polymer.CaseMap.camelToDashCase(parentProp) + '-changed' }
-}
-];
-Polymer.Bind._createAccessors(proto, parentProp, effects);
-}
-}
-var self = this;
-if (template != this) {
-Polymer.Bind.prepareInstance(template);
-template._forwardParentProp = function (source, value) {
-self._forwardParentProp(source, value);
-};
-}
-this._extendTemplate(template, proto);
-template._pathEffector = function (path, value, fromAbove) {
-return self._pathEffectorImpl(path, value, fromAbove);
-};
-}
-},
-_createForwardPropEffector: function (prop) {
-return function (source, value) {
-this._forwardParentProp(prop, value);
-};
-},
-_createHostPropEffector: function (prop) {
-var prefix = this._parentPropPrefix;
-return function (source, value) {
-this.dataHost._templatized[prefix + prop] = value;
-};
-},
-_createInstancePropEffector: function (prop) {
-return function (source, value, old, fromAbove) {
-if (!fromAbove) {
-this.dataHost._forwardInstanceProp(this, prop, value);
-}
-};
-},
-_extendTemplate: function (template, proto) {
-var n$ = Object.getOwnPropertyNames(proto);
-for (var i = 0, n; i < n$.length && (n = n$[i]); i++) {
-var val = template[n];
-var pd = Object.getOwnPropertyDescriptor(proto, n);
-Object.defineProperty(template, n, pd);
-if (val !== undefined) {
-template._propertySetter(n, val);
-}
-}
-},
-_showHideChildren: function (hidden) {
-},
-_forwardInstancePath: function (inst, path, value) {
-},
-_forwardInstanceProp: function (inst, prop, value) {
-},
-_notifyPathUpImpl: function (path, value) {
-var dataHost = this.dataHost;
-var dot = path.indexOf('.');
-var root = dot < 0 ? path : path.slice(0, dot);
-dataHost._forwardInstancePath.call(dataHost, this, path, value);
-if (root in dataHost._parentProps) {
-dataHost._templatized.notifyPath(dataHost._parentPropPrefix + path, value);
-}
-},
-_pathEffectorImpl: function (path, value, fromAbove) {
-if (this._forwardParentPath) {
-if (path.indexOf(this._parentPropPrefix) === 0) {
-var subPath = path.substring(this._parentPropPrefix.length);
-var model = this._modelForPath(subPath);
-if (model in this._parentProps) {
-this._forwardParentPath(subPath, value);
-}
-}
-}
-Polymer.Base._pathEffector.call(this._templatized, path, value, fromAbove);
-},
-_constructorImpl: function (model, host) {
-this._rootDataHost = host._getRootDataHost();
-this._setupConfigure(model);
-this._registerHost(host);
-this._beginHosting();
-this.root = this.instanceTemplate(this._template);
-this.root.__noContent = !this._notes._hasContent;
-this.root.__styleScoped = true;
-this._endHosting();
-this._marshalAnnotatedNodes();
-this._marshalInstanceEffects();
-this._marshalAnnotatedListeners();
-var children = [];
-for (var n = this.root.firstChild; n; n = n.nextSibling) {
-children.push(n);
-n._templateInstance = this;
-}
-this._children = children;
-if (host.__hideTemplateChildren__) {
-this._showHideChildren(true);
-}
-this._tryReady();
-},
-_listenImpl: function (node, eventName, methodName) {
-var model = this;
-var host = this._rootDataHost;
-var handler = host._createEventHandler(node, eventName, methodName);
-var decorated = function (e) {
-e.model = model;
-handler(e);
-};
-host._listen(node, eventName, decorated);
-},
-_scopeElementClassImpl: function (node, value) {
-var host = this._rootDataHost;
-if (host) {
-return host._scopeElementClass(node, value);
-}
-},
-stamp: function (model) {
-model = model || {};
-if (this._parentProps) {
-var templatized = this._templatized;
-for (var prop in this._parentProps) {
-model[prop] = templatized[this._parentPropPrefix + prop];
-}
-}
-return new this.ctor(model, this);
-},
-modelForElement: function (el) {
-var model;
-while (el) {
-if (model = el._templateInstance) {
-if (model.dataHost != this) {
-el = model.dataHost;
-} else {
-return model;
-}
-} else {
-el = el.parentNode;
-}
-}
-}
-};
-Polymer({
-is: 'dom-template',
-extends: 'template',
-_template: null,
-behaviors: [Polymer.Templatizer],
-ready: function () {
-this.templatize(this);
-}
-});
-Polymer._collections = new WeakMap();
-Polymer.Collection = function (userArray) {
-Polymer._collections.set(userArray, this);
-this.userArray = userArray;
-this.store = userArray.slice();
-this.initMap();
-};
-Polymer.Collection.prototype = {
-constructor: Polymer.Collection,
-initMap: function () {
-var omap = this.omap = new WeakMap();
-var pmap = this.pmap = {};
-var s = this.store;
-for (var i = 0; i < s.length; i++) {
-var item = s[i];
-if (item && typeof item == 'object') {
-omap.set(item, i);
-} else {
-pmap[item] = i;
-}
-}
-},
-add: function (item) {
-var key = this.store.push(item) - 1;
-if (item && typeof item == 'object') {
-this.omap.set(item, key);
-} else {
-this.pmap[item] = key;
-}
-return '#' + key;
-},
-removeKey: function (key) {
-key = this._parseKey(key);
-this._removeFromMap(this.store[key]);
-delete this.store[key];
-},
-_removeFromMap: function (item) {
-if (item && typeof item == 'object') {
-this.omap.delete(item);
-} else {
-delete this.pmap[item];
-}
-},
-remove: function (item) {
-var key = this.getKey(item);
-this.removeKey(key);
-return key;
-},
-getKey: function (item) {
-var key;
-if (item && typeof item == 'object') {
-key = this.omap.get(item);
-} else {
-key = this.pmap[item];
-}
-if (key != undefined) {
-return '#' + key;
-}
-},
-getKeys: function () {
-return Object.keys(this.store).map(function (key) {
-return '#' + key;
-});
-},
-_parseKey: function (key) {
-if (key[0] == '#') {
-return key.slice(1);
-}
-throw new Error('unexpected key ' + key);
-},
-setItem: function (key, item) {
-key = this._parseKey(key);
-var old = this.store[key];
-if (old) {
-this._removeFromMap(old);
-}
-if (item && typeof item == 'object') {
-this.omap.set(item, key);
-} else {
-this.pmap[item] = key;
-}
-this.store[key] = item;
-},
-getItem: function (key) {
-key = this._parseKey(key);
-return this.store[key];
-},
-getItems: function () {
-var items = [], store = this.store;
-for (var key in store) {
-items.push(store[key]);
-}
-return items;
-},
-_applySplices: function (splices) {
-var keyMap = {}, key;
-for (var i = 0, s; i < splices.length && (s = splices[i]); i++) {
-s.addedKeys = [];
-for (var j = 0; j < s.removed.length; j++) {
-key = this.getKey(s.removed[j]);
-keyMap[key] = keyMap[key] ? null : -1;
-}
-for (var j = 0; j < s.addedCount; j++) {
-var item = this.userArray[s.index + j];
-key = this.getKey(item);
-key = key === undefined ? this.add(item) : key;
-keyMap[key] = keyMap[key] ? null : 1;
-s.addedKeys.push(key);
-}
-}
-var removed = [];
-var added = [];
-for (var key in keyMap) {
-if (keyMap[key] < 0) {
-this.removeKey(key);
-removed.push(key);
-}
-if (keyMap[key] > 0) {
-added.push(key);
-}
-}
-return [{
-removed: removed,
-added: added
-}];
-}
-};
-Polymer.Collection.get = function (userArray) {
-return Polymer._collections.get(userArray) || new Polymer.Collection(userArray);
-};
-Polymer.Collection.applySplices = function (userArray, splices) {
-var coll = Polymer._collections.get(userArray);
-return coll ? coll._applySplices(splices) : null;
-};
-Polymer({
-is: 'dom-repeat',
-extends: 'template',
-_template: null,
-properties: {
-items: { type: Array },
-as: {
-type: String,
-value: 'item'
-},
-indexAs: {
-type: String,
-value: 'index'
-},
-sort: {
-type: Function,
-observer: '_sortChanged'
-},
-filter: {
-type: Function,
-observer: '_filterChanged'
-},
-observe: {
-type: String,
-observer: '_observeChanged'
-},
-delay: Number,
-initialCount: {
-type: Number,
-observer: '_initializeChunking'
-},
-targetFramerate: {
-type: Number,
-value: 20
-},
-_targetFrameTime: { computed: '_computeFrameTime(targetFramerate)' }
-},
-behaviors: [Polymer.Templatizer],
-observers: ['_itemsChanged(items.*)'],
-created: function () {
-this._instances = [];
-this._pool = [];
-this._limit = Infinity;
-var self = this;
-this._boundRenderChunk = function () {
-self._renderChunk();
-};
-},
-detached: function () {
-for (var i = 0; i < this._instances.length; i++) {
-this._detachInstance(i);
-}
-},
-attached: function () {
-var parent = Polymer.dom(Polymer.dom(this).parentNode);
-for (var i = 0; i < this._instances.length; i++) {
-this._attachInstance(i, parent);
-}
-},
-ready: function () {
-this._instanceProps = { __key__: true };
-this._instanceProps[this.as] = true;
-this._instanceProps[this.indexAs] = true;
-if (!this.ctor) {
-this.templatize(this);
-}
-},
-_sortChanged: function (sort) {
-var dataHost = this._getRootDataHost();
-this._sortFn = sort && (typeof sort == 'function' ? sort : function () {
-return dataHost[sort].apply(dataHost, arguments);
-});
-this._needFullRefresh = true;
-if (this.items) {
-this._debounceTemplate(this._render);
-}
-},
-_filterChanged: function (filter) {
-var dataHost = this._getRootDataHost();
-this._filterFn = filter && (typeof filter == 'function' ? filter : function () {
-return dataHost[filter].apply(dataHost, arguments);
-});
-this._needFullRefresh = true;
-if (this.items) {
-this._debounceTemplate(this._render);
-}
-},
-_computeFrameTime: function (rate) {
-return Math.ceil(1000 / rate);
-},
-_initializeChunking: function () {
-if (this.initialCount) {
-this._limit = this.initialCount;
-this._chunkCount = this.initialCount;
-this._lastChunkTime = performance.now();
-}
-},
-_tryRenderChunk: function () {
-if (this.items && this._limit < this.items.length) {
-this.debounce('renderChunk', this._requestRenderChunk);
-}
-},
-_requestRenderChunk: function () {
-requestAnimationFrame(this._boundRenderChunk);
-},
-_renderChunk: function () {
-var currChunkTime = performance.now();
-var ratio = this._targetFrameTime / (currChunkTime - this._lastChunkTime);
-this._chunkCount = Math.round(this._chunkCount * ratio) || 1;
-this._limit += this._chunkCount;
-this._lastChunkTime = currChunkTime;
-this._debounceTemplate(this._render);
-},
-_observeChanged: function () {
-this._observePaths = this.observe && this.observe.replace('.*', '.').split(' ');
-},
-_itemsChanged: function (change) {
-if (change.path == 'items') {
-if (Array.isArray(this.items)) {
-this.collection = Polymer.Collection.get(this.items);
-} else if (!this.items) {
-this.collection = null;
-} else {
-this._error(this._logf('dom-repeat', 'expected array for `items`,' + ' found', this.items));
-}
-this._keySplices = [];
-this._indexSplices = [];
-this._needFullRefresh = true;
-this._initializeChunking();
-this._debounceTemplate(this._render);
-} else if (change.path == 'items.splices') {
-this._keySplices = this._keySplices.concat(change.value.keySplices);
-this._indexSplices = this._indexSplices.concat(change.value.indexSplices);
-this._debounceTemplate(this._render);
-} else {
-var subpath = change.path.slice(6);
-this._forwardItemPath(subpath, change.value);
-this._checkObservedPaths(subpath);
-}
-},
-_checkObservedPaths: function (path) {
-if (this._observePaths) {
-path = path.substring(path.indexOf('.') + 1);
-var paths = this._observePaths;
-for (var i = 0; i < paths.length; i++) {
-if (path.indexOf(paths[i]) === 0) {
-this._needFullRefresh = true;
-if (this.delay) {
-this.debounce('render', this._render, this.delay);
-} else {
-this._debounceTemplate(this._render);
-}
-return;
-}
-}
-}
-},
-render: function () {
-this._needFullRefresh = true;
-this._debounceTemplate(this._render);
-this._flushTemplates();
-},
-_render: function () {
-var c = this.collection;
-if (this._needFullRefresh) {
-this._applyFullRefresh();
-this._needFullRefresh = false;
-} else if (this._keySplices.length) {
-if (this._sortFn) {
-this._applySplicesUserSort(this._keySplices);
-} else {
-if (this._filterFn) {
-this._applyFullRefresh();
-} else {
-this._applySplicesArrayOrder(this._indexSplices);
-}
-}
-} else {
-}
-this._keySplices = [];
-this._indexSplices = [];
-var keyToIdx = this._keyToInstIdx = {};
-for (var i = this._instances.length - 1; i >= 0; i--) {
-var inst = this._instances[i];
-if (inst.isPlaceholder && i < this._limit) {
-inst = this._insertInstance(i, inst.__key__);
-} else if (!inst.isPlaceholder && i >= this._limit) {
-inst = this._downgradeInstance(i, inst.__key__);
-}
-keyToIdx[inst.__key__] = i;
-if (!inst.isPlaceholder) {
-inst.__setProperty(this.indexAs, i, true);
-}
-}
-this._pool.length = 0;
-this.fire('dom-change');
-this._tryRenderChunk();
-},
-_applyFullRefresh: function () {
-var c = this.collection;
-var keys;
-if (this._sortFn) {
-keys = c ? c.getKeys() : [];
-} else {
-keys = [];
-var items = this.items;
-if (items) {
-for (var i = 0; i < items.length; i++) {
-keys.push(c.getKey(items[i]));
-}
-}
-}
-var self = this;
-if (this._filterFn) {
-keys = keys.filter(function (a) {
-return self._filterFn(c.getItem(a));
-});
-}
-if (this._sortFn) {
-keys.sort(function (a, b) {
-return self._sortFn(c.getItem(a), c.getItem(b));
-});
-}
-for (var i = 0; i < keys.length; i++) {
-var key = keys[i];
-var inst = this._instances[i];
-if (inst) {
-inst.__key__ = key;
-if (!inst.isPlaceholder && i < this._limit) {
-inst.__setProperty(this.as, c.getItem(key), true);
-}
-} else if (i < this._limit) {
-this._insertInstance(i, key);
-} else {
-this._insertPlaceholder(i, key);
-}
-}
-for (var j = this._instances.length - 1; j >= i; j--) {
-this._detachAndRemoveInstance(j);
-}
-},
-_numericSort: function (a, b) {
-return a - b;
-},
-_applySplicesUserSort: function (splices) {
-var c = this.collection;
-var instances = this._instances;
-var keyMap = {};
-for (var i = 0, s; i < splices.length && (s = splices[i]); i++) {
-for (var j = 0; j < s.removed.length; j++) {
-var key = s.removed[j];
-keyMap[key] = keyMap[key] ? null : -1;
-}
-for (var j = 0; j < s.added.length; j++) {
-var key = s.added[j];
-keyMap[key] = keyMap[key] ? null : 1;
-}
-}
-var removedIdxs = [];
-var addedKeys = [];
-for (var key in keyMap) {
-if (keyMap[key] === -1) {
-removedIdxs.push(this._keyToInstIdx[key]);
-}
-if (keyMap[key] === 1) {
-addedKeys.push(key);
-}
-}
-if (removedIdxs.length) {
-removedIdxs.sort(this._numericSort);
-for (var i = removedIdxs.length - 1; i >= 0; i--) {
-var idx = removedIdxs[i];
-if (idx !== undefined) {
-this._detachAndRemoveInstance(idx);
-}
-}
-}
-var self = this;
-if (addedKeys.length) {
-if (this._filterFn) {
-addedKeys = addedKeys.filter(function (a) {
-return self._filterFn(c.getItem(a));
-});
-}
-addedKeys.sort(function (a, b) {
-return self._sortFn(c.getItem(a), c.getItem(b));
-});
-var start = 0;
-for (var i = 0; i < addedKeys.length; i++) {
-start = this._insertRowUserSort(start, addedKeys[i]);
-}
-}
-},
-_insertRowUserSort: function (start, key) {
-var c = this.collection;
-var item = c.getItem(key);
-var end = this._instances.length - 1;
-var idx = -1;
-while (start <= end) {
-var mid = start + end >> 1;
-var midKey = this._instances[mid].__key__;
-var cmp = this._sortFn(c.getItem(midKey), item);
-if (cmp < 0) {
-start = mid + 1;
-} else if (cmp > 0) {
-end = mid - 1;
-} else {
-idx = mid;
-break;
-}
-}
-if (idx < 0) {
-idx = end + 1;
-}
-this._insertPlaceholder(idx, key);
-return idx;
-},
-_applySplicesArrayOrder: function (splices) {
-var c = this.collection;
-for (var i = 0, s; i < splices.length && (s = splices[i]); i++) {
-for (var j = 0; j < s.removed.length; j++) {
-this._detachAndRemoveInstance(s.index);
-}
-for (var j = 0; j < s.addedKeys.length; j++) {
-this._insertPlaceholder(s.index + j, s.addedKeys[j]);
-}
-}
-},
-_detachInstance: function (idx) {
-var inst = this._instances[idx];
-if (!inst.isPlaceholder) {
-for (var i = 0; i < inst._children.length; i++) {
-var el = inst._children[i];
-Polymer.dom(inst.root).appendChild(el);
-}
-return inst;
-}
-},
-_attachInstance: function (idx, parent) {
-var inst = this._instances[idx];
-if (!inst.isPlaceholder) {
-parent.insertBefore(inst.root, this);
-}
-},
-_detachAndRemoveInstance: function (idx) {
-var inst = this._detachInstance(idx);
-if (inst) {
-this._pool.push(inst);
-}
-this._instances.splice(idx, 1);
-},
-_insertPlaceholder: function (idx, key) {
-this._instances.splice(idx, 0, {
-isPlaceholder: true,
-__key__: key
-});
-},
-_stampInstance: function (idx, key) {
-var model = { __key__: key };
-model[this.as] = this.collection.getItem(key);
-model[this.indexAs] = idx;
-return this.stamp(model);
-},
-_insertInstance: function (idx, key) {
-var inst = this._pool.pop();
-if (inst) {
-inst.__setProperty(this.as, this.collection.getItem(key), true);
-inst.__setProperty('__key__', key, true);
-} else {
-inst = this._stampInstance(idx, key);
-}
-var beforeRow = this._instances[idx + 1];
-var beforeNode = beforeRow && !beforeRow.isPlaceholder ? beforeRow._children[0] : this;
-var parentNode = Polymer.dom(this).parentNode;
-Polymer.dom(parentNode).insertBefore(inst.root, beforeNode);
-this._instances[idx] = inst;
-return inst;
-},
-_downgradeInstance: function (idx, key) {
-var inst = this._detachInstance(idx);
-if (inst) {
-this._pool.push(inst);
-}
-inst = {
-isPlaceholder: true,
-__key__: key
-};
-this._instances[idx] = inst;
-return inst;
-},
-_showHideChildren: function (hidden) {
-for (var i = 0; i < this._instances.length; i++) {
-this._instances[i]._showHideChildren(hidden);
-}
-},
-_forwardInstanceProp: function (inst, prop, value) {
-if (prop == this.as) {
-var idx;
-if (this._sortFn || this._filterFn) {
-idx = this.items.indexOf(this.collection.getItem(inst.__key__));
-} else {
-idx = inst[this.indexAs];
-}
-this.set('items.' + idx, value);
-}
-},
-_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) {
-var i$ = this._instances;
-for (var i = 0, inst; i < i$.length && (inst = i$[i]); i++) {
-if (!inst.isPlaceholder) {
-inst.__setProperty(prop, value, true);
-}
-}
-},
-_forwardParentPath: function (path, value) {
-var i$ = this._instances;
-for (var i = 0, inst; i < i$.length && (inst = i$[i]); i++) {
-if (!inst.isPlaceholder) {
-inst._notifyPath(path, value, true);
-}
-}
-},
-_forwardItemPath: function (path, value) {
-if (this._keyToInstIdx) {
-var dot = path.indexOf('.');
-var key = path.substring(0, dot < 0 ? path.length : dot);
-var idx = this._keyToInstIdx[key];
-var inst = this._instances[idx];
-if (inst && !inst.isPlaceholder) {
-if (dot >= 0) {
-path = this.as + '.' + path.substring(dot + 1);
-inst._notifyPath(path, value, true);
-} else {
-inst.__setProperty(this.as, value, true);
-}
-}
-}
-},
-itemForElement: function (el) {
-var instance = this.modelForElement(el);
-return instance && instance[this.as];
-},
-keyForElement: function (el) {
-var instance = this.modelForElement(el);
-return instance && instance.__key__;
-},
-indexForElement: function (el) {
-var instance = this.modelForElement(el);
-return instance && instance[this.indexAs];
-}
-});
-Polymer({
-is: 'array-selector',
-_template: null,
-properties: {
-items: {
-type: Array,
-observer: 'clearSelection'
-},
-multi: {
-type: Boolean,
-value: false,
-observer: 'clearSelection'
-},
-selected: {
-type: Object,
-notify: true
-},
-selectedItem: {
-type: Object,
-notify: true
-},
-toggle: {
-type: Boolean,
-value: false
-}
-},
-clearSelection: function () {
-if (Array.isArray(this.selected)) {
-for (var i = 0; i < this.selected.length; i++) {
-this.unlinkPaths('selected.' + i);
-}
-} else {
-this.unlinkPaths('selected');
-this.unlinkPaths('selectedItem');
-}
-if (this.multi) {
-if (!this.selected || this.selected.length) {
-this.selected = [];
-this._selectedColl = Polymer.Collection.get(this.selected);
-}
-} else {
-this.selected = null;
-this._selectedColl = null;
-}
-this.selectedItem = null;
-},
-isSelected: function (item) {
-if (this.multi) {
-return this._selectedColl.getKey(item) !== undefined;
-} else {
-return this.selected == item;
-}
-},
-deselect: function (item) {
-if (this.multi) {
-if (this.isSelected(item)) {
-var skey = this._selectedColl.getKey(item);
-this.arrayDelete('selected', item);
-this.unlinkPaths('selected.' + skey);
-}
-} else {
-this.selected = null;
-this.selectedItem = null;
-this.unlinkPaths('selected');
-this.unlinkPaths('selectedItem');
-}
-},
-select: function (item) {
-var icol = Polymer.Collection.get(this.items);
-var key = icol.getKey(item);
-if (this.multi) {
-if (this.isSelected(item)) {
-if (this.toggle) {
-this.deselect(item);
-}
-} else {
-this.push('selected', item);
-var skey = this._selectedColl.getKey(item);
-this.linkPaths('selected.' + skey, 'items.' + key);
-}
-} else {
-if (this.toggle && item == this.selected) {
-this.deselect();
-} else {
-this.selected = item;
-this.selectedItem = item;
-this.linkPaths('selected', 'items.' + key);
-this.linkPaths('selectedItem', 'items.' + key);
-}
-}
-}
-});
-Polymer({
-is: 'dom-if',
-extends: 'template',
-_template: null,
-properties: {
-'if': {
-type: Boolean,
-value: false,
-observer: '_queueRender'
-},
-restamp: {
-type: Boolean,
-value: false,
-observer: '_queueRender'
-}
-},
-behaviors: [Polymer.Templatizer],
-_queueRender: function () {
-this._debounceTemplate(this._render);
-},
-detached: function () {
-this._teardownInstance();
-},
-attached: function () {
-if (this.if && this.ctor) {
-this.async(this._ensureInstance);
-}
-},
-render: function () {
-this._flushTemplates();
-},
-_render: function () {
-if (this.if) {
-if (!this.ctor) {
-this.templatize(this);
-}
-this._ensureInstance();
-this._showHideChildren();
-} else if (this.restamp) {
-this._teardownInstance();
-}
-if (!this.restamp && this._instance) {
-this._showHideChildren();
-}
-if (this.if != this._lastIf) {
-this.fire('dom-change');
-this._lastIf = this.if;
-}
-},
-_ensureInstance: function () {
-if (!this._instance) {
-var parentNode = Polymer.dom(this).parentNode;
-if (parentNode) {
-var parent = Polymer.dom(parentNode);
-this._instance = this.stamp();
-var root = this._instance.root;
-parent.insertBefore(root, this);
-}
-}
-},
-_teardownInstance: function () {
-if (this._instance) {
-var c$ = this._instance._children;
-if (c$) {
-var parent = Polymer.dom(Polymer.dom(c$[0]).parentNode);
-for (var i = 0, n; i < c$.length && (n = c$[i]); i++) {
-parent.removeChild(n);
-}
-}
-this._instance = null;
-}
-},
-_showHideChildren: function () {
-var hidden = this.__hideTemplateChildren__ || !this.if;
-if (this._instance) {
-this._instance._showHideChildren(hidden);
-}
-},
-_forwardParentProp: function (prop, value) {
-if (this._instance) {
-this._instance[prop] = value;
-}
-},
-_forwardParentPath: function (path, value) {
-if (this._instance) {
-this._instance._notifyPath(path, value, true);
-}
-}
-});
-Polymer({
-is: 'dom-bind',
-extends: 'template',
-_template: null,
-created: function () {
-var self = this;
-Polymer.RenderStatus.whenReady(function () {
-self._markImportsReady();
-});
-},
-_ensureReady: function () {
-if (!this._readied) {
-this._readySelf();
-}
-},
-_markImportsReady: function () {
-this._importsReady = true;
-this._ensureReady();
-},
-_registerFeatures: function () {
-this._prepConstructor();
-},
-_insertChildren: function () {
-var parentDom = Polymer.dom(Polymer.dom(this).parentNode);
-parentDom.insertBefore(this.root, this);
-},
-_removeChildren: function () {
-if (this._children) {
-for (var i = 0; i < this._children.length; i++) {
-this.root.appendChild(this._children[i]);
-}
-}
-},
-_initFeatures: function () {
-},
-_scopeElementClass: function (element, selector) {
-if (this.dataHost) {
-return this.dataHost._scopeElementClass(element, selector);
-} else {
-return selector;
-}
-},
-_prepConfigure: function () {
-var config = {};
-for (var prop in this._propertyEffects) {
-config[prop] = this[prop];
-}
-var setupConfigure = this._setupConfigure;
-this._setupConfigure = function () {
-setupConfigure.call(this, config);
-};
-},
-attached: function () {
-if (this._importsReady) {
-this.render();
-}
-},
-detached: function () {
-this._removeChildren();
-},
-render: function () {
-this._ensureReady();
-if (!this._children) {
-this._template = this;
-this._prepAnnotations();
-this._prepEffects();
-this._prepBehaviors();
-this._prepConfigure();
-this._prepBindings();
-this._prepPropertyInfo();
-Polymer.Base._initFeatures.call(this);
-this._children = Polymer.DomApi.arrayCopyChildNodes(this.root);
-}
-this._insertChildren();
-this.fire('dom-change');
-}
-});
/**
* `IronResizableBehavior` is a behavior that can be used in Polymer elements to
* coordinate the flow of resize events between "resizers" (elements that control the
* size or hidden state of their children) and "resizables" (elements that need to be
* notified when they are resized or un-hidden by their parents in order to take
* action on their new measurements).
+ *
* Elements that perform measurement should add the `IronResizableBehavior` behavior to
* their element definition and listen for the `iron-resize` event on themselves.
* This event will be fired when they become showing after having been hidden,
* when they are resized explicitly by another resizable, or when the window has been
* resized.
+ *
* Note, the `iron-resize` event is non-bubbling.
*
* @polymerBehavior Polymer.IronResizableBehavior
@@ -9262,11 +1712,670 @@ this.fire('dom-change');
}
};
(function() {
+ 'use strict';
+
+ /**
+ * Chrome uses an older version of DOM Level 3 Keyboard Events
+ *
+ * Most keys are labeled as text, but some are Unicode codepoints.
+ * Values taken from: http://www.w3.org/TR/2007/WD-DOM-Level-3-Events-20071221/keyset.html#KeySet-Set
+ */
+ var KEY_IDENTIFIER = {
+ 'U+0008': 'backspace',
+ 'U+0009': 'tab',
+ 'U+001B': 'esc',
+ 'U+0020': 'space',
+ 'U+007F': 'del'
+ };
+
+ /**
+ * Special table for KeyboardEvent.keyCode.
+ * KeyboardEvent.keyIdentifier is better, and KeyBoardEvent.key is even better
+ * than that.
+ *
+ * Values from: https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent.keyCode#Value_of_keyCode
+ */
+ 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: '*'
+ };
+
+ /**
+ * MODIFIER_KEYS maps the short name for modifier keys used in a key
+ * combo string to the property name that references those same keys
+ * in a KeyboardEvent instance.
+ */
+ var MODIFIER_KEYS = {
+ 'shift': 'shiftKey',
+ 'ctrl': 'ctrlKey',
+ 'alt': 'altKey',
+ 'meta': 'metaKey'
+ };
+
+ /**
+ * KeyboardEvent.key is mostly represented by printable character made by
+ * the keyboard, with unprintable keys labeled nicely.
+ *
+ * However, on OS X, Alt+char can make a Unicode character that follows an
+ * Apple-specific mapping. In this case, we fall back to .keyCode.
+ */
+ var KEY_CHAR = /[a-z0-9*]/;
+
+ /**
+ * Matches a keyIdentifier string.
+ */
+ var IDENT_CHAR = /U\+/;
+
+ /**
+ * Matches arrow keys in Gecko 27.0+
+ */
+ var ARROW_KEY = /^arrow/;
+
+ /**
+ * Matches space keys everywhere (notably including IE10's exceptional name
+ * `spacebar`).
+ */
+ var SPACE_KEY = /^space(bar)?/;
+
+ /**
+ * Matches ESC key.
+ *
+ * Value from: http://w3c.github.io/uievents-key/#key-Escape
+ */
+ var ESC_KEY = /^escape$/;
+
+ /**
+ * Transforms the key.
+ * @param {string} key The KeyBoardEvent.key
+ * @param {Boolean} [noSpecialChars] Limits the transformation to
+ * alpha-numeric characters.
+ */
+ 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') {
+ // numpad '*' can map to Multiply on IE/Windows
+ 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) {
+ // ascii a-z
+ // lowercase is 32 offset from uppercase
+ validKey = String.fromCharCode(32 + keyCode);
+ } else if (keyCode >= 112 && keyCode <= 123) {
+ // function keys f1-f12
+ validKey = 'f' + (keyCode - 112);
+ } else if (keyCode >= 48 && keyCode <= 57) {
+ // top 0-9 keys
+ validKey = String(keyCode - 48);
+ } else if (keyCode >= 96 && keyCode <= 105) {
+ // num pad 0-9
+ validKey = String(keyCode - 96);
+ } else {
+ validKey = KEY_CODE[keyCode];
+ }
+ }
+ return validKey;
+ }
+
+ /**
+ * Calculates the normalized key for a KeyboardEvent.
+ * @param {KeyboardEvent} keyEvent
+ * @param {Boolean} [noSpecialChars] Set to true to limit keyEvent.key
+ * transformation to alpha-numeric chars. This is useful with key
+ * combinations like shift + 2, which on FF for MacOS produces
+ * keyEvent.key = @
+ * To get 2 returned, set noSpecialChars = true
+ * To get @ returned, set noSpecialChars = false
+ */
+ function normalizedKeyForEvent(keyEvent, noSpecialChars) {
+ // Fall back from .key, to .keyIdentifier, to .keyCode, and then to
+ // .detail.key to support artificial keyboard events.
+ return transformKey(keyEvent.key, noSpecialChars) ||
+ transformKeyIdentifier(keyEvent.keyIdentifier) ||
+ transformKeyCode(keyEvent.keyCode) ||
+ transformKey(keyEvent.detail.key, noSpecialChars) || '';
+ }
+
+ function keyComboMatchesEvent(keyCombo, event) {
+ // For combos with modifiers we support only alpha-numeric keys
+ 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` provides a normalized interface for processing
+ * keyboard commands that pertain to [WAI-ARIA best practices](http://www.w3.org/TR/wai-aria-practices/#kbd_general_binding).
+ * The element takes care of browser differences with respect to Keyboard events
+ * and uses an expressive syntax to filter key presses.
+ *
+ * Use the `keyBindings` prototype property to express what combination of keys
+ * will trigger the event to fire.
+ *
+ * Use the `key-event-target` attribute to set up event handlers on a specific
+ * node.
+ * The `keys-pressed` event will fire when one of the key combinations set with the
+ * `keys` property is pressed.
+ *
+ * @demo demo/index.html
+ * @polymerBehavior
+ */
+ Polymer.IronA11yKeysBehavior = {
+ properties: {
+ /**
+ * The HTMLElement that will be firing relevant KeyboardEvents.
+ */
+ keyEventTarget: {
+ type: Object,
+ value: function() {
+ return this;
+ }
+ },
+
+ /**
+ * If true, this property will cause the implementing element to
+ * automatically stop propagation on any handled KeyboardEvents.
+ */
+ stopKeyboardEventPropagation: {
+ type: Boolean,
+ value: false
+ },
+
+ _boundKeyHandlers: {
+ type: Array,
+ value: function() {
+ return [];
+ }
+ },
+
+ // We use this due to a limitation in IE10 where instances will have
+ // own properties of everything on the "prototype".
+ _imperativeKeyBindings: {
+ type: Object,
+ value: function() {
+ return {};
+ }
+ }
+ },
+
+ observers: [
+ '_resetKeyEventListeners(keyEventTarget, _boundKeyHandlers)'
+ ],
+
+ keyBindings: {},
+
+ registered: function() {
+ this._prepKeyBindings();
+ },
+
+ attached: function() {
+ this._listenKeyEventListeners();
+ },
+
+ detached: function() {
+ this._unlistenKeyEventListeners();
+ },
+
+ /**
+ * Can be used to imperatively add a key binding to the implementing
+ * element. This is the imperative equivalent of declaring a keybinding
+ * in the `keyBindings` prototype property.
+ */
+ addOwnKeyBinding: function(eventString, handlerName) {
+ this._imperativeKeyBindings[eventString] = handlerName;
+ this._prepKeyBindings();
+ this._resetKeyEventListeners();
+ },
+
+ /**
+ * When called, will remove all imperatively-added key bindings.
+ */
+ removeOwnKeyBindings: function() {
+ this._imperativeKeyBindings = {};
+ this._prepKeyBindings();
+ this._resetKeyEventListeners();
+ },
+
+ /**
+ * Returns true if a keyboard event matches `eventString`.
+ *
+ * @param {KeyboardEvent} event
+ * @param {string} eventString
+ * @return {boolean}
+ */
+ 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]);
+ }
+
+ // Give precedence to combos with modifiers to be checked first.
+ 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() {
+ 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) {
+ // My kingdom for block-scope binding and destructuring assignment..
+ 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 has been already prevented, don't do anything
+ 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);
+ // exit the loop if eventDefault was prevented
+ 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` allows an element to respond to scroll events from a
+ * designated scroll target.
+ *
+ * Elements that consume this behavior can override the `_scrollHandler`
+ * method to add logic on the scroll event.
+ *
+ * @demo demo/scrolling-region.html Scrolling Region
+ * @demo demo/document.html Document Element
+ * @polymerBehavior
+ */
+ Polymer.IronScrollTargetBehavior = {
+
+ properties: {
+
+ /**
+ * Specifies the element that will handle the scroll event
+ * on the behalf of the current element. This is typically a reference to an `Element`,
+ * but there are a few more posibilities:
+ *
+ * ### Elements id
+ *
+ *```html
+ * <div id="scrollable-element" style="overflow-y: auto;">
+ * <x-element scroll-target="scrollable-element">
+ * Content
+ * </x-element>
+ * </div>
+ *```
+ * In this case, `scrollTarget` will point to the outer div element. Alternatively,
+ * you can set the property programatically:
+ *
+ *```js
+ * appHeader.scrollTarget = document.querySelector('#scrollable-element');
+ *```
+ *
+ * @type {HTMLElement}
+ */
+ scrollTarget: {
+ type: HTMLElement,
+ value: function() {
+ return this._defaultScrollTarget;
+ }
+ }
+ },
+
+ observers: [
+ '_scrollTargetChanged(scrollTarget, isAttached)'
+ ],
+
+ _scrollTargetChanged: function(scrollTarget, isAttached) {
+ // Remove lister to the current scroll target
+ if (this._oldScrollTarget) {
+ if (this._oldScrollTarget === this._doc) {
+ window.removeEventListener('scroll', this._boundScrollHandler);
+ } else if (this._oldScrollTarget.removeEventListener) {
+ this._oldScrollTarget.removeEventListener('scroll', this._boundScrollHandler);
+ }
+ this._oldScrollTarget = null;
+ }
+ if (isAttached) {
+ // Support element id references
+ if (typeof scrollTarget === 'string') {
+
+ var host = this.domHost;
+ this.scrollTarget = host && host.$ ? host.$[scrollTarget] :
+ Polymer.dom(this.ownerDocument).querySelector('#' + scrollTarget);
+
+ } else if (this._scrollHandler) {
+
+ this._boundScrollHandler = this._boundScrollHandler || this._scrollHandler.bind(this);
+ // Add a new listener
+ if (scrollTarget === this._doc) {
+ window.addEventListener('scroll', this._boundScrollHandler);
+ if (this._scrollTop !== 0 || this._scrollLeft !== 0) {
+ this._scrollHandler();
+ }
+ } else if (scrollTarget && scrollTarget.addEventListener) {
+ scrollTarget.addEventListener('scroll', this._boundScrollHandler);
+ }
+ this._oldScrollTarget = scrollTarget;
+ }
+ }
+ },
+
+ /**
+ * Runs on every scroll event. Consumer of this behavior may want to override this method.
+ *
+ * @protected
+ */
+ _scrollHandler: function scrollHandler() {},
+
+ /**
+ * The default scroll target. Consumers of this behavior may want to customize
+ * the default scroll target.
+ *
+ * @type {Element}
+ */
+ get _defaultScrollTarget() {
+ return this._doc;
+ },
+
+ /**
+ * Shortcut for the document element
+ *
+ * @type {Element}
+ */
+ get _doc() {
+ return this.ownerDocument.documentElement;
+ },
+
+ /**
+ * Gets the number of pixels that the content of an element is scrolled upward.
+ *
+ * @type {number}
+ */
+ get _scrollTop() {
+ if (this._isValidScrollTarget()) {
+ return this.scrollTarget === this._doc ? window.pageYOffset : this.scrollTarget.scrollTop;
+ }
+ return 0;
+ },
+
+ /**
+ * Gets the number of pixels that the content of an element is scrolled to the left.
+ *
+ * @type {number}
+ */
+ get _scrollLeft() {
+ if (this._isValidScrollTarget()) {
+ return this.scrollTarget === this._doc ? window.pageXOffset : this.scrollTarget.scrollLeft;
+ }
+ return 0;
+ },
+
+ /**
+ * Sets the number of pixels that the content of an element is scrolled upward.
+ *
+ * @type {number}
+ */
+ set _scrollTop(top) {
+ if (this.scrollTarget === this._doc) {
+ window.scrollTo(window.pageXOffset, top);
+ } else if (this._isValidScrollTarget()) {
+ this.scrollTarget.scrollTop = top;
+ }
+ },
+
+ /**
+ * Sets the number of pixels that the content of an element is scrolled to the left.
+ *
+ * @type {number}
+ */
+ set _scrollLeft(left) {
+ if (this.scrollTarget === this._doc) {
+ window.scrollTo(left, window.pageYOffset);
+ } else if (this._isValidScrollTarget()) {
+ this.scrollTarget.scrollLeft = left;
+ }
+ },
+
+ /**
+ * Scrolls the content to a particular place.
+ *
+ * @method scroll
+ * @param {number} left The left position
+ * @param {number} top The top position
+ */
+ 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;
+ }
+ },
+
+ /**
+ * Gets the width of the scroll target.
+ *
+ * @type {number}
+ */
+ get _scrollTargetWidth() {
+ if (this._isValidScrollTarget()) {
+ return this.scrollTarget === this._doc ? window.innerWidth : this.scrollTarget.offsetWidth;
+ }
+ return 0;
+ },
+
+ /**
+ * Gets the height of the scroll target.
+ *
+ * @type {number}
+ */
+ get _scrollTargetHeight() {
+ if (this._isValidScrollTarget()) {
+ return this.scrollTarget === this._doc ? window.innerHeight : this.scrollTarget.offsetHeight;
+ }
+ return 0;
+ },
+
+ /**
+ * Returns true if the scroll target is a valid HTMLElement.
+ *
+ * @return {boolean}
+ */
+ _isValidScrollTarget: function() {
+ return this.scrollTarget instanceof HTMLElement;
+ }
+ };
+(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 MAX_PHYSICAL_COUNT = 500;
+ var HIDDEN_Y = '-10000px';
Polymer({
@@ -9352,18 +2461,27 @@ this.fire('dom-change');
observers: [
'_itemsChanged(items.*)',
'_selectionEnabledChanged(selectionEnabled)',
- '_multiSelectionChanged(multiSelection)'
+ '_multiSelectionChanged(multiSelection)',
+ '_setOverflow(scrollTarget)'
],
behaviors: [
Polymer.Templatizer,
- Polymer.IronResizableBehavior
+ Polymer.IronResizableBehavior,
+ Polymer.IronA11yKeysBehavior,
+ Polymer.IronScrollTargetBehavior
],
listeners: {
'iron-resize': '_resizeHandler'
},
+ keyBindings: {
+ 'up': '_didMoveUp',
+ 'down': '_didMoveDown',
+ 'enter': '_didEnter'
+ },
+
/**
* The ratio of hidden tiles that should remain in the scroll direction.
* Recommended value ~0.5, so it will distribute tiles evely in both directions.
@@ -9371,13 +2489,7 @@ this.fire('dom-change');
_ratio: 0.5,
/**
- * The element that controls the scroll
- * @type {?Element}
- */
- _scroller: null,
-
- /**
- * The padding-top value of the `scroller` element
+ * The padding-top value for the list.
*/
_scrollerPaddingTop: 0,
@@ -9387,27 +2499,12 @@ this.fire('dom-change');
_scrollPosition: 0,
/**
- * The number of tiles in the DOM.
- */
- _physicalCount: 0,
-
- /**
- * The k-th tile that is at the top of the scrolling list.
- */
- _physicalStart: 0,
-
- /**
- * The k-th tile that is at the bottom of the scrolling list.
- */
- _physicalEnd: 0,
-
- /**
* The sum of the heights of all the tiles in the DOM.
*/
_physicalSize: 0,
/**
- * The average `offsetHeight` of the tiles observed till now.
+ * The average `F` of the tiles observed till now.
*/
_physicalAverage: 0,
@@ -9428,11 +2525,6 @@ this.fire('dom-change');
_virtualCount: 0,
/**
- * The n-th item rendered in the `_physicalStart` tile.
- */
- _virtualStartVal: 0,
-
- /**
* A map between an item key and its physical item index
*/
_physicalIndexForKey: null,
@@ -9465,13 +2557,20 @@ this.fire('dom-change');
_physicalSizes: null,
/**
- * A cached value for the visible index.
+ * A cached value for the first visible index.
* See `firstVisibleIndex`
* @type {?number}
*/
_firstVisibleIndexVal: null,
/**
+ * A cached value for the last visible index.
+ * See `lastVisibleIndex`
+ * @type {?number}
+ */
+ _lastVisibleIndexVal: null,
+
+ /**
* A Polymer collection for the items.
* @type {?Polymer.Collection}
*/
@@ -9494,6 +2593,28 @@ this.fire('dom-change');
_maxPages: 3,
/**
+ * The currently focused physical item.
+ */
+ _focusedItem: null,
+
+ /**
+ * The index of the `_focusedItem`.
+ */
+ _focusedIndex: -1,
+
+ /**
+ * The the item that is focused if it is moved offscreen.
+ * @private {?TemplatizerNode}
+ */
+ _offscreenFocusedItem: null,
+
+ /**
+ * The item that backfills the `_offscreenFocusedItem` in the physical items
+ * list when that item is moved offscreen.
+ */
+ _focusBackfillItem: null,
+
+ /**
* The bottom of the physical content.
*/
get _physicalBottom() {
@@ -9511,7 +2632,21 @@ this.fire('dom-change');
* The n-th item rendered in the last physical item.
*/
get _virtualEnd() {
- return this._virtualStartVal + this._physicalCount - 1;
+ return this._virtualStart + this._physicalCount - 1;
+ },
+
+ /**
+ * The height of the physical content that isn't on the screen.
+ */
+ get _hiddenContentSize() {
+ return this._physicalSize - this._viewportSize;
+ },
+
+ /**
+ * The maximum scroll top value.
+ */
+ get _maxScrollTop() {
+ return this._estScrollHeight - this._viewportSize + this._scrollerPaddingTop;
},
/**
@@ -9527,35 +2662,53 @@ this.fire('dom-change');
},
/**
- * The height of the physical content that isn't on the screen.
+ * The n-th item rendered in the `_physicalStart` tile.
*/
- get _hiddenContentSize() {
- return this._physicalSize - this._viewportSize;
+ _virtualStartVal: 0,
+
+ set _virtualStart(val) {
+ this._virtualStartVal = Math.min(this._maxVirtualStart, Math.max(this._minVirtualStart, val));
+ },
+
+ get _virtualStart() {
+ return this._virtualStartVal || 0;
},
/**
- * The maximum scroll top value.
+ * The k-th tile that is at the top of the scrolling list.
*/
- get _maxScrollTop() {
- return this._estScrollHeight - this._viewportSize;
+ _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;
},
/**
- * Sets the n-th item rendered in `_physicalStart`
+ * The number of tiles in the DOM.
*/
- set _virtualStart(val) {
- // clamp the value so that _minVirtualStart <= val <= _maxVirtualStart
- this._virtualStartVal = Math.min(this._maxVirtualStart, Math.max(this._minVirtualStart, val));
- this._physicalStart = this._virtualStartVal % this._physicalCount;
+ _physicalCountVal: 0,
+
+ set _physicalCount(val) {
+ this._physicalCountVal = val;
this._physicalEnd = (this._physicalStart + this._physicalCount - 1) % this._physicalCount;
},
+ get _physicalCount() {
+ return this._physicalCountVal;
+ },
+
/**
- * Gets the n-th item rendered in `_physicalStart`
+ * The k-th tile that is at the bottom of the scrolling list.
*/
- get _virtualStart() {
- return this._virtualStartVal;
- },
+ _physicalEnd: 0,
/**
* An optimal physical size such that we will have enough physical items
@@ -9572,7 +2725,7 @@ this.fire('dom-change');
* True if the current list is visible.
*/
get _isVisible() {
- return this._scroller && Boolean(this._scroller.offsetWidth || this._scroller.offsetHeight);
+ return this.scrollTarget && Boolean(this.scrollTarget.offsetWidth || this.scrollTarget.offsetHeight);
},
/**
@@ -9581,68 +2734,63 @@ this.fire('dom-change');
* @type {number}
*/
get firstVisibleIndex() {
- var physicalOffset;
-
if (this._firstVisibleIndexVal === null) {
- physicalOffset = this._physicalTop;
+ var physicalOffset = this._physicalTop + this._scrollerPaddingTop;
this._firstVisibleIndexVal = this._iterateItems(
function(pidx, vidx) {
physicalOffset += this._physicalSizes[pidx];
-
if (physicalOffset > this._scrollPosition) {
return vidx;
}
}) || 0;
}
-
return this._firstVisibleIndexVal;
},
- ready: function() {
- if (IOS_TOUCH_SCROLLING) {
- this._scrollListener = function() {
- requestAnimationFrame(this._scrollHandler.bind(this));
- }.bind(this);
- } else {
- this._scrollListener = this._scrollHandler.bind(this);
- }
- },
-
/**
- * When the element has been attached to the DOM tree.
+ * Gets the index of the last visible item in the viewport.
+ *
+ * @type {number}
*/
- attached: function() {
- // delegate to the parent's scroller
- // e.g. paper-scroll-header-panel
- var el = Polymer.dom(this);
+ get lastVisibleIndex() {
+ if (this._lastVisibleIndexVal === null) {
+ var physicalOffset = this._physicalTop;
- var parentNode = /** @type {?{scroller: ?Element}} */ (el.parentNode);
- if (parentNode && parentNode.scroller) {
- this._scroller = parentNode.scroller;
- } else {
- this._scroller = this;
- this.classList.add('has-scroller');
- }
+ this._iterateItems(function(pidx, vidx) {
+ physicalOffset += this._physicalSizes[pidx];
- if (IOS_TOUCH_SCROLLING) {
- this._scroller.style.webkitOverflowScrolling = 'touch';
+ if (physicalOffset <= this._scrollBottom) {
+ this._lastVisibleIndexVal = vidx;
+ }
+ });
}
+ return this._lastVisibleIndexVal;
+ },
- this._scroller.addEventListener('scroll', this._scrollListener);
+ get _defaultScrollTarget() {
+ return this;
+ },
+
+ ready: function() {
+ this.addEventListener('focus', this._didFocus.bind(this), true);
+ },
+ attached: function() {
this.updateViewportBoundaries();
this._render();
},
- /**
- * When the element has been removed from the DOM tree.
- */
detached: function() {
this._itemsRendered = false;
- if (this._scroller) {
- this._scroller.removeEventListener('scroll', this._scrollListener);
- }
+ },
+
+ /**
+ * Set the overflow property if this element has its own scrolling region
+ */
+ _setOverflow: function(scrollTarget) {
+ this.style.webkitOverflowScrolling = scrollTarget === this ? 'touch' : '';
+ this.style.overflow = scrollTarget === this ? 'auto' : '';
},
/**
@@ -9652,23 +2800,22 @@ this.fire('dom-change');
* @method updateViewportBoundaries
*/
updateViewportBoundaries: function() {
- var scrollerStyle = window.getComputedStyle(this._scroller);
- this._scrollerPaddingTop = parseInt(scrollerStyle['padding-top'], 10);
- this._viewportSize = this._scroller.offsetHeight;
+ this._scrollerPaddingTop = this.scrollTarget === this ? 0 :
+ parseInt(window.getComputedStyle(this)['padding-top'], 10);
+
+ this._viewportSize = this._scrollTargetHeight;
},
/**
* Update the models, the position of the
* items in the viewport and recycle tiles as needed.
*/
- _refresh: function() {
+ _scrollHandler: function() {
// clamp the `scrollTop` value
- // IE 10|11 scrollTop may go above `_maxScrollTop`
- // iOS `scrollTop` may go below 0 and above `_maxScrollTop`
- var scrollTop = Math.max(0, Math.min(this._maxScrollTop, this._scroller.scrollTop));
+ var scrollTop = Math.max(0, Math.min(this._maxScrollTop, this._scrollTop));
+ var delta = scrollTop - this._scrollPosition;
var tileHeight, tileTop, kth, recycledTileSet, scrollBottom, physicalBottom;
var ratio = this._ratio;
- var delta = scrollTop - this._scrollPosition;
var recycledTiles = 0;
var hiddenContentSize = this._hiddenContentSize;
var currentRatio = ratio;
@@ -9677,8 +2824,9 @@ this.fire('dom-change');
// track the last `scrollTop`
this._scrollPosition = scrollTop;
- // clear cached visible index
+ // clear cached visible indexes
this._firstVisibleIndexVal = null;
+ this._lastVisibleIndexVal = null;
scrollBottom = this._scrollBottom;
physicalBottom = this._physicalBottom;
@@ -9763,22 +2911,23 @@ this.fire('dom-change');
}
} else {
this._virtualStart = this._virtualStart + recycledTiles;
+ this._physicalStart = this._physicalStart + recycledTiles;
this._update(recycledTileSet, movingUp);
}
},
/**
- * Update the list of items, starting from the `_virtualStartVal` item.
+ * Update the list of items, starting from the `_virtualStart` item.
* @param {!Array<number>=} itemSet
* @param {!Array<number>=} movingUp
*/
_update: function(itemSet, movingUp) {
+ // manage focus
+ this._manageFocus();
// update models
this._assignModels(itemSet);
-
// measure heights
this._updateMetrics(itemSet);
-
// adjust offset after measuring
if (movingUp) {
while (movingUp.length) {
@@ -9787,10 +2936,8 @@ this.fire('dom-change');
}
// update the position of the items
this._positionItems();
-
// set the scroller size
this._updateScrollerSize();
-
// increase the pool of physical items
this._increasePoolIfNeeded();
},
@@ -9810,7 +2957,6 @@ this.fire('dom-change');
physicalItems[i] = inst.root.querySelector('*');
Polymer.dom(this).appendChild(inst.root);
}
-
return physicalItems;
},
@@ -9820,47 +2966,56 @@ this.fire('dom-change');
* if the physical size is shorter than `_optPhysicalSize`
*/
_increasePoolIfNeeded: function() {
- if (this._viewportSize !== 0 && this._physicalSize < this._optPhysicalSize) {
- // 0 <= `currentPage` <= `_maxPages`
- var currentPage = Math.floor(this._physicalSize / this._viewportSize);
-
- if (currentPage === 0) {
- // fill the first page
- this.async(this._increasePool.bind(this, Math.round(this._physicalCount * 0.5)));
- } else if (this._lastPage !== currentPage) {
- // once a page is filled up, paint it and defer the next increase
- requestAnimationFrame(this._increasePool.bind(this, 1));
- } else {
- // fill the rest of the pages
- this.async(this._increasePool.bind(this, 1));
- }
- this._lastPage = currentPage;
- return true;
+ if (this._viewportSize === 0 || this._physicalSize >= this._optPhysicalSize) {
+ return false;
}
- return false;
+ // 0 <= `currentPage` <= `_maxPages`
+ var currentPage = Math.floor(this._physicalSize / this._viewportSize);
+ if (currentPage === 0) {
+ // fill the first page
+ this._debounceTemplate(this._increasePool.bind(this, Math.round(this._physicalCount * 0.5)));
+ } else if (this._lastPage !== currentPage) {
+ // paint the page and defer the next increase
+ // wait 16ms which is rough enough to get paint cycle.
+ Polymer.dom.addDebouncer(this.debounce('_debounceTemplate', this._increasePool.bind(this, 1), 16));
+ } else {
+ // fill the rest of the pages
+ this._debounceTemplate(this._increasePool.bind(this, 1));
+ }
+ this._lastPage = currentPage;
+ return true;
},
/**
* Increases the pool size.
*/
_increasePool: function(missingItems) {
- // limit the size
var nextPhysicalCount = Math.min(
this._physicalCount + missingItems,
- this._virtualCount,
+ this._virtualCount - this._virtualStart,
MAX_PHYSICAL_COUNT
);
var prevPhysicalCount = this._physicalCount;
var delta = nextPhysicalCount - prevPhysicalCount;
- if (delta > 0) {
- [].push.apply(this._physicalItems, this._createPool(delta));
- [].push.apply(this._physicalSizes, new Array(delta));
+ if (delta <= 0) {
+ return;
+ }
+
+ [].push.apply(this._physicalItems, this._createPool(delta));
+ [].push.apply(this._physicalSizes, new Array(delta));
- this._physicalCount = prevPhysicalCount + delta;
- // tail call
- return this._update();
+ this._physicalCount = prevPhysicalCount + delta;
+
+ // update the physical start if we need to preserve the model of the focused item.
+ // In this situation, the focused item is currently rendered and its model would
+ // have changed after increasing the pool if the physical start remained unchanged.
+ if (this._physicalStart > this._physicalEnd &&
+ this._isIndexRendered(this._focusedIndex) &&
+ this._getPhysicalIndex(this._focusedIndex) < this._physicalEnd) {
+ this._physicalStart = this._physicalStart + delta;
}
+ this._update();
},
/**
@@ -9873,6 +3028,7 @@ this.fire('dom-change');
if (this.isAttached && !this._itemsRendered && this._isVisible && requiresUpdate) {
this._lastPage = 0;
this._update();
+ this._scrollHandler();
this._itemsRendered = true;
}
},
@@ -9884,11 +3040,11 @@ this.fire('dom-change');
if (!this.ctor) {
// Template instance props that should be excluded from forwarding
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');
@@ -9948,23 +3104,36 @@ this.fire('dom-change');
/**
* Called as a side effect of a host items.<key>.<path> path change,
- * responsible for notifying item.<path> changes to row for key.
+ * responsible for notifying item.<path> changes.
*/
_forwardItemPath: function(path, value) {
- if (this._physicalIndexForKey) {
- var dot = path.indexOf('.');
- var key = path.substring(0, dot < 0 ? path.length : dot);
- var idx = this._physicalIndexForKey[key];
- var row = this._physicalItems[idx];
- if (row) {
- var inst = row._templateInstance;
- if (dot >= 0) {
- path = this.as + '.' + path.substring(dot+1);
- inst.notifyPath(path, value, true);
- } else {
- inst[this.as] = value;
- }
- }
+ if (!this._physicalIndexForKey) {
+ return;
+ }
+ var inst;
+ var dot = path.indexOf('.');
+ var key = path.substring(0, dot < 0 ? path.length : dot);
+ var idx = this._physicalIndexForKey[key];
+ var el = this._physicalItems[idx];
+
+
+ if (idx === this._focusedIndex && this._offscreenFocusedItem) {
+ el = this._offscreenFocusedItem;
+ }
+ if (!el) {
+ return;
+ }
+
+ inst = el._templateInstance;
+
+ if (inst.__key__ !== key) {
+ return;
+ }
+ if (dot >= 0) {
+ path = this.as + '.' + path.substring(dot+1);
+ inst.notifyPath(path, value, true);
+ } else {
+ inst[this.as] = value;
}
},
@@ -9974,18 +3143,15 @@ this.fire('dom-change');
*/
_itemsChanged: function(change) {
if (change.path === 'items') {
- // render the new set
- this._itemsRendered = false;
-
- // update the whole set
- this._virtualStartVal = 0;
+ // reset 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 = {};
- // scroll to the top
this._resetScrollPosition(0);
+ this._removeFocusedItem();
// create the initial physical items
if (!this._physicalItems) {
@@ -9994,48 +3160,50 @@ this.fire('dom-change');
this._physicalSizes = new Array(this._physicalCount);
}
- this.debounce('refresh', this._render);
+ this._physicalStart = 0;
} else if (change.path === 'items.splices') {
- // render the new set
- this._itemsRendered = false;
-
this._adjustVirtualIndex(change.value.indexSplices);
this._virtualCount = this.items ? this.items.length : 0;
- this.debounce('refresh', this._render);
-
} else {
// update a single item
this._forwardItemPath(change.path.split('.').slice(1).join('.'), change.value);
+ return;
}
+
+ this._itemsRendered = false;
+ this._debounceTemplate(this._render);
},
/**
* @param {!Array<!PolymerSplice>} splices
*/
_adjustVirtualIndex: function(splices) {
- var i, splice, idx;
-
- for (i = 0; i < splices.length; i++) {
- splice = splices[i];
-
+ splices.forEach(function(splice) {
// deselect removed items
- splice.removed.forEach(this.$.selector.deselect, this.$.selector);
-
- idx = splice.index;
+ splice.removed.forEach(this._removeItem, this);
// We only need to care about changes happening above the current position
- if (idx >= this._virtualStartVal) {
- break;
- }
+ if (splice.index < this._virtualStart) {
+ var delta = Math.max(
+ splice.addedCount - splice.removed.length,
+ splice.index - this._virtualStart);
- this._virtualStart = this._virtualStart +
- Math.max(splice.addedCount - splice.removed.length, idx - this._virtualStartVal);
- }
+ this._virtualStart = this._virtualStart + delta;
+
+ if (this._focusedIndex >= 0) {
+ this._focusedIndex = this._focusedIndex + delta;
+ }
+ }
+ }, this);
},
- _scrollHandler: function() {
- this._refresh();
+ _removeItem: function(item) {
+ this.$.selector.deselect(item);
+ // remove the current focused item
+ if (this._focusedItem && this._focusedItem._templateInstance[this.as] === item) {
+ this._removeFocusedItem();
+ }
},
/**
@@ -10052,9 +3220,9 @@ this.fire('dom-change');
for (i = 0; i < itemSet.length; i++) {
pidx = itemSet[i];
if (pidx >= this._physicalStart) {
- vidx = this._virtualStartVal + (pidx - this._physicalStart);
+ vidx = this._virtualStart + (pidx - this._physicalStart);
} else {
- vidx = this._virtualStartVal + (this._physicalCount - this._physicalStart) + pidx;
+ vidx = this._virtualStart + (this._physicalCount - this._physicalStart) + pidx;
}
if ((rtn = fn.call(this, pidx, vidx)) != null) {
return rtn;
@@ -10062,17 +3230,14 @@ this.fire('dom-change');
}
} else {
pidx = this._physicalStart;
- vidx = this._virtualStartVal;
+ vidx = this._virtualStart;
for (; pidx < this._physicalCount; pidx++, vidx++) {
if ((rtn = fn.call(this, pidx, vidx)) != null) {
return rtn;
}
}
-
- pidx = 0;
-
- for (; pidx < this._physicalStart; pidx++, vidx++) {
+ for (pidx = 0; pidx < this._physicalStart; pidx++, vidx++) {
if ((rtn = fn.call(this, pidx, vidx)) != null) {
return rtn;
}
@@ -10090,19 +3255,18 @@ this.fire('dom-change');
var inst = el._templateInstance;
var item = this.items && this.items[vidx];
- if (item) {
+ if (item != null) {
inst[this.as] = item;
inst.__key__ = this._collection.getKey(item);
- inst[this.selectedAs] =
- /** @type {!ArraySelectorElement} */ (this.$.selector).isSelected(item);
+ inst[this.selectedAs] = /** @type {!ArraySelectorElement} */ (this.$.selector).isSelected(item);
inst[this.indexAs] = vidx;
- el.removeAttribute('hidden');
+ inst.tabIndex = this._focusedIndex === vidx ? 0 : -1;
this._physicalIndexForKey[inst.__key__] = pidx;
+ el.removeAttribute('hidden');
} else {
inst.__key__ = null;
el.setAttribute('hidden', '');
}
-
}, itemSet);
},
@@ -10112,23 +3276,26 @@ this.fire('dom-change');
* @param {!Array<number>=} itemSet
*/
_updateMetrics: function(itemSet) {
+ // Make sure we distributed all the physical items
+ // so we can measure them
+ Polymer.dom.flush();
+
var newPhysicalSize = 0;
var oldPhysicalSize = 0;
var prevAvgCount = this._physicalAverageCount;
var prevPhysicalAvg = this._physicalAverage;
- // Make sure we distributed all the physical items
- // so we can measure them
- Polymer.dom.flush();
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);
this._physicalSize = this._physicalSize + newPhysicalSize - oldPhysicalSize;
- this._viewportSize = this._scroller.offsetHeight;
+ this._viewportSize = this._scrollTargetHeight;
// update the average if we measured something
if (this._physicalAverageCount !== prevAvgCount) {
@@ -10147,10 +3314,8 @@ this.fire('dom-change');
var y = this._physicalTop;
this._iterateItems(function(pidx) {
-
- this.transform('translate3d(0, ' + y + 'px, 0)', this._physicalItems[pidx]);
+ this.translate3d(0, y + 'px', 0, this._physicalItems[pidx]);
y += this._physicalSizes[pidx];
-
});
},
@@ -10158,15 +3323,14 @@ this.fire('dom-change');
* Adjusts the scroll position when it was overestimated.
*/
_adjustScrollPosition: function() {
- var deltaHeight = this._virtualStartVal === 0 ? this._physicalTop :
+ var deltaHeight = this._virtualStart === 0 ? this._physicalTop :
Math.min(this._scrollPosition + this._physicalTop, 0);
if (deltaHeight) {
this._physicalTop = this._physicalTop - deltaHeight;
-
// juking scroll position during interial scrolling on iOS is no bueno
if (!IOS_TOUCH_SCROLLING) {
- this._resetScrollPosition(this._scroller.scrollTop - deltaHeight);
+ this._resetScrollPosition(this._scrollTop - deltaHeight);
}
}
},
@@ -10175,9 +3339,9 @@ this.fire('dom-change');
* Sets the position of the scroll.
*/
_resetScrollPosition: function(pos) {
- if (this._scroller) {
- this._scroller.scrollTop = pos;
- this._scrollPosition = this._scroller.scrollTop;
+ if (this.scrollTarget) {
+ this._scrollTop = pos;
+ this._scrollPosition = this._scrollTop;
}
},
@@ -10188,7 +3352,7 @@ this.fire('dom-change');
*/
_updateScrollerSize: function(forceUpdate) {
this._estScrollHeight = (this._physicalBottom +
- Math.max(this._virtualCount - this._physicalCount - this._virtualStartVal, 0) * this._physicalAverage);
+ Math.max(this._virtualCount - this._physicalCount - this._virtualStart, 0) * this._physicalAverage);
forceUpdate = forceUpdate || this._scrollHeight === 0;
forceUpdate = forceUpdate || this._scrollPosition >= this._estScrollHeight - this._physicalSize;
@@ -10199,7 +3363,6 @@ this.fire('dom-change');
this._scrollHeight = this._estScrollHeight;
}
},
-
/**
* Scroll to a specific item in the virtual list regardless
* of the physical items in the DOM tree.
@@ -10212,20 +3375,19 @@ this.fire('dom-change');
return;
}
- var firstVisible = this.firstVisibleIndex;
+ Polymer.dom.flush();
idx = Math.min(Math.max(idx, 0), this._virtualCount-1);
-
- // start at the previous virtual item
- // so we have a item above the first visible item
- this._virtualStart = idx - 1;
-
+ // update the virtual start only when needed
+ if (!this._isIndexRendered(idx) || idx >= this._maxVirtualStart) {
+ this._virtualStart = idx - 1;
+ }
+ // manage focus
+ this._manageFocus();
// assign new models
this._assignModels();
-
// measure the new sizes
this._updateMetrics();
-
// estimate new physical offset
this._physicalTop = this._virtualStart * this._physicalAverage;
@@ -10240,21 +3402,17 @@ this.fire('dom-change');
currentTopItem = (currentTopItem + 1) % this._physicalCount;
currentVirtualItem++;
}
-
// update the scroller size
this._updateScrollerSize(true);
-
// update the position of the items
this._positionItems();
-
// set the new scroll position
- this._resetScrollPosition(this._physicalTop + targetOffsetTop + 1);
-
+ this._resetScrollPosition(this._physicalTop + this._scrollerPaddingTop + targetOffsetTop + 1);
// increase the pool of physical items if needed
this._increasePoolIfNeeded();
-
// clear cached visible index
this._firstVisibleIndexVal = null;
+ this._lastVisibleIndexVal = null;
},
/**
@@ -10270,7 +3428,11 @@ this.fire('dom-change');
* when the element is resized.
*/
_resizeHandler: function() {
- this.debounce('resize', function() {
+ // iOS fires the resize event when the address bar slides up
+ if (IOS && Math.abs(this._viewportSize - this._scrollTargetHeight) < 100) {
+ return;
+ }
+ this._debounceTemplate(function() {
this._render();
if (this._itemsRendered && this._physicalItems && this._isVisible) {
this._resetAverage();
@@ -10284,7 +3446,7 @@ this.fire('dom-change');
var key = this._collection.getKey(item);
var pidx = this._physicalIndexForKey[key];
- if (pidx !== undefined) {
+ if (pidx != null) {
return this._physicalItems[pidx]._templateInstance;
}
return null;
@@ -10296,12 +3458,14 @@ this.fire('dom-change');
* @param {(Object|number)} item The item object or its index
*/
_getNormalizedItem: function(item) {
- if (typeof item === 'number') {
- item = this.items[item];
- if (!item) {
- throw new RangeError('<item> not found');
+ if (this._collection.getKey(item) === undefined) {
+ if (typeof item === 'number') {
+ item = this.items[item];
+ if (!item) {
+ throw new RangeError('<item> not found');
+ }
+ return item;
}
- } else if (this._collection.getKey(item) === undefined) {
throw new TypeError('<item> should be a valid item');
}
return item;
@@ -10324,6 +3488,7 @@ this.fire('dom-change');
model[this.selectedAs] = true;
}
this.$.selector.select(item);
+ this.updateSizeForItem(item);
},
/**
@@ -10341,6 +3506,7 @@ this.fire('dom-change');
model[this.selectedAs] = false;
}
this.$.selector.deselect(item);
+ this.updateSizeForItem(item);
},
/**
@@ -10386,20 +3552,15 @@ this.fire('dom-change');
* it will remove the listener otherwise.
*/
_selectionEnabledChanged: function(selectionEnabled) {
- if (selectionEnabled) {
- this.listen(this, 'tap', '_selectionHandler');
- this.listen(this, 'keypress', '_selectionHandler');
- } else {
- this.unlisten(this, 'tap', '_selectionHandler');
- this.unlisten(this, 'keypress', '_selectionHandler');
- }
+ var handler = selectionEnabled ? this.listen : this.unlisten;
+ handler.call(this, this, 'tap', '_selectionHandler');
},
/**
* Select an item from an event object.
*/
_selectionHandler: function(e) {
- if (e.type !== 'keypress' || e.keyCode === 13) {
+ if (this.selectionEnabled) {
var model = this.modelForElement(e.target);
if (model) {
this.toggleSelectionForItem(model[this.as]);
@@ -10423,14 +3584,539 @@ this.fire('dom-change');
var key = this._collection.getKey(item);
var pidx = this._physicalIndexForKey[key];
- if (pidx !== undefined) {
+ if (pidx != null) {
this._updateMetrics([pidx]);
this._positionItems();
}
+ },
+
+ /**
+ * Creates a temporary backfill item in the rendered pool of physical items
+ * to replace the main focused item. The focused item has tabIndex = 0
+ * and might be currently focused by the user.
+ *
+ * This dynamic replacement helps to preserve the focus state.
+ */
+ _manageFocus: function() {
+ var fidx = this._focusedIndex;
+
+ if (fidx >= 0 && fidx < this._virtualCount) {
+ // if it's a valid index, check if that index is rendered
+ // in a physical item.
+ if (this._isIndexRendered(fidx)) {
+ this._restoreFocusedItem();
+ } else {
+ this._createFocusBackfillItem();
+ }
+ } else if (this._virtualCount > 0 && this._physicalCount > 0) {
+ // otherwise, assign the initial focused index.
+ 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();
+ // scroll to index to make sure it's rendered
+ if (!this._isIndexRendered(idx)) {
+ this.scrollToIndex(idx);
+ }
+
+ var physicalItem = this._physicalItems[this._getPhysicalIndex(idx)];
+ var SECRET = ~(Math.random() * 100);
+ var model = physicalItem._templateInstance;
+ var focusable;
+
+ // set a secret tab index
+ model.tabIndex = SECRET;
+ // check if focusable element is the physical item
+ if (physicalItem.tabIndex === SECRET) {
+ focusable = physicalItem;
+ }
+ // search for the element which tabindex is bound to the secret tab index
+ if (!focusable) {
+ focusable = Polymer.dom(physicalItem).querySelector('[tabindex="' + SECRET + '"]');
+ }
+ // restore the tab index
+ model.tabIndex = 0;
+ // focus the focusable element
+ 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) {
+ // create a physical item, so that it backfills the focused item.
+ var stampedTemplate = this.stamp(null);
+ this._focusBackfillItem = stampedTemplate.root.querySelector('*');
+ Polymer.dom(this).appendChild(stampedTemplate.root);
+ }
+ // get the physical index for the focused index
+ pidx = this._getPhysicalIndex(fidx);
+
+ if (pidx != null) {
+ // set the offcreen focused physical item
+ this._offscreenFocusedItem = this._physicalItems[pidx];
+ // backfill the focused physical item
+ this._physicalItems[pidx] = this._focusBackfillItem;
+ // hide the focused physical
+ this.translate3d(0, HIDDEN_Y, 0, this._offscreenFocusedItem);
+ }
+ },
+
+ _restoreFocusedItem: function() {
+ var pidx, fidx = this._focusedIndex;
+
+ if (!this._offscreenFocusedItem || this._focusedIndex < 0) {
+ return;
+ }
+ // assign models to the focused index
+ this._assignModels();
+ // get the new physical index for the focused index
+ pidx = this._getPhysicalIndex(fidx);
+
+ if (pidx != null) {
+ // flip the focus backfill
+ this._focusBackfillItem = this._physicalItems[pidx];
+ // restore the focused physical item
+ this._physicalItems[pidx] = this._offscreenFocusedItem;
+ // reset the offscreen focused item
+ this._offscreenFocusedItem = null;
+ // hide the physical item that backfills
+ 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 the user focused the same item, then bring it into view if it's not visible
+ if (!this._isIndexVisible(fidx)) {
+ this.scrollToIndex(fidx);
+ }
+ } else {
+ this._restoreFocusedItem();
+ // restore tabIndex for the currently focused item
+ focusedModel.tabIndex = -1;
+ // set the tabIndex for the next focused item
+ 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() {
+ this._focusPhysicalItem(this._focusedIndex + 1);
+ },
+
+ _didEnter: function(e) {
+ this._focusPhysicalItem(this._focusedIndex);
+ this._selectionHandler(e.detail.keyboardEvent);
}
});
})();
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/**
+ * @fileoverview Assertion support.
+ */
+
+/**
+ * Verify |condition| is truthy and return |condition| if so.
+ * @template T
+ * @param {T} condition A condition to check for truthiness. Note that this
+ * may be used to test whether a value is defined or not, and we don't want
+ * to force a cast to Boolean.
+ * @param {string=} opt_message A message to show on failure.
+ * @return {T} A non-null |condition|.
+ */
+function assert(condition, opt_message) {
+ if (!condition) {
+ var message = 'Assertion failed';
+ if (opt_message)
+ message = message + ': ' + opt_message;
+ var error = new Error(message);
+ var global = function() { return this; }();
+ if (global.traceAssertionsForTesting)
+ console.warn(error.stack);
+ throw error;
+ }
+ return condition;
+}
+
+/**
+ * Call this from places in the code that should never be reached.
+ *
+ * For example, handling all the values of enum with a switch() like this:
+ *
+ * function getValueFromEnum(enum) {
+ * switch (enum) {
+ * case ENUM_FIRST_OF_TWO:
+ * return first
+ * case ENUM_LAST_OF_TWO:
+ * return last;
+ * }
+ * assertNotReached();
+ * return document;
+ * }
+ *
+ * This code should only be hit in the case of serious programmer error or
+ * unexpected input.
+ *
+ * @param {string=} opt_message A message to show when this is hit.
+ */
+function assertNotReached(opt_message) {
+ assert(false, opt_message || 'Unreachable code hit');
+}
+
+/**
+ * @param {*} value The value to check.
+ * @param {function(new: T, ...)} type A user-defined constructor.
+ * @param {string=} opt_message A message to show when this is hit.
+ * @return {T}
+ * @template T
+ */
+function assertInstanceof(value, type, opt_message) {
+ // We don't use assert immediately here so that we avoid constructing an error
+ // message if we don't have to.
+ if (!(value instanceof type)) {
+ assertNotReached(opt_message || 'Value ' + value +
+ ' is not a[n] ' + (type.name || typeof type));
+ }
+ return value;
+};
+// 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() {
+ /**
+ * @param {string} chromeSendName
+ * @return {function(string):void} A chrome.send() callback with curried name.
+ */
+ function chromeSendWithId(chromeSendName) {
+ return function(id) { chrome.send(chromeSendName, [id]); };
+ }
+
+ /** @constructor */
+ function ActionService() {
+ /** @private {Array<string>} */
+ this.searchTerms_ = [];
+ }
+
+ /**
+ * @param {string} s
+ * @return {string} |s| without whitespace at the beginning or end.
+ */
+ function trim(s) { return s.trim(); }
+
+ /**
+ * @param {string|undefined} value
+ * @return {boolean} Whether |value| is truthy.
+ */
+ function truthy(value) { return !!value; }
+
+ /**
+ * @param {string} searchText Input typed by the user into a search box.
+ * @return {Array<string>} A list of terms extracted from |searchText|.
+ */
+ ActionService.splitTerms = function(searchText) {
+ // Split quoted terms (e.g., 'The "lazy" dog' => ['The', 'lazy', 'dog']).
+ return searchText.split(/"([^"]*)"/).map(trim).filter(truthy);
+ };
+
+ ActionService.prototype = {
+ /** @param {string} id ID of the download to cancel. */
+ cancel: chromeSendWithId('cancel'),
+
+ /** Instructs the browser to clear all finished downloads. */
+ clearAll: function() {
+ if (loadTimeData.getBoolean('allowDeletingHistory')) {
+ chrome.send('clearAll');
+ this.search('');
+ }
+ },
+
+ /** @param {string} id ID of the dangerous download to discard. */
+ discardDangerous: chromeSendWithId('discardDangerous'),
+
+ /** @param {string} url URL of a file to download. */
+ download: function(url) {
+ var a = document.createElement('a');
+ a.href = url;
+ a.setAttribute('download', '');
+ a.click();
+ },
+
+ /** @param {string} id ID of the download that the user started dragging. */
+ drag: chromeSendWithId('drag'),
+
+ /** Loads more downloads with the current search terms. */
+ loadMore: function() {
+ chrome.send('getDownloads', this.searchTerms_);
+ },
+
+ /**
+ * @return {boolean} Whether the user is currently searching for downloads
+ * (i.e. has a non-empty search term).
+ */
+ isSearching: function() {
+ return this.searchTerms_.length > 0;
+ },
+
+ /** Opens the current local destination for downloads. */
+ openDownloadsFolder: chrome.send.bind(chrome, 'openDownloadsFolder'),
+
+ /**
+ * @param {string} id ID of the download to run locally on the user's box.
+ */
+ openFile: chromeSendWithId('openFile'),
+
+ /** @param {string} id ID the of the progressing download to pause. */
+ pause: chromeSendWithId('pause'),
+
+ /** @param {string} id ID of the finished download to remove. */
+ remove: chromeSendWithId('remove'),
+
+ /** @param {string} id ID of the paused download to resume. */
+ resume: chromeSendWithId('resume'),
+
+ /**
+ * @param {string} id ID of the dangerous download to save despite
+ * warnings.
+ */
+ saveDangerous: chromeSendWithId('saveDangerous'),
+
+ /** @param {string} searchText What to search for. */
+ search: function(searchText) {
+ var searchTerms = ActionService.splitTerms(searchText);
+ var sameTerms = searchTerms.length == this.searchTerms_.length;
+
+ for (var i = 0; sameTerms && i < searchTerms.length; ++i) {
+ if (searchTerms[i] != this.searchTerms_[i])
+ sameTerms = false;
+ }
+
+ if (sameTerms)
+ return;
+
+ this.searchTerms_ = searchTerms;
+ this.loadMore();
+ },
+
+ /**
+ * Shows the local folder a finished download resides in.
+ * @param {string} id ID of the download to show.
+ */
+ show: chromeSendWithId('show'),
+
+ /** Undo download removal. */
+ undo: chrome.send.bind(chrome, 'undo'),
+ };
+
+ cr.addSingletonGetter(ActionService);
+
+ return {ActionService: ActionService};
+});
+// 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() {
+ /**
+ * Explains why a download is in DANGEROUS state.
+ * @enum {string}
+ */
+ var DangerType = {
+ NOT_DANGEROUS: 'NOT_DANGEROUS',
+ DANGEROUS_FILE: 'DANGEROUS_FILE',
+ DANGEROUS_URL: 'DANGEROUS_URL',
+ DANGEROUS_CONTENT: 'DANGEROUS_CONTENT',
+ UNCOMMON_CONTENT: 'UNCOMMON_CONTENT',
+ DANGEROUS_HOST: 'DANGEROUS_HOST',
+ POTENTIALLY_UNWANTED: 'POTENTIALLY_UNWANTED',
+ };
+
+ /**
+ * The states a download can be in. These correspond to states defined in
+ * DownloadsDOMHandler::CreateDownloadItemValue
+ * @enum {string}
+ */
+ var States = {
+ IN_PROGRESS: 'IN_PROGRESS',
+ CANCELLED: 'CANCELLED',
+ COMPLETE: 'COMPLETE',
+ PAUSED: 'PAUSED',
+ DANGEROUS: 'DANGEROUS',
+ INTERRUPTED: 'INTERRUPTED',
+ };
+
+ return {
+ DangerType: DangerType,
+ States: States,
+ };
+});
+// 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.
+
+// Action links are elements that are used to perform an in-page navigation or
+// action (e.g. showing a dialog).
+//
+// They look like normal anchor (<a>) tags as their text color is blue. However,
+// they're subtly different as they're not initially underlined (giving users a
+// clue that underlined links navigate while action links don't).
+//
+// Action links look very similar to normal links when hovered (hand cursor,
+// underlined). This gives the user an idea that clicking this link will do
+// something similar to navigation but in the same page.
+//
+// They can be created in JavaScript like this:
+//
+// var link = document.createElement('a', 'action-link'); // Note second arg.
+//
+// or with a constructor like this:
+//
+// var link = new ActionLink();
+//
+// They can be used easily from HTML as well, like so:
+//
+// <a is="action-link">Click me!</a>
+//
+// NOTE: <action-link> and document.createElement('action-link') don't work.
+
+/**
+ * @constructor
+ * @extends {HTMLAnchorElement}
+ */
+var ActionLink = document.registerElement('action-link', {
+ prototype: {
+ __proto__: HTMLAnchorElement.prototype,
+
+ /** @this {ActionLink} */
+ createdCallback: function() {
+ // Action links can start disabled (e.g. <a is="action-link" disabled>).
+ this.tabIndex = this.disabled ? -1 : 0;
+
+ if (!this.hasAttribute('role'))
+ this.setAttribute('role', 'link');
+
+ this.addEventListener('keydown', function(e) {
+ if (!this.disabled && e.keyIdentifier == 'Enter' && !this.href) {
+ // Schedule a click asynchronously because other 'keydown' handlers
+ // may still run later (e.g. document.addEventListener('keydown')).
+ // Specifically options dialogs break when this timeout isn't here.
+ // NOTE: this affects the "trusted" state of the ensuing click. I
+ // haven't found anything that breaks because of this (yet).
+ 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() {
+ // This handlers strives to match the behavior of <a href="...">.
+
+ // While the mouse is down, prevent text selection from dragging.
+ document.addEventListener('selectstart', preventDefault);
+ document.addEventListener('mouseup', removePreventDefault);
+
+ // If focus started via mouse press, don't show an outline.
+ if (document.activeElement != this)
+ this.classList.add('no-outline');
+ });
+
+ this.addEventListener('blur', function() {
+ this.classList.remove('no-outline');
+ });
+ },
+
+ /** @type {boolean} */
+ 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');
+ },
+
+ /** @override */
+ setAttribute: function(attr, val) {
+ if (attr.toLowerCase() == 'disabled')
+ this.disabled = true;
+ else
+ HTMLAnchorElement.prototype.setAttribute.apply(this, arguments);
+ },
+
+ /** @override */
+ removeAttribute: function(attr) {
+ if (attr.toLowerCase() == 'disabled')
+ this.disabled = false;
+ else
+ HTMLAnchorElement.prototype.removeAttribute.apply(this, arguments);
+ },
+ },
+
+ extends: 'a',
+});
(function() {
// monostate data
@@ -10746,7 +4432,8 @@ Polymer({
* @type {!Polymer.IronMeta}
*/
_meta: {
- value: Polymer.Base.create('iron-meta', {type: 'iconset'})
+ value: Polymer.Base.create('iron-meta', {type: 'iconset'}),
+ observer: '_updateIcon'
}
},
@@ -10771,7 +4458,14 @@ Polymer({
/** @suppress {visibility} */
_updateIcon: function() {
if (this._usesIconset()) {
- if (this._iconsetName) {
+ 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 = /** @type {?Polymer.Iconset} */ (
this._meta.byKey(this._iconsetName));
if (this._iconset) {
@@ -10782,6 +4476,9 @@ Polymer({
}
}
} else {
+ if (this._iconset) {
+ this._iconset.removeIcon(this);
+ }
if (!this._img) {
this._img = document.createElement('img');
this._img.style.width = '100%';
@@ -10973,411 +4670,6 @@ Polymer({
}
});
-(function() {
- 'use strict';
-
- /**
- * Chrome uses an older version of DOM Level 3 Keyboard Events
- *
- * Most keys are labeled as text, but some are Unicode codepoints.
- * Values taken from: http://www.w3.org/TR/2007/WD-DOM-Level-3-Events-20071221/keyset.html#KeySet-Set
- */
- var KEY_IDENTIFIER = {
- 'U+0008': 'backspace',
- 'U+0009': 'tab',
- 'U+001B': 'esc',
- 'U+0020': 'space',
- 'U+007F': 'del'
- };
-
- /**
- * Special table for KeyboardEvent.keyCode.
- * KeyboardEvent.keyIdentifier is better, and KeyBoardEvent.key is even better
- * than that.
- *
- * Values from: https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent.keyCode#Value_of_keyCode
- */
- 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: '*'
- };
-
- /**
- * MODIFIER_KEYS maps the short name for modifier keys used in a key
- * combo string to the property name that references those same keys
- * in a KeyboardEvent instance.
- */
- var MODIFIER_KEYS = {
- 'shift': 'shiftKey',
- 'ctrl': 'ctrlKey',
- 'alt': 'altKey',
- 'meta': 'metaKey'
- };
-
- /**
- * Matches a keyIdentifier string.
- */
- var IDENT_CHAR = /U\+/;
-
- /**
- * Matches arrow keys in Gecko 27.0+
- */
- var ARROW_KEY = /^arrow/;
-
- /**
- * Matches space keys everywhere (notably including IE10's exceptional name
- * `spacebar`).
- */
- var SPACE_KEY = /^space(bar)?/;
-
- function transformKey(key) {
- var validKey = '';
- if (key) {
- var lKey = key.toLowerCase();
- if (lKey === ' ' || SPACE_KEY.test(lKey)) {
- validKey = 'space';
- } else if (lKey.length == 1) {
- validKey = lKey;
- } else if (ARROW_KEY.test(lKey)) {
- validKey = lKey.replace('arrow', '');
- } else if (lKey == 'multiply') {
- // numpad '*' can map to Multiply on IE/Windows
- 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) {
- // ascii a-z
- // lowercase is 32 offset from uppercase
- validKey = String.fromCharCode(32 + keyCode);
- } else if (keyCode >= 112 && keyCode <= 123) {
- // function keys f1-f12
- validKey = 'f' + (keyCode - 112);
- } else if (keyCode >= 48 && keyCode <= 57) {
- // top 0-9 keys
- validKey = String(48 - keyCode);
- } else if (keyCode >= 96 && keyCode <= 105) {
- // num pad 0-9
- validKey = String(96 - keyCode);
- } else {
- validKey = KEY_CODE[keyCode];
- }
- }
- return validKey;
- }
-
- function normalizedKeyForEvent(keyEvent) {
- // fall back from .key, to .keyIdentifier, to .keyCode, and then to
- // .detail.key to support artificial keyboard events
- return transformKey(keyEvent.key) ||
- transformKeyIdentifier(keyEvent.keyIdentifier) ||
- transformKeyCode(keyEvent.keyCode) ||
- transformKey(keyEvent.detail.key) || '';
- }
-
- function keyComboMatchesEvent(keyCombo, event, eventKey) {
- return eventKey === 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` provides a normalized interface for processing
- * keyboard commands that pertain to [WAI-ARIA best practices](http://www.w3.org/TR/wai-aria-practices/#kbd_general_binding).
- * The element takes care of browser differences with respect to Keyboard events
- * and uses an expressive syntax to filter key presses.
- *
- * Use the `keyBindings` prototype property to express what combination of keys
- * will trigger the event to fire.
- *
- * Use the `key-event-target` attribute to set up event handlers on a specific
- * node.
- * The `keys-pressed` event will fire when one of the key combinations set with the
- * `keys` property is pressed.
- *
- * @demo demo/index.html
- * @polymerBehavior
- */
- Polymer.IronA11yKeysBehavior = {
- properties: {
- /**
- * The HTMLElement that will be firing relevant KeyboardEvents.
- */
- keyEventTarget: {
- type: Object,
- value: function() {
- return this;
- }
- },
-
- /**
- * If true, this property will cause the implementing element to
- * automatically stop propagation on any handled KeyboardEvents.
- */
- stopKeyboardEventPropagation: {
- type: Boolean,
- value: false
- },
-
- _boundKeyHandlers: {
- type: Array,
- value: function() {
- return [];
- }
- },
-
- // We use this due to a limitation in IE10 where instances will have
- // own properties of everything on the "prototype".
- _imperativeKeyBindings: {
- type: Object,
- value: function() {
- return {};
- }
- }
- },
-
- observers: [
- '_resetKeyEventListeners(keyEventTarget, _boundKeyHandlers)'
- ],
-
- keyBindings: {},
-
- registered: function() {
- this._prepKeyBindings();
- },
-
- attached: function() {
- this._listenKeyEventListeners();
- },
-
- detached: function() {
- this._unlistenKeyEventListeners();
- },
-
- /**
- * Can be used to imperatively add a key binding to the implementing
- * element. This is the imperative equivalent of declaring a keybinding
- * in the `keyBindings` prototype property.
- */
- addOwnKeyBinding: function(eventString, handlerName) {
- this._imperativeKeyBindings[eventString] = handlerName;
- this._prepKeyBindings();
- this._resetKeyEventListeners();
- },
-
- /**
- * When called, will remove all imperatively-added key bindings.
- */
- removeOwnKeyBindings: function() {
- this._imperativeKeyBindings = {};
- this._prepKeyBindings();
- this._resetKeyEventListeners();
- },
-
- keyboardEventMatchesKeys: function(event, eventString) {
- var keyCombos = parseEventString(eventString);
- var eventKey = normalizedKeyForEvent(event);
- for (var i = 0; i < keyCombos.length; ++i) {
- if (keyComboMatchesEvent(keyCombos[i], event, eventKey)) {
- 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]);
- }
-
- // Give precedence to combos with modifiers to be checked first.
- 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() {
- 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) {
- // My kingdom for block-scope binding and destructuring assignment..
- 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 has been already prevented, don't do anything
- if (event.defaultPrevented) {
- return;
- }
-
- var eventKey = normalizedKeyForEvent(event);
- for (var i = 0; i < keyBindings.length; i++) {
- var keyCombo = keyBindings[i][0];
- var handlerName = keyBindings[i][1];
- if (keyComboMatchesEvent(keyCombo, event, eventKey)) {
- this._triggerKeyHandler(keyCombo, handlerName, event);
- // exit the loop if eventDefault was prevented
- 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();
- }
- }
- };
- })();
/**
* @demo demo/index.html
* @polymerBehavior
@@ -11455,6 +4747,7 @@ Polymer({
this._oldTabIndex = this.tabIndex;
this.focused = false;
this.tabIndex = -1;
+ this.blur();
} else if (this._oldTabIndex !== undefined) {
this.tabIndex = this._oldTabIndex;
}
@@ -12505,7 +5798,7 @@ Polymer({
},
_computeKeyboardClass: function(receivedFocusFromKeyboard) {
- this.classList.toggle('keyboard-focus', receivedFocusFromKeyboard);
+ this.toggleClass('keyboard-focus', receivedFocusFromKeyboard);
},
/**
@@ -12516,7 +5809,8 @@ Polymer({
*/
_spaceKeyDownHandler: function(event) {
Polymer.IronButtonStateImpl._spaceKeyDownHandler.call(this, event);
- if (this.hasRipple()) {
+ // Ensure that there is at most one ripple when the space key is held down.
+ if (this.hasRipple() && this.getRipple().ripples.length < 1) {
this._ripple.uiDownAction();
}
},
@@ -12564,7 +5858,7 @@ Polymer({
_calculateElevation: function() {
if (!this.raised) {
- this.elevation = 0;
+ this._setElevation(0);
} else {
Polymer.PaperButtonBehaviorImpl._calculateElevation.apply(this);
}
@@ -12677,7 +5971,6 @@ Polymer({
};
Polymer({
-
is: 'paper-progress',
behaviors: [
@@ -12685,7 +5978,6 @@ Polymer({
],
properties: {
-
/**
* The number that represents the current secondary progress.
*/
@@ -12771,7 +6063,6 @@ Polymer({
_hideSecondaryProgress: function(secondaryRatio) {
return secondaryRatio === 0;
}
-
});
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
@@ -13119,8 +6410,8 @@ cr.define('downloads', function() {
/** @polymerBehavior */
Polymer.PaperItemBehavior = [
- Polymer.IronControlState,
Polymer.IronButtonState,
+ Polymer.IronControlState,
Polymer.PaperItemBehaviorImpl
];
Polymer({
@@ -13187,16 +6478,19 @@ Polymer({
*/
setItemSelected: function(item, isSelected) {
if (item != null) {
- if (isSelected) {
- this.selection.push(item);
- } else {
- var i = this.selection.indexOf(item);
- if (i >= 0) {
- this.selection.splice(i, 1);
+ if (isSelected !== this.isSelected(item)) {
+ // proceed to update selection only if requested state differs from current
+ 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);
}
- }
- if (this.selectCallback) {
- this.selectCallback(item, isSelected);
}
}
},
@@ -13273,6 +6567,7 @@ Polymer({
/**
* Gets or sets the selected element. The default is to use the index of the item.
+ * @type {string|number}
*/
selected: {
type: String,
@@ -13329,6 +6624,7 @@ Polymer({
items: {
type: Array,
readOnly: true,
+ notify: true,
value: function() {
return [];
}
@@ -13351,7 +6647,8 @@ Polymer({
},
observers: [
- '_updateSelected(attrForSelected, selected)'
+ '_updateAttrForSelected(attrForSelected)',
+ '_updateSelected(selected)'
],
created: function() {
@@ -13363,7 +6660,7 @@ Polymer({
this._observer = this._observeItems(this);
this._updateItems();
if (!this._shouldUpdateSelection) {
- this._updateSelected(this.attrForSelected,this.selected)
+ this._updateSelected();
}
this._addListener(this.activateEvent);
},
@@ -13390,7 +6687,7 @@ Polymer({
* Selects the given value.
*
* @method select
- * @param {string} value the value to select.
+ * @param {string|number} value the value to select.
*/
select: function(value) {
this.selected = value;
@@ -13417,6 +6714,22 @@ Polymer({
this.selected = this._indexToValue(index);
},
+ /**
+ * Force a synchronous update of the `items` property.
+ *
+ * NOTE: Consider listening for the `iron-items-changed` event to respond to
+ * updates to the set of selectable items after updates to the DOM list and
+ * selection state have been made.
+ *
+ * WARNING: If you are using this method, you should probably consider an
+ * alternate approach. Synchronously querying for items is potentially
+ * slow for many use cases. The `items` property will update asynchronously
+ * on its own to reflect selectable items in the DOM.
+ */
+ forceSynchronousItemUpdate: function() {
+ this._updateItems();
+ },
+
get _shouldUpdateSelection() {
return this.selected != null;
},
@@ -13440,6 +6753,12 @@ Polymer({
this._setItems(nodes);
},
+ _updateAttrForSelected: function() {
+ if (this._shouldUpdateSelection) {
+ this.selected = this._indexToValue(this.indexOf(this.selectedItem));
+ }
+ },
+
_updateSelected: function() {
this._selectSelected(this.selected);
},
@@ -13480,7 +6799,8 @@ Polymer({
},
_valueForItem: function(item) {
- return item[this.attrForSelected] || item.getAttribute(this.attrForSelected);
+ var propValue = item[this.attrForSelected];
+ return propValue != undefined ? propValue : item.getAttribute(this.attrForSelected);
},
_applySelection: function(item, isSelected) {
@@ -13501,18 +6821,18 @@ Polymer({
// observe items change under the given node.
_observeItems: function(node) {
return Polymer.dom(node).observeNodes(function(mutations) {
- // Let other interested parties know about the change so that
- // we don't have to recreate mutation observers everywher.
- this.fire('iron-items-changed', mutations, {
- bubbles: false,
- cancelable: false
- });
-
this._updateItems();
if (this._shouldUpdateSelection) {
this._updateSelected();
}
+
+ // Let other interested parties know about the change so that
+ // we don't have to recreate mutation observers everywhere.
+ this.fire('iron-items-changed', mutations, {
+ bubbles: false,
+ cancelable: false
+ });
});
},
@@ -13572,7 +6892,7 @@ Polymer({
},
observers: [
- '_updateSelected(attrForSelected, selectedValues)'
+ '_updateSelected(selectedValues)'
],
/**
@@ -13580,7 +6900,7 @@ Polymer({
* `value` will be toggled; otherwise the `value` will be selected.
*
* @method select
- * @param {string} value the value to select.
+ * @param {string|number} value the value to select.
*/
select: function(value) {
if (this.multi) {
@@ -13603,6 +6923,18 @@ Polymer({
(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);
@@ -13612,11 +6944,16 @@ Polymer({
},
_selectMulti: function(values) {
- this._selection.clear();
if (values) {
- for (var i = 0; i < values.length; i++) {
- this._selection.setItemSelected(this._valueToItem(values[i]), true);
+ var selectedItems = this._valuesToItems(values);
+ // clear all but the current selected items
+ this._selection.clear(selectedItems);
+ // select only those not selected yet
+ for (var i = 0; i < selectedItems.length; i++) {
+ this._selection.setItemSelected(selectedItems[i], true);
}
+ } else {
+ this._selection.clear();
}
},
@@ -13639,6 +6976,12 @@ Polymer({
this.splice('selectedValues',i,1);
}
this._selection.setItemSelected(this._valueToItem(value), unselected);
+ },
+
+ _valuesToItems: function(values) {
+ return (values == null) ? null : values.map(function(value) {
+ return this._valueToItem(value);
+ }, this);
}
};
@@ -13707,7 +7050,7 @@ Polymer({
* Selects the given value. If the `multi` property is true, then the selected state of the
* `value` will be toggled; otherwise the `value` will be selected.
*
- * @param {string} value the value to select.
+ * @param {string|number} value the value to select.
*/
select: function(value) {
if (this._defaultFocusAsync) {
@@ -13872,6 +7215,14 @@ Polymer({
return;
}
+ // Do not focus the selected tab if the deepest target is part of the
+ // menu element's local DOM and is focusable.
+ var rootTarget = /** @type {?HTMLElement} */(
+ Polymer.dom(event).rootTarget);
+ if (rootTarget !== this && typeof rootTarget.tabIndex !== "undefined" && !this.isLightDescendant(rootTarget)) {
+ return;
+ }
+
this.blur();
// clear the cached focus item
@@ -13899,6 +7250,7 @@ Polymer({
_onUpKey: function(event) {
// up and down arrows moves the focus
this._focusPrevious();
+ event.detail.keyboardEvent.preventDefault();
},
/**
@@ -13908,6 +7260,7 @@ Polymer({
*/
_onDownKey: function(event) {
this._focusNext();
+ event.detail.keyboardEvent.preventDefault();
},
/**
@@ -14116,14 +7469,14 @@ CSS properties | Action
* the memoized data.
*/
resetFit: function() {
- if (!this._fitInfo || !this._fitInfo.sizedBy.height) {
- this.sizingTarget.style.maxHeight = '';
- this.style.top = this._fitInfo ? this._fitInfo.inlineStyle.top : '';
- }
if (!this._fitInfo || !this._fitInfo.sizedBy.width) {
this.sizingTarget.style.maxWidth = '';
- this.style.left = this._fitInfo ? this._fitInfo.inlineStyle.left : '';
}
+ if (!this._fitInfo || !this._fitInfo.sizedBy.height) {
+ this.sizingTarget.style.maxHeight = '';
+ }
+ this.style.top = this._fitInfo ? this._fitInfo.inlineStyle.top : '';
+ this.style.left = this._fitInfo ? this._fitInfo.inlineStyle.left : '';
if (this._fitInfo) {
this.style.position = this._fitInfo.positionedBy.css;
}
@@ -14184,122 +7537,230 @@ CSS properties | Action
* `position:fixed`.
*/
center: function() {
- if (!this._fitInfo.positionedBy.vertically || !this._fitInfo.positionedBy.horizontally) {
- // need position:fixed to center
- this.style.position = 'fixed';
+ var positionedBy = this._fitInfo.positionedBy;
+ if (positionedBy.vertically && positionedBy.horizontally) {
+ // Already positioned.
+ return;
}
- if (!this._fitInfo.positionedBy.vertically) {
- var top = (this._fitHeight - this.offsetHeight) / 2 + this._fitTop;
- top -= this._fitInfo.margin.top;
+ // Need position:fixed to center
+ this.style.position = 'fixed';
+ // Take into account the offset caused by parents that create stacking
+ // contexts (e.g. with transform: translate3d). Translate to 0,0 and
+ // measure the bounding rect.
+ if (!positionedBy.vertically) {
+ this.style.top = '0px';
+ }
+ if (!positionedBy.horizontally) {
+ this.style.left = '0px';
+ }
+ // It will take in consideration margins and transforms
+ var rect = this.getBoundingClientRect();
+ if (!positionedBy.vertically) {
+ var top = this._fitTop - rect.top + (this._fitHeight - rect.height) / 2;
this.style.top = top + 'px';
}
- if (!this._fitInfo.positionedBy.horizontally) {
- var left = (this._fitWidth - this.offsetWidth) / 2 + this._fitLeft;
- left -= this._fitInfo.margin.left;
+ if (!positionedBy.horizontally) {
+ var left = this._fitLeft - rect.left + (this._fitWidth - rect.width) / 2;
this.style.left = left + 'px';
}
}
};
-Polymer.IronOverlayManager = {
-
- _overlays: [],
+/**
+ * @struct
+ * @constructor
+ */
+ Polymer.IronOverlayManagerClass = function() {
+ this._overlays = [];
+ // Used to keep track of the last focused node before an overlay gets opened.
+ this._lastFocusedNodes = [];
- // iframes have a default z-index of 100, so this default should be at least
- // that.
- _minimumZ: 101,
+ /**
+ * iframes have a default z-index of 100, so this default should be at least
+ * that.
+ * @private {number}
+ */
+ this._minimumZ = 101;
- _backdrops: [],
+ this._backdrops = [];
- _applyOverlayZ: function(overlay, aboveZ) {
- this._setZ(overlay, aboveZ + 2);
- },
+ this._backdropElement = null;
+ Object.defineProperty(this, 'backdropElement', {
+ get: function() {
+ if (!this._backdropElement) {
+ this._backdropElement = document.createElement('iron-overlay-backdrop');
+ }
+ return this._backdropElement;
+ }.bind(this)
+ });
- _setZ: function(element, z) {
- element.style.zIndex = z;
- },
+ /**
+ * The deepest active element.
+ * returns {?Node} element the active element
+ */
+ this.deepActiveElement = null;
+ Object.defineProperty(this, 'deepActiveElement', {
+ get: function() {
+ var active = document.activeElement;
+ // document.activeElement can be null
+ // https://developer.mozilla.org/en-US/docs/Web/API/Document/activeElement
+ while (active && active.root && Polymer.dom(active.root).activeElement) {
+ active = Polymer.dom(active.root).activeElement;
+ }
+ return active;
+ }.bind(this)
+ });
+ };
- // track overlays for z-index and focus managemant
- addOverlay: function(overlay) {
- var minimumZ = Math.max(this.currentOverlayZ(), this._minimumZ);
- this._overlays.push(overlay);
- var newZ = this.currentOverlayZ();
- if (newZ <= minimumZ) {
- this._applyOverlayZ(overlay, minimumZ);
+ /**
+ * If a node is contained in an overlay.
+ * @private
+ * @param {Node} node
+ * @returns {Boolean}
+ */
+ Polymer.IronOverlayManagerClass.prototype._isChildOfOverlay = function(node) {
+ while (node && node !== document.body) {
+ // Use logical parentNode, or native ShadowRoot host.
+ node = Polymer.dom(node).parentNode || node.host;
+ // Check if it is an overlay.
+ if (node && node.behaviors && node.behaviors.indexOf(Polymer.IronOverlayBehaviorImpl) !== -1) {
+ return true;
}
- },
+ }
+ return false;
+ };
- removeOverlay: function(overlay) {
- var i = this._overlays.indexOf(overlay);
- if (i >= 0) {
- this._overlays.splice(i, 1);
- this._setZ(overlay, '');
- }
- },
+ Polymer.IronOverlayManagerClass.prototype._applyOverlayZ = function(overlay, aboveZ) {
+ this._setZ(overlay, aboveZ + 2);
+ };
- currentOverlay: function() {
- var i = this._overlays.length - 1;
- while (this._overlays[i] && !this._overlays[i].opened) {
- --i;
- }
- return this._overlays[i];
- },
+ Polymer.IronOverlayManagerClass.prototype._setZ = function(element, z) {
+ element.style.zIndex = z;
+ };
- currentOverlayZ: function() {
- var z = this._minimumZ;
- var current = this.currentOverlay();
- if (current) {
- var z1 = window.getComputedStyle(current).zIndex;
- if (!isNaN(z1)) {
- z = Number(z1);
- }
- }
- return z;
- },
+ /**
+ * track overlays for z-index and focus managemant
+ */
+ Polymer.IronOverlayManagerClass.prototype.addOverlay = function(overlay) {
+ var minimumZ = Math.max(this.currentOverlayZ(), this._minimumZ);
+ this._overlays.push(overlay);
+ var newZ = this.currentOverlayZ();
+ if (newZ <= minimumZ) {
+ this._applyOverlayZ(overlay, minimumZ);
+ }
+ var element = this.deepActiveElement;
+ // If already in other overlay, don't reset focus there.
+ if (this._isChildOfOverlay(element)) {
+ element = null;
+ }
+ this._lastFocusedNodes.push(element);
+ };
- /**
- * Ensures that the minimum z-index of new overlays is at least `minimumZ`.
- * This does not effect the z-index of any existing overlays.
- *
- * @param {number} minimumZ
- */
- ensureMinimumZ: function(minimumZ) {
- this._minimumZ = Math.max(this._minimumZ, minimumZ);
- },
+ Polymer.IronOverlayManagerClass.prototype.removeOverlay = function(overlay) {
+ var i = this._overlays.indexOf(overlay);
+ if (i >= 0) {
+ this._overlays.splice(i, 1);
+ this._setZ(overlay, '');
- focusOverlay: function() {
- var current = this.currentOverlay();
- // We have to be careful to focus the next overlay _after_ any current
- // transitions are complete (due to the state being toggled prior to the
- // transition). Otherwise, we risk infinite recursion when a transitioning
- // (closed) overlay becomes the current overlay.
- //
- // NOTE: We make the assumption that any overlay that completes a transition
- // will call into focusOverlay to kick the process back off. Currently:
- // transitionend -> _applyFocus -> focusOverlay.
- if (current && !current.transitioning) {
- current._applyFocus();
+ var node = this._lastFocusedNodes[i];
+ // Focus only if still contained in document.body
+ if (overlay.restoreFocusOnClose && node && Polymer.dom(document.body).deepContains(node)) {
+ node.focus();
}
- },
+ this._lastFocusedNodes.splice(i, 1);
+ }
+ };
- trackBackdrop: function(element) {
- // backdrops contains the overlays with a backdrop that are currently
- // visible
- if (element.opened) {
+ Polymer.IronOverlayManagerClass.prototype.currentOverlay = function() {
+ var i = this._overlays.length - 1;
+ while (this._overlays[i] && !this._overlays[i].opened) {
+ --i;
+ }
+ return this._overlays[i];
+ };
+
+ Polymer.IronOverlayManagerClass.prototype.currentOverlayZ = function() {
+ return this._getOverlayZ(this.currentOverlay());
+ };
+
+ /**
+ * Ensures that the minimum z-index of new overlays is at least `minimumZ`.
+ * This does not effect the z-index of any existing overlays.
+ *
+ * @param {number} minimumZ
+ */
+ Polymer.IronOverlayManagerClass.prototype.ensureMinimumZ = function(minimumZ) {
+ this._minimumZ = Math.max(this._minimumZ, minimumZ);
+ };
+
+ Polymer.IronOverlayManagerClass.prototype.focusOverlay = function() {
+ var current = this.currentOverlay();
+ // We have to be careful to focus the next overlay _after_ any current
+ // transitions are complete (due to the state being toggled prior to the
+ // transition). Otherwise, we risk infinite recursion when a transitioning
+ // (closed) overlay becomes the current overlay.
+ //
+ // NOTE: We make the assumption that any overlay that completes a transition
+ // will call into focusOverlay to kick the process back off. Currently:
+ // transitionend -> _applyFocus -> focusOverlay.
+ if (current && !current.transitioning) {
+ current._applyFocus();
+ }
+ };
+
+ Polymer.IronOverlayManagerClass.prototype.trackBackdrop = function(element) {
+ // backdrops contains the overlays with a backdrop that are currently
+ // visible
+ var index = this._backdrops.indexOf(element);
+ if (element.opened && element.withBackdrop) {
+ // no duplicates
+ if (index === -1) {
this._backdrops.push(element);
- } else {
- var index = this._backdrops.indexOf(element);
- if (index >= 0) {
- this._backdrops.splice(index, 1);
- }
}
- },
+ } else if (index >= 0) {
+ this._backdrops.splice(index, 1);
+ }
+ };
+
+ Polymer.IronOverlayManagerClass.prototype.getBackdrops = function() {
+ return this._backdrops;
+ };
+
+ /**
+ * Returns the z-index for the backdrop.
+ */
+ Polymer.IronOverlayManagerClass.prototype.backdropZ = function() {
+ return this._getOverlayZ(this._overlayWithBackdrop()) - 1;
+ };
- getBackdrops: function() {
- return this._backdrops;
+ /**
+ * Returns the first opened overlay that has a backdrop.
+ */
+ Polymer.IronOverlayManagerClass.prototype._overlayWithBackdrop = function() {
+ for (var i = 0; i < this._overlays.length; i++) {
+ if (this._overlays[i].opened && this._overlays[i].withBackdrop) {
+ return this._overlays[i];
+ }
}
+ };
+ /**
+ * Calculates the minimum z-index for the overlay.
+ */
+ Polymer.IronOverlayManagerClass.prototype._getOverlayZ = function(overlay) {
+ var z = this._minimumZ;
+ if (overlay) {
+ var z1 = Number(window.getComputedStyle(overlay).zIndex);
+ // Check if is a number
+ // Number.isNaN not supported in IE 10+
+ if (z1 === z1) {
+ z = z1;
+ }
+ }
+ return z;
};
+
+ Polymer.IronOverlayManager = new Polymer.IronOverlayManagerClass();
(function() {
Polymer({
@@ -14325,13 +7786,18 @@ Polymer.IronOverlayManager = {
},
+ listeners: {
+ 'transitionend' : '_onTransitionend'
+ },
+
/**
* Appends the backdrop to document body and sets its `z-index` to be below the latest overlay.
*/
prepare: function() {
+ // Always update z-index
+ this.style.zIndex = this._manager.backdropZ();
if (!this.parentNode) {
Polymer.dom(document.body).appendChild(this);
- this.style.zIndex = this._manager.currentOverlayZ() - 1;
}
},
@@ -14349,9 +7815,18 @@ Polymer.IronOverlayManager = {
* Hides the backdrop if needed.
*/
close: function() {
- // only need to make the backdrop invisible if this is called by the last overlay with a backdrop
- if (this._manager.getBackdrops().length < 2) {
+ // Always update z-index
+ this.style.zIndex = this._manager.backdropZ();
+ // close only if no element with backdrop is left
+ if (this._manager.getBackdrops().length === 0) {
+ // Read style before setting opened.
+ var cs = getComputedStyle(this);
+ var noAnimation = (cs.transitionDuration === '0s' || cs.opacity == 0);
this._setOpened(false);
+ // In case of no animations, complete
+ if (noAnimation) {
+ this.complete();
+ }
}
},
@@ -14363,6 +7838,12 @@ Polymer.IronOverlayManager = {
if (this._manager.getBackdrops().length === 0 && this.parentNode) {
Polymer.dom(this.parentNode).removeChild(this);
}
+ },
+
+ _onTransitionend: function (event) {
+ if (event && event.target === this) {
+ this.complete();
+ }
}
});
@@ -14432,8 +7913,8 @@ context. You should place this element as a child of `<body>` whenever possible.
* Set to true to display a backdrop behind the overlay.
*/
withBackdrop: {
- type: Boolean,
- value: false
+ observer: '_withBackdropChanged',
+ type: Boolean
},
/**
@@ -14470,6 +7951,23 @@ context. You should place this element as a child of `<body>` whenever possible.
type: Object
},
+ /**
+ * The HTMLElement that will be firing relevant KeyboardEvents.
+ * Used for capturing esc and tab. Overridden from `IronA11yKeysBehavior`.
+ */
+ keyEventTarget: {
+ type: Object,
+ value: document
+ },
+
+ /**
+ * Set to true to enable restoring of focus when overlay is closed.
+ */
+ restoreFocusOnClose: {
+ type: Boolean,
+ value: false
+ },
+
_manager: {
type: Object,
value: Polymer.IronOverlayManager
@@ -14482,46 +7980,122 @@ context. You should place this element as a child of `<body>` whenever possible.
}
},
- _boundOnCaptureKeydown: {
+ _boundOnCaptureFocus: {
type: Function,
value: function() {
- return this._onCaptureKeydown.bind(this);
+ return this._onCaptureFocus.bind(this);
}
+ },
+
+ /**
+ * The node being focused.
+ * @type {?Node}
+ */
+ _focusedChild: {
+ type: Object
}
},
+ keyBindings: {
+ 'esc': '__onEsc',
+ 'tab': '__onTab'
+ },
+
listeners: {
- 'tap': '_onClick',
'iron-resize': '_onIronResize'
},
/**
* The backdrop element.
- * @type Node
+ * @type {Node}
*/
get backdropElement() {
- return this._backdrop;
+ return this._manager.backdropElement;
},
+ /**
+ * Returns the node to give focus to.
+ * @type {Node}
+ */
get _focusNode() {
- return Polymer.dom(this).querySelector('[autofocus]') || this;
+ return this._focusedChild || Polymer.dom(this).querySelector('[autofocus]') || this;
},
- registered: function() {
- this._backdrop = document.createElement('iron-overlay-backdrop');
+ /**
+ * Array of nodes that can receive focus (overlay included), ordered by `tabindex`.
+ * This is used to retrieve which is the first and last focusable nodes in order
+ * to wrap the focus for overlays `with-backdrop`.
+ *
+ * If you know what is your content (specifically the first and last focusable children),
+ * you can override this method to return only `[firstFocusable, lastFocusable];`
+ * @type {[Node]}
+ * @protected
+ */
+ get _focusableNodes() {
+ // Elements that can be focused even if they have [disabled] attribute.
+ var FOCUSABLE_WITH_DISABLED = [
+ 'a[href]',
+ 'area[href]',
+ 'iframe',
+ '[tabindex]',
+ '[contentEditable=true]'
+ ];
+
+ // Elements that cannot be focused if they have [disabled] attribute.
+ var FOCUSABLE_WITHOUT_DISABLED = [
+ 'input',
+ 'select',
+ 'textarea',
+ 'button'
+ ];
+
+ // Discard elements with tabindex=-1 (makes them not focusable).
+ 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) {
+ // Insert at the beginning because we might have all elements with tabIndex = 0,
+ // and the overlay should be the first of the list.
+ focusables.splice(0, 0, this);
+ }
+ // Sort by tabindex.
+ 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() {
+ // with-backdrop needs tabindex to be set in order to trap the focus.
+ // If it is not set, IronOverlayBehavior will set it, and remove it if with-backdrop = false.
+ this.__shouldRemoveTabIndex = false;
+ // Used for wrapping the focus on TAB / Shift+TAB.
+ this.__firstFocusableNode = this.__lastFocusableNode = null;
this._ensureSetup();
- if (this._callOpenedWhenReady) {
+ },
+
+ attached: function() {
+ // Call _openedChanged here so that position can be computed correctly.
+ if (this.opened) {
this._openedChanged();
}
+ this._observer = Polymer.dom(this).observeNodes(this._onNodesChange);
},
detached: function() {
+ Polymer.dom(this).unobserveNodes(this._observer);
+ this._observer = null;
this.opened = false;
- this._completeBackdrop();
+ this._manager.trackBackdrop(this);
this._manager.removeOverlay(this);
},
@@ -14529,6 +8103,7 @@ context. You should place this element as a child of `<body>` whenever possible.
* Toggle the opened state of the overlay.
*/
toggle: function() {
+ this._setCanceled(false);
this.opened = !this.opened;
},
@@ -14536,29 +8111,30 @@ context. You should place this element as a child of `<body>` whenever possible.
* Open the overlay.
*/
open: function() {
+ this._setCanceled(false);
this.opened = true;
- this.closingReason = {canceled: false};
},
/**
* Close the overlay.
*/
close: function() {
- this.opened = false;
this._setCanceled(false);
+ this.opened = false;
},
/**
* Cancels the overlay.
+ * @param {?Event} event The original event
*/
- cancel: function() {
- var cancelEvent = this.fire('iron-overlay-canceled', undefined, {cancelable: true});
+ cancel: function(event) {
+ var cancelEvent = this.fire('iron-overlay-canceled', event, {cancelable: true});
if (cancelEvent.defaultPrevented) {
return;
}
- this.opened = false;
this._setCanceled(true);
+ this.opened = false;
},
_ensureSetup: function() {
@@ -14579,33 +8155,34 @@ context. You should place this element as a child of `<body>` whenever possible.
// wait to call after ready only if we're initially open
if (!this._overlaySetup) {
- this._callOpenedWhenReady = this.opened;
return;
}
- if (this._openChangedAsync) {
- this.cancelAsync(this._openChangedAsync);
- }
- this._toggleListeners();
+ this._manager.trackBackdrop(this);
if (this.opened) {
this._prepareRenderOpened();
}
- // async here to allow overlay layer to become visible.
+ if (this._openChangedAsync) {
+ this.cancelAsync(this._openChangedAsync);
+ }
+ // Async here to allow overlay layer to become visible, and to avoid
+ // listeners to immediately close via a click.
this._openChangedAsync = this.async(function() {
// overlay becomes visible here
this.style.display = '';
- // force layout to ensure transitions will go
- /** @suppress {suspiciousCode} */ this.offsetWidth;
+ // Force layout to ensure transition will go. Set offsetWidth to itself
+ // so that compilers won't remove it.
+ this.offsetWidth = this.offsetWidth;
if (this.opened) {
this._renderOpened();
} else {
this._renderClosed();
}
+ this._toggleListeners();
this._openChangedAsync = null;
- });
-
+ }, 1);
},
_canceledChanged: function() {
@@ -14613,6 +8190,29 @@ context. You should place this element as a child of `<body>` whenever possible.
this.closingReason.canceled = this.canceled;
},
+ _withBackdropChanged: function() {
+ // If tabindex is already set, no need to override it.
+ 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._manager.trackBackdrop(this);
+ if (this.withBackdrop) {
+ this.backdropElement.prepare();
+ // Give time to be added to document.
+ this.async(function(){
+ this.backdropElement.open();
+ }, 1);
+ } else {
+ this.backdropElement.close();
+ }
+ }
+ },
+
_toggleListener: function(enable, node, event, boundListener, capture) {
if (enable) {
// enable document-wide tap recognizer
@@ -14630,29 +8230,30 @@ context. You should place this element as a child of `<body>` whenever possible.
},
_toggleListeners: function() {
- if (this._toggleListenersAsync) {
- this.cancelAsync(this._toggleListenersAsync);
- }
- // async so we don't auto-close immediately via a click.
- this._toggleListenersAsync = this.async(function() {
- this._toggleListener(this.opened, document, 'tap', this._boundOnCaptureClick, true);
- this._toggleListener(this.opened, document, 'keydown', this._boundOnCaptureKeydown, true);
- this._toggleListenersAsync = null;
- }, 1);
+ this._toggleListener(this.opened, document, 'tap', this._boundOnCaptureClick, true);
+ this._toggleListener(this.opened, document, 'focus', this._boundOnCaptureFocus, true);
},
// tasks which must occur before opening; e.g. making the element visible
_prepareRenderOpened: function() {
+
this._manager.addOverlay(this);
+ // Needed to calculate the size of the overlay so that transitions on its size
+ // will have the correct starting points.
+ this._preparePositioning();
+ this.fit();
+ this._finishPositioning();
+
if (this.withBackdrop) {
this.backdropElement.prepare();
- this._manager.trackBackdrop(this);
}
- this._preparePositioning();
- this.fit();
- this._finishPositioning();
+ // Safari will apply the focus to the autofocus element when displayed for the first time,
+ // so we blur it. Later, _applyFocus will set the focus if necessary.
+ if (this.noAutoFocus && document.activeElement === this._focusNode) {
+ this._focusNode.blur();
+ }
},
// tasks which cause the overlay to actually open; typically play an
@@ -14671,52 +8272,26 @@ context. You should place this element as a child of `<body>` whenever possible.
this._finishRenderClosed();
},
- _onTransitionend: function(event) {
- // make sure this is our transition event.
- if (event && event.target !== this) {
- return;
- }
- if (this.opened) {
- this._finishRenderOpened();
- } else {
- this._finishRenderClosed();
- }
- },
-
_finishRenderOpened: function() {
- // focus the child node with [autofocus]
- if (!this.noAutoFocus) {
- this._focusNode.focus();
- }
+ // This ensures the overlay is visible before we set the focus
+ // (by calling _onIronResize -> refit).
+ this.notifyResize();
+ // Focus the child node with [autofocus]
+ this._applyFocus();
this.fire('iron-overlay-opened');
-
- this._squelchNextResize = true;
- this.async(this.notifyResize);
},
_finishRenderClosed: function() {
- // hide the overlay and remove the backdrop
+ // Hide the overlay and remove the backdrop.
this.resetFit();
this.style.display = 'none';
- this._completeBackdrop();
this._manager.removeOverlay(this);
- this._focusNode.blur();
- // focus the next overlay, if there is one
- this._manager.focusOverlay();
+ this._applyFocus();
+ this.notifyResize();
this.fire('iron-overlay-closed', this.closingReason);
-
- this._squelchNextResize = true;
- this.async(this.notifyResize);
- },
-
- _completeBackdrop: function() {
- if (this.withBackdrop) {
- this._manager.trackBackdrop(this);
- this.backdropElement.complete();
- }
},
_preparePositioning: function() {
@@ -14728,8 +8303,9 @@ context. You should place this element as a child of `<body>` whenever possible.
_finishPositioning: function() {
this.style.display = 'none';
this.style.transform = this.style.webkitTransform = '';
- // force layout to avoid application of transform
- /** @suppress {suspiciousCode} */ this.offsetWidth;
+ // Force layout layout to avoid application of transform.
+ // Set offsetWidth to itself so that compilers won't remove it.
+ this.offsetWidth = this.offsetWidth;
this.style.transition = this.style.webkitTransition = '';
},
@@ -14740,66 +8316,105 @@ context. You should place this element as a child of `<body>` whenever possible.
}
} else {
this._focusNode.blur();
+ this._focusedChild = null;
this._manager.focusOverlay();
}
},
_onCaptureClick: function(event) {
- // attempt to close asynchronously and prevent the close of a tap event is immediately heard
- // on target. This is because in shadow dom due to event retargetting event.target is not
- // useful.
- if (!this.noCancelOnOutsideClick && (this._manager.currentOverlay() == this)) {
- this._cancelJob = this.async(function() {
- this.cancel();
- }, 10);
+ if (this._manager.currentOverlay() === this &&
+ Polymer.dom(event).path.indexOf(this) === -1) {
+ if (this.noCancelOnOutsideClick) {
+ this._applyFocus();
+ } else {
+ this.cancel(event);
+ }
}
},
- _onClick: function(event) {
- if (this._cancelJob) {
- this.cancelAsync(this._cancelJob);
- this._cancelJob = null;
+ _onCaptureFocus: function (event) {
+ if (this._manager.currentOverlay() === this && this.withBackdrop) {
+ var path = Polymer.dom(event).path;
+ if (path.indexOf(this) === -1) {
+ event.stopPropagation();
+ this._applyFocus();
+ } else {
+ this._focusedChild = path[0];
+ }
}
},
- _onCaptureKeydown: function(event) {
- var ESC = 27;
- if (!this.noCancelOnEscKey && (event.keyCode === ESC)) {
- this.cancel();
- event.stopPropagation();
+ _onIronResize: function() {
+ if (this.opened) {
+ this.refit();
}
},
- _onIronResize: function() {
- if (this._squelchNextResize) {
- this._squelchNextResize = false;
+ /**
+ * @protected
+ * Will call notifyResize if overlay is opened.
+ * Can be overridden in order to avoid multiple observers on the same node.
+ */
+ _onNodesChange: function() {
+ if (this.opened) {
+ this.notifyResize();
+ }
+ // Store it so we don't query too much.
+ var focusableNodes = this._focusableNodes;
+ this.__firstFocusableNode = focusableNodes[0];
+ this.__lastFocusableNode = focusableNodes[focusableNodes.length - 1];
+ },
+
+ __onEsc: function(event) {
+ // Not opened or not on top, so return.
+ if (this._manager.currentOverlay() !== this) {
return;
}
- if (this.opened) {
- this.refit();
+ if (!this.noCancelOnEscKey) {
+ this.cancel(event);
+ }
+ },
+
+ __onTab: function(event) {
+ // Not opened or not on top, so return.
+ if (this._manager.currentOverlay() !== this) {
+ return;
+ }
+ // TAB wraps from last to first focusable.
+ // Shift + TAB wraps from first to last focusable.
+ var shift = event.detail.keyboardEvent.shiftKey;
+ var nodeToCheck = shift ? this.__firstFocusableNode : this.__lastFocusableNode;
+ var nodeToSet = shift ? this.__lastFocusableNode : this.__firstFocusableNode;
+ if (this.withBackdrop && this._focusedChild === nodeToCheck) {
+ // We set here the _focusedChild so that _onCaptureFocus will handle the
+ // wrapping of the focus (the next event after tab is focus).
+ this._focusedChild = nodeToSet;
}
}
+ };
-/**
- * Fired after the `iron-overlay` opens.
- * @event iron-overlay-opened
- */
+ /** @polymerBehavior */
+ Polymer.IronOverlayBehavior = [Polymer.IronA11yKeysBehavior, Polymer.IronFitBehavior, Polymer.IronResizableBehavior, Polymer.IronOverlayBehaviorImpl];
-/**
- * Fired when the `iron-overlay` is canceled, but before it is closed.
- * Cancel the event to prevent the `iron-overlay` from closing.
- * @event iron-overlay-canceled
- */
+ /**
+ * Fired after the `iron-overlay` opens.
+ * @event iron-overlay-opened
+ */
-/**
- * Fired after the `iron-overlay` closes.
- * @event iron-overlay-closed
- * @param {{canceled: (boolean|undefined)}} set to the `closingReason` attribute
- */
- };
+ /**
+ * Fired when the `iron-overlay` is canceled, but before it is closed.
+ * Cancel the event to prevent the `iron-overlay` from closing.
+ * @event iron-overlay-canceled
+ * @param {Event} event The closing of the `iron-overlay` can be prevented
+ * by calling `event.preventDefault()`. The `event.detail` is the original event that originated
+ * the canceling (e.g. ESC keyboard event or click event outside the `iron-overlay`).
+ */
- /** @polymerBehavior */
- Polymer.IronOverlayBehavior = [Polymer.IronFitBehavior, Polymer.IronResizableBehavior, Polymer.IronOverlayBehaviorImpl];
+ /**
+ * Fired after the `iron-overlay` closes.
+ * @event iron-overlay-closed
+ * @param {{canceled: (boolean|undefined)}} closingReason Contains `canceled` (whether the overlay was canceled).
+ */
/**
* Use `Polymer.NeonAnimationBehavior` to implement an animation.
* @polymerBehavior
@@ -14974,6 +8589,11 @@ Polymer({
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;
+ }
+
// type is optional
var thisConfig;
if (type) {
@@ -15020,7 +8640,7 @@ Polymer({
* or a map of animation type to array of configuration objects.
*/
getAnimationConfig: function(type) {
- var map = [];
+ var map = {};
var allConfigs = [];
this._getAnimationConfigRecursive(type, map, allConfigs);
// append the configurations saved in the map to the array
@@ -15164,6 +8784,10 @@ Polymer({
*/
elementIsScrollLocked: function(element) {
var currentLockingElement = this.currentLockingElement;
+
+ if (currentLockingElement === undefined)
+ return false;
+
var scrollLocked;
if (this._hasCachedLockedElement(element)) {
@@ -15198,6 +8822,11 @@ Polymer({
* @param {HTMLElement} element The element that should lock scroll.
*/
pushScrollLock: function(element) {
+ // Prevent pushing the same element twice
+ if (this._lockingElements.indexOf(element) >= 0) {
+ return;
+ }
+
if (this._lockingElements.length === 0) {
this._lockScrollInteractions();
}
@@ -15291,7 +8920,7 @@ Polymer({
_scrollInteractionHandler: function(event) {
if (Polymer
.IronDropdownScrollManager
- .elementIsScrollLocked(event.target)) {
+ .elementIsScrollLocked(Polymer.dom(event).rootTarget)) {
if (event.type === 'keydown' &&
!Polymer.IronDropdownScrollManager._isScrollingKeypress(event)) {
return;
@@ -15318,13 +8947,13 @@ Polymer({
document.body.style.overflowY = 'hidden';
// Modern `wheel` event for mouse wheel scrolling:
- window.addEventListener('wheel', this._scrollInteractionHandler, true);
+ document.addEventListener('wheel', this._scrollInteractionHandler, true);
// Older, non-standard `mousewheel` event for some FF:
- window.addEventListener('mousewheel', this._scrollInteractionHandler, true);
+ document.addEventListener('mousewheel', this._scrollInteractionHandler, true);
// IE:
- window.addEventListener('DOMMouseScroll', this._scrollInteractionHandler, true);
+ document.addEventListener('DOMMouseScroll', this._scrollInteractionHandler, true);
// Mobile devices can scroll on touch move:
- window.addEventListener('touchmove', this._scrollInteractionHandler, true);
+ document.addEventListener('touchmove', this._scrollInteractionHandler, true);
// Capture keydown to prevent scrolling keys (pageup, pagedown etc.)
document.addEventListener('keydown', this._scrollInteractionHandler, true);
},
@@ -15334,10 +8963,10 @@ Polymer({
document.body.style.overflowX = this._originalBodyStyles.overflowX;
document.body.style.overflowY = this._originalBodyStyles.overflowY;
- window.removeEventListener('wheel', this._scrollInteractionHandler, true);
- window.removeEventListener('mousewheel', this._scrollInteractionHandler, true);
- window.removeEventListener('DOMMouseScroll', this._scrollInteractionHandler, true);
- window.removeEventListener('touchmove', this._scrollInteractionHandler, true);
+ document.removeEventListener('wheel', this._scrollInteractionHandler, true);
+ document.removeEventListener('mousewheel', this._scrollInteractionHandler, true);
+ document.removeEventListener('DOMMouseScroll', this._scrollInteractionHandler, true);
+ document.removeEventListener('touchmove', this._scrollInteractionHandler, true);
document.removeEventListener('keydown', this._scrollInteractionHandler, true);
}
};
@@ -15378,8 +9007,17 @@ Polymer({
/**
* A pixel value that will be added to the position calculated for the
- * given `horizontalAlign`. Use a negative value to offset to the
- * left, or a positive value to offset to the right.
+ * given `horizontalAlign`, in the direction of alignment. You can think
+ * of it as increasing or decreasing the distance to the side of the
+ * screen given by `horizontalAlign`.
+ *
+ * If `horizontalAlign` is "left", this offset will increase or decrease
+ * the distance to the left side of the screen: a negative offset will
+ * move the dropdown to the left; a positive one, to the right.
+ *
+ * Conversely if `horizontalAlign` is "right", this offset will increase
+ * or decrease the distance to the right side of the screen: a negative
+ * offset will move the dropdown to the right; a positive one, to the left.
*/
horizontalOffset: {
type: Number,
@@ -15389,8 +9027,17 @@ Polymer({
/**
* A pixel value that will be added to the position calculated for the
- * given `verticalAlign`. Use a negative value to offset towards the
- * top, or a positive value to offset towards the bottom.
+ * given `verticalAlign`, in the direction of alignment. You can think
+ * of it as increasing or decreasing the distance to the side of the
+ * screen given by `verticalAlign`.
+ *
+ * If `verticalAlign` is "top", this offset will increase or decrease
+ * the distance to the top side of the screen: a negative offset will
+ * move the dropdown upwards; a positive one, downwards.
+ *
+ * Conversely if `verticalAlign` is "bottom", this offset will increase
+ * or decrease the distance to the bottom side of the screen: a negative
+ * offset will move the dropdown downwards; a positive one, upwards.
*/
verticalOffset: {
type: Number,
@@ -15484,12 +9131,20 @@ Polymer({
/**
* The element that should be focused when the dropdown opens.
+ * @deprecated
*/
get _focusTarget() {
return this.focusTarget || this.containedElement;
},
/**
+ * Whether the text direction is RTL
+ */
+ _isRTL: function() {
+ return window.getComputedStyle(this).direction == 'rtl';
+ },
+
+ /**
* The element that should be used to position the dropdown when
* it opens, if no position target is configured.
*/
@@ -15520,7 +9175,10 @@ Polymer({
get _horizontalAlignTargetValue() {
var target;
- if (this.horizontalAlign === 'right') {
+ // In RTL, the direction flips, so what is "right" in LTR becomes "left".
+ var isRTL = this._isRTL();
+ if ((!isRTL && this.horizontalAlign === 'right') ||
+ (isRTL && this.horizontalAlign === 'left')) {
target = document.documentElement.clientWidth - this._positionRect.right;
} else {
target = this._positionRect.left;
@@ -15549,6 +9207,18 @@ Polymer({
},
/**
+ * The horizontal align value, accounting for the RTL/LTR text direction.
+ */
+ get _localeHorizontalAlign() {
+ // In RTL, "left" becomes "right".
+ if (this._isRTL()) {
+ return this.horizontalAlign === 'right' ? 'left' : 'right';
+ } else {
+ return this.horizontalAlign;
+ }
+ },
+
+ /**
* Called when the value of `opened` changes.
*
* @param {boolean} opened True if the dropdown is opened.
@@ -15561,10 +9231,6 @@ Polymer({
this._prepareDropdown();
Polymer.IronOverlayBehaviorImpl._openedChanged.apply(this, arguments);
}
-
- if (this.opened) {
- this._focusContent();
- }
},
/**
@@ -15619,7 +9285,7 @@ Polymer({
var scrollTop;
var scrollLeft;
- if (containedElement) {
+ if (this.opened && containedElement) {
scrollTop = containedElement.scrollTop;
scrollLeft = containedElement.scrollLeft;
}
@@ -15630,7 +9296,7 @@ Polymer({
Polymer.IronOverlayBehaviorImpl._onIronResize.apply(this, arguments);
- if (containedElement) {
+ if (this.opened && containedElement) {
containedElement.scrollTop = scrollTop;
containedElement.scrollLeft = scrollLeft;
}
@@ -15696,7 +9362,7 @@ Polymer({
return;
}
- this.style[this.horizontalAlign] =
+ this.style[this._localeHorizontalAlign] =
this._horizontalAlignTargetValue + 'px';
this.style[this.verticalAlign] =
@@ -15715,16 +9381,15 @@ Polymer({
},
/**
- * Focuses the configured focus target.
+ * Apply focus to focusTarget or containedElement
*/
- _focusContent: function() {
- // NOTE(cdata): This is async so that it can attempt the focus after
- // `display: none` is removed from the element.
- this.async(function() {
- if (this._focusTarget) {
- this._focusTarget.focus();
- }
- });
+ _applyFocus: function () {
+ var focusTarget = this.focusTarget || this.containedElement;
+ if (focusTarget && this.opened && !this.noAutoFocus) {
+ focusTarget.focus();
+ } else {
+ Polymer.IronOverlayBehaviorImpl._applyFocus.apply(this, arguments);
+ }
}
});
})();
@@ -16300,7 +9965,7 @@ It may be desirable to only allow users to enter certain characters. You can use
`prevent-invalid-input` and `allowed-pattern` attributes together to accomplish this. This feature
is separate from validation, and `allowed-pattern` does not affect how the input is validated.
- <!-- only allow characters that match [0-9] -->
+ \x3c!-- only allow characters that match [0-9] --\x3e
<input is="iron-input" prevent-invalid-input allowed-pattern="[0-9]">
@hero hero.svg
@@ -16329,15 +9994,17 @@ is separate from validation, and `allowed-pattern` does not affect how the input
/**
* Set to true to prevent the user from entering invalid input. The new input characters are
- * matched with `allowedPattern` if it is set, otherwise it will use the `pattern` attribute if
- * set, or the `type` attribute (only supported for `type=number`).
+ * matched with `allowedPattern` if it is set, otherwise it will use the `type` attribute (only
+ * supported for `type=number`).
*/
preventInvalidInput: {
type: Boolean
},
/**
- * Regular expression to match valid input characters.
+ * Regular expression expressing a set of characters to enforce the validity of input characters.
+ * The recommended value should follow this format: `[a-ZA-Z0-9.+-!;:]` that list the characters
+ * allowed as input.
*/
allowedPattern: {
type: String,
@@ -16365,8 +10032,6 @@ is separate from validation, and `allowed-pattern` does not affect how the input
var pattern;
if (this.allowedPattern) {
pattern = new RegExp(this.allowedPattern);
- } else if (this.pattern) {
- pattern = new RegExp(this.pattern);
} else {
switch (this.type) {
case 'number':
@@ -16386,7 +10051,7 @@ is separate from validation, and `allowed-pattern` does not affect how the input
*/
_bindValueChanged: function() {
if (this.value !== this.bindValue) {
- this.value = !(this.bindValue || this.bindValue === 0) ? '' : this.bindValue;
+ this.value = !(this.bindValue || this.bindValue === 0 || this.bindValue === false) ? '' : this.bindValue;
}
// manually notify because we don't want to notify until after setting value
this.fire('bind-value-changed', {value: this.bindValue});
@@ -16495,8 +10160,8 @@ is separate from validation, and `allowed-pattern` does not affect how the input
if (this.hasValidator()) {
valid = Polymer.IronValidatableBehavior.validate.call(this, this.value);
} else {
- this.invalid = !this.validity.valid;
- valid = this.validity.valid;
+ valid = this.checkValidity();
+ this.invalid = !valid;
}
this.fire('iron-input-validate');
return valid;
@@ -16817,21 +10482,63 @@ var SearchField = Polymer({
showingSearch_: {
type: Boolean,
value: false,
+ observer: 'showingSearchChanged_',
},
},
+ /**
+ * Returns the value of the search field.
+ * @return {string}
+ */
+ getValue: function() {
+ var searchInput = this.getSearchInput_();
+ return searchInput ? searchInput.value : '';
+ },
+
+ /**
+ * Sets the value of the search field, if it exists.
+ * @param {string} value
+ */
+ setValue: function(value) {
+ var searchInput = this.getSearchInput_();
+ if (searchInput)
+ searchInput.value = value;
+ },
+
/** @param {SearchFieldDelegate} delegate */
setDelegate: function(delegate) {
this.delegate_ = delegate;
},
+ /** @return {Promise<boolean>} */
+ showAndFocus: function() {
+ this.showingSearch_ = true;
+ return this.focus_();
+ },
+
/**
- * Returns the value of the search field.
- * @return {string}
+ * @return {Promise<boolean>}
+ * @private
*/
- getValue: function() {
- var searchInput = this.$$('#search-input');
- return searchInput ? searchInput.value : '';
+ focus_: function() {
+ return new Promise(function(resolve) {
+ this.async(function() {
+ if (this.showingSearch_) {
+ var searchInput = this.getSearchInput_();
+ if (searchInput)
+ searchInput.focus();
+ }
+ resolve(this.showingSearch_);
+ });
+ }.bind(this));
+ },
+
+ /**
+ * @return {?Element}
+ * @private
+ */
+ getSearchInput_: function() {
+ return this.$$('#search-input');
},
/** @private */
@@ -16842,23 +10549,28 @@ var SearchField = Polymer({
/** @private */
onSearchTermKeydown_: function(e) {
- assert(this.showingSearch_);
if (e.keyIdentifier == 'U+001B') // Escape.
- this.toggleShowingSearch_();
+ this.showingSearch_ = false;
+ },
+
+ /** @private */
+ showingSearchChanged_: function() {
+ if (this.showingSearch_) {
+ this.focus_();
+ return;
+ }
+
+ var searchInput = this.getSearchInput_();
+ if (!searchInput)
+ return;
+
+ searchInput.value = '';
+ this.onSearchTermSearch_();
},
/** @private */
toggleShowingSearch_: function() {
this.showingSearch_ = !this.showingSearch_;
- this.async(function() {
- var searchInput = this.$$('#search-input');
- if (this.showingSearch_) {
- searchInput.focus();
- } else {
- searchInput.value = '';
- this.onSearchTermSearch_();
- }
- });
},
});
// Copyright 2015 The Chromium Authors. All rights reserved.
@@ -16883,7 +10595,7 @@ cr.define('downloads', function() {
reflectToAttribute: true,
type: Boolean,
value: false,
- observer: 'onDownloadsShowingChange_',
+ observer: 'downloadsShowingChanged_',
},
overflowAlign_: {
@@ -16902,6 +10614,10 @@ cr.define('downloads', function() {
return !this.$['search-input'].getValue() && this.downloadsShowing;
},
+ onFindCommand: function() {
+ this.$['search-input'].showAndFocus();
+ },
+
/** @private */
onClearAllTap_: function() {
assert(this.canClearAll());
@@ -16909,7 +10625,7 @@ cr.define('downloads', function() {
},
/** @private */
- onDownloadsShowingChange_: function() {
+ downloadsShowingChanged_: function() {
this.updateClearAll_();
},
@@ -17038,6 +10754,9 @@ cr.define('downloads', function() {
case 'clear-all-command':
e.canExecute = this.$.toolbar.canClearAll();
break;
+ case 'find-command':
+ e.canExecute = true;
+ break;
}
},
@@ -17050,6 +10769,8 @@ cr.define('downloads', function() {
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();
},
/** @private */
@@ -17103,7 +10824,8 @@ cr.define('downloads', function() {
updateItem_: function(index, data) {
this.set('items_.' + index, data);
this.updateHideDates_(index, index);
- this.$['downloads-list'].updateSizeForItem(index);
+ var list = /** @type {!IronListElement} */(this.$['downloads-list']);
+ list.updateSizeForItem(index);
},
});
@@ -17135,6 +10857,13 @@ cr.define('downloads', function() {
return {Manager: Manager};
});
+// 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 src="../../../../ui/webui/resources/js/i18n_template_no_process.js">
+
+i18nTemplate.process(document, loadTimeData);
// 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/downloads.html b/chromium/chrome/browser/resources/md_downloads/downloads.html
index e5b0bc551c5..81e86789528 100644
--- a/chromium/chrome/browser/resources/md_downloads/downloads.html
+++ b/chromium/chrome/browser/resources/md_downloads/downloads.html
@@ -3,8 +3,7 @@
<head>
<meta charset="utf-8">
<title i18n-content="title"></title>
- <link rel="stylesheet" href="chrome://resources/css/roboto.css">
- <link rel="stylesheet" href="chrome://resources/css/text_defaults.css">
+ <link rel="stylesheet" href="chrome://resources/css/text_defaults_md.css">
<style>
html {
background: rgb(236, 239, 241);
@@ -17,8 +16,6 @@
body {
display: flex;
- font-family: Roboto;
- font-size: 81.25%;
margin: 0;
}
</style>
@@ -28,11 +25,13 @@
<command id="clear-all-command" shortcut="Alt-U+0043"><!-- Alt+C -->
<if expr="is_macosx">
<command id="undo-command" shortcut="Meta-U+005A"><!-- Command+Z -->
+ <command id="find-command" shortcut="Meta-U+0046"><!-- Command+F -->
</if>
<if expr="not is_macosx">
<command id="undo-command" shortcut="Ctrl-U+005A"><!-- Ctrl+Z -->
+ <command id="find-command" shortcut="Ctrl-U+0046"><!-- Ctrl+F -->
</if>
- <link rel="import" href="chrome://resources/html/polymer_config.html">
+ <link rel="import" href="chrome://resources/html/polymer.html">
<link rel="import" href="chrome://downloads/i18n_setup.html">
<link rel="import" href="chrome://downloads/manager.html">
<!-- i18n_template.html actually does i18n-* attribute substitutions.
diff --git a/chromium/chrome/browser/resources/md_downloads/externs.js b/chromium/chrome/browser/resources/md_downloads/externs.js
index 65efb05f944..51830ff98a9 100644
--- a/chromium/chrome/browser/resources/md_downloads/externs.js
+++ b/chromium/chrome/browser/resources/md_downloads/externs.js
@@ -11,7 +11,7 @@ var downloads = {};
/**
* The type of the download object. The definition is based on
- * chrome/browser/ui/webui/downloads_dom_handler.cc:CreateDownloadItemValue()
+ * MdDownloadsDOMHandler::CreateDownloadItemValue()
* @typedef {{by_ext_id: string,
* by_ext_name: string,
* danger_type: string,
diff --git a/chromium/chrome/browser/resources/md_downloads/item.css b/chromium/chrome/browser/resources/md_downloads/item.css
index af5d94430cd..41cc3cb4c8c 100644
--- a/chromium/chrome/browser/resources/md_downloads/item.css
+++ b/chromium/chrome/browser/resources/md_downloads/item.css
@@ -36,7 +36,9 @@
}
#content:not(.is-active) {
- opacity: .6;
+ background: rgba(255, 255, 255, .6);
+ box-shadow: 0 2px 2px 0 rgba(0, 0, 0, .03), 0 1px 4px 0 rgba(0, 0, 0, .048),
+ 0 3px 1px -2px rgba(0, 0, 0, .12);
}
#details {
@@ -52,7 +54,7 @@
}
#content:not(.is-active) #details {
- color: #bababa;
+ color: rgba(186, 186, 186, .6);
}
#content:not(.is-active) #name {
@@ -111,7 +113,8 @@
-webkit-margin-end: 12px; /* Only really affects #tag. */
}
-.is-active :-webkit-any(#name, #file-link, #pause, #resume, #show) {
+#resume,
+.is-active :-webkit-any(#name, #file-link, #pause, #show) {
color: rgb(51, 103, 214);
}
diff --git a/chromium/chrome/browser/resources/md_downloads/item.html b/chromium/chrome/browser/resources/md_downloads/item.html
index 7bf53d3ce3e..e9f2c8315c6 100644
--- a/chromium/chrome/browser/resources/md_downloads/item.html
+++ b/chromium/chrome/browser/resources/md_downloads/item.html
@@ -1,6 +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/polymer/v1_0/polymer/polymer.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/polymer/v1_0/iron-icons/iron-icons.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-behaviors/paper-inky-focus-behavior.html">
diff --git a/chromium/chrome/browser/resources/md_downloads/manager.html b/chromium/chrome/browser/resources/md_downloads/manager.html
index 159a0d598d0..9aae9aca342 100644
--- a/chromium/chrome/browser/resources/md_downloads/manager.html
+++ b/chromium/chrome/browser/resources/md_downloads/manager.html
@@ -1,8 +1,8 @@
<link rel="import" href="chrome://resources/html/cr.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/polymer.html">
<link rel="import" href="chrome://resources/html/util.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
<link rel="import" href="chrome://resources/polymer/v1_0/iron-list/iron-list.html">
<link rel="import" href="chrome://downloads/action_service.html">
<link rel="import" href="chrome://downloads/constants.html">
diff --git a/chromium/chrome/browser/resources/md_downloads/manager.js b/chromium/chrome/browser/resources/md_downloads/manager.js
index 489663d9423..4700cff65a9 100644
--- a/chromium/chrome/browser/resources/md_downloads/manager.js
+++ b/chromium/chrome/browser/resources/md_downloads/manager.js
@@ -79,6 +79,9 @@ cr.define('downloads', function() {
case 'clear-all-command':
e.canExecute = this.$.toolbar.canClearAll();
break;
+ case 'find-command':
+ e.canExecute = true;
+ break;
}
},
@@ -91,6 +94,8 @@ cr.define('downloads', function() {
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();
},
/** @private */
@@ -144,7 +149,8 @@ cr.define('downloads', function() {
updateItem_: function(index, data) {
this.set('items_.' + index, data);
this.updateHideDates_(index, index);
- this.$['downloads-list'].updateSizeForItem(index);
+ var list = /** @type {!IronListElement} */(this.$['downloads-list']);
+ list.updateSizeForItem(index);
},
});
diff --git a/chromium/chrome/browser/resources/md_downloads/toolbar.html b/chromium/chrome/browser/resources/md_downloads/toolbar.html
index 72fe293517a..fcb005be1e2 100644
--- a/chromium/chrome/browser/resources/md_downloads/toolbar.html
+++ b/chromium/chrome/browser/resources/md_downloads/toolbar.html
@@ -1,4 +1,7 @@
-<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
+<link rel="import" href="chrome://resources/html/assert.html">
+<link rel="import" href="chrome://resources/html/cr.html">
+<link rel="import" href="chrome://resources/html/polymer.html">
+<link rel="import" href="chrome://resources/html/util.html">
<link rel="import" href="chrome://resources/polymer/v1_0/iron-icons/iron-icons.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-item/paper-item.html">
@@ -6,9 +9,6 @@
<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-icon-button/paper-icon-button.html">
<link rel="import" href="chrome://resources/cr_elements/cr_search_field/cr_search_field.html">
-<link rel="import" href="chrome://resources/html/assert.html">
-<link rel="import" href="chrome://resources/html/cr.html">
-<link rel="import" href="chrome://resources/html/util.html">
<link rel="import" href="chrome://downloads/i18n_setup.html">
<dom-module id="downloads-toolbar">
diff --git a/chromium/chrome/browser/resources/md_downloads/toolbar.js b/chromium/chrome/browser/resources/md_downloads/toolbar.js
index ff9173ee452..c23364b3a9f 100644
--- a/chromium/chrome/browser/resources/md_downloads/toolbar.js
+++ b/chromium/chrome/browser/resources/md_downloads/toolbar.js
@@ -20,7 +20,7 @@ cr.define('downloads', function() {
reflectToAttribute: true,
type: Boolean,
value: false,
- observer: 'onDownloadsShowingChange_',
+ observer: 'downloadsShowingChanged_',
},
overflowAlign_: {
@@ -39,6 +39,10 @@ cr.define('downloads', function() {
return !this.$['search-input'].getValue() && this.downloadsShowing;
},
+ onFindCommand: function() {
+ this.$['search-input'].showAndFocus();
+ },
+
/** @private */
onClearAllTap_: function() {
assert(this.canClearAll());
@@ -46,7 +50,7 @@ cr.define('downloads', function() {
},
/** @private */
- onDownloadsShowingChange_: function() {
+ downloadsShowingChanged_: function() {
this.updateClearAll_();
},
diff --git a/chromium/chrome/browser/resources/md_downloads/vulcanize.py b/chromium/chrome/browser/resources/md_downloads/vulcanize.py
index ab324856b95..673b0d581f9 100755
--- a/chromium/chrome/browser/resources/md_downloads/vulcanize.py
+++ b/chromium/chrome/browser/resources/md_downloads/vulcanize.py
@@ -26,23 +26,30 @@ _JS_RESOURCES_PATH = os.path.join(_RESOURCES_PATH, 'js')
_POLYMER_PATH = os.path.join(
_SRC_PATH, 'third_party', 'polymer', 'v1_0', 'components-chromium')
-_WEB_ANIMATIONS_PATH = os.path.join(
- _SRC_PATH, 'third_party', 'web-animations-js', 'sources')
_VULCANIZE_ARGS = [
'--exclude', 'crisper.js',
+
+ # These files are already combined and minified.
+ '--exclude', 'chrome://resources/html/polymer.html',
+ '--exclude', 'web-animations-next-lite.min.js',
+
+ # These files are dynamically created by C++.
'--exclude', 'load_time_data.js',
'--exclude', 'strings.js',
'--exclude', 'text_defaults.css',
+ '--exclude', 'text_defaults_md.css',
+
'--inline-css',
'--inline-scripts',
+
'--redirect', 'chrome://downloads/|%s' % _HERE_PATH,
'--redirect', 'chrome://resources/cr_elements/|%s' % _CR_ELEMENTS_PATH,
'--redirect', 'chrome://resources/css/|%s' % _CSS_RESOURCES_PATH,
'--redirect', 'chrome://resources/html/|%s' % _HTML_RESOURCES_PATH,
'--redirect', 'chrome://resources/js/|%s' % _JS_RESOURCES_PATH,
- '--redirect', 'chrome://resources/polymer/v1_0/web-animations-js/|%s' % _WEB_ANIMATIONS_PATH,
'--redirect', 'chrome://resources/polymer/v1_0/|%s' % _POLYMER_PATH,
+
'--strip-comments',
]
@@ -66,8 +73,10 @@ def main():
'<include src="', '<include src="../../../../ui/webui/resources/js/'))
try:
- _run_cmd(['crisper', '--source', tmp.name, '--html', _HTML_OUT_PATH,
- '--js', _JS_OUT_PATH])
+ _run_cmd(['crisper', '--source', tmp.name,
+ '--script-in-head', 'false',
+ '--html', _HTML_OUT_PATH,
+ '--js', _JS_OUT_PATH])
finally:
os.remove(tmp.name)
diff --git a/chromium/chrome/browser/resources/md_downloads/vulcanize_readme.md b/chromium/chrome/browser/resources/md_downloads/vulcanize_readme.md
index 1a20f9c4d09..2be2248ada9 100644
--- a/chromium/chrome/browser/resources/md_downloads/vulcanize_readme.md
+++ b/chromium/chrome/browser/resources/md_downloads/vulcanize_readme.md
@@ -8,22 +8,31 @@ files to combine them and reduce blocking load/parse time.
Vulcanization currently requires:
-- node.js: v0.10.25 (can be found with `node --version`)
-- npm: 1.3.10 (can be found with `npm --version`)
-- vulcanize: 1.12.3 (can be found with `vulcanize --version`)
-- crisper: 1.0.7 (can be found with `npm info crisper`)
+- node.js: >= v4.4.2 (can be found with `node --version`)
+- npm: >= 1.3.10 (can be found with `npm --version`)
+- vulcanize: 1.14.8 (can be found with `vulcanize --version`)
+- crisper: 2.0.1 (can be found with `npm list -g crisper`)
## Installing required software
For instructions on installing node and npm, see
[here](https://docs.npmjs.com/getting-started/installing-node).
-Once you've installed npm, you can get `crisper` and `vulcanize` via:
+We recommend telling npm where to store downloaded modules:
```bash
-$ sudo npm install -g crisper vulcanize
+$ npm config set -g prefix "$HOME/node_modules"
```
+Then install `crisper` and `vulcanize` like this:
+
+```bash
+$ npm install -g crisper vulcanize
+```
+
+Ultimately, all that is required to run this script is that `crisper` and
+`vulcanize` are on your `$PATH`.
+
## Combining resources with vulcanize
To combine all the CSS/HTML/JS for the downloads page to make it production
@@ -41,5 +50,5 @@ This should overwrite the following files:
## Testing downloads without vulcanizing
-If you're locally working on the downloads page, you can simply load this URL to
-bypass the vulcanized version: `chrome://downloads/dev.html`
+Build with "use_vulcanize=0" in your GYP_DEFINES to build downloads without
+vulcanizing.
diff --git a/chromium/chrome/browser/resources/md_downloads/vulcanized.html b/chromium/chrome/browser/resources/md_downloads/vulcanized.html
index c8610f43a2a..994982244de 100644
--- a/chromium/chrome/browser/resources/md_downloads/vulcanized.html
+++ b/chromium/chrome/browser/resources/md_downloads/vulcanized.html
@@ -1,6 +1,6 @@
<!DOCTYPE html><html i18n-values="dir:textdirection;lang:language"><head><!--
@license
-Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
+Copyright (c) 2016 The Polymer Project Authors. All rights reserved.
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
@@ -14,40 +14,10 @@ The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
Code distributed by Google as part of the polymer project is also
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
---><!--
-@license
-Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
-This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE
-The complete set of authors may be found at http://polymer.github.io/AUTHORS
-The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS
-Code distributed by Google as part of the polymer project is also
-subject to an additional IP rights grant found at http://polymer.github.io/PATENTS
-->
<meta charset="utf-8">
<title i18n-content="title"></title>
- <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. */
-
-@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');
-}
-
-</style>
- <link rel="stylesheet" href="chrome://resources/css/text_defaults.css">
+ <link rel="stylesheet" href="chrome://resources/css/text_defaults_md.css">
<style>
html {
background: rgb(236, 239, 241);
@@ -60,13 +30,50 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
body {
display: flex;
- font-family: Roboto;
- font-size: 81.25%;
margin: 0;
}
</style>
-<script src="chrome://resources/js/load_time_data.js"></script>
+</head>
+<body><div hidden="" by-vulcanize=""><script src="chrome://resources/js/load_time_data.js"></script>
<script src="chrome://downloads/strings.js"></script>
+<dom-module id="iron-list" assetpath="chrome://resources/polymer/v1_0/iron-list/">
+ <template>
+ <style>
+ :host {
+ display: block;
+ position: relative;
+ }
+
+ @media only screen and (-webkit-max-device-pixel-ratio: 1) {
+ :host {
+ will-change: transform;
+ }
+ }
+
+ #items {
+ @apply(--iron-list-items-container);
+ position: relative;
+ }
+
+ #items > ::content > * {
+ width: 100%;
+ box-sizing: border-box;
+ position: absolute;
+ top: 0;
+ will-change: transform;
+ }
+ </style>
+
+ <array-selector id="selector" items="{{items}}" selected="{{selectedItems}}" selected-item="{{selectedItem}}">
+ </array-selector>
+
+ <div id="items">
+ <content></content>
+ </div>
+
+ </template>
+</dom-module>
+
<style>
/* IE 10 support for HTML5 hidden attr */
[hidden] {
@@ -260,7 +267,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
};
--layout-around-justified: {
- -ms-flex-pack: around;
+ -ms-flex-pack: distribute;
-webkit-justify-content: space-around;
justify-content: space-around;
};
@@ -371,702 +378,6 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
</style>
-
-
-<style is="custom-style">
-
- :root {
-
- --shadow-transition: {
- transition: box-shadow 0.28s cubic-bezier(0.4, 0, 0.2, 1);
- };
-
- --shadow-none: {
- box-shadow: none;
- };
-
- /* from http://codepen.io/shyndman/pen/c5394ddf2e8b2a5c9185904b57421cdb */
-
- --shadow-elevation-2dp: {
- box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14),
- 0 1px 5px 0 rgba(0, 0, 0, 0.12),
- 0 3px 1px -2px rgba(0, 0, 0, 0.2);
- };
-
- --shadow-elevation-3dp: {
- box-shadow: 0 3px 4px 0 rgba(0, 0, 0, 0.14),
- 0 1px 8px 0 rgba(0, 0, 0, 0.12),
- 0 3px 3px -2px rgba(0, 0, 0, 0.4);
- };
-
- --shadow-elevation-4dp: {
- box-shadow: 0 4px 5px 0 rgba(0, 0, 0, 0.14),
- 0 1px 10px 0 rgba(0, 0, 0, 0.12),
- 0 2px 4px -1px rgba(0, 0, 0, 0.4);
- };
-
- --shadow-elevation-6dp: {
- box-shadow: 0 6px 10px 0 rgba(0, 0, 0, 0.14),
- 0 1px 18px 0 rgba(0, 0, 0, 0.12),
- 0 3px 5px -1px rgba(0, 0, 0, 0.4);
- };
-
- --shadow-elevation-8dp: {
- box-shadow: 0 8px 10px 1px rgba(0, 0, 0, 0.14),
- 0 3px 14px 2px rgba(0, 0, 0, 0.12),
- 0 5px 5px -3px rgba(0, 0, 0, 0.4);
- };
-
- --shadow-elevation-16dp: {
- box-shadow: 0 16px 24px 2px rgba(0, 0, 0, 0.14),
- 0 6px 30px 5px rgba(0, 0, 0, 0.12),
- 0 8px 10px -5px rgba(0, 0, 0, 0.4);
- };
-
- }
-
-</style>
-
-
-
-
-<style is="custom-style">
-
- :root {
-
- /* Material Design color palette for Google products */
-
- --google-red-100: #f4c7c3;
- --google-red-300: #e67c73;
- --google-red-500: #db4437;
- --google-red-700: #c53929;
-
- --google-blue-100: #c6dafc;
- --google-blue-300: #7baaf7;
- --google-blue-500: #4285f4;
- --google-blue-700: #3367d6;
-
- --google-green-100: #b7e1cd;
- --google-green-300: #57bb8a;
- --google-green-500: #0f9d58;
- --google-green-700: #0b8043;
-
- --google-yellow-100: #fce8b2;
- --google-yellow-300: #f7cb4d;
- --google-yellow-500: #f4b400;
- --google-yellow-700: #f09300;
-
- --google-grey-100: #f5f5f5;
- --google-grey-300: #e0e0e0;
- --google-grey-500: #9e9e9e;
- --google-grey-700: #616161;
-
- /* Material Design color palette from online spec document */
-
- --paper-red-50: #ffebee;
- --paper-red-100: #ffcdd2;
- --paper-red-200: #ef9a9a;
- --paper-red-300: #e57373;
- --paper-red-400: #ef5350;
- --paper-red-500: #f44336;
- --paper-red-600: #e53935;
- --paper-red-700: #d32f2f;
- --paper-red-800: #c62828;
- --paper-red-900: #b71c1c;
- --paper-red-a100: #ff8a80;
- --paper-red-a200: #ff5252;
- --paper-red-a400: #ff1744;
- --paper-red-a700: #d50000;
-
- --paper-pink-50: #fce4ec;
- --paper-pink-100: #f8bbd0;
- --paper-pink-200: #f48fb1;
- --paper-pink-300: #f06292;
- --paper-pink-400: #ec407a;
- --paper-pink-500: #e91e63;
- --paper-pink-600: #d81b60;
- --paper-pink-700: #c2185b;
- --paper-pink-800: #ad1457;
- --paper-pink-900: #880e4f;
- --paper-pink-a100: #ff80ab;
- --paper-pink-a200: #ff4081;
- --paper-pink-a400: #f50057;
- --paper-pink-a700: #c51162;
-
- --paper-purple-50: #f3e5f5;
- --paper-purple-100: #e1bee7;
- --paper-purple-200: #ce93d8;
- --paper-purple-300: #ba68c8;
- --paper-purple-400: #ab47bc;
- --paper-purple-500: #9c27b0;
- --paper-purple-600: #8e24aa;
- --paper-purple-700: #7b1fa2;
- --paper-purple-800: #6a1b9a;
- --paper-purple-900: #4a148c;
- --paper-purple-a100: #ea80fc;
- --paper-purple-a200: #e040fb;
- --paper-purple-a400: #d500f9;
- --paper-purple-a700: #aa00ff;
-
- --paper-deep-purple-50: #ede7f6;
- --paper-deep-purple-100: #d1c4e9;
- --paper-deep-purple-200: #b39ddb;
- --paper-deep-purple-300: #9575cd;
- --paper-deep-purple-400: #7e57c2;
- --paper-deep-purple-500: #673ab7;
- --paper-deep-purple-600: #5e35b1;
- --paper-deep-purple-700: #512da8;
- --paper-deep-purple-800: #4527a0;
- --paper-deep-purple-900: #311b92;
- --paper-deep-purple-a100: #b388ff;
- --paper-deep-purple-a200: #7c4dff;
- --paper-deep-purple-a400: #651fff;
- --paper-deep-purple-a700: #6200ea;
-
- --paper-indigo-50: #e8eaf6;
- --paper-indigo-100: #c5cae9;
- --paper-indigo-200: #9fa8da;
- --paper-indigo-300: #7986cb;
- --paper-indigo-400: #5c6bc0;
- --paper-indigo-500: #3f51b5;
- --paper-indigo-600: #3949ab;
- --paper-indigo-700: #303f9f;
- --paper-indigo-800: #283593;
- --paper-indigo-900: #1a237e;
- --paper-indigo-a100: #8c9eff;
- --paper-indigo-a200: #536dfe;
- --paper-indigo-a400: #3d5afe;
- --paper-indigo-a700: #304ffe;
-
- --paper-blue-50: #e3f2fd;
- --paper-blue-100: #bbdefb;
- --paper-blue-200: #90caf9;
- --paper-blue-300: #64b5f6;
- --paper-blue-400: #42a5f5;
- --paper-blue-500: #2196f3;
- --paper-blue-600: #1e88e5;
- --paper-blue-700: #1976d2;
- --paper-blue-800: #1565c0;
- --paper-blue-900: #0d47a1;
- --paper-blue-a100: #82b1ff;
- --paper-blue-a200: #448aff;
- --paper-blue-a400: #2979ff;
- --paper-blue-a700: #2962ff;
-
- --paper-light-blue-50: #e1f5fe;
- --paper-light-blue-100: #b3e5fc;
- --paper-light-blue-200: #81d4fa;
- --paper-light-blue-300: #4fc3f7;
- --paper-light-blue-400: #29b6f6;
- --paper-light-blue-500: #03a9f4;
- --paper-light-blue-600: #039be5;
- --paper-light-blue-700: #0288d1;
- --paper-light-blue-800: #0277bd;
- --paper-light-blue-900: #01579b;
- --paper-light-blue-a100: #80d8ff;
- --paper-light-blue-a200: #40c4ff;
- --paper-light-blue-a400: #00b0ff;
- --paper-light-blue-a700: #0091ea;
-
- --paper-cyan-50: #e0f7fa;
- --paper-cyan-100: #b2ebf2;
- --paper-cyan-200: #80deea;
- --paper-cyan-300: #4dd0e1;
- --paper-cyan-400: #26c6da;
- --paper-cyan-500: #00bcd4;
- --paper-cyan-600: #00acc1;
- --paper-cyan-700: #0097a7;
- --paper-cyan-800: #00838f;
- --paper-cyan-900: #006064;
- --paper-cyan-a100: #84ffff;
- --paper-cyan-a200: #18ffff;
- --paper-cyan-a400: #00e5ff;
- --paper-cyan-a700: #00b8d4;
-
- --paper-teal-50: #e0f2f1;
- --paper-teal-100: #b2dfdb;
- --paper-teal-200: #80cbc4;
- --paper-teal-300: #4db6ac;
- --paper-teal-400: #26a69a;
- --paper-teal-500: #009688;
- --paper-teal-600: #00897b;
- --paper-teal-700: #00796b;
- --paper-teal-800: #00695c;
- --paper-teal-900: #004d40;
- --paper-teal-a100: #a7ffeb;
- --paper-teal-a200: #64ffda;
- --paper-teal-a400: #1de9b6;
- --paper-teal-a700: #00bfa5;
-
- --paper-green-50: #e8f5e9;
- --paper-green-100: #c8e6c9;
- --paper-green-200: #a5d6a7;
- --paper-green-300: #81c784;
- --paper-green-400: #66bb6a;
- --paper-green-500: #4caf50;
- --paper-green-600: #43a047;
- --paper-green-700: #388e3c;
- --paper-green-800: #2e7d32;
- --paper-green-900: #1b5e20;
- --paper-green-a100: #b9f6ca;
- --paper-green-a200: #69f0ae;
- --paper-green-a400: #00e676;
- --paper-green-a700: #00c853;
-
- --paper-light-green-50: #f1f8e9;
- --paper-light-green-100: #dcedc8;
- --paper-light-green-200: #c5e1a5;
- --paper-light-green-300: #aed581;
- --paper-light-green-400: #9ccc65;
- --paper-light-green-500: #8bc34a;
- --paper-light-green-600: #7cb342;
- --paper-light-green-700: #689f38;
- --paper-light-green-800: #558b2f;
- --paper-light-green-900: #33691e;
- --paper-light-green-a100: #ccff90;
- --paper-light-green-a200: #b2ff59;
- --paper-light-green-a400: #76ff03;
- --paper-light-green-a700: #64dd17;
-
- --paper-lime-50: #f9fbe7;
- --paper-lime-100: #f0f4c3;
- --paper-lime-200: #e6ee9c;
- --paper-lime-300: #dce775;
- --paper-lime-400: #d4e157;
- --paper-lime-500: #cddc39;
- --paper-lime-600: #c0ca33;
- --paper-lime-700: #afb42b;
- --paper-lime-800: #9e9d24;
- --paper-lime-900: #827717;
- --paper-lime-a100: #f4ff81;
- --paper-lime-a200: #eeff41;
- --paper-lime-a400: #c6ff00;
- --paper-lime-a700: #aeea00;
-
- --paper-yellow-50: #fffde7;
- --paper-yellow-100: #fff9c4;
- --paper-yellow-200: #fff59d;
- --paper-yellow-300: #fff176;
- --paper-yellow-400: #ffee58;
- --paper-yellow-500: #ffeb3b;
- --paper-yellow-600: #fdd835;
- --paper-yellow-700: #fbc02d;
- --paper-yellow-800: #f9a825;
- --paper-yellow-900: #f57f17;
- --paper-yellow-a100: #ffff8d;
- --paper-yellow-a200: #ffff00;
- --paper-yellow-a400: #ffea00;
- --paper-yellow-a700: #ffd600;
-
- --paper-amber-50: #fff8e1;
- --paper-amber-100: #ffecb3;
- --paper-amber-200: #ffe082;
- --paper-amber-300: #ffd54f;
- --paper-amber-400: #ffca28;
- --paper-amber-500: #ffc107;
- --paper-amber-600: #ffb300;
- --paper-amber-700: #ffa000;
- --paper-amber-800: #ff8f00;
- --paper-amber-900: #ff6f00;
- --paper-amber-a100: #ffe57f;
- --paper-amber-a200: #ffd740;
- --paper-amber-a400: #ffc400;
- --paper-amber-a700: #ffab00;
-
- --paper-orange-50: #fff3e0;
- --paper-orange-100: #ffe0b2;
- --paper-orange-200: #ffcc80;
- --paper-orange-300: #ffb74d;
- --paper-orange-400: #ffa726;
- --paper-orange-500: #ff9800;
- --paper-orange-600: #fb8c00;
- --paper-orange-700: #f57c00;
- --paper-orange-800: #ef6c00;
- --paper-orange-900: #e65100;
- --paper-orange-a100: #ffd180;
- --paper-orange-a200: #ffab40;
- --paper-orange-a400: #ff9100;
- --paper-orange-a700: #ff6500;
-
- --paper-deep-orange-50: #fbe9e7;
- --paper-deep-orange-100: #ffccbc;
- --paper-deep-orange-200: #ffab91;
- --paper-deep-orange-300: #ff8a65;
- --paper-deep-orange-400: #ff7043;
- --paper-deep-orange-500: #ff5722;
- --paper-deep-orange-600: #f4511e;
- --paper-deep-orange-700: #e64a19;
- --paper-deep-orange-800: #d84315;
- --paper-deep-orange-900: #bf360c;
- --paper-deep-orange-a100: #ff9e80;
- --paper-deep-orange-a200: #ff6e40;
- --paper-deep-orange-a400: #ff3d00;
- --paper-deep-orange-a700: #dd2c00;
-
- --paper-brown-50: #efebe9;
- --paper-brown-100: #d7ccc8;
- --paper-brown-200: #bcaaa4;
- --paper-brown-300: #a1887f;
- --paper-brown-400: #8d6e63;
- --paper-brown-500: #795548;
- --paper-brown-600: #6d4c41;
- --paper-brown-700: #5d4037;
- --paper-brown-800: #4e342e;
- --paper-brown-900: #3e2723;
-
- --paper-grey-50: #fafafa;
- --paper-grey-100: #f5f5f5;
- --paper-grey-200: #eeeeee;
- --paper-grey-300: #e0e0e0;
- --paper-grey-400: #bdbdbd;
- --paper-grey-500: #9e9e9e;
- --paper-grey-600: #757575;
- --paper-grey-700: #616161;
- --paper-grey-800: #424242;
- --paper-grey-900: #212121;
-
- --paper-blue-grey-50: #eceff1;
- --paper-blue-grey-100: #cfd8dc;
- --paper-blue-grey-200: #b0bec5;
- --paper-blue-grey-300: #90a4ae;
- --paper-blue-grey-400: #78909c;
- --paper-blue-grey-500: #607d8b;
- --paper-blue-grey-600: #546e7a;
- --paper-blue-grey-700: #455a64;
- --paper-blue-grey-800: #37474f;
- --paper-blue-grey-900: #263238;
-
- /* opacity for dark text on a light background */
- --dark-divider-opacity: 0.12;
- --dark-disabled-opacity: 0.38; /* or hint text or icon */
- --dark-secondary-opacity: 0.54;
- --dark-primary-opacity: 0.87;
-
- /* opacity for light text on a dark background */
- --light-divider-opacity: 0.12;
- --light-disabled-opacity: 0.3; /* or hint text or icon */
- --light-secondary-opacity: 0.7;
- --light-primary-opacity: 1.0;
-
- }
-
-</style>
-
-
-<style is="custom-style">
-
- :root {
-
- --dark-primary-color: #303f9f;
-
- --default-primary-color: #3f51b5;
-
- --light-primary-color: #c5cae9;
-
- --text-primary-color: #ffffff;
-
- --accent-color: #ff4081;
-
- --primary-background-color: #ffffff;
-
- --primary-text-color: #212121;
-
- --secondary-text-color: #757575;
-
- --disabled-text-color: #bdbdbd;
-
- --divider-color: #e0e0e0;
-
- }
-
-</style>
-
-
-
-
-
-
-
-
-<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. */
-
-@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');
-}
-
-</style>
-<style is="custom-style">
-
- :root {
-
- /* Shared Styles */
-
- /*
- Unfortunately, we can't use nested rules
- See https://github.com/Polymer/polymer/issues/1399
- */
- --paper-font-common-base: {
- font-family: 'Roboto', 'Noto', sans-serif;
- -webkit-font-smoothing: antialiased;
- };
-
- --paper-font-common-code: {
- font-family: 'Roboto Mono', 'Consolas', 'Menlo', monospace;
- -webkit-font-smoothing: antialiased;
- };
-
- --paper-font-common-expensive-kerning: {
- text-rendering: optimizeLegibility;
- };
-
- --paper-font-common-nowrap: {
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
- };
-
- /* Material Font Styles */
-
- --paper-font-display4: {
- /* @apply(--paper-font-common-base) */
- font-family: 'Roboto', 'Noto', sans-serif;
- -webkit-font-smoothing: antialiased;
-
- /* @apply(--paper-font-common-nowrap); */
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
-
- font-size: 112px;
- font-weight: 300;
- letter-spacing: -.044em;
- line-height: 120px;
- };
-
- --paper-font-display3: {
- /* @apply(--paper-font-common-base) */
- font-family: 'Roboto', 'Noto', sans-serif;
- -webkit-font-smoothing: antialiased;
-
- /* @apply(--paper-font-common-nowrap); */
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
-
- font-size: 56px;
- font-weight: 400;
- letter-spacing: -.026em;
- line-height: 60px;
- };
-
- --paper-font-display2: {
- /* @apply(--paper-font-common-base) */
- font-family: 'Roboto', 'Noto', sans-serif;
- -webkit-font-smoothing: antialiased;
-
-
- font-size: 45px;
- font-weight: 400;
- letter-spacing: -.018em;
- line-height: 48px;
- };
-
- --paper-font-display1: {
- /* @apply(--paper-font-common-base) */
- font-family: 'Roboto', 'Noto', sans-serif;
- -webkit-font-smoothing: antialiased;
-
-
- font-size: 34px;
- font-weight: 400;
- letter-spacing: -.01em;
- line-height: 40px;
- };
-
- --paper-font-headline: {
- /* @apply(--paper-font-common-base) */
- font-family: 'Roboto', 'Noto', sans-serif;
- -webkit-font-smoothing: antialiased;
-
-
- font-size: 24px;
- font-weight: 400;
- letter-spacing: -.012em;
- line-height: 32px;
- };
-
- --paper-font-title: {
- /* @apply(--paper-font-common-base) */
- font-family: 'Roboto', 'Noto', sans-serif;
- -webkit-font-smoothing: antialiased;
-
- /* @apply(--paper-font-common-nowrap); */
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
-
- font-size: 20px;
- font-weight: 500;
- line-height: 28px;
- };
-
- --paper-font-subhead: {
- /* @apply(--paper-font-common-base) */
- font-family: 'Roboto', 'Noto', sans-serif;
- -webkit-font-smoothing: antialiased;
-
-
- font-size: 16px;
- font-weight: 400;
- line-height: 24px;
- };
-
- --paper-font-body2: {
- /* @apply(--paper-font-common-base) */
- font-family: 'Roboto', 'Noto', sans-serif;
- -webkit-font-smoothing: antialiased;
-
- font-size: 14px;
- font-weight: 500;
- line-height: 24px;
- };
-
- --paper-font-body1: {
- /* @apply(--paper-font-common-base) */
- font-family: 'Roboto', 'Noto', sans-serif;
- -webkit-font-smoothing: antialiased;
-
- font-size: 14px;
- font-weight: 400;
- line-height: 20px;
- };
-
- --paper-font-caption: {
- /* @apply(--paper-font-common-base) */
- font-family: 'Roboto', 'Noto', sans-serif;
- -webkit-font-smoothing: antialiased;
- /* @apply(--paper-font-common-nowrap); */
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
-
- font-size: 12px;
- font-weight: 400;
- letter-spacing: 0.011em;
- line-height: 20px;
- };
-
- --paper-font-menu: {
- /* @apply(--paper-font-common-base) */
- font-family: 'Roboto', 'Noto', sans-serif;
- -webkit-font-smoothing: antialiased;
-
- /* @apply(--paper-font-common-nowrap); */
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
-
- font-size: 13px;
- font-weight: 500;
- line-height: 24px;
- };
-
- --paper-font-button: {
- /* @apply(--paper-font-common-base) */
- font-family: 'Roboto', 'Noto', sans-serif;
- -webkit-font-smoothing: antialiased;
-
- /* @apply(--paper-font-common-nowrap); */
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
-
- font-size: 14px;
- font-weight: 500;
- letter-spacing: 0.018em;
- line-height: 24px;
- text-transform: uppercase;
- };
-
- --paper-font-code2: {
- /* @apply(--paper-font-common-code); */
- font-family: 'Roboto Mono', 'Consolas', 'Menlo', monospace;
- -webkit-font-smoothing: antialiased;
-
- font-size: 14px;
- font-weight: 700;
- line-height: 20px;
- };
-
- --paper-font-code1: {
- /* @apply(--paper-font-common-code); */
- font-family: 'Roboto Mono', 'Consolas', 'Menlo', monospace;
- -webkit-font-smoothing: antialiased;
-
- font-size: 14px;
- font-weight: 500;
- line-height: 20px;
- };
-
- }
-
-</style>
-
-</head>
-<body><div hidden="" by-vulcanize=""><dom-module id="iron-list" assetpath="chrome://resources/polymer/v1_0/iron-list/">
- <template>
- <style>
- :host {
- display: block;
- }
-
- :host(.has-scroller) {
- overflow: auto;
- }
-
- :host(:not(.has-scroller)) {
- position: relative;
- }
-
- #items {
- @apply(--iron-list-items-container);
- position: relative;
- }
-
- #items > ::content > * {
- width: 100%;
- box-sizing: border-box;
- position: absolute;
- top: 0;
- will-change: transform;
- }
- </style>
-
- <array-selector id="selector" items="{{items}}" selected="{{selectedItems}}" selected-item="{{selectedItem}}">
- </array-selector>
-
- <div id="items">
- <content></content>
- </div>
-
- </template>
-</dom-module>
-
<dom-module id="iron-icon" assetpath="chrome://resources/polymer/v1_0/iron-icon/">
<style>
@@ -1093,6 +404,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
<svg><defs>
<g id="3d-rotation"><path d="M7.52 21.48C4.25 19.94 1.91 16.76 1.55 13H.05C.56 19.16 5.71 24 12 24l.66-.03-3.81-3.81-1.33 1.32zm.89-6.52c-.19 0-.37-.03-.52-.08-.16-.06-.29-.13-.4-.24-.11-.1-.2-.22-.26-.37-.06-.14-.09-.3-.09-.47h-1.3c0 .36.07.68.21.95.14.27.33.5.56.69.24.18.51.32.82.41.3.1.62.15.96.15.37 0 .72-.05 1.03-.15.32-.1.6-.25.83-.44s.42-.43.55-.72c.13-.29.2-.61.2-.97 0-.19-.02-.38-.07-.56-.05-.18-.12-.35-.23-.51-.1-.16-.24-.3-.4-.43-.17-.13-.37-.23-.61-.31.2-.09.37-.2.52-.33.15-.13.27-.27.37-.42.1-.15.17-.3.22-.46.05-.16.07-.32.07-.48 0-.36-.06-.68-.18-.96-.12-.28-.29-.51-.51-.69-.2-.19-.47-.33-.77-.43C9.1 8.05 8.76 8 8.39 8c-.36 0-.69.05-1 .16-.3.11-.57.26-.79.45-.21.19-.38.41-.51.67-.12.26-.18.54-.18.85h1.3c0-.17.03-.32.09-.45s.14-.25.25-.34c.11-.09.23-.17.38-.22.15-.05.3-.08.48-.08.4 0 .7.1.89.31.19.2.29.49.29.86 0 .18-.03.34-.08.49-.05.15-.14.27-.25.37-.11.1-.25.18-.41.24-.16.06-.36.09-.58.09H7.5v1.03h.77c.22 0 .42.02.6.07s.33.13.45.23c.12.11.22.24.29.4.07.16.1.35.1.57 0 .41-.12.72-.35.93-.23.23-.55.33-.95.33zm8.55-5.92c-.32-.33-.7-.59-1.14-.77-.43-.18-.92-.27-1.46-.27H12v8h2.3c.55 0 1.06-.09 1.51-.27.45-.18.84-.43 1.16-.76.32-.33.57-.73.74-1.19.17-.47.26-.99.26-1.57v-.4c0-.58-.09-1.1-.26-1.57-.18-.47-.43-.87-.75-1.2zm-.39 3.16c0 .42-.05.79-.14 1.13-.1.33-.24.62-.43.85-.19.23-.43.41-.71.53-.29.12-.62.18-.99.18h-.91V9.12h.97c.72 0 1.27.23 1.64.69.38.46.57 1.12.57 1.99v.4zM12 0l-.66.03 3.81 3.81 1.33-1.33c3.27 1.55 5.61 4.72 5.96 8.48h1.5C23.44 4.84 18.29 0 12 0z"></path></g>
<g id="accessibility"><path d="M12 2c1.1 0 2 .9 2 2s-.9 2-2 2-2-.9-2-2 .9-2 2-2zm9 7h-6v13h-2v-6h-2v6H9V9H3V7h18v2z"></path></g>
+<g id="accessible"><circle cx="12" cy="4" r="2"></circle><path d="M19 13v-2c-1.54.02-3.09-.75-4.07-1.83l-1.29-1.43c-.17-.19-.38-.34-.61-.45-.01 0-.01-.01-.02-.01H13c-.35-.2-.75-.3-1.19-.26C10.76 7.11 10 8.04 10 9.09V15c0 1.1.9 2 2 2h5v5h2v-5.5c0-1.1-.9-2-2-2h-3v-3.45c1.29 1.07 3.25 1.94 5 1.95zm-6.17 5c-.41 1.16-1.52 2-2.83 2-1.66 0-3-1.34-3-3 0-1.31.84-2.41 2-2.83V12.1c-2.28.46-4 2.48-4 4.9 0 2.76 2.24 5 5 5 2.42 0 4.44-1.72 4.9-4h-2.07z"></path></g>
<g id="account-balance"><path d="M4 10v7h3v-7H4zm6 0v7h3v-7h-3zM2 22h19v-3H2v3zm14-12v7h3v-7h-3zm-4.5-9L2 6v2h19V6l-9.5-5z"></path></g>
<g id="account-balance-wallet"><path d="M21 18v1c0 1.1-.9 2-2 2H5c-1.11 0-2-.9-2-2V5c0-1.1.89-2 2-2h14c1.1 0 2 .9 2 2v1h-9c-1.11 0-2 .9-2 2v8c0 1.1.89 2 2 2h9zm-9-2h10V8H12v8zm4-2.5c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5z"></path></g>
<g id="account-box"><path d="M3 5v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2H5c-1.11 0-2 .9-2 2zm12 4c0 1.66-1.34 3-3 3s-3-1.34-3-3 1.34-3 3-3 3 1.34 3 3zm-9 8c0-2 4-3.1 6-3.1s6 1.1 6 3.1v1H6v-1z"></path></g>
@@ -1107,15 +419,18 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
<g id="alarm-add"><path d="M7.88 3.39L6.6 1.86 2 5.71l1.29 1.53 4.59-3.85zM22 5.72l-4.6-3.86-1.29 1.53 4.6 3.86L22 5.72zM12 4c-4.97 0-9 4.03-9 9s4.02 9 9 9c4.97 0 9-4.03 9-9s-4.03-9-9-9zm0 16c-3.87 0-7-3.13-7-7s3.13-7 7-7 7 3.13 7 7-3.13 7-7 7zm1-11h-2v3H8v2h3v3h2v-3h3v-2h-3V9z"></path></g>
<g id="alarm-off"><path d="M12 6c3.87 0 7 3.13 7 7 0 .84-.16 1.65-.43 2.4l1.52 1.52c.58-1.19.91-2.51.91-3.92 0-4.97-4.03-9-9-9-1.41 0-2.73.33-3.92.91L9.6 6.43C10.35 6.16 11.16 6 12 6zm10-.28l-4.6-3.86-1.29 1.53 4.6 3.86L22 5.72zM2.92 2.29L1.65 3.57 2.98 4.9l-1.11.93 1.42 1.42 1.11-.94.8.8C3.83 8.69 3 10.75 3 13c0 4.97 4.02 9 9 9 2.25 0 4.31-.83 5.89-2.2l2.2 2.2 1.27-1.27L3.89 3.27l-.97-.98zm13.55 16.1C15.26 19.39 13.7 20 12 20c-3.87 0-7-3.13-7-7 0-1.7.61-3.26 1.61-4.47l9.86 9.86zM8.02 3.28L6.6 1.86l-.86.71 1.42 1.42.86-.71z"></path></g>
<g id="alarm-on"><path d="M22 5.72l-4.6-3.86-1.29 1.53 4.6 3.86L22 5.72zM7.88 3.39L6.6 1.86 2 5.71l1.29 1.53 4.59-3.85zM12 4c-4.97 0-9 4.03-9 9s4.02 9 9 9c4.97 0 9-4.03 9-9s-4.03-9-9-9zm0 16c-3.87 0-7-3.13-7-7s3.13-7 7-7 7 3.13 7 7-3.13 7-7 7zm-1.46-5.47L8.41 12.4l-1.06 1.06 3.18 3.18 6-6-1.06-1.06-4.93 4.95z"></path></g>
+<g id="all-out"><path d="M16.21 4.16l4 4v-4zm4 12l-4 4h4zm-12 4l-4-4v4zm-4-12l4-4h-4zm12.95-.95c-2.73-2.73-7.17-2.73-9.9 0s-2.73 7.17 0 9.9 7.17 2.73 9.9 0 2.73-7.16 0-9.9zm-1.1 8.8c-2.13 2.13-5.57 2.13-7.7 0s-2.13-5.57 0-7.7 5.57-2.13 7.7 0 2.13 5.57 0 7.7z"></path></g>
<g id="android"><path d="M6 18c0 .55.45 1 1 1h1v3.5c0 .83.67 1.5 1.5 1.5s1.5-.67 1.5-1.5V19h2v3.5c0 .83.67 1.5 1.5 1.5s1.5-.67 1.5-1.5V19h1c.55 0 1-.45 1-1V8H6v10zM3.5 8C2.67 8 2 8.67 2 9.5v7c0 .83.67 1.5 1.5 1.5S5 17.33 5 16.5v-7C5 8.67 4.33 8 3.5 8zm17 0c-.83 0-1.5.67-1.5 1.5v7c0 .83.67 1.5 1.5 1.5s1.5-.67 1.5-1.5v-7c0-.83-.67-1.5-1.5-1.5zm-4.97-5.84l1.3-1.3c.2-.2.2-.51 0-.71-.2-.2-.51-.2-.71 0l-1.48 1.48C13.85 1.23 12.95 1 12 1c-.96 0-1.86.23-2.66.63L7.85.15c-.2-.2-.51-.2-.71 0-.2.2-.2.51 0 .71l1.31 1.31C6.97 3.26 6 5.01 6 7h12c0-1.99-.97-3.75-2.47-4.84zM10 5H9V4h1v1zm5 0h-1V4h1v1z"></path></g>
<g id="announcement"><path d="M20 2H4c-1.1 0-1.99.9-1.99 2L2 22l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm-7 9h-2V5h2v6zm0 4h-2v-2h2v2z"></path></g>
<g id="apps"><path d="M4 8h4V4H4v4zm6 12h4v-4h-4v4zm-6 0h4v-4H4v4zm0-6h4v-4H4v4zm6 0h4v-4h-4v4zm6-10v4h4V4h-4zm-6 4h4V4h-4v4zm6 6h4v-4h-4v4zm0 6h4v-4h-4v4z"></path></g>
<g id="archive"><path d="M20.54 5.23l-1.39-1.68C18.88 3.21 18.47 3 18 3H6c-.47 0-.88.21-1.16.55L3.46 5.23C3.17 5.57 3 6.02 3 6.5V19c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V6.5c0-.48-.17-.93-.46-1.27zM12 17.5L6.5 12H10v-2h4v2h3.5L12 17.5zM5.12 5l.81-1h12l.94 1H5.12z"></path></g>
<g id="arrow-back"><path d="M20 11H7.83l5.59-5.59L12 4l-8 8 8 8 1.41-1.41L7.83 13H20v-2z"></path></g>
+<g id="arrow-downward"><path d="M20 12l-1.41-1.41L13 16.17V4h-2v12.17l-5.58-5.59L4 12l8 8 8-8z"></path></g>
<g id="arrow-drop-down"><path d="M7 10l5 5 5-5z"></path></g>
<g id="arrow-drop-down-circle"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 12l-4-4h8l-4 4z"></path></g>
<g id="arrow-drop-up"><path d="M7 14l5-5 5 5z"></path></g>
<g id="arrow-forward"><path d="M12 4l-1.41 1.41L16.17 11H4v2h12.17l-5.58 5.59L12 20l8-8z"></path></g>
+<g id="arrow-upward"><path d="M4 12l1.41 1.41L11 7.83V20h2V7.83l5.58 5.59L20 12l-8-8-8 8z"></path></g>
<g id="aspect-ratio"><path d="M19 12h-2v3h-3v2h5v-5zM7 9h3V7H5v5h2V9zm14-6H3c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h18c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 16.01H3V4.99h18v14.02z"></path></g>
<g id="assessment"><path d="M19 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-2zM9 17H7v-7h2v7zm4 0h-2V7h2v10zm4 0h-2v-4h2v4z"></path></g>
<g id="assignment"><path d="M19 3h-4.18C14.4 1.84 13.3 1 12 1c-1.3 0-2.4.84-2.82 2H5c-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-7 0c.55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1zm2 14H7v-2h7v2zm3-4H7v-2h10v2zm0-4H7V7h10v2z"></path></g>
@@ -1124,7 +439,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
<g id="assignment-return"><path d="M19 3h-4.18C14.4 1.84 13.3 1 12 1c-1.3 0-2.4.84-2.82 2H5c-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-7 0c.55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1zm4 12h-4v3l-5-5 5-5v3h4v4z"></path></g>
<g id="assignment-returned"><path d="M19 3h-4.18C14.4 1.84 13.3 1 12 1c-1.3 0-2.4.84-2.82 2H5c-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-7 0c.55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1zm0 15l-5-5h3V9h4v4h3l-5 5z"></path></g>
<g id="assignment-turned-in"><path d="M19 3h-4.18C14.4 1.84 13.3 1 12 1c-1.3 0-2.4.84-2.82 2H5c-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-7 0c.55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1zm-2 14l-4-4 1.41-1.41L10 14.17l6.59-6.59L18 9l-8 8z"></path></g>
-<g id="attachment"><path d="M7.5 18C4.46 18 2 15.54 2 12.5S4.46 7 7.5 7H18c2.21 0 4 1.79 4 4s-1.79 4-4 4H9.5C8.12 15 7 13.88 7 12.5S8.12 10 9.5 10H17v1.5H9.5c-.55 0-1 .45-1 1s.45 1 1 1H18c1.38 0 2.5-1.12 2.5-2.5S19.38 8.5 18 8.5H7.5c-2.21 0-4 1.79-4 4s1.79 4 4 4H17V18H7.5z"></path></g>
+<g id="attachment"><path d="M2 12.5C2 9.46 4.46 7 7.5 7H18c2.21 0 4 1.79 4 4s-1.79 4-4 4H9.5C8.12 15 7 13.88 7 12.5S8.12 10 9.5 10H17v2H9.41c-.55 0-.55 1 0 1H18c1.1 0 2-.9 2-2s-.9-2-2-2H7.5C5.57 9 4 10.57 4 12.5S5.57 16 7.5 16H17v2H7.5C4.46 18 2 15.54 2 12.5z"></path></g>
<g id="autorenew"><path d="M12 6v3l4-4-4-4v3c-4.42 0-8 3.58-8 8 0 1.57.46 3.03 1.24 4.26L6.7 14.8c-.45-.83-.7-1.79-.7-2.8 0-3.31 2.69-6 6-6zm6.76 1.74L17.3 9.2c.44.84.7 1.79.7 2.8 0 3.31-2.69 6-6 6v-3l-4 4 4 4v-3c4.42 0 8-3.58 8-8 0-1.57-.46-3.03-1.24-4.26z"></path></g>
<g id="backspace"><path d="M22 3H7c-.69 0-1.23.35-1.59.88L0 12l5.41 8.11c.36.53.9.89 1.59.89h15c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-3 12.59L17.59 17 14 13.41 10.41 17 9 15.59 12.59 12 9 8.41 10.41 7 14 10.59 17.59 7 19 8.41 15.41 12 19 15.59z"></path></g>
<g id="backup"><path d="M19.35 10.04C18.67 6.59 15.64 4 12 4 9.11 4 6.6 5.64 5.35 8.04 2.34 8.36 0 10.91 0 14c0 3.31 2.69 6 6 6h13c2.76 0 5-2.24 5-5 0-2.64-2.05-4.78-4.65-4.96zM14 13v4h-4v-4H7l5-5 5 5h-3z"></path></g>
@@ -1135,7 +450,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
<g id="bug-report"><path d="M20 8h-2.81c-.45-.78-1.07-1.45-1.82-1.96L17 4.41 15.59 3l-2.17 2.17C12.96 5.06 12.49 5 12 5c-.49 0-.96.06-1.41.17L8.41 3 7 4.41l1.62 1.63C7.88 6.55 7.26 7.22 6.81 8H4v2h2.09c-.05.33-.09.66-.09 1v1H4v2h2v1c0 .34.04.67.09 1H4v2h2.81c1.04 1.79 2.97 3 5.19 3s4.15-1.21 5.19-3H20v-2h-2.09c.05-.33.09-.66.09-1v-1h2v-2h-2v-1c0-.34-.04-.67-.09-1H20V8zm-6 8h-4v-2h4v2zm0-4h-4v-2h4v2z"></path></g>
<g id="build"><path d="M22.7 19l-9.1-9.1c.9-2.3.4-5-1.5-6.9-2-2-5-2.4-7.4-1.3L9 6 6 9 1.6 4.7C.4 7.1.9 10.1 2.9 12.1c1.9 1.9 4.6 2.4 6.9 1.5l9.1 9.1c.4.4 1 .4 1.4 0l2.3-2.3c.5-.4.5-1.1.1-1.4z"></path></g>
<g id="cached"><path d="M19 8l-4 4h3c0 3.31-2.69 6-6 6-1.01 0-1.97-.25-2.8-.7l-1.46 1.46C8.97 19.54 10.43 20 12 20c4.42 0 8-3.58 8-8h3l-4-4zM6 12c0-3.31 2.69-6 6-6 1.01 0 1.97.25 2.8.7l1.46-1.46C15.03 4.46 13.57 4 12 4c-4.42 0-8 3.58-8 8H1l4 4 4-4H6z"></path></g>
-<g id="camera-enhance"><path d="M9 3L7.17 5H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2h-3.17L15 3H9zm3 15c-2.76 0-5-2.24-5-5s2.24-5 5-5 5 2.24 5 5-2.24 5-5 5zM12 17l1.25-2.75L16 13l-2.75-1.25L12 9l-1.25 2.75L8 13l2.75 1.25z"></path></g>
+<g id="camera-enhance"><path d="M9 3L7.17 5H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2h-3.17L15 3H9zm3 15c-2.76 0-5-2.24-5-5s2.24-5 5-5 5 2.24 5 5-2.24 5-5 5zm0-1l1.25-2.75L16 13l-2.75-1.25L12 9l-1.25 2.75L8 13l2.75 1.25z"></path></g>
<g id="cancel"><path d="M12 2C6.47 2 2 6.47 2 12s4.47 10 10 10 10-4.47 10-10S17.53 2 12 2zm5 13.59L15.59 17 12 13.41 8.41 17 7 15.59 10.59 12 7 8.41 8.41 7 12 10.59 15.59 7 17 8.41 13.41 12 17 15.59z"></path></g>
<g id="card-giftcard"><path d="M20 6h-2.18c.11-.31.18-.65.18-1 0-1.66-1.34-3-3-3-1.05 0-1.96.54-2.5 1.35l-.5.67-.5-.68C10.96 2.54 10.05 2 9 2 7.34 2 6 3.34 6 5c0 .35.07.69.18 1H4c-1.11 0-1.99.89-1.99 2L2 19c0 1.11.89 2 2 2h16c1.11 0 2-.89 2-2V8c0-1.11-.89-2-2-2zm-5-2c.55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1zM9 4c.55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1zm11 15H4v-2h16v2zm0-5H4V8h5.08L7 10.83 8.62 12 11 8.76l1-1.36 1 1.36L15.38 12 17 10.83 14.92 8H20v6z"></path></g>
<g id="card-membership"><path d="M20 2H4c-1.11 0-2 .89-2 2v11c0 1.11.89 2 2 2h4v5l4-2 4 2v-5h4c1.11 0 2-.89 2-2V4c0-1.11-.89-2-2-2zm0 13H4v-2h16v2zm0-5H4V4h16v6z"></path></g>
@@ -1159,23 +474,29 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
<g id="cloud-queue"><path d="M19.35 10.04C18.67 6.59 15.64 4 12 4 9.11 4 6.6 5.64 5.35 8.04 2.34 8.36 0 10.91 0 14c0 3.31 2.69 6 6 6h13c2.76 0 5-2.24 5-5 0-2.64-2.05-4.78-4.65-4.96zM19 18H6c-2.21 0-4-1.79-4-4s1.79-4 4-4h.71C7.37 7.69 9.48 6 12 6c3.04 0 5.5 2.46 5.5 5.5v.5H19c1.66 0 3 1.34 3 3s-1.34 3-3 3z"></path></g>
<g id="cloud-upload"><path d="M19.35 10.04C18.67 6.59 15.64 4 12 4 9.11 4 6.6 5.64 5.35 8.04 2.34 8.36 0 10.91 0 14c0 3.31 2.69 6 6 6h13c2.76 0 5-2.24 5-5 0-2.64-2.05-4.78-4.65-4.96zM14 13v4h-4v-4H7l5-5 5 5h-3z"></path></g>
<g id="code"><path d="M9.4 16.6L4.8 12l4.6-4.6L8 6l-6 6 6 6 1.4-1.4zm5.2 0l4.6-4.6-4.6-4.6L16 6l6 6-6 6-1.4-1.4z"></path></g>
+<g id="compare-arrows"><path d="M9.01 14H2v2h7.01v3L13 15l-3.99-4v3zm5.98-1v-3H22V8h-7.01V5L11 9l3.99 4z"></path></g>
<g id="content-copy"><path d="M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm3 4H8c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 16H8V7h11v14z"></path></g>
<g id="content-cut"><path d="M9.64 7.64c.23-.5.36-1.05.36-1.64 0-2.21-1.79-4-4-4S2 3.79 2 6s1.79 4 4 4c.59 0 1.14-.13 1.64-.36L10 12l-2.36 2.36C7.14 14.13 6.59 14 6 14c-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4c0-.59-.13-1.14-.36-1.64L12 14l7 7h3v-1L9.64 7.64zM6 8c-1.1 0-2-.89-2-2s.9-2 2-2 2 .89 2 2-.9 2-2 2zm0 12c-1.1 0-2-.89-2-2s.9-2 2-2 2 .89 2 2-.9 2-2 2zm6-7.5c-.28 0-.5-.22-.5-.5s.22-.5.5-.5.5.22.5.5-.22.5-.5.5zM19 3l-6 6 2 2 7-7V3z"></path></g>
<g id="content-paste"><path d="M19 2h-4.18C14.4.84 13.3 0 12 0c-1.3 0-2.4.84-2.82 2H5c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm-7 0c.55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1zm7 18H5V4h2v3h10V4h2v16z"></path></g>
+<g id="copyright"><path d="M10.08 10.86c.05-.33.16-.62.3-.87s.34-.46.59-.62c.24-.15.54-.22.91-.23.23.01.44.05.63.13.2.09.38.21.52.36s.25.33.34.53.13.42.14.64h1.79c-.02-.47-.11-.9-.28-1.29s-.4-.73-.7-1.01-.66-.5-1.08-.66-.88-.23-1.39-.23c-.65 0-1.22.11-1.7.34s-.88.53-1.2.92-.56.84-.71 1.36S8 11.29 8 11.87v.27c0 .58.08 1.12.23 1.64s.39.97.71 1.35.72.69 1.2.91 1.05.34 1.7.34c.47 0 .91-.08 1.32-.23s.77-.36 1.08-.63.56-.58.74-.94.29-.74.3-1.15h-1.79c-.01.21-.06.4-.15.58s-.21.33-.36.46-.32.23-.52.3c-.19.07-.39.09-.6.1-.36-.01-.66-.08-.89-.23-.25-.16-.45-.37-.59-.62s-.25-.55-.3-.88-.08-.67-.08-1v-.27c0-.35.03-.68.08-1.01zM12 2C6.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 8z"></path></g>
<g id="create"><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>
+<g id="create-new-folder"><path d="M20 6h-8l-2-2H4c-1.11 0-1.99.89-1.99 2L2 18c0 1.11.89 2 2 2h16c1.11 0 2-.89 2-2V8c0-1.11-.89-2-2-2zm-1 8h-3v3h-2v-3h-3v-2h3V9h2v3h3v2z"></path></g>
<g id="credit-card"><path d="M20 4H4c-1.11 0-1.99.89-1.99 2L2 18c0 1.11.89 2 2 2h16c1.11 0 2-.89 2-2V6c0-1.11-.89-2-2-2zm0 14H4v-6h16v6zm0-10H4V6h16v2z"></path></g>
<g id="dashboard"><path d="M3 13h8V3H3v10zm0 8h8v-6H3v6zm10 0h8V11h-8v10zm0-18v6h8V3h-8z"></path></g>
+<g id="date-range"><path d="M9 11H7v2h2v-2zm4 0h-2v2h2v-2zm4 0h-2v2h2v-2zm2-7h-1V2h-2v2H8V2H6v2H5c-1.11 0-1.99.9-1.99 2L3 20c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm0 16H5V9h14v11z"></path></g>
<g id="delete"><path d="M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zM19 4h-3.5l-1-1h-5l-1 1H5v2h14V4z"></path></g>
<g id="description"><path d="M14 2H6c-1.1 0-1.99.9-1.99 2L4 20c0 1.1.89 2 1.99 2H18c1.1 0 2-.9 2-2V8l-6-6zm2 16H8v-2h8v2zm0-4H8v-2h8v2zm-3-5V3.5L18.5 9H13z"></path></g>
<g id="dns"><path d="M20 13H4c-.55 0-1 .45-1 1v6c0 .55.45 1 1 1h16c.55 0 1-.45 1-1v-6c0-.55-.45-1-1-1zM7 19c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2zM20 3H4c-.55 0-1 .45-1 1v6c0 .55.45 1 1 1h16c.55 0 1-.45 1-1V4c0-.55-.45-1-1-1zM7 9c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2z"></path></g>
<g id="done"><path d="M9 16.2L4.8 12l-1.4 1.4L9 19 21 7l-1.4-1.4L9 16.2z"></path></g>
<g id="done-all"><path d="M18 7l-1.41-1.41-6.34 6.34 1.41 1.41L18 7zm4.24-1.41L11.66 16.17 7.48 12l-1.41 1.41L11.66 19l12-12-1.42-1.41zM.41 13.41L6 19l1.41-1.41L1.83 12 .41 13.41z"></path></g>
+<g id="donut-large"><path d="M11 5.08V2c-5 .5-9 4.81-9 10s4 9.5 9 10v-3.08c-3-.48-6-3.4-6-6.92s3-6.44 6-6.92zM18.97 11H22c-.47-5-4-8.53-9-9v3.08C16 5.51 18.54 8 18.97 11zM13 18.92V22c5-.47 8.53-4 9-9h-3.03c-.43 3-2.97 5.49-5.97 5.92z"></path></g>
+<g id="donut-small"><path d="M11 9.16V2c-5 .5-9 4.79-9 10s4 9.5 9 10v-7.16c-1-.41-2-1.52-2-2.84s1-2.43 2-2.84zM14.86 11H22c-.48-4.75-4-8.53-9-9v7.16c1 .3 1.52.98 1.86 1.84zM13 14.84V22c5-.47 8.52-4.25 9-9h-7.14c-.34.86-.86 1.54-1.86 1.84z"></path></g>
<g id="drafts"><path d="M21.99 8c0-.72-.37-1.35-.94-1.7L12 1 2.95 6.3C2.38 6.65 2 7.28 2 8v10c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2l-.01-10zM12 13L3.74 7.84 12 3l8.26 4.84L12 13z"></path></g>
<g id="eject"><path d="M5 17h14v2H5zm7-12L5.33 15h13.34z"></path></g>
<g id="error"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-2h2v2zm0-4h-2V7h2v6z"></path></g>
<g id="error-outline"><path d="M11 15h2v2h-2zm0-8h2v6h-2zm.99-5C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zM12 20c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8z"></path></g>
<g id="event"><path d="M17 12h-5v5h5v-5zM16 1v2H8V1H6v2H5c-1.11 0-1.99.9-1.99 2L3 19c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2h-1V1h-2zm3 18H5V8h14v11z"></path></g>
-<g id="event-seat"><defs><path id="a" d="M0 0h24v24H0V0z"></path></defs><clipPath id="b"><use xlink:href="#a" overflow="visible"></use></clipPath><path d="M4 18v3h3v-3h10v3h3v-6H4zm15-8h3v3h-3zM2 10h3v3H2zm15 3H7V5c0-1.1.9-2 2-2h6c1.1 0 2 .9 2 2v8z" clip-path="url(#b)"></path></g>
+<g id="event-seat"><path d="M4 18v3h3v-3h10v3h3v-6H4zm15-8h3v3h-3zM2 10h3v3H2zm15 3H7V5c0-1.1.9-2 2-2h6c1.1 0 2 .9 2 2v8z"></path></g>
<g id="exit-to-app"><path d="M10.09 15.59L11.5 17l5-5-5-5-1.41 1.41L12.67 11H3v2h9.67l-2.58 2.59zM19 3H5c-1.11 0-2 .9-2 2v4h2V5h14v14H5v-4H3v4c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2z"></path></g>
<g id="expand-less"><path d="M12 8l-6 6 1.41 1.41L12 10.83l4.59 4.58L18 14z"></path></g>
<g id="expand-more"><path d="M16.59 8.59L12 13.17 7.41 8.59 6 10l6 6 6-6z"></path></g>
@@ -1190,9 +511,10 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
<g id="filter-list"><path d="M10 18h4v-2h-4v2zM3 6v2h18V6H3zm3 7h12v-2H6v2z"></path></g>
<g id="find-in-page"><path d="M20 19.59V8l-6-6H6c-1.1 0-1.99.9-1.99 2L4 20c0 1.1.89 2 1.99 2H18c.45 0 .85-.15 1.19-.4l-4.43-4.43c-.8.52-1.74.83-2.76.83-2.76 0-5-2.24-5-5s2.24-5 5-5 5 2.24 5 5c0 1.02-.31 1.96-.83 2.75L20 19.59zM9 13c0 1.66 1.34 3 3 3s3-1.34 3-3-1.34-3-3-3-3 1.34-3 3z"></path></g>
<g id="find-replace"><path d="M11 6c1.38 0 2.63.56 3.54 1.46L12 10h6V4l-2.05 2.05C14.68 4.78 12.93 4 11 4c-3.53 0-6.43 2.61-6.92 6H6.1c.46-2.28 2.48-4 4.9-4zm5.64 9.14c.66-.9 1.12-1.97 1.28-3.14H15.9c-.46 2.28-2.48 4-4.9 4-1.38 0-2.63-.56-3.54-1.46L10 12H4v6l2.05-2.05C7.32 17.22 9.07 18 11 18c1.55 0 2.98-.51 4.14-1.36L20 21.49 21.49 20l-4.85-4.86z"></path></g>
+<g id="fingerprint"><path d="M17.81 4.47c-.08 0-.16-.02-.23-.06C15.66 3.42 14 3 12.01 3c-1.98 0-3.86.47-5.57 1.41-.24.13-.54.04-.68-.2-.13-.24-.04-.55.2-.68C7.82 2.52 9.86 2 12.01 2c2.13 0 3.99.47 6.03 1.52.25.13.34.43.21.67-.09.18-.26.28-.44.28zM3.5 9.72c-.1 0-.2-.03-.29-.09-.23-.16-.28-.47-.12-.7.99-1.4 2.25-2.5 3.75-3.27C9.98 4.04 14 4.03 17.15 5.65c1.5.77 2.76 1.86 3.75 3.25.16.22.11.54-.12.7-.23.16-.54.11-.7-.12-.9-1.26-2.04-2.25-3.39-2.94-2.87-1.47-6.54-1.47-9.4.01-1.36.7-2.5 1.7-3.4 2.96-.08.14-.23.21-.39.21zm6.25 12.07c-.13 0-.26-.05-.35-.15-.87-.87-1.34-1.43-2.01-2.64-.69-1.23-1.05-2.73-1.05-4.34 0-2.97 2.54-5.39 5.66-5.39s5.66 2.42 5.66 5.39c0 .28-.22.5-.5.5s-.5-.22-.5-.5c0-2.42-2.09-4.39-4.66-4.39-2.57 0-4.66 1.97-4.66 4.39 0 1.44.32 2.77.93 3.85.64 1.15 1.08 1.64 1.85 2.42.19.2.19.51 0 .71-.11.1-.24.15-.37.15zm7.17-1.85c-1.19 0-2.24-.3-3.1-.89-1.49-1.01-2.38-2.65-2.38-4.39 0-.28.22-.5.5-.5s.5.22.5.5c0 1.41.72 2.74 1.94 3.56.71.48 1.54.71 2.54.71.24 0 .64-.03 1.04-.1.27-.05.53.13.58.41.05.27-.13.53-.41.58-.57.11-1.07.12-1.21.12zM14.91 22c-.04 0-.09-.01-.13-.02-1.59-.44-2.63-1.03-3.72-2.1-1.4-1.39-2.17-3.24-2.17-5.22 0-1.62 1.38-2.94 3.08-2.94 1.7 0 3.08 1.32 3.08 2.94 0 1.07.93 1.94 2.08 1.94s2.08-.87 2.08-1.94c0-3.77-3.25-6.83-7.25-6.83-2.84 0-5.44 1.58-6.61 4.03-.39.81-.59 1.76-.59 2.8 0 .78.07 2.01.67 3.61.1.26-.03.55-.29.64-.26.1-.55-.04-.64-.29-.49-1.31-.73-2.61-.73-3.96 0-1.2.23-2.29.68-3.24 1.33-2.79 4.28-4.6 7.51-4.6 4.55 0 8.25 3.51 8.25 7.83 0 1.62-1.38 2.94-3.08 2.94s-3.08-1.32-3.08-2.94c0-1.07-.93-1.94-2.08-1.94s-2.08.87-2.08 1.94c0 1.71.66 3.31 1.87 4.51.95.94 1.86 1.46 3.27 1.85.27.07.42.35.35.61-.05.23-.26.38-.47.38z"></path></g>
<g id="flag"><path d="M14.4 6L14 4H5v17h2v-7h5.6l.4 2h7V6z"></path></g>
-<g id="flight-land"><defs><path id="a" d="M0 0h24v24H0V0z"></path></defs><defs><path id="c" d="M0 0h24v24H0V0z"></path></defs><clipPath id="b"><use xlink:href="#a" overflow="visible"></use></clipPath><clipPath id="d" clip-path="url(#b)"><use xlink:href="#c" overflow="visible"></use></clipPath><path d="M2.5 19h19v2h-19zm7.18-5.73l4.35 1.16 5.31 1.42c.8.21 1.62-.26 1.84-1.06.21-.8-.26-1.62-1.06-1.84l-5.31-1.42-2.76-9.02L10.12 2v8.28L5.15 8.95l-.93-2.32-1.45-.39v5.17l1.6.43 5.31 1.43z" clip-path="url(#d)"></path></g>
-<g id="flight-takeoff"><defs><path id="a" d="M0 0h24v24H0V0z"></path></defs><clipPath id="b"><use xlink:href="#a" overflow="visible"></use></clipPath><path d="M2.5 19h19v2h-19zm19.57-9.36c-.21-.8-1.04-1.28-1.84-1.06L14.92 10l-6.9-6.43-1.93.51 4.14 7.17-4.97 1.33-1.97-1.54-1.45.39 1.82 3.16.77 1.33 1.6-.43 5.31-1.42 4.35-1.16L21 11.49c.81-.23 1.28-1.05 1.07-1.85z" clip-path="url(#b)"></path></g>
+<g id="flight-land"><path d="M2.5 19h19v2h-19zm7.18-5.73l4.35 1.16 5.31 1.42c.8.21 1.62-.26 1.84-1.06.21-.8-.26-1.62-1.06-1.84l-5.31-1.42-2.76-9.02L10.12 2v8.28L5.15 8.95l-.93-2.32-1.45-.39v5.17l1.6.43 5.31 1.43z"></path></g>
+<g id="flight-takeoff"><path d="M2.5 19h19v2h-19zm19.57-9.36c-.21-.8-1.04-1.28-1.84-1.06L14.92 10l-6.9-6.43-1.93.51 4.14 7.17-4.97 1.33-1.97-1.54-1.45.39 1.82 3.16.77 1.33 1.6-.43 5.31-1.42 4.35-1.16L21 11.49c.81-.23 1.28-1.05 1.07-1.85z"></path></g>
<g id="flip-to-back"><path d="M9 7H7v2h2V7zm0 4H7v2h2v-2zm0-8c-1.11 0-2 .9-2 2h2V3zm4 12h-2v2h2v-2zm6-12v2h2c0-1.1-.9-2-2-2zm-6 0h-2v2h2V3zM9 17v-2H7c0 1.1.89 2 2 2zm10-4h2v-2h-2v2zm0-4h2V7h-2v2zm0 8c1.1 0 2-.9 2-2h-2v2zM5 7H3v12c0 1.1.89 2 2 2h12v-2H5V7zm10-2h2V3h-2v2zm0 12h2v-2h-2v2z"></path></g>
<g id="flip-to-front"><path d="M3 13h2v-2H3v2zm0 4h2v-2H3v2zm2 4v-2H3c0 1.1.89 2 2 2zM3 9h2V7H3v2zm12 12h2v-2h-2v2zm4-18H9c-1.11 0-2 .9-2 2v10c0 1.1.89 2 2 2h10c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 12H9V5h10v10zm-8 6h2v-2h-2v2zm-4 0h2v-2H7v2z"></path></g>
<g id="folder"><path d="M10 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2h-8l-2-2z"></path></g>
@@ -1202,22 +524,24 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
<g id="forward"><path d="M12 8V4l8 8-8 8v-4H4V8z"></path></g>
<g id="fullscreen"><path d="M7 14H5v5h5v-2H7v-3zm-2-4h2V7h3V5H5v5zm12 7h-3v2h5v-5h-2v3zM14 5v2h3v3h2V5h-5z"></path></g>
<g id="fullscreen-exit"><path d="M5 16h3v3h2v-5H5v2zm3-8H5v2h5V5H8v3zm6 11h2v-3h3v-2h-5v5zm2-11V5h-2v5h5V8h-3z"></path></g>
+<g id="gavel"><path d="M1 21h12v2H1zM5.245 8.07l2.83-2.827 14.14 14.142-2.828 2.828zM12.317 1l5.657 5.656-2.83 2.83-5.654-5.66zM3.825 9.485l5.657 5.657-2.828 2.828-5.657-5.657z"></path></g>
<g id="gesture"><path d="M4.59 6.89c.7-.71 1.4-1.35 1.71-1.22.5.2 0 1.03-.3 1.52-.25.42-2.86 3.89-2.86 6.31 0 1.28.48 2.34 1.34 2.98.75.56 1.74.73 2.64.46 1.07-.31 1.95-1.4 3.06-2.77 1.21-1.49 2.83-3.44 4.08-3.44 1.63 0 1.65 1.01 1.76 1.79-3.78.64-5.38 3.67-5.38 5.37 0 1.7 1.44 3.09 3.21 3.09 1.63 0 4.29-1.33 4.69-6.1H21v-2.5h-2.47c-.15-1.65-1.09-4.2-4.03-4.2-2.25 0-4.18 1.91-4.94 2.84-.58.73-2.06 2.48-2.29 2.72-.25.3-.68.84-1.11.84-.45 0-.72-.83-.36-1.92.35-1.09 1.4-2.86 1.85-3.52.78-1.14 1.3-1.92 1.3-3.28C8.95 3.69 7.31 3 6.44 3 5.12 3 3.97 4 3.72 4.25c-.36.36-.66.66-.88.93l1.75 1.71zm9.29 11.66c-.31 0-.74-.26-.74-.72 0-.6.73-2.2 2.87-2.76-.3 2.69-1.43 3.48-2.13 3.48z"></path></g>
<g id="get-app"><path d="M19 9h-4V3H9v6H5l7 7 7-7zM5 18v2h14v-2H5z"></path></g>
-<g id="gif"><defs><path id="a" d="M24 24H0V0h24v24z"></path></defs><clipPath id="b"><use xlink:href="#a" overflow="visible"></use></clipPath><path d="M11.5 9H13v6h-1.5zM9 9H6c-.6 0-1 .5-1 1v4c0 .5.4 1 1 1h3c.6 0 1-.5 1-1v-2H8.5v1.5h-2v-3H10V10c0-.5-.4-1-1-1zm10 1.5V9h-4.5v6H16v-2h2v-1.5h-2v-1z" clip-path="url(#b)"></path></g>
+<g id="gif"><path d="M11.5 9H13v6h-1.5zM9 9H6c-.6 0-1 .5-1 1v4c0 .5.4 1 1 1h3c.6 0 1-.5 1-1v-2H8.5v1.5h-2v-3H10V10c0-.5-.4-1-1-1zm10 1.5V9h-4.5v6H16v-2h2v-1.5h-2v-1z"></path></g>
<g id="grade"><path d="M12 17.27L18.18 21l-1.64-7.03L22 9.24l-7.19-.61L12 2 9.19 8.63 2 9.24l5.46 4.73L5.82 21z"></path></g>
<g id="group-work"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zM8 17.5c-1.38 0-2.5-1.12-2.5-2.5s1.12-2.5 2.5-2.5 2.5 1.12 2.5 2.5-1.12 2.5-2.5 2.5zM9.5 8c0-1.38 1.12-2.5 2.5-2.5s2.5 1.12 2.5 2.5-1.12 2.5-2.5 2.5S9.5 9.38 9.5 8zm6.5 9.5c-1.38 0-2.5-1.12-2.5-2.5s1.12-2.5 2.5-2.5 2.5 1.12 2.5 2.5-1.12 2.5-2.5 2.5z"></path></g>
<g id="help"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 17h-2v-2h2v2zm2.07-7.75l-.9.92C13.45 12.9 13 13.5 13 15h-2v-.5c0-1.1.45-2.1 1.17-2.83l1.24-1.26c.37-.36.59-.86.59-1.41 0-1.1-.9-2-2-2s-2 .9-2 2H8c0-2.21 1.79-4 4-4s4 1.79 4 4c0 .88-.36 1.68-.93 2.25z"></path></g>
<g id="help-outline"><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"></path></g>
<g id="highlight-off"><path d="M14.59 8L12 10.59 9.41 8 8 9.41 10.59 12 8 14.59 9.41 16 12 13.41 14.59 16 16 14.59 13.41 12 16 9.41 14.59 8zM12 2C6.47 2 2 6.47 2 12s4.47 10 10 10 10-4.47 10-10S17.53 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 8z"></path></g>
-<g id="history"><path opacity=".9" d="M13 3c-4.97 0-9 4.03-9 9H1l3.89 3.89.07.14L9 12H6c0-3.87 3.13-7 7-7s7 3.13 7 7-3.13 7-7 7c-1.93 0-3.68-.79-4.94-2.06l-1.42 1.42C8.27 19.99 10.51 21 13 21c4.97 0 9-4.03 9-9s-4.03-9-9-9zm-1 5v5l4.28 2.54.72-1.21-3.5-2.08V8H12z"></path></g>
+<g id="history"><path d="M13 3c-4.97 0-9 4.03-9 9H1l3.89 3.89.07.14L9 12H6c0-3.87 3.13-7 7-7s7 3.13 7 7-3.13 7-7 7c-1.93 0-3.68-.79-4.94-2.06l-1.42 1.42C8.27 19.99 10.51 21 13 21c4.97 0 9-4.03 9-9s-4.03-9-9-9zm-1 5v5l4.28 2.54.72-1.21-3.5-2.08V8H12z"></path></g>
<g id="home"><path d="M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z"></path></g>
<g id="hourglass-empty"><path d="M6 2v6h.01L6 8.01 10 12l-4 4 .01.01H6V22h12v-5.99h-.01L18 16l-4-4 4-3.99-.01-.01H18V2H6zm10 14.5V20H8v-3.5l4-4 4 4zm-4-5l-4-4V4h8v3.5l-4 4z"></path></g>
<g id="hourglass-full"><path d="M6 2v6h.01L6 8.01 10 12l-4 4 .01.01H6V22h12v-5.99h-.01L18 16l-4-4 4-3.99-.01-.01H18V2H6z"></path></g>
<g id="http"><path d="M4.5 11h-2V9H1v6h1.5v-2.5h2V15H6V9H4.5v2zm2.5-.5h1.5V15H10v-4.5h1.5V9H7v1.5zm5.5 0H14V15h1.5v-4.5H17V9h-4.5v1.5zm9-1.5H18v6h1.5v-2h2c.8 0 1.5-.7 1.5-1.5v-1c0-.8-.7-1.5-1.5-1.5zm0 2.5h-2v-1h2v1z"></path></g>
<g id="https"><path d="M18 8h-1V6c0-2.76-2.24-5-5-5S7 3.24 7 6v2H6c-1.1 0-2 .9-2 2v10c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V10c0-1.1-.9-2-2-2zm-6 9c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2zm3.1-9H8.9V6c0-1.71 1.39-3.1 3.1-3.1 1.71 0 3.1 1.39 3.1 3.1v2z"></path></g>
-<g id="inbox"><path d="M19 3H4.99c-1.1 0-1.98.9-1.98 2L3 19c0 1.1.89 2 1.99 2H19c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 12h-4c0 1.66-1.34 3-3 3s-3-1.34-3-3H4.99V5H19v10zm-3-5h-2V7h-4v3H8l4 4 4-4z"></path></g>
-<g id="indeterminate-check-box"><defs><path id="a" d="M0 0h24v24H0z"></path></defs><clipPath id="b"><use xlink:href="#a" overflow="visible"></use></clipPath><path clip-path="url(#b)" d="M19 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-2 10H7v-2h10v2z"></path></g>
+<g id="important-devices"><path d="M23 11.01L18 11c-.55 0-1 .45-1 1v9c0 .55.45 1 1 1h5c.55 0 1-.45 1-1v-9c0-.55-.45-.99-1-.99zM23 20h-5v-7h5v7zM20 2H2C.89 2 0 2.89 0 4v12c0 1.1.89 2 2 2h7v2H7v2h8v-2h-2v-2h2v-2H2V4h18v5h2V4c0-1.11-.9-2-2-2zm-8.03 7L11 6l-.97 3H7l2.47 1.76-.94 2.91 2.47-1.8 2.47 1.8-.94-2.91L15 9h-3.03z"></path></g>
+<g id="inbox"><path d="M19 3H4.99c-1.11 0-1.98.89-1.98 2L3 19c0 1.1.88 2 1.99 2H19c1.1 0 2-.9 2-2V5c0-1.11-.9-2-2-2zm0 12h-4c0 1.66-1.35 3-3 3s-3-1.34-3-3H4.99V5H19v10z"></path></g>
+<g id="indeterminate-check-box"><path d="M19 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-2 10H7v-2h10v2z"></path></g>
<g id="info"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z"></path></g>
<g id="info-outline"><path d="M11 17h2v-6h-2v6zm1-15C6.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 8zM11 9h2V7h-2v2z"></path></g>
<g id="input"><path d="M21 3.01H3c-1.1 0-2 .9-2 2V9h2V4.99h18v14.03H3V15H1v4.01c0 1.1.9 1.98 2 1.98h18c1.1 0 2-.88 2-1.98v-14c0-1.11-.9-2-2-2zM11 16l4-4-4-4v3H1v2h10v3z"></path></g>
@@ -1226,11 +550,14 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
<g id="label-outline"><path d="M17.63 5.84C17.27 5.33 16.67 5 16 5L5 5.01C3.9 5.01 3 5.9 3 7v10c0 1.1.9 1.99 2 1.99L16 19c.67 0 1.27-.33 1.63-.84L22 12l-4.37-6.16zM16 17H5V7h11l3.55 5L16 17z"></path></g>
<g id="language"><path d="M11.99 2C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zm6.93 6h-2.95c-.32-1.25-.78-2.45-1.38-3.56 1.84.63 3.37 1.91 4.33 3.56zM12 4.04c.83 1.2 1.48 2.53 1.91 3.96h-3.82c.43-1.43 1.08-2.76 1.91-3.96zM4.26 14C4.1 13.36 4 12.69 4 12s.1-1.36.26-2h3.38c-.08.66-.14 1.32-.14 2 0 .68.06 1.34.14 2H4.26zm.82 2h2.95c.32 1.25.78 2.45 1.38 3.56-1.84-.63-3.37-1.9-4.33-3.56zm2.95-8H5.08c.96-1.66 2.49-2.93 4.33-3.56C8.81 5.55 8.35 6.75 8.03 8zM12 19.96c-.83-1.2-1.48-2.53-1.91-3.96h3.82c-.43 1.43-1.08 2.76-1.91 3.96zM14.34 14H9.66c-.09-.66-.16-1.32-.16-2 0-.68.07-1.35.16-2h4.68c.09.65.16 1.32.16 2 0 .68-.07 1.34-.16 2zm.25 5.56c.6-1.11 1.06-2.31 1.38-3.56h2.95c-.96 1.65-2.49 2.93-4.33 3.56zM16.36 14c.08-.66.14-1.32.14-2 0-.68-.06-1.34-.14-2h3.38c.16.64.26 1.31.26 2s-.1 1.36-.26 2h-3.38z"></path></g>
<g id="launch"><path d="M19 19H5V5h7V3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2v-7h-2v7zM14 3v2h3.59l-9.83 9.83 1.41 1.41L19 6.41V10h2V3h-7z"></path></g>
+<g id="lightbulb-outline"><path d="M9 21c0 .55.45 1 1 1h4c.55 0 1-.45 1-1v-1H9v1zm3-19C8.14 2 5 5.14 5 9c0 2.38 1.19 4.47 3 5.74V17c0 .55.45 1 1 1h6c.55 0 1-.45 1-1v-2.26c1.81-1.27 3-3.36 3-5.74 0-3.86-3.14-7-7-7zm2.85 11.1l-.85.6V16h-4v-2.3l-.85-.6C7.8 12.16 7 10.63 7 9c0-2.76 2.24-5 5-5s5 2.24 5 5c0 1.63-.8 3.16-2.15 4.1z"></path></g>
+<g id="line-style"><path d="M3 16h5v-2H3v2zm6.5 0h5v-2h-5v2zm6.5 0h5v-2h-5v2zM3 20h2v-2H3v2zm4 0h2v-2H7v2zm4 0h2v-2h-2v2zm4 0h2v-2h-2v2zm4 0h2v-2h-2v2zM3 12h8v-2H3v2zm10 0h8v-2h-8v2zM3 4v4h18V4H3z"></path></g>
+<g id="line-weight"><path d="M3 17h18v-2H3v2zm0 3h18v-1H3v1zm0-7h18v-3H3v3zm0-9v4h18V4H3z"></path></g>
<g id="link"><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76 0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71 0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71 0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76 0 5-2.24 5-5s-2.24-5-5-5z"></path></g>
<g id="list"><path d="M3 13h2v-2H3v2zm0 4h2v-2H3v2zm0-8h2V7H3v2zm4 4h14v-2H7v2zm0 4h14v-2H7v2zM7 7v2h14V7H7z"></path></g>
<g id="lock"><path d="M18 8h-1V6c0-2.76-2.24-5-5-5S7 3.24 7 6v2H6c-1.1 0-2 .9-2 2v10c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V10c0-1.1-.9-2-2-2zm-6 9c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2zm3.1-9H8.9V6c0-1.71 1.39-3.1 3.1-3.1 1.71 0 3.1 1.39 3.1 3.1v2z"></path></g>
<g id="lock-open"><path d="M12 17c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm6-9h-1V6c0-2.76-2.24-5-5-5S7 3.24 7 6h1.9c0-1.71 1.39-3.1 3.1-3.1 1.71 0 3.1 1.39 3.1 3.1v2H6c-1.1 0-2 .9-2 2v10c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V10c0-1.1-.9-2-2-2zm0 12H6V10h12v10z"></path></g>
-<g id="lock-outline"><path d="M18 8h-1V6c0-2.76-2.24-5-5-5S7 3.24 7 6v2H6c-1.1 0-2 .9-2 2v10c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V10c0-1.1-.9-2-2-2zm-6-5.1c1.71 0 3.1 1.39 3.1 3.1v2H9V6h-.1c0-1.71 1.39-3.1 3.1-3.1zM18 20H6V10h12v10zm-6-3c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2z"></path></g>
+<g id="lock-outline"><path d="M12 17c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm6-9h-1V6c0-2.76-2.24-5-5-5S7 3.24 7 6v2H6c-1.1 0-2 .9-2 2v10c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V10c0-1.1-.9-2-2-2zM8.9 6c0-1.71 1.39-3.1 3.1-3.1s3.1 1.39 3.1 3.1v2H8.9V6zM18 20H6V10h12v10z"></path></g>
<g id="loyalty"><path d="M21.41 11.58l-9-9C12.05 2.22 11.55 2 11 2H4c-1.1 0-2 .9-2 2v7c0 .55.22 1.05.59 1.42l9 9c.36.36.86.58 1.41.58.55 0 1.05-.22 1.41-.59l7-7c.37-.36.59-.86.59-1.41 0-.55-.23-1.06-.59-1.42zM5.5 7C4.67 7 4 6.33 4 5.5S4.67 4 5.5 4 7 4.67 7 5.5 6.33 7 5.5 7zm11.77 8.27L13 19.54l-4.27-4.27C8.28 14.81 8 14.19 8 13.5c0-1.38 1.12-2.5 2.5-2.5.69 0 1.32.28 1.77.74l.73.72.73-.73c.45-.45 1.08-.73 1.77-.73 1.38 0 2.5 1.12 2.5 2.5 0 .69-.28 1.32-.73 1.77z"></path></g>
<g id="mail"><path d="M20 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm0 4l-8 5-8-5V6l8 5 8-5v2z"></path></g>
<g id="markunread"><path d="M20 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm0 4l-8 5-8-5V6l8 5 8-5v2z"></path></g>
@@ -1238,12 +565,17 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
<g id="menu"><path d="M3 18h18v-2H3v2zm0-5h18v-2H3v2zm0-7v2h18V6H3z"></path></g>
<g id="more-horiz"><path d="M6 10c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm12 0c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm-6 0c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z"></path></g>
<g id="more-vert"><path d="M12 8c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm0 2c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0 6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z"></path></g>
+<g id="motorcycle"><path d="M19.44 9.03L15.41 5H11v2h3.59l2 2H5c-2.8 0-5 2.2-5 5s2.2 5 5 5c2.46 0 4.45-1.69 4.9-4h1.65l2.77-2.77c-.21.54-.32 1.14-.32 1.77 0 2.8 2.2 5 5 5s5-2.2 5-5c0-2.65-1.97-4.77-4.56-4.97zM7.82 15C7.4 16.15 6.28 17 5 17c-1.63 0-3-1.37-3-3s1.37-3 3-3c1.28 0 2.4.85 2.82 2H5v2h2.82zM19 17c-1.66 0-3-1.34-3-3s1.34-3 3-3 3 1.34 3 3-1.34 3-3 3z"></path></g>
+<g id="move-to-inbox"><path d="M19 3H4.99c-1.11 0-1.98.9-1.98 2L3 19c0 1.1.88 2 1.99 2H19c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 12h-4c0 1.66-1.35 3-3 3s-3-1.34-3-3H4.99V5H19v10zm-3-5h-2V7h-4v3H8l4 4 4-4z"></path></g>
+<g id="next-week"><path d="M20 7h-4V5c0-.55-.22-1.05-.59-1.41C15.05 3.22 14.55 3 14 3h-4c-1.1 0-2 .9-2 2v2H4c-1.1 0-2 .9-2 2v11c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V9c0-1.1-.9-2-2-2zM10 5h4v2h-4V5zm1 13.5l-1-1 3-3-3-3 1-1 4 4-4 4z"></path></g>
<g id="note-add"><path d="M14 2H6c-1.1 0-1.99.9-1.99 2L4 20c0 1.1.89 2 1.99 2H18c1.1 0 2-.9 2-2V8l-6-6zm2 14h-3v3h-2v-3H8v-2h3v-3h2v3h3v2zm-3-7V3.5L18.5 9H13z"></path></g>
-<g id="offline-pin"><defs><path id="a" d="M0 0h24v24H0V0z"></path></defs><clipPath id="b"><use xlink:href="#a" overflow="visible"></use></clipPath><path clip-path="url(#b)" d="M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10 10-4.5 10-10S17.5 2 12 2zm5 16H7v-2h10v2zm-6.7-4L7 10.7l1.4-1.4 1.9 1.9 5.3-5.3L17 7.3 10.3 14z"></path></g>
+<g id="offline-pin"><path d="M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10 10-4.5 10-10S17.5 2 12 2zm5 16H7v-2h10v2zm-6.7-4L7 10.7l1.4-1.4 1.9 1.9 5.3-5.3L17 7.3 10.3 14z"></path></g>
+<g id="opacity"><path d="M17.66 8L12 2.35 6.34 8C4.78 9.56 4 11.64 4 13.64s.78 4.11 2.34 5.67 3.61 2.35 5.66 2.35 4.1-.79 5.66-2.35S20 15.64 20 13.64 19.22 9.56 17.66 8zM6 14c.01-2 .62-3.27 1.76-4.4L12 5.27l4.24 4.38C17.38 10.77 17.99 12 18 14H6z"></path></g>
<g id="open-in-browser"><path d="M19 4H5c-1.11 0-2 .9-2 2v12c0 1.1.89 2 2 2h4v-2H5V8h14v10h-4v2h4c1.1 0 2-.9 2-2V6c0-1.1-.89-2-2-2zm-7 6l-4 4h3v6h2v-6h3l-4-4z"></path></g>
<g id="open-in-new"><path d="M19 19H5V5h7V3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2v-7h-2v7zM14 3v2h3.59l-9.83 9.83 1.41 1.41L19 6.41V10h2V3h-7z"></path></g>
<g id="open-with"><path d="M10 9h4V6h3l-5-5-5 5h3v3zm-1 1H6V7l-5 5 5 5v-3h3v-4zm14 2l-5-5v3h-3v4h3v3l5-5zm-9 3h-4v3H7l5 5 5-5h-3v-3z"></path></g>
<g id="pageview"><path d="M11.5 9C10.12 9 9 10.12 9 11.5s1.12 2.5 2.5 2.5 2.5-1.12 2.5-2.5S12.88 9 11.5 9zM20 4H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm-3.21 14.21l-2.91-2.91c-.69.44-1.51.7-2.39.7C9.01 16 7 13.99 7 11.5S9.01 7 11.5 7 16 9.01 16 11.5c0 .88-.26 1.69-.7 2.39l2.91 2.9-1.42 1.42z"></path></g>
+<g id="pan-tool"><path d="M23 5.5V20c0 2.2-1.8 4-4 4h-7.3c-1.08 0-2.1-.43-2.85-1.19L1 14.83s1.26-1.23 1.3-1.25c.22-.19.49-.29.79-.29.22 0 .42.06.6.16.04.01 4.31 2.46 4.31 2.46V4c0-.83.67-1.5 1.5-1.5S11 3.17 11 4v7h1V1.5c0-.83.67-1.5 1.5-1.5S15 .67 15 1.5V11h1V2.5c0-.83.67-1.5 1.5-1.5s1.5.67 1.5 1.5V11h1V5.5c0-.83.67-1.5 1.5-1.5s1.5.67 1.5 1.5z"></path></g>
<g id="payment"><path d="M20 4H4c-1.11 0-1.99.89-1.99 2L2 18c0 1.11.89 2 2 2h16c1.11 0 2-.89 2-2V6c0-1.11-.89-2-2-2zm0 14H4v-6h16v6zm0-10H4V6h16v2z"></path></g>
<g id="perm-camera-mic"><path d="M20 5h-3.17L15 3H9L7.17 5H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h7v-2.09c-2.83-.48-5-2.94-5-5.91h2c0 2.21 1.79 4 4 4s4-1.79 4-4h2c0 2.97-2.17 5.43-5 5.91V21h7c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm-6 8c0 1.1-.9 2-2 2s-2-.9-2-2V9c0-1.1.9-2 2-2s2 .9 2 2v4z"></path></g>
<g id="perm-contact-calendar"><path d="M19 3h-1V1h-2v2H8V1H6v2H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-7 3c1.66 0 3 1.34 3 3s-1.34 3-3 3-3-1.34-3-3 1.34-3 3-3zm6 12H6v-1c0-2 4-3.1 6-3.1s6 1.1 6 3.1v1z"></path></g>
@@ -1253,16 +585,20 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
<g id="perm-media"><path d="M2 6H0v5h.01L0 20c0 1.1.9 2 2 2h18v-2H2V6zm20-2h-8l-2-2H6c-1.1 0-1.99.9-1.99 2L4 16c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zM7 15l4.5-6 3.5 4.51 2.5-3.01L21 15H7z"></path></g>
<g id="perm-phone-msg"><path d="M20 15.5c-1.25 0-2.45-.2-3.57-.57-.35-.11-.74-.03-1.02.24l-2.2 2.2c-2.83-1.44-5.15-3.75-6.59-6.58l2.2-2.21c.28-.27.36-.66.25-1.01C8.7 6.45 8.5 5.25 8.5 4c0-.55-.45-1-1-1H4c-.55 0-1 .45-1 1 0 9.39 7.61 17 17 17 .55 0 1-.45 1-1v-3.5c0-.55-.45-1-1-1zM12 3v10l3-3h6V3h-9z"></path></g>
<g id="perm-scan-wifi"><path d="M12 3C6.95 3 3.15 4.85 0 7.23L12 22 24 7.25C20.85 4.87 17.05 3 12 3zm1 13h-2v-6h2v6zm-2-8V6h2v2h-2z"></path></g>
+<g id="pets"><circle cx="4.5" cy="9.5" r="2.5"></circle><circle cx="9" cy="5.5" r="2.5"></circle><circle cx="15" cy="5.5" r="2.5"></circle><circle cx="19.5" cy="9.5" r="2.5"></circle><path d="M17.34 14.86c-.87-1.02-1.6-1.89-2.48-2.91-.46-.54-1.05-1.08-1.75-1.32-.11-.04-.22-.07-.33-.09-.25-.04-.52-.04-.78-.04s-.53 0-.79.05c-.11.02-.22.05-.33.09-.7.24-1.28.78-1.75 1.32-.87 1.02-1.6 1.89-2.48 2.91-1.31 1.31-2.92 2.76-2.62 4.79.29 1.02 1.02 2.03 2.33 2.32.73.15 3.06-.44 5.54-.44h.18c2.48 0 4.81.58 5.54.44 1.31-.29 2.04-1.31 2.33-2.32.31-2.04-1.3-3.49-2.61-4.8z"></path></g>
<g id="picture-in-picture"><path d="M19 7h-8v6h8V7zm2-4H3c-1.1 0-2 .9-2 2v14c0 1.1.9 1.98 2 1.98h18c1.1 0 2-.88 2-1.98V5c0-1.1-.9-2-2-2zm0 16.01H3V4.98h18v14.03z"></path></g>
-<g id="play-for-work"><path fill="#010101" d="M11 5v5.59H7.5l4.5 4.5 4.5-4.5H13V5h-2zm-5 9c0 3.31 2.69 6 6 6s6-2.69 6-6h-2c0 2.21-1.79 4-4 4s-4-1.79-4-4H6z"></path></g>
+<g id="picture-in-picture-alt"><path d="M19 11h-8v6h8v-6zm4 8V4.98C23 3.88 22.1 3 21 3H3c-1.1 0-2 .88-2 1.98V19c0 1.1.9 2 2 2h18c1.1 0 2-.9 2-2zm-2 .02H3V4.97h18v14.05z"></path></g>
+<g id="play-for-work"><path d="M11 5v5.59H7.5l4.5 4.5 4.5-4.5H13V5h-2zm-5 9c0 3.31 2.69 6 6 6s6-2.69 6-6h-2c0 2.21-1.79 4-4 4s-4-1.79-4-4H6z"></path></g>
<g id="polymer"><path d="M19 4h-4L7.11 16.63 4.5 12 9 4H5L.5 12 5 20h4l7.89-12.63L19.5 12 15 20h4l4.5-8z"></path></g>
<g id="power-settings-new"><path d="M13 3h-2v10h2V3zm4.83 2.17l-1.42 1.42C17.99 7.86 19 9.81 19 12c0 3.87-3.13 7-7 7s-7-3.13-7-7c0-2.19 1.01-4.14 2.58-5.42L6.17 5.17C4.23 6.82 3 9.26 3 12c0 4.97 4.03 9 9 9s9-4.03 9-9c0-2.74-1.23-5.18-3.17-6.83z"></path></g>
+<g id="pregnant-woman"><path d="M9 4c0-1.11.89-2 2-2s2 .89 2 2-.89 2-2 2-2-.89-2-2zm7 9c-.01-1.34-.83-2.51-2-3 0-1.66-1.34-3-3-3s-3 1.34-3 3v7h2v5h3v-5h3v-4z"></path></g>
<g id="print"><path d="M19 8H5c-1.66 0-3 1.34-3 3v6h4v4h12v-4h4v-6c0-1.66-1.34-3-3-3zm-3 11H8v-5h8v5zm3-7c-.55 0-1-.45-1-1s.45-1 1-1 1 .45 1 1-.45 1-1 1zm-1-9H6v4h12V3z"></path></g>
-<g id="query-builder"><path d="M11.99 2C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zM12 20c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8zM12.5 7H11v6l5.25 3.15.75-1.23-4.5-2.67z"></path></g>
+<g id="query-builder"><path d="M11.99 2C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zM12 20c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8zm.5-13H11v6l5.25 3.15.75-1.23-4.5-2.67z"></path></g>
<g id="question-answer"><path d="M21 6h-2v9H6v2c0 .55.45 1 1 1h11l4 4V7c0-.55-.45-1-1-1zm-4 6V3c0-.55-.45-1-1-1H3c-.55 0-1 .45-1 1v14l4-4h10c.55 0 1-.45 1-1z"></path></g>
<g id="radio-button-checked"><path d="M12 7c-2.76 0-5 2.24-5 5s2.24 5 5 5 5-2.24 5-5-2.24-5-5-5zm0-5C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8z"></path></g>
<g id="radio-button-unchecked"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8z"></path></g>
<g id="receipt"><path d="M18 17H6v-2h12v2zm0-4H6v-2h12v2zm0-4H6V7h12v2zM3 22l1.5-1.5L6 22l1.5-1.5L9 22l1.5-1.5L12 22l1.5-1.5L15 22l1.5-1.5L18 22l1.5-1.5L21 22V2l-1.5 1.5L18 2l-1.5 1.5L15 2l-1.5 1.5L12 2l-1.5 1.5L9 2 7.5 3.5 6 2 4.5 3.5 3 2v20z"></path></g>
+<g id="record-voice-over"><circle cx="9" cy="9" r="4"></circle><path d="M9 15c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4zm7.76-9.64l-1.68 1.69c.84 1.18.84 2.71 0 3.89l1.68 1.69c2.02-2.02 2.02-5.07 0-7.27zM20.07 2l-1.63 1.63c2.77 3.02 2.77 7.56 0 10.74L20.07 16c3.9-3.89 3.91-9.95 0-14z"></path></g>
<g id="redeem"><path d="M20 6h-2.18c.11-.31.18-.65.18-1 0-1.66-1.34-3-3-3-1.05 0-1.96.54-2.5 1.35l-.5.67-.5-.68C10.96 2.54 10.05 2 9 2 7.34 2 6 3.34 6 5c0 .35.07.69.18 1H4c-1.11 0-1.99.89-1.99 2L2 19c0 1.11.89 2 2 2h16c1.11 0 2-.89 2-2V8c0-1.11-.89-2-2-2zm-5-2c.55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1zM9 4c.55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1zm11 15H4v-2h16v2zm0-5H4V8h5.08L7 10.83 8.62 12 11 8.76l1-1.36 1 1.36L15.38 12 17 10.83 14.92 8H20v6z"></path></g>
<g id="redo"><path d="M18.4 10.6C16.55 8.99 14.15 8 11.5 8c-4.65 0-8.58 3.03-9.96 7.22L3.9 16c1.05-3.19 4.05-5.5 7.6-5.5 1.95 0 3.73.72 5.12 1.88L13 16h9V7l-3.6 3.6z"></path></g>
<g id="refresh"><path d="M17.65 6.35C16.2 4.9 14.21 4 12 4c-4.42 0-7.99 3.58-7.99 8s3.57 8 7.99 8c3.73 0 6.84-2.55 7.73-6h-2.08c-.82 2.33-3.04 4-5.65 4-3.31 0-6-2.69-6-6s2.69-6 6-6c1.66 0 3.14.69 4.22 1.78L13 11h7V4l-2.35 2.35z"></path></g>
@@ -1276,8 +612,10 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
<g id="report-problem"><path d="M1 21h22L12 2 1 21zm12-3h-2v-2h2v2zm0-4h-2v-4h2v4z"></path></g>
<g id="restore"><path d="M13 3c-4.97 0-9 4.03-9 9H1l3.89 3.89.07.14L9 12H6c0-3.87 3.13-7 7-7s7 3.13 7 7-3.13 7-7 7c-1.93 0-3.68-.79-4.94-2.06l-1.42 1.42C8.27 19.99 10.51 21 13 21c4.97 0 9-4.03 9-9s-4.03-9-9-9zm-1 5v5l4.28 2.54.72-1.21-3.5-2.08V8H12z"></path></g>
<g id="room"><path d="M12 2C8.13 2 5 5.13 5 9c0 5.25 7 13 7 13s7-7.75 7-13c0-3.87-3.13-7-7-7zm0 9.5c-1.38 0-2.5-1.12-2.5-2.5s1.12-2.5 2.5-2.5 2.5 1.12 2.5 2.5-1.12 2.5-2.5 2.5z"></path></g>
+<g id="rounded-corner"><path d="M19 19h2v2h-2v-2zm0-2h2v-2h-2v2zM3 13h2v-2H3v2zm0 4h2v-2H3v2zm0-8h2V7H3v2zm0-4h2V3H3v2zm4 0h2V3H7v2zm8 16h2v-2h-2v2zm-4 0h2v-2h-2v2zm4 0h2v-2h-2v2zm-8 0h2v-2H7v2zm-4 0h2v-2H3v2zM21 8c0-2.76-2.24-5-5-5h-5v2h5c1.65 0 3 1.35 3 3v5h2V8z"></path></g>
+<g id="rowing"><path d="M8.5 14.5L4 19l1.5 1.5L9 17h2l-2.5-2.5zM15 1c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm6 20.01L18 24l-2.99-3.01V19.5l-7.1-7.09c-.31.05-.61.07-.91.07v-2.16c1.66.03 3.61-.87 4.67-2.04l1.4-1.55c.19-.21.43-.38.69-.5.29-.14.62-.23.96-.23h.03C15.99 6.01 17 7.02 17 8.26v5.75c0 .84-.35 1.61-.92 2.16l-3.58-3.58v-2.27c-.63.52-1.43 1.02-2.29 1.39L16.5 18H18l3 3.01z"></path></g>
<g id="save"><path d="M17 3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V7l-4-4zm-5 16c-1.66 0-3-1.34-3-3s1.34-3 3-3 3 1.34 3 3-1.34 3-3 3zm3-10H5V5h10v4z"></path></g>
-<g id="schedule"><path fill-opacity=".9" d="M11.99 2C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zM12 20c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8zM12.5 7H11v6l5.25 3.15.75-1.23-4.5-2.67z"></path></g>
+<g id="schedule"><path d="M11.99 2C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zM12 20c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8zm.5-13H11v6l5.25 3.15.75-1.23-4.5-2.67z"></path></g>
<g id="search"><path d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"></path></g>
<g id="select-all"><path d="M3 5h2V3c-1.1 0-2 .9-2 2zm0 8h2v-2H3v2zm4 8h2v-2H7v2zM3 9h2V7H3v2zm10-6h-2v2h2V3zm6 0v2h2c0-1.1-.9-2-2-2zM5 21v-2H3c0 1.1.9 2 2 2zm-2-4h2v-2H3v2zM9 3H7v2h2V3zm2 18h2v-2h-2v2zm8-8h2v-2h-2v2zm0 8c1.1 0 2-.9 2-2h-2v2zm0-12h2V7h-2v2zm0 8h2v-2h-2v2zm-4 4h2v-2h-2v2zm0-16h2V3h-2v2zM7 17h10V7H7v10zm2-8h6v6H9V9z"></path></g>
<g id="send"><path d="M2.01 21L23 12 2.01 3 2 10l15 2-15 2z"></path></g>
@@ -1307,9 +645,11 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
<g id="spellcheck"><path d="M12.45 16h2.09L9.43 3H7.57L2.46 16h2.09l1.12-3h5.64l1.14 3zm-6.02-5L8.5 5.48 10.57 11H6.43zm15.16.59l-8.09 8.09L9.83 16l-1.41 1.41 5.09 5.09L23 13l-1.41-1.41z"></path></g>
<g id="star"><path d="M12 17.27L18.18 21l-1.64-7.03L22 9.24l-7.19-.61L12 2 9.19 8.63 2 9.24l5.46 4.73L5.82 21z"></path></g>
<g id="star-border"><path d="M22 9.24l-7.19-.62L12 2 9.19 8.63 2 9.24l5.46 4.73L5.82 21 12 17.27 18.18 21l-1.63-7.03L22 9.24zM12 15.4l-3.76 2.27 1-4.28-3.32-2.88 4.38-.38L12 6.1l1.71 4.04 4.38.38-3.32 2.88 1 4.28L12 15.4z"></path></g>
-<g id="star-half"><path d="M22 9.74l-7.19-.62L12 2.5 9.19 9.13 2 9.74l5.46 4.73-1.64 7.03L12 17.77l6.18 3.73-1.63-7.03L22 9.74zM12 15.9V6.6l1.71 4.04 4.38.38-3.32 2.88 1 4.28L12 15.9z"></path></g>
+<g id="star-half"><path d="M22 9.24l-7.19-.62L12 2 9.19 8.63 2 9.24l5.46 4.73L5.82 21 12 17.27 18.18 21l-1.63-7.03L22 9.24zM12 15.4V6.1l1.71 4.04 4.38.38-3.32 2.88 1 4.28L12 15.4z"></path></g>
<g id="stars"><path d="M11.99 2C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zm4.24 16L12 15.45 7.77 18l1.12-4.81-3.73-3.23 4.92-.42L12 5l1.92 4.53 4.92.42-3.73 3.23L16.23 18z"></path></g>
<g id="store"><path d="M20 4H4v2h16V4zm1 10v-2l-1-5H4l-1 5v2h1v6h10v-6h4v6h2v-6h1zm-9 4H6v-4h6v4z"></path></g>
+<g id="subdirectory-arrow-left"><path d="M11 9l1.42 1.42L8.83 14H18V4h2v12H8.83l3.59 3.58L11 21l-6-6 6-6z"></path></g>
+<g id="subdirectory-arrow-right"><path d="M19 15l-6 6-1.42-1.42L15.17 16H4V4h2v10h9.17l-3.59-3.58L13 9l6 6z"></path></g>
<g id="subject"><path d="M14 17H4v2h10v-2zm6-8H4v2h16V9zM4 15h16v-2H4v2zM4 5v2h16V5H4z"></path></g>
<g id="supervisor-account"><path d="M16.5 12c1.38 0 2.49-1.12 2.49-2.5S17.88 7 16.5 7C15.12 7 14 8.12 14 9.5s1.12 2.5 2.5 2.5zM9 11c1.66 0 2.99-1.34 2.99-3S10.66 5 9 5C7.34 5 6 6.34 6 8s1.34 3 3 3zm7.5 3c-1.83 0-5.5.92-5.5 2.75V19h11v-2.25c0-1.83-3.67-2.75-5.5-2.75zM9 13c-2.33 0-7 1.17-7 3.5V19h7v-2.25c0-.85.33-2.34 2.37-3.47C10.5 13.1 9.66 13 9 13z"></path></g>
<g id="swap-horiz"><path d="M6.99 11L3 15l3.99 4v-3H14v-2H6.99v-3zM21 9l-3.99-4v3H10v2h7.01v3L21 9z"></path></g>
@@ -1323,19 +663,23 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
<g id="thumb-down"><path d="M15 3H6c-.83 0-1.54.5-1.84 1.22l-3.02 7.05c-.09.23-.14.47-.14.73v1.91l.01.01L1 14c0 1.1.9 2 2 2h6.31l-.95 4.57-.03.32c0 .41.17.79.44 1.06L9.83 23l6.59-6.59c.36-.36.58-.86.58-1.41V5c0-1.1-.9-2-2-2zm4 0v12h4V3h-4z"></path></g>
<g id="thumb-up"><path d="M1 21h4V9H1v12zm22-11c0-1.1-.9-2-2-2h-6.31l.95-4.57.03-.32c0-.41-.17-.79-.44-1.06L14.17 1 7.59 7.59C7.22 7.95 7 8.45 7 9v10c0 1.1.9 2 2 2h9c.83 0 1.54-.5 1.84-1.22l3.02-7.05c.09-.23.14-.47.14-.73v-1.91l-.01-.01L23 10z"></path></g>
<g id="thumbs-up-down"><path d="M12 6c0-.55-.45-1-1-1H5.82l.66-3.18.02-.23c0-.31-.13-.59-.33-.8L5.38 0 .44 4.94C.17 5.21 0 5.59 0 6v6.5c0 .83.67 1.5 1.5 1.5h6.75c.62 0 1.15-.38 1.38-.91l2.26-5.29c.07-.17.11-.36.11-.55V6zm10.5 4h-6.75c-.62 0-1.15.38-1.38.91l-2.26 5.29c-.07.17-.11.36-.11.55V18c0 .55.45 1 1 1h5.18l-.66 3.18-.02.24c0 .31.13.59.33.8l.79.78 4.94-4.94c.27-.27.44-.65.44-1.06v-6.5c0-.83-.67-1.5-1.5-1.5z"></path></g>
+<g id="timeline"><path d="M23 8c0 1.1-.9 2-2 2-.18 0-.35-.02-.51-.07l-3.56 3.55c.05.16.07.34.07.52 0 1.1-.9 2-2 2s-2-.9-2-2c0-.18.02-.36.07-.52l-2.55-2.55c-.16.05-.34.07-.52.07s-.36-.02-.52-.07l-4.55 4.56c.05.16.07.33.07.51 0 1.1-.9 2-2 2s-2-.9-2-2 .9-2 2-2c.18 0 .35.02.51.07l4.56-4.55C8.02 9.36 8 9.18 8 9c0-1.1.9-2 2-2s2 .9 2 2c0 .18-.02.36-.07.52l2.55 2.55c.16-.05.34-.07.52-.07s.36.02.52.07l3.55-3.56C19.02 8.35 19 8.18 19 8c0-1.1.9-2 2-2s2 .9 2 2z"></path></g>
<g id="toc"><path d="M3 9h14V7H3v2zm0 4h14v-2H3v2zm0 4h14v-2H3v2zm16 0h2v-2h-2v2zm0-10v2h2V7h-2zm0 6h2v-2h-2v2z"></path></g>
<g id="today"><path d="M19 3h-1V1h-2v2H8V1H6v2H5c-1.11 0-1.99.9-1.99 2L3 19c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 16H5V8h14v11zM7 10h5v5H7z"></path></g>
<g id="toll"><path d="M15 4c-4.42 0-8 3.58-8 8s3.58 8 8 8 8-3.58 8-8-3.58-8-8-8zm0 14c-3.31 0-6-2.69-6-6s2.69-6 6-6 6 2.69 6 6-2.69 6-6 6zM3 12c0-2.61 1.67-4.83 4-5.65V4.26C3.55 5.15 1 8.27 1 12s2.55 6.85 6 7.74v-2.09c-2.33-.82-4-3.04-4-5.65z"></path></g>
-<g id="track-changes"><path fill="#231F20" d="M19.07 4.93l-1.41 1.41C19.1 7.79 20 9.79 20 12c0 4.42-3.58 8-8 8s-8-3.58-8-8c0-4.08 3.05-7.44 7-7.93v2.02C8.16 6.57 6 9.03 6 12c0 3.31 2.69 6 6 6s6-2.69 6-6c0-1.66-.67-3.16-1.76-4.24l-1.41 1.41C15.55 9.9 16 10.9 16 12c0 2.21-1.79 4-4 4s-4-1.79-4-4c0-1.86 1.28-3.41 3-3.86v2.14c-.6.35-1 .98-1 1.72 0 1.1.9 2 2 2s2-.9 2-2c0-.74-.4-1.38-1-1.72V2h-1C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10c0-2.76-1.12-5.26-2.93-7.07z"></path></g>
+<g id="touch-app"><path d="M9 11.24V7.5C9 6.12 10.12 5 11.5 5S14 6.12 14 7.5v3.74c1.21-.81 2-2.18 2-3.74C16 5.01 13.99 3 11.5 3S7 5.01 7 7.5c0 1.56.79 2.93 2 3.74zm9.84 4.63l-4.54-2.26c-.17-.07-.35-.11-.54-.11H13v-6c0-.83-.67-1.5-1.5-1.5S10 6.67 10 7.5v10.74l-3.43-.72c-.08-.01-.15-.03-.24-.03-.31 0-.59.13-.79.33l-.79.8 4.94 4.94c.27.27.65.44 1.06.44h6.79c.75 0 1.33-.55 1.44-1.28l.75-5.27c.01-.07.02-.14.02-.2 0-.62-.38-1.16-.91-1.38z"></path></g>
+<g id="track-changes"><path d="M19.07 4.93l-1.41 1.41C19.1 7.79 20 9.79 20 12c0 4.42-3.58 8-8 8s-8-3.58-8-8c0-4.08 3.05-7.44 7-7.93v2.02C8.16 6.57 6 9.03 6 12c0 3.31 2.69 6 6 6s6-2.69 6-6c0-1.66-.67-3.16-1.76-4.24l-1.41 1.41C15.55 9.9 16 10.9 16 12c0 2.21-1.79 4-4 4s-4-1.79-4-4c0-1.86 1.28-3.41 3-3.86v2.14c-.6.35-1 .98-1 1.72 0 1.1.9 2 2 2s2-.9 2-2c0-.74-.4-1.38-1-1.72V2h-1C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10c0-2.76-1.12-5.26-2.93-7.07z"></path></g>
<g id="translate"><path d="M12.87 15.07l-2.54-2.51.03-.03c1.74-1.94 2.98-4.17 3.71-6.53H17V4h-7V2H8v2H1v1.99h11.17C11.5 7.92 10.44 9.75 9 11.35 8.07 10.32 7.3 9.19 6.69 8h-2c.73 1.63 1.73 3.17 2.98 4.56l-5.09 5.02L4 19l5-5 3.11 3.11.76-2.04zM18.5 10h-2L12 22h2l1.12-3h4.75L21 22h2l-4.5-12zm-2.62 7l1.62-4.33L19.12 17h-3.24z"></path></g>
<g id="trending-down"><path d="M16 18l2.29-2.29-4.88-4.88-4 4L2 7.41 3.41 6l6 6 4-4 6.3 6.29L22 12v6z"></path></g>
<g id="trending-flat"><path d="M22 12l-4-4v3H3v2h15v3z"></path></g>
<g id="trending-up"><path d="M16 6l2.29 2.29-4.88 4.88-4-4L2 16.59 3.41 18l6-6 4 4 6.3-6.29L22 12V6z"></path></g>
<g id="turned-in"><path d="M17 3H7c-1.1 0-1.99.9-1.99 2L5 21l7-3 7 3V5c0-1.1-.9-2-2-2z"></path></g>
<g id="turned-in-not"><path d="M17 3H7c-1.1 0-1.99.9-1.99 2L5 21l7-3 7 3V5c0-1.1-.9-2-2-2zm0 15l-5-2.18L7 18V5h10v13z"></path></g>
+<g id="unarchive"><path d="M20.55 5.22l-1.39-1.68C18.88 3.21 18.47 3 18 3H6c-.47 0-.88.21-1.15.55L3.46 5.22C3.17 5.57 3 6.01 3 6.5V19c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V6.5c0-.49-.17-.93-.45-1.28zM12 9.5l5.5 5.5H14v2h-4v-2H6.5L12 9.5zM5.12 5l.82-1h12l.93 1H5.12z"></path></g>
<g id="undo"><path d="M12.5 8c-2.65 0-5.05.99-6.9 2.6L2 7v9h9l-3.62-3.62c1.39-1.16 3.16-1.88 5.12-1.88 3.54 0 6.55 2.31 7.6 5.5l2.37-.78C21.08 11.03 17.15 8 12.5 8z"></path></g>
<g id="unfold-less"><path d="M7.41 18.59L8.83 20 12 16.83 15.17 20l1.41-1.41L12 14l-4.59 4.59zm9.18-13.18L15.17 4 12 7.17 8.83 4 7.41 5.41 12 10l4.59-4.59z"></path></g>
<g id="unfold-more"><path d="M12 5.83L15.17 9l1.41-1.41L12 3 7.41 7.59 8.83 9 12 5.83zm0 12.34L8.83 15l-1.41 1.41L12 21l4.59-4.59L15.17 15 12 18.17z"></path></g>
+<g id="update"><path d="M21 10.12h-6.78l2.74-2.82c-2.73-2.7-7.15-2.8-9.88-.1-2.73 2.71-2.73 7.08 0 9.79 2.73 2.71 7.15 2.71 9.88 0C18.32 15.65 19 14.08 19 12.1h2c0 1.98-.88 4.55-2.64 6.29-3.51 3.48-9.21 3.48-12.72 0-3.5-3.47-3.53-9.11-.02-12.58 3.51-3.47 9.14-3.47 12.65 0L21 3v7.12zM12.5 8v4.25l3.5 2.08-.72 1.21L11 13V8h1.5z"></path></g>
<g id="verified-user"><path d="M12 1L3 5v6c0 5.55 3.84 10.74 9 12 5.16-1.26 9-6.45 9-12V5l-9-4zm-2 16l-4-4 1.41-1.41L10 14.17l6.59-6.59L18 9l-8 8z"></path></g>
<g id="view-agenda"><path d="M20 13H3c-.55 0-1 .45-1 1v6c0 .55.45 1 1 1h17c.55 0 1-.45 1-1v-6c0-.55-.45-1-1-1zm0-10H3c-.55 0-1 .45-1 1v6c0 .55.45 1 1 1h17c.55 0 1-.45 1-1V4c0-.55-.45-1-1-1z"></path></g>
<g id="view-array"><path d="M4 18h3V5H4v13zM18 5v13h3V5h-3zM8 18h9V5H8v13z"></path></g>
@@ -1351,9 +695,11 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
<g id="visibility"><path d="M12 4.5C7 4.5 2.73 7.61 1 12c1.73 4.39 6 7.5 11 7.5s9.27-3.11 11-7.5c-1.73-4.39-6-7.5-11-7.5zM12 17c-2.76 0-5-2.24-5-5s2.24-5 5-5 5 2.24 5 5-2.24 5-5 5zm0-8c-1.66 0-3 1.34-3 3s1.34 3 3 3 3-1.34 3-3-1.34-3-3-3z"></path></g>
<g id="visibility-off"><path d="M12 7c2.76 0 5 2.24 5 5 0 .65-.13 1.26-.36 1.83l2.92 2.92c1.51-1.26 2.7-2.89 3.43-4.75-1.73-4.39-6-7.5-11-7.5-1.4 0-2.74.25-3.98.7l2.16 2.16C10.74 7.13 11.35 7 12 7zM2 4.27l2.28 2.28.46.46C3.08 8.3 1.78 10.02 1 12c1.73 4.39 6 7.5 11 7.5 1.55 0 3.03-.3 4.38-.84l.42.42L19.73 22 21 20.73 3.27 3 2 4.27zM7.53 9.8l1.55 1.55c-.05.21-.08.43-.08.65 0 1.66 1.34 3 3 3 .22 0 .44-.03.65-.08l1.55 1.55c-.67.33-1.41.53-2.2.53-2.76 0-5-2.24-5-5 0-.79.2-1.53.53-2.2zm4.31-.78l3.15 3.15.02-.16c0-1.66-1.34-3-3-3l-.17.01z"></path></g>
<g id="warning"><path d="M1 21h22L12 2 1 21zm12-3h-2v-2h2v2zm0-4h-2v-4h2v4z"></path></g>
+<g id="watch-later"><path d="M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10 10-4.5 10-10S17.5 2 12 2zm4.2 14.2L11 13V7h1.5v5.2l4.5 2.7-.8 1.3z"></path></g>
+<g id="weekend"><path d="M21 10c-1.1 0-2 .9-2 2v3H5v-3c0-1.1-.9-2-2-2s-2 .9-2 2v5c0 1.1.9 2 2 2h18c1.1 0 2-.9 2-2v-5c0-1.1-.9-2-2-2zm-3-5H6c-1.1 0-2 .9-2 2v2.15c1.16.41 2 1.51 2 2.82V14h12v-2.03c0-1.3.84-2.4 2-2.82V7c0-1.1-.9-2-2-2z"></path></g>
<g id="work"><path d="M20 6h-4V4c0-1.11-.89-2-2-2h-4c-1.11 0-2 .89-2 2v2H4c-1.11 0-1.99.89-1.99 2L2 19c0 1.11.89 2 2 2h16c1.11 0 2-.89 2-2V8c0-1.11-.89-2-2-2zm-6 0h-4V4h4v2z"></path></g>
<g id="youtube-searched-for"><path d="M17.01 14h-.8l-.27-.27c.98-1.14 1.57-2.61 1.57-4.23 0-3.59-2.91-6.5-6.5-6.5s-6.5 3-6.5 6.5H2l3.84 4 4.16-4H6.51C6.51 7 8.53 5 11.01 5s4.5 2.01 4.5 4.5c0 2.48-2.02 4.5-4.5 4.5-.65 0-1.26-.14-1.82-.38L7.71 15.1c.97.57 2.09.9 3.3.9 1.61 0 3.08-.59 4.22-1.57l.27.27v.79l5.01 4.99L22 19l-4.99-5z"></path></g>
-<g id="zoom-in"><path d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14zM12 10h-2v2H9v-2H7V9h2V7h1v2h2v1z"></path></g>
+<g id="zoom-in"><path d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14zm2.5-4h-2v2H9v-2H7V9h2V7h1v2h2v1z"></path></g>
<g id="zoom-out"><path d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14zM7 9h5v1H7z"></path></g>
</defs></svg>
</iron-iconset-svg>
@@ -1433,7 +779,66 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
<div id="waves"></div>
</template>
</dom-module>
-<dom-module id="paper-material" assetpath="chrome://resources/polymer/v1_0/paper-material/">
+<style is="custom-style">
+
+ :root {
+
+ --shadow-transition: {
+ transition: box-shadow 0.28s cubic-bezier(0.4, 0, 0.2, 1);
+ };
+
+ --shadow-none: {
+ box-shadow: none;
+ };
+
+ /* from http://codepen.io/shyndman/pen/c5394ddf2e8b2a5c9185904b57421cdb */
+
+ --shadow-elevation-2dp: {
+ box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14),
+ 0 1px 5px 0 rgba(0, 0, 0, 0.12),
+ 0 3px 1px -2px rgba(0, 0, 0, 0.2);
+ };
+
+ --shadow-elevation-3dp: {
+ box-shadow: 0 3px 4px 0 rgba(0, 0, 0, 0.14),
+ 0 1px 8px 0 rgba(0, 0, 0, 0.12),
+ 0 3px 3px -2px rgba(0, 0, 0, 0.4);
+ };
+
+ --shadow-elevation-4dp: {
+ box-shadow: 0 4px 5px 0 rgba(0, 0, 0, 0.14),
+ 0 1px 10px 0 rgba(0, 0, 0, 0.12),
+ 0 2px 4px -1px rgba(0, 0, 0, 0.4);
+ };
+
+ --shadow-elevation-6dp: {
+ box-shadow: 0 6px 10px 0 rgba(0, 0, 0, 0.14),
+ 0 1px 18px 0 rgba(0, 0, 0, 0.12),
+ 0 3px 5px -1px rgba(0, 0, 0, 0.4);
+ };
+
+ --shadow-elevation-8dp: {
+ box-shadow: 0 8px 10px 1px rgba(0, 0, 0, 0.14),
+ 0 3px 14px 2px rgba(0, 0, 0, 0.12),
+ 0 5px 5px -3px rgba(0, 0, 0, 0.4);
+ };
+
+ --shadow-elevation-12dp: {
+ box-shadow: 0 12px 16px 1px rgba(0, 0, 0, 0.14),
+ 0 4px 22px 3px rgba(0, 0, 0, 0.12),
+ 0 6px 7px -4px rgba(0, 0, 0, 0.4);
+ };
+
+ --shadow-elevation-16dp: {
+ box-shadow: 0 16px 24px 2px rgba(0, 0, 0, 0.14),
+ 0 6px 30px 5px rgba(0, 0, 0, 0.12),
+ 0 8px 10px -5px rgba(0, 0, 0, 0.4);
+ };
+
+ }
+
+</style>
+<dom-module id="paper-material-shared-styles" assetpath="chrome://resources/polymer/v1_0/paper-material/">
<template>
<style>
:host {
@@ -1441,10 +846,6 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
position: relative;
}
- :host([animated]) {
- @apply(--shadow-transition);
- }
-
:host([elevation="1"]) {
@apply(--shadow-elevation-2dp);
}
@@ -1465,6 +866,18 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
@apply(--shadow-elevation-16dp);
}
</style>
+ </template>
+</dom-module>
+
+
+<dom-module id="paper-material" assetpath="chrome://resources/polymer/v1_0/paper-material/">
+ <template>
+ <style include="paper-material-shared-styles"></style>
+ <style>
+ :host([animated]) {
+ @apply(--shadow-transition);
+ }
+ </style>
<content></content>
</template>
@@ -1527,162 +940,486 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
</template>
</dom-module>
-<dom-module id="paper-progress" assetpath="chrome://resources/polymer/v1_0/paper-progress/">
- <style>
- :host {
- display: block;
- width: 200px;
- position: relative;
- overflow: hidden;
- }
-
- #progressContainer {
- position: relative;
- }
-
- #progressContainer,
- /* the stripe for the indeterminate animation*/
- .indeterminate:after {
- height: var(--paper-progress-height, 4px);
- }
-
- #primaryProgress,
- #secondaryProgress,
- .indeterminate:after {
- @apply(--layout-fit);
- }
+<style is="custom-style">
- #progressContainer,
- .indeterminate:after {
- background-color: var(--paper-progress-container-color, --google-grey-300);
- }
+ :root {
- :host(.transiting) #primaryProgress,
- :host(.transiting) #secondaryProgress {
- -webkit-transition-property: -webkit-transform;
- transition-property: transform;
+ /* Material Design color palette for Google products */
- /* Duration */
- -webkit-transition-duration: var(--paper-progress-transition-duration, 0.08s);
- transition-duration: var(--paper-progress-transition-duration, 0.08s);
+ --google-red-100: #f4c7c3;
+ --google-red-300: #e67c73;
+ --google-red-500: #db4437;
+ --google-red-700: #c53929;
- /* Timing function */
- -webkit-transition-timing-function: var(--paper-progress-transition-timing-function, ease);
- transition-timing-function: var(--paper-progress-transition-timing-function, ease);
+ --google-blue-100: #c6dafc;
+ --google-blue-300: #7baaf7;
+ --google-blue-500: #4285f4;
+ --google-blue-700: #3367d6;
- /* Delay */
- -webkit-transition-delay: var(--paper-progress-transition-delay, 0s);
- transition-delay: var(--paper-progress-transition-delay, 0s);
- }
+ --google-green-100: #b7e1cd;
+ --google-green-300: #57bb8a;
+ --google-green-500: #0f9d58;
+ --google-green-700: #0b8043;
- #primaryProgress,
- #secondaryProgress {
- @apply(--layout-fit);
- -webkit-transform-origin: left center;
- transform-origin: left center;
- -webkit-transform: scaleX(0);
- transform: scaleX(0);
- will-change: transform;
- }
+ --google-yellow-100: #fce8b2;
+ --google-yellow-300: #f7cb4d;
+ --google-yellow-500: #f4b400;
+ --google-yellow-700: #f09300;
- #primaryProgress {
- background-color: var(--paper-progress-active-color, --google-green-500);
- }
+ --google-grey-100: #f5f5f5;
+ --google-grey-300: #e0e0e0;
+ --google-grey-500: #9e9e9e;
+ --google-grey-700: #616161;
+
+ /* Material Design color palette from online spec document */
- #secondaryProgress {
- position: relative;
- background-color: var(--paper-progress-secondary-color, --google-green-100);
- }
+ --paper-red-50: #ffebee;
+ --paper-red-100: #ffcdd2;
+ --paper-red-200: #ef9a9a;
+ --paper-red-300: #e57373;
+ --paper-red-400: #ef5350;
+ --paper-red-500: #f44336;
+ --paper-red-600: #e53935;
+ --paper-red-700: #d32f2f;
+ --paper-red-800: #c62828;
+ --paper-red-900: #b71c1c;
+ --paper-red-a100: #ff8a80;
+ --paper-red-a200: #ff5252;
+ --paper-red-a400: #ff1744;
+ --paper-red-a700: #d50000;
+
+ --paper-pink-50: #fce4ec;
+ --paper-pink-100: #f8bbd0;
+ --paper-pink-200: #f48fb1;
+ --paper-pink-300: #f06292;
+ --paper-pink-400: #ec407a;
+ --paper-pink-500: #e91e63;
+ --paper-pink-600: #d81b60;
+ --paper-pink-700: #c2185b;
+ --paper-pink-800: #ad1457;
+ --paper-pink-900: #880e4f;
+ --paper-pink-a100: #ff80ab;
+ --paper-pink-a200: #ff4081;
+ --paper-pink-a400: #f50057;
+ --paper-pink-a700: #c51162;
+
+ --paper-purple-50: #f3e5f5;
+ --paper-purple-100: #e1bee7;
+ --paper-purple-200: #ce93d8;
+ --paper-purple-300: #ba68c8;
+ --paper-purple-400: #ab47bc;
+ --paper-purple-500: #9c27b0;
+ --paper-purple-600: #8e24aa;
+ --paper-purple-700: #7b1fa2;
+ --paper-purple-800: #6a1b9a;
+ --paper-purple-900: #4a148c;
+ --paper-purple-a100: #ea80fc;
+ --paper-purple-a200: #e040fb;
+ --paper-purple-a400: #d500f9;
+ --paper-purple-a700: #aa00ff;
+
+ --paper-deep-purple-50: #ede7f6;
+ --paper-deep-purple-100: #d1c4e9;
+ --paper-deep-purple-200: #b39ddb;
+ --paper-deep-purple-300: #9575cd;
+ --paper-deep-purple-400: #7e57c2;
+ --paper-deep-purple-500: #673ab7;
+ --paper-deep-purple-600: #5e35b1;
+ --paper-deep-purple-700: #512da8;
+ --paper-deep-purple-800: #4527a0;
+ --paper-deep-purple-900: #311b92;
+ --paper-deep-purple-a100: #b388ff;
+ --paper-deep-purple-a200: #7c4dff;
+ --paper-deep-purple-a400: #651fff;
+ --paper-deep-purple-a700: #6200ea;
+
+ --paper-indigo-50: #e8eaf6;
+ --paper-indigo-100: #c5cae9;
+ --paper-indigo-200: #9fa8da;
+ --paper-indigo-300: #7986cb;
+ --paper-indigo-400: #5c6bc0;
+ --paper-indigo-500: #3f51b5;
+ --paper-indigo-600: #3949ab;
+ --paper-indigo-700: #303f9f;
+ --paper-indigo-800: #283593;
+ --paper-indigo-900: #1a237e;
+ --paper-indigo-a100: #8c9eff;
+ --paper-indigo-a200: #536dfe;
+ --paper-indigo-a400: #3d5afe;
+ --paper-indigo-a700: #304ffe;
+
+ --paper-blue-50: #e3f2fd;
+ --paper-blue-100: #bbdefb;
+ --paper-blue-200: #90caf9;
+ --paper-blue-300: #64b5f6;
+ --paper-blue-400: #42a5f5;
+ --paper-blue-500: #2196f3;
+ --paper-blue-600: #1e88e5;
+ --paper-blue-700: #1976d2;
+ --paper-blue-800: #1565c0;
+ --paper-blue-900: #0d47a1;
+ --paper-blue-a100: #82b1ff;
+ --paper-blue-a200: #448aff;
+ --paper-blue-a400: #2979ff;
+ --paper-blue-a700: #2962ff;
+
+ --paper-light-blue-50: #e1f5fe;
+ --paper-light-blue-100: #b3e5fc;
+ --paper-light-blue-200: #81d4fa;
+ --paper-light-blue-300: #4fc3f7;
+ --paper-light-blue-400: #29b6f6;
+ --paper-light-blue-500: #03a9f4;
+ --paper-light-blue-600: #039be5;
+ --paper-light-blue-700: #0288d1;
+ --paper-light-blue-800: #0277bd;
+ --paper-light-blue-900: #01579b;
+ --paper-light-blue-a100: #80d8ff;
+ --paper-light-blue-a200: #40c4ff;
+ --paper-light-blue-a400: #00b0ff;
+ --paper-light-blue-a700: #0091ea;
+
+ --paper-cyan-50: #e0f7fa;
+ --paper-cyan-100: #b2ebf2;
+ --paper-cyan-200: #80deea;
+ --paper-cyan-300: #4dd0e1;
+ --paper-cyan-400: #26c6da;
+ --paper-cyan-500: #00bcd4;
+ --paper-cyan-600: #00acc1;
+ --paper-cyan-700: #0097a7;
+ --paper-cyan-800: #00838f;
+ --paper-cyan-900: #006064;
+ --paper-cyan-a100: #84ffff;
+ --paper-cyan-a200: #18ffff;
+ --paper-cyan-a400: #00e5ff;
+ --paper-cyan-a700: #00b8d4;
+
+ --paper-teal-50: #e0f2f1;
+ --paper-teal-100: #b2dfdb;
+ --paper-teal-200: #80cbc4;
+ --paper-teal-300: #4db6ac;
+ --paper-teal-400: #26a69a;
+ --paper-teal-500: #009688;
+ --paper-teal-600: #00897b;
+ --paper-teal-700: #00796b;
+ --paper-teal-800: #00695c;
+ --paper-teal-900: #004d40;
+ --paper-teal-a100: #a7ffeb;
+ --paper-teal-a200: #64ffda;
+ --paper-teal-a400: #1de9b6;
+ --paper-teal-a700: #00bfa5;
+
+ --paper-green-50: #e8f5e9;
+ --paper-green-100: #c8e6c9;
+ --paper-green-200: #a5d6a7;
+ --paper-green-300: #81c784;
+ --paper-green-400: #66bb6a;
+ --paper-green-500: #4caf50;
+ --paper-green-600: #43a047;
+ --paper-green-700: #388e3c;
+ --paper-green-800: #2e7d32;
+ --paper-green-900: #1b5e20;
+ --paper-green-a100: #b9f6ca;
+ --paper-green-a200: #69f0ae;
+ --paper-green-a400: #00e676;
+ --paper-green-a700: #00c853;
+
+ --paper-light-green-50: #f1f8e9;
+ --paper-light-green-100: #dcedc8;
+ --paper-light-green-200: #c5e1a5;
+ --paper-light-green-300: #aed581;
+ --paper-light-green-400: #9ccc65;
+ --paper-light-green-500: #8bc34a;
+ --paper-light-green-600: #7cb342;
+ --paper-light-green-700: #689f38;
+ --paper-light-green-800: #558b2f;
+ --paper-light-green-900: #33691e;
+ --paper-light-green-a100: #ccff90;
+ --paper-light-green-a200: #b2ff59;
+ --paper-light-green-a400: #76ff03;
+ --paper-light-green-a700: #64dd17;
+
+ --paper-lime-50: #f9fbe7;
+ --paper-lime-100: #f0f4c3;
+ --paper-lime-200: #e6ee9c;
+ --paper-lime-300: #dce775;
+ --paper-lime-400: #d4e157;
+ --paper-lime-500: #cddc39;
+ --paper-lime-600: #c0ca33;
+ --paper-lime-700: #afb42b;
+ --paper-lime-800: #9e9d24;
+ --paper-lime-900: #827717;
+ --paper-lime-a100: #f4ff81;
+ --paper-lime-a200: #eeff41;
+ --paper-lime-a400: #c6ff00;
+ --paper-lime-a700: #aeea00;
+
+ --paper-yellow-50: #fffde7;
+ --paper-yellow-100: #fff9c4;
+ --paper-yellow-200: #fff59d;
+ --paper-yellow-300: #fff176;
+ --paper-yellow-400: #ffee58;
+ --paper-yellow-500: #ffeb3b;
+ --paper-yellow-600: #fdd835;
+ --paper-yellow-700: #fbc02d;
+ --paper-yellow-800: #f9a825;
+ --paper-yellow-900: #f57f17;
+ --paper-yellow-a100: #ffff8d;
+ --paper-yellow-a200: #ffff00;
+ --paper-yellow-a400: #ffea00;
+ --paper-yellow-a700: #ffd600;
+
+ --paper-amber-50: #fff8e1;
+ --paper-amber-100: #ffecb3;
+ --paper-amber-200: #ffe082;
+ --paper-amber-300: #ffd54f;
+ --paper-amber-400: #ffca28;
+ --paper-amber-500: #ffc107;
+ --paper-amber-600: #ffb300;
+ --paper-amber-700: #ffa000;
+ --paper-amber-800: #ff8f00;
+ --paper-amber-900: #ff6f00;
+ --paper-amber-a100: #ffe57f;
+ --paper-amber-a200: #ffd740;
+ --paper-amber-a400: #ffc400;
+ --paper-amber-a700: #ffab00;
+
+ --paper-orange-50: #fff3e0;
+ --paper-orange-100: #ffe0b2;
+ --paper-orange-200: #ffcc80;
+ --paper-orange-300: #ffb74d;
+ --paper-orange-400: #ffa726;
+ --paper-orange-500: #ff9800;
+ --paper-orange-600: #fb8c00;
+ --paper-orange-700: #f57c00;
+ --paper-orange-800: #ef6c00;
+ --paper-orange-900: #e65100;
+ --paper-orange-a100: #ffd180;
+ --paper-orange-a200: #ffab40;
+ --paper-orange-a400: #ff9100;
+ --paper-orange-a700: #ff6500;
+
+ --paper-deep-orange-50: #fbe9e7;
+ --paper-deep-orange-100: #ffccbc;
+ --paper-deep-orange-200: #ffab91;
+ --paper-deep-orange-300: #ff8a65;
+ --paper-deep-orange-400: #ff7043;
+ --paper-deep-orange-500: #ff5722;
+ --paper-deep-orange-600: #f4511e;
+ --paper-deep-orange-700: #e64a19;
+ --paper-deep-orange-800: #d84315;
+ --paper-deep-orange-900: #bf360c;
+ --paper-deep-orange-a100: #ff9e80;
+ --paper-deep-orange-a200: #ff6e40;
+ --paper-deep-orange-a400: #ff3d00;
+ --paper-deep-orange-a700: #dd2c00;
+
+ --paper-brown-50: #efebe9;
+ --paper-brown-100: #d7ccc8;
+ --paper-brown-200: #bcaaa4;
+ --paper-brown-300: #a1887f;
+ --paper-brown-400: #8d6e63;
+ --paper-brown-500: #795548;
+ --paper-brown-600: #6d4c41;
+ --paper-brown-700: #5d4037;
+ --paper-brown-800: #4e342e;
+ --paper-brown-900: #3e2723;
+
+ --paper-grey-50: #fafafa;
+ --paper-grey-100: #f5f5f5;
+ --paper-grey-200: #eeeeee;
+ --paper-grey-300: #e0e0e0;
+ --paper-grey-400: #bdbdbd;
+ --paper-grey-500: #9e9e9e;
+ --paper-grey-600: #757575;
+ --paper-grey-700: #616161;
+ --paper-grey-800: #424242;
+ --paper-grey-900: #212121;
+
+ --paper-blue-grey-50: #eceff1;
+ --paper-blue-grey-100: #cfd8dc;
+ --paper-blue-grey-200: #b0bec5;
+ --paper-blue-grey-300: #90a4ae;
+ --paper-blue-grey-400: #78909c;
+ --paper-blue-grey-500: #607d8b;
+ --paper-blue-grey-600: #546e7a;
+ --paper-blue-grey-700: #455a64;
+ --paper-blue-grey-800: #37474f;
+ --paper-blue-grey-900: #263238;
- :host([disabled]) #primaryProgress {
- background-color: var(--paper-progress-disabled-active-color, --google-grey-500);
- }
+ /* opacity for dark text on a light background */
+ --dark-divider-opacity: 0.12;
+ --dark-disabled-opacity: 0.38; /* or hint text or icon */
+ --dark-secondary-opacity: 0.54;
+ --dark-primary-opacity: 0.87;
- :host([disabled]) #secondaryProgress {
- background-color: var(--paper-progress-disabled-active-color, --google-grey-300);
- }
+ /* opacity for light text on a dark background */
+ --light-divider-opacity: 0.12;
+ --light-disabled-opacity: 0.3; /* or hint text or icon */
+ --light-secondary-opacity: 0.7;
+ --light-primary-opacity: 1.0;
- :host(:not([disabled])) #primaryProgress.indeterminate {
- -webkit-transform-origin: right center;
- transform-origin: right center;
- -webkit-animation: indeterminate-bar 2s linear infinite;
- animation: indeterminate-bar 2s linear infinite;
- }
+ }
- :host(:not([disabled])) #primaryProgress.indeterminate:after {
- content: "";
- -webkit-transform-origin: center center;
- transform-origin: center center;
+</style>
- -webkit-animation: indeterminate-splitter 2s linear infinite;
- animation: indeterminate-splitter 2s linear infinite;
- }
- @-webkit-keyframes indeterminate-bar {
- 0% {
- -webkit-transform: scaleX(1) translateX(-100%);
- }
- 50% {
- -webkit-transform: scaleX(1) translateX(0%);
- }
- 75% {
- -webkit-transform: scaleX(1) translateX(0%);
- -webkit-animation-timing-function: cubic-bezier(.28,.62,.37,.91);
- }
- 100% {
- -webkit-transform: scaleX(0) translateX(0%);
+<dom-module id="paper-progress" assetpath="chrome://resources/polymer/v1_0/paper-progress/">
+ <template>
+ <style>
+ :host {
+ display: block;
+ width: 200px;
+ position: relative;
+ overflow: hidden;
}
- }
- @-webkit-keyframes indeterminate-splitter {
- 0% {
- -webkit-transform: scaleX(.75) translateX(-125%);
+ #progressContainer {
+ position: relative;
}
- 30% {
- -webkit-transform: scaleX(.75) translateX(-125%);
- -webkit-animation-timing-function: cubic-bezier(.42,0,.6,.8);
+
+ #progressContainer,
+ /* the stripe for the indeterminate animation*/
+ .indeterminate::after {
+ height: var(--paper-progress-height, 4px);
}
- 90% {
- -webkit-transform: scaleX(.75) translateX(125%);
+
+ #primaryProgress,
+ #secondaryProgress,
+ .indeterminate::after {
+ @apply(--layout-fit);
}
- 100% {
- -webkit-transform: scaleX(.75) translateX(125%);
+
+ #progressContainer,
+ .indeterminate::after {
+ background-color: var(--paper-progress-container-color, --google-grey-300);
}
- }
- @keyframes indeterminate-bar {
- 0% {
- transform: scaleX(1) translateX(-100%);
+ :host(.transiting) #primaryProgress,
+ :host(.transiting) #secondaryProgress {
+ -webkit-transition-property: -webkit-transform;
+ transition-property: transform;
+
+ /* Duration */
+ -webkit-transition-duration: var(--paper-progress-transition-duration, 0.08s);
+ transition-duration: var(--paper-progress-transition-duration, 0.08s);
+
+ /* Timing function */
+ -webkit-transition-timing-function: var(--paper-progress-transition-timing-function, ease);
+ transition-timing-function: var(--paper-progress-transition-timing-function, ease);
+
+ /* Delay */
+ -webkit-transition-delay: var(--paper-progress-transition-delay, 0s);
+ transition-delay: var(--paper-progress-transition-delay, 0s);
}
- 50% {
- transform: scaleX(1) translateX(0%);
+
+ #primaryProgress,
+ #secondaryProgress {
+ @apply(--layout-fit);
+ -webkit-transform-origin: left center;
+ transform-origin: left center;
+ -webkit-transform: scaleX(0);
+ transform: scaleX(0);
+ will-change: transform;
}
- 75% {
- transform: scaleX(1) translateX(0%);
- animation-timing-function: cubic-bezier(.28,.62,.37,.91);
+
+ #primaryProgress {
+ background-color: var(--paper-progress-active-color, --google-green-500);
}
- 100% {
- transform: scaleX(0) translateX(0%);
+
+ #secondaryProgress {
+ position: relative;
+ background-color: var(--paper-progress-secondary-color, --google-green-100);
}
- }
- @keyframes indeterminate-splitter {
- 0% {
- transform: scaleX(.75) translateX(-125%);
+ :host([disabled]) #primaryProgress {
+ background-color: var(--paper-progress-disabled-active-color, --google-grey-500);
}
- 30% {
- transform: scaleX(.75) translateX(-125%);
- animation-timing-function: cubic-bezier(.42,0,.6,.8);
+
+ :host([disabled]) #secondaryProgress {
+ background-color: var(--paper-progress-disabled-secondary-color, --google-grey-300);
}
- 90% {
- transform: scaleX(.75) translateX(125%);
+
+ :host(:not([disabled])) #primaryProgress.indeterminate {
+ -webkit-transform-origin: right center;
+ transform-origin: right center;
+ -webkit-animation: indeterminate-bar 2s linear infinite;
+ animation: indeterminate-bar 2s linear infinite;
}
- 100% {
- transform: scaleX(.75) translateX(125%);
+
+ :host(:not([disabled])) #primaryProgress.indeterminate::after {
+ content: "";
+ -webkit-transform-origin: center center;
+ transform-origin: center center;
+
+ -webkit-animation: indeterminate-splitter 2s linear infinite;
+ animation: indeterminate-splitter 2s linear infinite;
+ }
+
+ @-webkit-keyframes indeterminate-bar {
+ 0% {
+ -webkit-transform: scaleX(1) translateX(-100%);
+ }
+ 50% {
+ -webkit-transform: scaleX(1) translateX(0%);
+ }
+ 75% {
+ -webkit-transform: scaleX(1) translateX(0%);
+ -webkit-animation-timing-function: cubic-bezier(.28,.62,.37,.91);
+ }
+ 100% {
+ -webkit-transform: scaleX(0) translateX(0%);
+ }
+ }
+
+ @-webkit-keyframes indeterminate-splitter {
+ 0% {
+ -webkit-transform: scaleX(.75) translateX(-125%);
+ }
+ 30% {
+ -webkit-transform: scaleX(.75) translateX(-125%);
+ -webkit-animation-timing-function: cubic-bezier(.42,0,.6,.8);
+ }
+ 90% {
+ -webkit-transform: scaleX(.75) translateX(125%);
+ }
+ 100% {
+ -webkit-transform: scaleX(.75) translateX(125%);
+ }
+ }
+
+ @keyframes indeterminate-bar {
+ 0% {
+ transform: scaleX(1) translateX(-100%);
+ }
+ 50% {
+ transform: scaleX(1) translateX(0%);
+ }
+ 75% {
+ transform: scaleX(1) translateX(0%);
+ animation-timing-function: cubic-bezier(.28,.62,.37,.91);
+ }
+ 100% {
+ transform: scaleX(0) translateX(0%);
+ }
+ }
+
+ @keyframes indeterminate-splitter {
+ 0% {
+ transform: scaleX(.75) translateX(-125%);
+ }
+ 30% {
+ transform: scaleX(.75) translateX(-125%);
+ animation-timing-function: cubic-bezier(.42,0,.6,.8);
+ }
+ 90% {
+ transform: scaleX(.75) translateX(125%);
+ }
+ 100% {
+ transform: scaleX(.75) translateX(125%);
+ }
}
- }
- </style>
- <template>
+ </style>
+
<div id="progressContainer">
<div id="secondaryProgress" hidden$="[[_hideSecondaryProgress(secondaryRatio)]]"></div>
<div id="primaryProgress"></div>
@@ -1705,123 +1442,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
</dom-module>
<dom-module id="downloads-item" assetpath="chrome://downloads/">
- <template>
- <h3 id="date">[[computeDate_(data.hideDate, data.since_string, data.date_string)]]</h3>
-
- <div id="content" on-dragstart="onDragStart_" class$="[[computeClass_(isActive_, isDangerous_, showProgress_)]]">
- <div id="file-icon-wrapper" class="icon-wrapper">
- <img class="icon" id="file-icon" alt="" hidden="[[isDangerous_]]">
- <iron-icon id="danger-icon" icon$="[[computeDangerIcon_(isDangerous_, data.danger_type)]]" hidden="[[!isDangerous_]]"></iron-icon>
- </div>
-
- <div id="details">
- <div id="title-area"><a is="action-link" id="file-link" href="[[data.url]]" on-tap="onFileLinkTap_" hidden="[[!completelyOnDisk_]]">[[data.file_name]]</a><span id="name" hidden="[[completelyOnDisk_]]">[[data.file_name]]</span>
- <span id="tag">[[computeTag_(data.state, data.last_reason_text, data.file_externally_removed)]]</span>
- </div>
-
- <a id="url" target="_blank" href="[[data.url]]">[[data.url]]</a>
-
- <div id="description">[[computeDescription_(data.state, data.danger_type, data.file_name, data.progress_status_text)]]</div>
-
- <template is="dom-if" if="[[showProgress_]]">
- <paper-progress id="progress" indeterminate="[[isIndeterminate_(data.percent)]]" value="[[data.percent]]"></paper-progress>
- </template>
-
- <div id="safe" class="controls" hidden="[[isDangerous_]]">
- <a is="action-link" id="show" i18n-content="controlShowInFolder" on-tap="onShowTap_" hidden="[[!completelyOnDisk_]]"></a>
- <template is="dom-if" if="[[data.retry]]">
- <paper-button id="retry" on-tap="onRetryTap_">[[i18n_.retry]]</paper-button>
- </template>
- <template is="dom-if" if="[[isInProgress_]]">
- <paper-button id="pause" on-tap="onPauseTap_">[[i18n_.pause]]</paper-button>
- </template>
- <template is="dom-if" if="[[data.resume]]">
- <paper-button id="resume" on-tap="onResumeTap_">[[i18n_.resume]]</paper-button>
- </template>
- <template is="dom-if" if="[[showCancel_]]">
- <paper-button id="cancel" on-tap="onCancelTap_">[[i18n_.cancel]]</paper-button>
- </template>
- <span id="controlled-by"></span>
- </div>
-
- <template is="dom-if" if="[[isDangerous_]]">
- <div id="dangerous" class="controls">
-
- <template is="dom-if" if="[[!isMalware_]]">
- <paper-button id="discard" on-tap="onDiscardDangerousTap_" class="discard">[[i18n_.discard]]</paper-button>
- <paper-button id="save" on-tap="onSaveDangerousTap_" class="keep">[[i18n_.save]]</paper-button>
- </template>
-
-
- <template is="dom-if" if="[[isMalware_]]">
- <paper-button id="danger-remove" on-tap="onDiscardDangerousTap_" class="discard">[[i18n_.remove]]</paper-button>
- <paper-button id="restore" on-tap="onSaveDangerousTap_" class="keep">[[i18n_.restore]]</paper-button>
- </template>
- </div>
- </template>
- </div>
-
- <div id="remove-wrapper" class="icon-wrapper">
- <inky-text-button id="remove" i18n-values="title:controlRemoveFromList" style$="[[computeRemoveStyle_(isDangerous_, showCancel_)]]" on-tap="onRemoveTap_">✕</inky-text-button>
- </div>
-
- <div id="incognito" i18n-values="title:inIncognito" hidden="[[!data.otr]]"></div>
- </div>
-
- </template>
- <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. */
-
-[is='action-link'] {
- cursor: pointer;
- display: inline-block;
- text-decoration: none;
-}
-
-[is='action-link']:hover {
- text-decoration: underline;
-}
-
-[is='action-link']:active {
- color: rgb(5, 37, 119);
- text-decoration: underline;
-}
-
-[is='action-link'][disabled] {
- color: #999;
- cursor: default;
- pointer-events: none;
- text-decoration: none;
-}
-
-[is='action-link'].no-outline {
- outline: none;
-}
-
-</style>
- <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. */
-
-* {
- --downloads-item-width: 622px;
-}
-
-[hidden] {
- display: none !important;
-}
-
-paper-button {
- font-weight: 500;
- margin: 0;
- min-width: auto;
-}
-
-</style>
- <style>
+ <template><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. */
@@ -1860,7 +1481,9 @@ paper-button {
}
#content:not(.is-active) {
- opacity: .6;
+ background: rgba(255, 255, 255, .6);
+ box-shadow: 0 2px 2px 0 rgba(0, 0, 0, .03), 0 1px 4px 0 rgba(0, 0, 0, .048),
+ 0 3px 1px -2px rgba(0, 0, 0, .12);
}
#details {
@@ -1876,7 +1499,7 @@ paper-button {
}
#content:not(.is-active) #details {
- color: #bababa;
+ color: rgba(186, 186, 186, .6);
}
#content:not(.is-active) #name {
@@ -1935,7 +1558,8 @@ paper-button {
-webkit-margin-end: 12px; /* Only really affects #tag. */
}
-.is-active :-webkit-any(#name, #file-link, #pause, #resume, #show) {
+#resume,
+.is-active :-webkit-any(#name, #file-link, #pause, #show) {
color: rgb(51, 103, 214);
}
@@ -2033,37 +1657,221 @@ paper-button {
right: 10px;
}
+</style><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. */
+
+* {
+ --downloads-item-width: 622px;
+}
+
+[hidden] {
+ display: none !important;
+}
+
+paper-button {
+ font-weight: 500;
+ margin: 0;
+ min-width: auto;
+}
+
+</style><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. */
+
+[is='action-link'] {
+ cursor: pointer;
+ display: inline-block;
+ text-decoration: none;
+}
+
+[is='action-link']:hover {
+ text-decoration: underline;
+}
+
+[is='action-link']:active {
+ color: rgb(5, 37, 119);
+ text-decoration: underline;
+}
+
+[is='action-link'][disabled] {
+ color: #999;
+ cursor: default;
+ pointer-events: none;
+ text-decoration: none;
+}
+
+[is='action-link'].no-outline {
+ outline: none;
+}
+
</style>
+ <h3 id="date">[[computeDate_(data.hideDate, data.since_string, data.date_string)]]</h3>
+
+ <div id="content" on-dragstart="onDragStart_" class$="[[computeClass_(isActive_, isDangerous_, showProgress_)]]">
+ <div id="file-icon-wrapper" class="icon-wrapper">
+ <img class="icon" id="file-icon" alt="" hidden="[[isDangerous_]]">
+ <iron-icon id="danger-icon" icon$="[[computeDangerIcon_(isDangerous_, data.danger_type)]]" hidden="[[!isDangerous_]]"></iron-icon>
+ </div>
+
+ <div id="details">
+ <div id="title-area"><a is="action-link" id="file-link" href="[[data.url]]" on-tap="onFileLinkTap_" hidden="[[!completelyOnDisk_]]">[[data.file_name]]</a><span id="name" hidden="[[completelyOnDisk_]]">[[data.file_name]]</span>
+ <span id="tag">[[computeTag_(data.state, data.last_reason_text, data.file_externally_removed)]]</span>
+ </div>
+
+ <a id="url" target="_blank" href="[[data.url]]">[[data.url]]</a>
+
+ <div id="description">[[computeDescription_(data.state, data.danger_type, data.file_name, data.progress_status_text)]]</div>
+
+ <template is="dom-if" if="[[showProgress_]]">
+ <paper-progress id="progress" indeterminate="[[isIndeterminate_(data.percent)]]" value="[[data.percent]]"></paper-progress>
+ </template>
+
+ <div id="safe" class="controls" hidden="[[isDangerous_]]">
+ <a is="action-link" id="show" i18n-content="controlShowInFolder" on-tap="onShowTap_" hidden="[[!completelyOnDisk_]]"></a>
+ <template is="dom-if" if="[[data.retry]]">
+ <paper-button id="retry" on-tap="onRetryTap_">[[i18n_.retry]]</paper-button>
+ </template>
+ <template is="dom-if" if="[[isInProgress_]]">
+ <paper-button id="pause" on-tap="onPauseTap_">[[i18n_.pause]]</paper-button>
+ </template>
+ <template is="dom-if" if="[[data.resume]]">
+ <paper-button id="resume" on-tap="onResumeTap_">[[i18n_.resume]]</paper-button>
+ </template>
+ <template is="dom-if" if="[[showCancel_]]">
+ <paper-button id="cancel" on-tap="onCancelTap_">[[i18n_.cancel]]</paper-button>
+ </template>
+ <span id="controlled-by"></span>
+ </div>
+
+ <template is="dom-if" if="[[isDangerous_]]">
+ <div id="dangerous" class="controls">
+
+ <template is="dom-if" if="[[!isMalware_]]">
+ <paper-button id="discard" on-tap="onDiscardDangerousTap_" class="discard">[[i18n_.discard]]</paper-button>
+ <paper-button id="save" on-tap="onSaveDangerousTap_" class="keep">[[i18n_.save]]</paper-button>
+ </template>
+
+
+ <template is="dom-if" if="[[isMalware_]]">
+ <paper-button id="danger-remove" on-tap="onDiscardDangerousTap_" class="discard">[[i18n_.remove]]</paper-button>
+ <paper-button id="restore" on-tap="onSaveDangerousTap_" class="keep">[[i18n_.restore]]</paper-button>
+ </template>
+ </div>
+ </template>
+ </div>
+
+ <div id="remove-wrapper" class="icon-wrapper">
+ <inky-text-button id="remove" i18n-values="title:controlRemoveFromList" style$="[[computeRemoveStyle_(isDangerous_, showCancel_)]]" on-tap="onRemoveTap_">✕</inky-text-button>
+ </div>
+
+ <div id="incognito" i18n-values="title:inIncognito" hidden="[[!data.otr]]"></div>
+ </div>
+
+ </template>
+
+
+
</dom-module>
+
+
+<style is="custom-style">
+
+ :root {
+ /*
+ * You can use these generic variables in your elements for easy theming.
+ * For example, if all your elements use `--primary-text-color` as its main
+ * color, then switching from a light to a dark theme is just a matter of
+ * changing the value of `--primary-text-color` in your application.
+ */
+ --primary-text-color: var(--light-theme-text-color);
+ --primary-background-color: var(--light-theme-background-color);
+ --secondary-text-color: var(--light-theme-secondary-color);
+ --disabled-text-color: var(--light-theme-disabled-color);
+ --divider-color: var(--light-theme-divider-color);
+ --error-color: var(--paper-deep-orange-a700);
+
+ /*
+ * Primary and accent colors. Also see color.html for more colors.
+ */
+ --primary-color: var(--paper-indigo-500);
+ --light-primary-color: var(--paper-indigo-100);
+ --dark-primary-color: var(--paper-indigo-700);
+
+ --accent-color: var(--paper-pink-a200);
+ --light-accent-color: var(--paper-pink-a100);
+ --dark-accent-color: var(--paper-pink-a400);
+
+
+ /*
+ * Material Design Light background theme
+ */
+ --light-theme-background-color: #ffffff;
+ --light-theme-base-color: #000000;
+ --light-theme-text-color: var(--paper-grey-900);
+ --light-theme-secondary-color: #737373; /* for secondary text and icons */
+ --light-theme-disabled-color: #9b9b9b; /* disabled/hint text */
+ --light-theme-divider-color: #dbdbdb;
+
+ /*
+ * Material Design Dark background theme
+ */
+ --dark-theme-background-color: var(--paper-grey-900);
+ --dark-theme-base-color: #ffffff;
+ --dark-theme-text-color: #ffffff;
+ --dark-theme-secondary-color: #bcbcbc; /* for secondary text and icons */
+ --dark-theme-disabled-color: #646464; /* disabled/hint text */
+ --dark-theme-divider-color: #3c3c3c;
+
+ /*
+ * Deprecated values because of their confusing names.
+ */
+ --text-primary-color: var(--dark-theme-text-color);
+ --default-primary-color: var(--primary-color);
+
+ }
+
+</style>
<dom-module id="paper-item-shared-styles" assetpath="chrome://resources/polymer/v1_0/paper-item/">
<template>
<style>
:host {
display: block;
+ position: relative;
min-height: var(--paper-item-min-height, 48px);
padding: 0px 16px;
}
+ :host([hidden]) {
+ display: none !important;
+ }
+
:host(.iron-selected) {
font-weight: var(--paper-item-selected-weight, bold);
+
@apply(--paper-item-selected);
}
:host([disabled]) {
color: var(--paper-item-disabled-color, --disabled-text-color);
+
@apply(--paper-item-disabled);
}
:host(:focus) {
position: relative;
outline: 0;
+
@apply(--paper-item-focused);
}
:host(:focus):before {
@apply(--layout-fit);
- content: '';
+
background: currentColor;
+ content: '';
opacity: var(--dark-divider-opacity);
pointer-events: none;
@@ -2072,6 +1880,8 @@ paper-button {
</style>
</template>
</dom-module>
+
+
<dom-module id="paper-item" assetpath="chrome://resources/polymer/v1_0/paper-item/">
<template>
<style include="paper-item-shared-styles"></style>
@@ -2115,6 +1925,7 @@ paper-button {
background: currentColor;
opacity: var(--dark-divider-opacity);
content: '';
+ pointer-events: none;
@apply(--paper-menu-focused-item-after);
}
@@ -2125,6 +1936,8 @@ paper-button {
</style>
</template>
</dom-module>
+
+
<dom-module id="paper-menu" assetpath="chrome://resources/polymer/v1_0/paper-menu/">
<template>
<style include="paper-menu-shared-styles"></style>
@@ -2177,6 +1990,9 @@ paper-button {
</dom-module>
+<script src="chrome://resources/polymer/v1_0/web-animations-js/web-animations-next-lite.min.js"></script>
+
+
<dom-module id="iron-dropdown" assetpath="chrome://resources/polymer/v1_0/iron-dropdown/">
<style>
:host {
@@ -2198,7 +2014,6 @@ paper-button {
</template>
</dom-module>
-
<dom-module id="paper-menu-button" assetpath="chrome://resources/polymer/v1_0/paper-menu-button/">
<style>
:host {
@@ -2229,11 +2044,14 @@ paper-button {
margin-top: 20px;
}
- paper-material {
+ iron-dropdown {
+ @apply(--paper-menu-button-dropdown);
+ }
+
+ .dropdown-content {
border-radius: 2px;
background-color: var(--paper-menu-button-dropdown-background, --primary-background-color);
-
- @apply(--paper-menu-button-dropdown);
+ @apply(--paper-menu-button-content);
}
</style>
<template>
@@ -2283,6 +2101,10 @@ paper-button {
cursor: auto;
@apply(--paper-icon-button-disabled);
}
+
+ :host(:hover) {
+ @apply(--paper-icon-button-hover);
+ }
iron-icon {
--iron-icon-width: 100%;
@@ -2293,9 +2115,196 @@ paper-button {
</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. */
+
+@font-face {
+ font-family: 'Roboto';
+ font-style: normal;
+ font-weight: 300;
+ src: local('Roboto Light'), local('Roboto-Light'),
+ url("chrome://resources/roboto/roboto-light.woff2") format('woff2');
+}
+
+@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');
+}
+
+</style>
+<style is="custom-style">
+
+ :root {
+
+ /* Shared Styles */
+ --paper-font-common-base: {
+ font-family: 'Roboto', 'Noto', sans-serif;
+ -webkit-font-smoothing: antialiased;
+ };
+
+ --paper-font-common-code: {
+ font-family: 'Roboto Mono', 'Consolas', 'Menlo', monospace;
+ -webkit-font-smoothing: antialiased;
+ };
+
+ --paper-font-common-expensive-kerning: {
+ text-rendering: optimizeLegibility;
+ };
+
+ --paper-font-common-nowrap: {
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ };
+
+ /* Material Font Styles */
+
+ --paper-font-display4: {
+ @apply(--paper-font-common-base);
+ @apply(--paper-font-common-nowrap);
+
+ font-size: 112px;
+ font-weight: 300;
+ letter-spacing: -.044em;
+ line-height: 120px;
+ };
+
+ --paper-font-display3: {
+ @apply(--paper-font-common-base);
+ @apply(--paper-font-common-nowrap);
+
+ font-size: 56px;
+ font-weight: 400;
+ letter-spacing: -.026em;
+ line-height: 60px;
+ };
+
+ --paper-font-display2: {
+ @apply(--paper-font-common-base);
+
+ font-size: 45px;
+ font-weight: 400;
+ letter-spacing: -.018em;
+ line-height: 48px;
+ };
+
+ --paper-font-display1: {
+ @apply(--paper-font-common-base);
+
+ font-size: 34px;
+ font-weight: 400;
+ letter-spacing: -.01em;
+ line-height: 40px;
+ };
+
+ --paper-font-headline: {
+ @apply(--paper-font-common-base);
+
+ font-size: 24px;
+ font-weight: 400;
+ letter-spacing: -.012em;
+ line-height: 32px;
+ };
+
+ --paper-font-title: {
+ @apply(--paper-font-common-base);
+ @apply(--paper-font-common-nowrap);
+
+ font-size: 20px;
+ font-weight: 500;
+ line-height: 28px;
+ };
+
+ --paper-font-subhead: {
+ @apply(--paper-font-common-base);
+
+ font-size: 16px;
+ font-weight: 400;
+ line-height: 24px;
+ };
+
+ --paper-font-body2: {
+ @apply(--paper-font-common-base);
+
+ font-size: 14px;
+ font-weight: 500;
+ line-height: 24px;
+ };
+
+ --paper-font-body1: {
+ @apply(--paper-font-common-base);
+
+ font-size: 14px;
+ font-weight: 400;
+ line-height: 20px;
+ };
+
+ --paper-font-caption: {
+ @apply(--paper-font-common-base);
+ @apply(--paper-font-common-nowrap);
+
+ font-size: 12px;
+ font-weight: 400;
+ letter-spacing: 0.011em;
+ line-height: 20px;
+ };
+
+ --paper-font-menu: {
+ @apply(--paper-font-common-base);
+ @apply(--paper-font-common-nowrap);
+
+ font-size: 13px;
+ font-weight: 500;
+ line-height: 24px;
+ };
+
+ --paper-font-button: {
+ @apply(--paper-font-common-base);
+ @apply(--paper-font-common-nowrap);
+
+ font-size: 14px;
+ font-weight: 500;
+ letter-spacing: 0.018em;
+ line-height: 24px;
+ text-transform: uppercase;
+ };
+
+ --paper-font-code2: {
+ @apply(--paper-font-common-code);
+
+ font-size: 14px;
+ font-weight: 700;
+ line-height: 20px;
+ };
+
+ --paper-font-code1: {
+ @apply(--paper-font-common-code);
+
+ font-size: 14px;
+ font-weight: 500;
+ line-height: 20px;
+ };
+
+ }
+
+</style>
+
+
<dom-module id="paper-input-container" assetpath="chrome://resources/polymer/v1_0/paper-input/">
<template>
-
<style>
:host {
display: block;
@@ -2324,16 +2333,16 @@ paper-button {
}
.focused-line {
- height: 2px;
@apply(--layout-fit);
+ background: var(--paper-input-container-focus-color, --primary-color);
+ height: 2px;
+
-webkit-transform-origin: center center;
transform-origin: center center;
-webkit-transform: scale3d(0,1,1);
transform: scale3d(0,1,1);
- background: var(--paper-input-container-focus-color, --default-primary-color);
-
@apply(--paper-input-container-underline-focus);
}
@@ -2347,8 +2356,7 @@ paper-button {
}
.underline.is-invalid .focused-line {
- background: var(--paper-input-container-invalid-color, --google-red-500);
-
+ background: var(--paper-input-container-invalid-color, --error-color);
-webkit-transform: none;
transform: none;
-webkit-transition: -webkit-transform 0.25s;
@@ -2358,9 +2366,10 @@ paper-button {
}
.unfocused-line {
- height: 1px;
@apply(--layout-fit);
+
background: var(--paper-input-container-color, --secondary-text-color);
+ height: 1px;
@apply(--paper-input-container-underline);
}
@@ -2374,14 +2383,18 @@ paper-button {
}
.label-and-input-container {
- @apply(--layout-flex);
+ @apply(--layout-flex-auto);
@apply(--layout-relative);
+
+ width: 100%;
+ max-width: 100%;
}
.input-content {
- position: relative;
@apply(--layout-horizontal);
@apply(--layout-center);
+
+ position: relative;
}
.input-content ::content label,
@@ -2390,29 +2403,30 @@ paper-button {
top: 0;
right: 0;
left: 0;
+ width: 100%;
font: inherit;
color: var(--paper-input-container-color, --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;
@apply(--paper-font-common-nowrap);
@apply(--paper-font-subhead);
@apply(--paper-input-container-label);
+ @apply(--paper-transition-easing);
}
.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);
- -webkit-transition: -webkit-transform 0.25s;
- transition: transform 0.25s;
-
- -webkit-transform-origin: left top;
- transform-origin: left top;
/* Since we scale to 75/100 of the size, we actually have 100/75 of the
original space now available */
width: 133%;
- @apply(--paper-transition-easing);
+ @apply(--paper-input-container-label-floating);
}
:host-context([dir="rtl"]) .input-content.label-is-floating ::content label,
@@ -2427,14 +2441,14 @@ paper-button {
.input-content.label-is-highlighted ::content label,
.input-content.label-is-highlighted ::content .paper-input-label {
- color: var(--paper-input-container-focus-color, --default-primary-color);
+ color: var(--paper-input-container-focus-color, --primary-color);
@apply(--paper-input-container-label-focus);
}
.input-content.is-invalid ::content label,
.input-content.is-invalid ::content .paper-input-label {
- color: var(--paper-input-container-invalid-color, --google-red-500);
+ color: var(--paper-input-container-invalid-color, --error-color);
}
.input-content.label-is-hidden ::content label,
@@ -2451,6 +2465,7 @@ paper-button {
box-shadow: none;
padding: 0;
width: 100%;
+ max-width: 100%;
background: transparent;
border: none;
color: var(--paper-input-container-input-color, --primary-text-color);
@@ -2463,12 +2478,16 @@ paper-button {
::content [prefix] {
@apply(--paper-font-subhead);
+
@apply(--paper-input-prefix);
+ @apply(--layout-flex-none);
}
::content [suffix] {
@apply(--paper-font-subhead);
+
@apply(--paper-input-suffix);
+ @apply(--layout-flex-none);
}
/* Firefox sets a min-width on the input, which can cause layout issues */
@@ -2485,11 +2504,11 @@ paper-button {
}
.add-on-content.is-invalid ::content * {
- color: var(--paper-input-container-invalid-color, --google-red-500);
+ color: var(--paper-input-container-invalid-color, --error-color);
}
.add-on-content.is-highlighted ::content * {
- color: var(--paper-input-container-focus-color, --default-primary-color);
+ color: var(--paper-input-container-focus-color, --primary-color);
}
</style>
@@ -2503,6 +2522,7 @@ paper-button {
<div class="label-and-input-container" id="labelAndInputContainer">
<content select=":not([add-on]):not([prefix]):not([suffix])"></content>
</div>
+
<content select="[suffix]"></content>
</div>
@@ -2514,21 +2534,11 @@ paper-button {
<div class$="[[_computeAddOnContentClass(focused,invalid)]]">
<content id="addOnContent" select="[add-on]"></content>
</div>
-
</template>
</dom-module>
<dom-module id="cr-search-field" assetpath="chrome://resources/cr_elements/cr_search_field/">
- <template>
- <paper-icon-button icon="search" id="search-button" disabled$="[[showingSearch_]]" title="[[label]]" on-click="toggleShowingSearch_"></paper-icon-button>
- <template is="dom-if" if="[[showingSearch_]]" id="search-container">
- <paper-input-container id="search-term" on-search="onSearchTermSearch_" on-keydown="onSearchTermKeydown_" hidden$="[[!showingSearch_]]" no-label-float="">
- <input is="iron-input" id="search-input" type="search" placeholder="[[label]]" incremental="">
- <paper-icon-button icon="cancel" id="clear-search" on-click="toggleShowingSearch_" title="[[clearLabel]]" hidden$="[[!showingSearch_]]"></paper-icon-button>
- </paper-input-container>
- </template>
- </template>
- <style>
+ <template><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. */
@@ -2602,48 +2612,18 @@ paper-icon-button {
}
</style>
+ <paper-icon-button icon="search" id="search-button" disabled$="[[showingSearch_]]" title="[[label]]" on-click="toggleShowingSearch_"></paper-icon-button>
+ <template is="dom-if" if="[[showingSearch_]]" id="search-container">
+ <paper-input-container id="search-term" on-search="onSearchTermSearch_" on-keydown="onSearchTermKeydown_" hidden$="[[!showingSearch_]]" no-label-float="">
+ <input is="iron-input" id="search-input" type="search" placeholder="[[label]]" incremental="">
+ <paper-icon-button icon="cancel" id="clear-search" on-click="toggleShowingSearch_" title="[[clearLabel]]" hidden$="[[!showingSearch_]]"></paper-icon-button>
+ </paper-input-container>
+ </template>
+ </template>
+
</dom-module>
<dom-module id="downloads-toolbar" assetpath="chrome://downloads/">
- <template>
- <div id="title">
- <h1 i18n-content="title"></h1>
- </div>
- <div id="actions">
- <paper-button class="clear-all" i18n-content="clearAll" on-tap="onClearAllTap_"></paper-button>
- <paper-button i18n-content="openDownloadsFolder" on-tap="onOpenDownloadsFolderTap_"></paper-button>
- </div>
- <div id="search">
- <cr-search-field id="search-input" i18n-values="label:search;clear-label:clearSearch"></cr-search-field>
- <paper-menu-button id="more" horizontal-align="[[overflowAlign_]]">
- <paper-icon-button icon="more-vert" i18n-values="title:moreActions" class="dropdown-trigger"></paper-icon-button>
- <paper-menu class="dropdown-content">
- <paper-item class="clear-all" i18n-content="clearAll" on-tap="onClearAllTap_"></paper-item>
- <paper-item i18n-content="openDownloadsFolder" on-tap="onOpenDownloadsFolderTap_"></paper-item>
- </paper-menu>
- </paper-menu-button>
- </div>
- </template>
- <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. */
-
-* {
- --downloads-item-width: 622px;
-}
-
-[hidden] {
- display: none !important;
-}
-
-paper-button {
- font-weight: 500;
- margin: 0;
- min-width: auto;
-}
-
-</style>
- <style>
+ <template><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. */
@@ -2754,25 +2734,7 @@ paper-item:hover {
}
}
-</style>
- </dom-module>
-<dom-module id="downloads-manager" assetpath="chrome://downloads/">
- <template>
- <downloads-toolbar id="toolbar"></downloads-toolbar>
- <iron-list id="downloads-list" items="{{items_}}" hidden="[[!hasDownloads_]]">
- <template>
- <downloads-item data="[[item]]" hide-date="[[item.hideDate]]">
- </downloads-item>
- </template>
- </iron-list>
- <div id="no-downloads" hidden="[[hasDownloads_]]">
- <div>
- <div class="illustration"></div>
- <span></span>
- </div>
- </div>
- </template>
- <style>
+</style><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. */
@@ -2792,7 +2754,29 @@ paper-button {
}
</style>
- <style>
+ <div id="title">
+ <h1 i18n-content="title"></h1>
+ </div>
+ <div id="actions">
+ <paper-button class="clear-all" i18n-content="clearAll" on-tap="onClearAllTap_"></paper-button>
+ <paper-button i18n-content="openDownloadsFolder" on-tap="onOpenDownloadsFolderTap_"></paper-button>
+ </div>
+ <div id="search">
+ <cr-search-field id="search-input" i18n-values="label:search;clear-label:clearSearch"></cr-search-field>
+ <paper-menu-button id="more" horizontal-align="[[overflowAlign_]]">
+ <paper-icon-button icon="more-vert" i18n-values="title:moreActions" class="dropdown-trigger"></paper-icon-button>
+ <paper-menu class="dropdown-content">
+ <paper-item class="clear-all" i18n-content="clearAll" on-tap="onClearAllTap_"></paper-item>
+ <paper-item i18n-content="openDownloadsFolder" on-tap="onOpenDownloadsFolderTap_"></paper-item>
+ </paper-menu>
+ </paper-menu-button>
+ </div>
+ </template>
+
+
+ </dom-module>
+<dom-module id="downloads-manager" assetpath="chrome://downloads/">
+ <template><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. */
@@ -2838,16 +2822,54 @@ paper-button {
margin-bottom: 32px;
}
+</style><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. */
+
+* {
+ --downloads-item-width: 622px;
+}
+
+[hidden] {
+ display: none !important;
+}
+
+paper-button {
+ font-weight: 500;
+ margin: 0;
+ min-width: auto;
+}
+
</style>
+ <downloads-toolbar id="toolbar"></downloads-toolbar>
+ <iron-list id="downloads-list" items="{{items_}}" hidden="[[!hasDownloads_]]">
+ <template>
+ <downloads-item data="[[item]]" hide-date="[[item.hideDate]]">
+ </downloads-item>
+ </template>
+ </iron-list>
+ <div id="no-downloads" hidden="[[hasDownloads_]]">
+ <div>
+ <div class="illustration"></div>
+ <span></span>
+ </div>
+ </div>
+ </template>
+
+
</dom-module>
</div>
<downloads-manager></downloads-manager>
<command id="clear-all-command" shortcut="Alt-U+0043"></command>
<if expr="is_macosx">
<command id="undo-command" shortcut="Meta-U+005A"></command>
+ <command id="find-command" shortcut="Meta-U+0046"></command>
</if>
<if expr="not is_macosx">
<command id="undo-command" shortcut="Ctrl-U+005A"></command>
+ <command id="find-command" shortcut="Ctrl-U+0046"></command>
</if>
+ <link rel="import" href="chrome://resources/html/polymer.html">
<script src="crisper.js"></script></body></html> \ No newline at end of file
diff --git a/chromium/chrome/browser/resources/md_extensions/compiled_resources.gyp b/chromium/chrome/browser/resources/md_extensions/compiled_resources.gyp
index 868cae39a5e..7f1c7697bb1 100644
--- a/chromium/chrome/browser/resources/md_extensions/compiled_resources.gyp
+++ b/chromium/chrome/browser/resources/md_extensions/compiled_resources.gyp
@@ -12,6 +12,7 @@
'../../../../ui/webui/resources/js/compiled_resources.gyp:load_time_data',
'../../../../ui/webui/resources/js/cr.js',
'../../../../ui/webui/resources/js/i18n_behavior.js',
+ '../../../../ui/webui/resources/js/promise_resolver.js',
'item.js',
'item_list.js',
'manager.js',
diff --git a/chromium/chrome/browser/resources/md_extensions/extensions.html b/chromium/chrome/browser/resources/md_extensions/extensions.html
index bca5f8bbae4..75c0b878fca 100644
--- a/chromium/chrome/browser/resources/md_extensions/extensions.html
+++ b/chromium/chrome/browser/resources/md_extensions/extensions.html
@@ -3,7 +3,7 @@
<head>
<meta charset="utf8">
<title i18n-content="title"></title>
- <link rel="import" href="chrome://resources/html/polymer_config.html">
+ <link rel="import" href="chrome://resources/html/polymer.html">
<link rel="import" href="chrome://extensions/manager.html">
<style>
html {
diff --git a/chromium/chrome/browser/resources/md_extensions/icons.html b/chromium/chrome/browser/resources/md_extensions/icons.html
index 72b51e217d4..0d93dfb2e9b 100644
--- a/chromium/chrome/browser/resources/md_extensions/icons.html
+++ b/chromium/chrome/browser/resources/md_extensions/icons.html
@@ -1,4 +1,4 @@
-<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
+<link rel="import" href="chrome://resources/html/polymer.html">
<link rel="import" href="chrome://resources/polymer/v1_0/iron-iconset-svg/iron-iconset-svg.html">
<iron-iconset-svg name="extensions-icons" size="24">
diff --git a/chromium/chrome/browser/resources/md_extensions/item.html b/chromium/chrome/browser/resources/md_extensions/item.html
index 69d8cbcf173..c78cc51d613 100644
--- a/chromium/chrome/browser/resources/md_extensions/item.html
+++ b/chromium/chrome/browser/resources/md_extensions/item.html
@@ -2,8 +2,8 @@
<link rel="import" href="chrome://resources/html/cr.html">
<link rel="import" href="chrome://resources/html/i18n_behavior.html">
<link rel="import" href="chrome://resources/html/load_time_data.html">
+<link rel="import" href="chrome://resources/html/polymer.html">
<link rel="import" href="chrome://extensions/strings.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/polymer/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-checkbox/paper-checkbox.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button.html">
diff --git a/chromium/chrome/browser/resources/md_extensions/item.js b/chromium/chrome/browser/resources/md_extensions/item.js
index 9c0ead59b2e..d7a9858ad64 100644
--- a/chromium/chrome/browser/resources/md_extensions/item.js
+++ b/chromium/chrome/browser/resources/md_extensions/item.js
@@ -148,7 +148,6 @@ cr.define('extensions', function() {
/**
* @param {chrome.developerPrivate.ExtensionView} view
- * @suppress {checkTypes} Needed for URL externs. :(
* @private
*/
computeInspectLabel_: function(view) {
diff --git a/chromium/chrome/browser/resources/md_extensions/item_list.html b/chromium/chrome/browser/resources/md_extensions/item_list.html
index 18a2b35efcc..b3c08940e1e 100644
--- a/chromium/chrome/browser/resources/md_extensions/item_list.html
+++ b/chromium/chrome/browser/resources/md_extensions/item_list.html
@@ -1,5 +1,5 @@
<link rel="import" href="chrome://resources/html/cr.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.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://extensions/item.html">
diff --git a/chromium/chrome/browser/resources/md_extensions/manager.html b/chromium/chrome/browser/resources/md_extensions/manager.html
index e5d30a16f98..dc736958c58 100644
--- a/chromium/chrome/browser/resources/md_extensions/manager.html
+++ b/chromium/chrome/browser/resources/md_extensions/manager.html
@@ -1,6 +1,6 @@
<link rel="import" href="chrome://resources/html/cr.html">
<link rel="import" href="chrome://resources/html/i18n_behavior.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
+<link rel="import" href="chrome://resources/html/polymer.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-header-panel/paper-header-panel.html">
<link rel="import" href="chrome://extensions/item_list.html">
<link rel="import" href="chrome://extensions/service.html">
diff --git a/chromium/chrome/browser/resources/md_extensions/sidebar.html b/chromium/chrome/browser/resources/md_extensions/sidebar.html
index a56a9e46de7..418dee24d3e 100644
--- a/chromium/chrome/browser/resources/md_extensions/sidebar.html
+++ b/chromium/chrome/browser/resources/md_extensions/sidebar.html
@@ -1,6 +1,6 @@
<link rel="import" href="chrome://resources/html/cr.html">
<link rel="import" href="chrome://resources/html/i18n_behavior.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
+<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-item.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-menu/paper-menu.html">
diff --git a/chromium/chrome/browser/resources/md_extensions/toolbar.html b/chromium/chrome/browser/resources/md_extensions/toolbar.html
index 8cc0aee2c8e..a3fbf898615 100644
--- a/chromium/chrome/browser/resources/md_extensions/toolbar.html
+++ b/chromium/chrome/browser/resources/md_extensions/toolbar.html
@@ -1,6 +1,6 @@
-<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
-<link rel="import" href="chrome://resources/cr_elements/cr_search_field/cr_search_field.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_search_field/cr_search_field.html">
<dom-module id="extensions-toolbar">
<template>
diff --git a/chromium/chrome/browser/resources/md_history/compiled_resources2.gyp b/chromium/chrome/browser/resources/md_history/compiled_resources2.gyp
new file mode 100644
index 00000000000..d8345cf1f18
--- /dev/null
+++ b/chromium/chrome/browser/resources/md_history/compiled_resources2.gyp
@@ -0,0 +1,75 @@
+# 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.
+{
+ 'targets': [
+ {
+ 'target_name': 'constants',
+ 'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'history_item',
+ 'dependencies': [
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:load_time_data',
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:util',
+ '../history/compiled_resources2.gyp:externs',
+ ],
+ 'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'history_list',
+ 'dependencies': [
+ '<(DEPTH)/ui/webui/resources/cr_elements/cr_shared_menu/compiled_resources2.gyp:cr_shared_menu',
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:load_time_data',
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:util',
+ 'constants',
+ 'history_item',
+ '../history/compiled_resources2.gyp:externs',
+ ],
+ 'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'history_toolbar',
+ 'dependencies': [
+ '<(DEPTH)/ui/webui/resources/cr_elements/cr_search_field/compiled_resources2.gyp:cr_search_field',
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:load_time_data',
+ ],
+ 'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'history',
+ 'dependencies': [
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:load_time_data',
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:util',
+ 'constants',
+ 'history_list',
+ 'history_toolbar',
+ 'side_bar',
+ 'synced_device_card',
+ 'synced_device_manager',
+ '<(EXTERNS_GYP):chrome_send',
+ '../history/compiled_resources2.gyp:externs',
+ ],
+ 'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'side_bar',
+ 'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'synced_device_card',
+ 'dependencies': [
+ '../history/compiled_resources2.gyp:externs',
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:util',
+ ],
+ 'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'synced_device_manager',
+ 'dependencies': [
+ 'synced_device_card',
+ ],
+ 'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ ],
+}
diff --git a/chromium/chrome/browser/resources/md_history/constants.html b/chromium/chrome/browser/resources/md_history/constants.html
new file mode 100644
index 00000000000..7d01ff31756
--- /dev/null
+++ b/chromium/chrome/browser/resources/md_history/constants.html
@@ -0,0 +1 @@
+<script src="chrome://history/constants.js"></script>
diff --git a/chromium/chrome/browser/resources/md_history/constants.js b/chromium/chrome/browser/resources/md_history/constants.js
new file mode 100644
index 00000000000..54202c3bd06
--- /dev/null
+++ b/chromium/chrome/browser/resources/md_history/constants.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.
+
+// Globals:
+/** @const */ var RESULTS_PER_PAGE = 150;
+
+/**
+ * Amount of time between pageviews that we consider a 'break' in browsing,
+ * measured in milliseconds.
+ * @const
+ */
+var BROWSING_GAP_TIME = 15 * 60 * 1000;
diff --git a/chromium/chrome/browser/resources/md_history/elements.html b/chromium/chrome/browser/resources/md_history/elements.html
new file mode 100644
index 00000000000..57fe11d531a
--- /dev/null
+++ b/chromium/chrome/browser/resources/md_history/elements.html
@@ -0,0 +1,4 @@
+<link rel="import" href="chrome://history/history_list.html">
+<link rel="import" href="chrome://history/history_toolbar.html">
+<link rel="import" href="chrome://history/synced_device_manager.html">
+<link rel="import" href="chrome://history/side_bar.html">
diff --git a/chromium/chrome/browser/resources/md_history/history.html b/chromium/chrome/browser/resources/md_history/history.html
index a2af6fb18e7..30040553097 100644
--- a/chromium/chrome/browser/resources/md_history/history.html
+++ b/chromium/chrome/browser/resources/md_history/history.html
@@ -2,20 +2,99 @@
<html i18n-values="dir:textdirection;lang:language">
<head>
<meta charset="utf8">
- <title i18n-content="title"></title>
+ <title>$i18n{title}</title>
- <link rel="stylesheet" href="chrome://resources/css/roboto.css">
- <link rel="stylesheet" href="chrome://resources/css/text_defaults.css">
+ <link rel="stylesheet" href="chrome://resources/css/text_defaults_md.css">
+
+ <style>
+ html,
+ body {
+ height: 100%;
+ margin: 0;
+ }
+
+ body {
+ background: #f2f2f2;
+ display: flex;
+ flex-direction: column;
+ min-width: 800px;
+ }
+
+ #toolbar {
+ flex: 0 0 56px;
+ }
+
+ #toolbar:unresolved {
+ align-items: center;
+ background: rgb(63, 85, 102);
+ color: #fff;
+ display: flex;
+ flex-direction: row;
+ font-size: 16px;
+ font-weight: 400;
+ height: 56px;
+ padding-left: 24px;
+ }
+
+ #history-list {
+ flex: 1 0 0;
+ overflow: auto;
+ }
+
+ #history-synced-device-manager {
+ flex: 1 0 0;
+ }
+
+ #main-container {
+ display: flex;
+ flex: 1 0 0;
+ overflow: hidden;
+ }
+
+ .loading #main-container,
+ #loading-message {
+ display: none;
+ }
+
+ .loading #loading-message {
+ align-items: center;
+ color: #b4b4b4;
+ display: flex;
+ flex: 1;
+ font-size: 16px;
+ font-weight: 500;
+ justify-content: center;
+ }
+ </style>
</head>
-<body>
- <h1 i18n-content="title"></h1>
- <link rel="import" href="chrome://resources/html/polymer_config.html">
+<body class="loading">
+ <history-toolbar class="paper-header" id="toolbar">
+ $i18n{title}
+ </history-toolbar>
+ <div id="main-container">
+ <history-side-bar id="history-side-bar"></history-side-bar>
+ <history-list id="history-list"></history-list>
+ <history-synced-device-manager id="history-synced-device-manager" hidden>
+ </history-synced-device-manager>
+ </div>
+ <span id="loading-message">$i18n{loading}</span>
- <!-- Prepare strings and perform i18n substitutions. -->
+ <link rel="import" href="chrome://resources/html/cr.html">
+ <link rel="import" href="chrome://resources/html/util.html">
<link rel="import" href="chrome://resources/html/load_time_data.html">
+ <link rel="import" href="chrome://history/constants.html">
<script src="strings.js"></script>
- <link rel="import" href="chrome://resources/html/i18n_template.html">
+ <script src="history.js"></script>
+
+ <link rel="import" href="chrome://history/elements.html" async id="bundle">
+
+ <!--
+ Prepare strings and perform i18n substitutions.
+ TODO(tsergeant): Remove once we are fully converted to
+ ReplaceTemplateExpressions. It is currently only used for the <html> tag.
+ -->
+ <link rel="import" href="chrome://resources/html/i18n_template.html" async>
</body>
</html>
diff --git a/chromium/chrome/browser/resources/md_history/history.js b/chromium/chrome/browser/resources/md_history/history.js
new file mode 100644
index 00000000000..72aecafbc29
--- /dev/null
+++ b/chromium/chrome/browser/resources/md_history/history.js
@@ -0,0 +1,156 @@
+// 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.
+
+// Send the history query immediately. This allows the query to process during
+// the initial page startup.
+chrome.send('queryHistory', ['', 0, 0, 0, RESULTS_PER_PAGE]);
+chrome.send('getForeignSessions');
+
+/**
+ * @param {HTMLElement} element
+ * @return {!Promise} Resolves once a Polymer element has been fully upgraded.
+ */
+function waitForUpgrade(element) {
+ return new Promise(function(resolve, reject) {
+ if (window.Polymer && Polymer.isInstance && Polymer.isInstance(element))
+ resolve();
+ else
+ $('bundle').addEventListener('load', resolve);
+ });
+}
+
+/**
+ * Listens for history-item being selected or deselected (through checkbox)
+ * and changes the view of the top toolbar.
+ * @param {{detail: {countAddition: number}}} e
+ */
+window.addEventListener('history-checkbox-select', function(e) {
+ var toolbar = /** @type {HistoryToolbarElement} */($('toolbar'));
+ toolbar.count += e.detail.countAddition;
+});
+
+/**
+ * Listens for call to cancel selection and loops through all items to set
+ * checkbox to be unselected.
+ */
+window.addEventListener('unselect-all', function() {
+ var historyList = /** @type {HistoryListElement} */($('history-list'));
+ var toolbar = /** @type {HistoryToolbarElement} */($('toolbar'));
+ historyList.unselectAllItems(toolbar.count);
+ toolbar.count = 0;
+});
+
+/**
+ * Listens for call to delete all selected items and loops through all items to
+ * to determine which ones are selected and deletes these.
+ */
+window.addEventListener('delete-selected', function() {
+ if (!loadTimeData.getBoolean('allowDeletingHistory'))
+ return;
+
+ // TODO(hsampson): add a popup to check whether the user definitely wants to
+ // delete the selected items.
+
+ var historyList = /** @type {HistoryListElement} */($('history-list'));
+ var toolbar = /** @type {HistoryToolbarElement} */($('toolbar'));
+ var toBeRemoved = historyList.getSelectedItems(toolbar.count);
+ chrome.send('removeVisits', toBeRemoved);
+});
+
+/**
+ * When the search is changed refresh the results from the backend. Ensures that
+ * the search bar is updated with the new search term.
+ * @param {{detail: {search: string}}} e
+ */
+window.addEventListener('search-changed', function(e) {
+ $('toolbar').setSearchTerm(e.detail.search);
+ /** @type {HistoryListElement} */($('history-list')).setLoading();
+ chrome.send('queryHistory', [e.detail.search, 0, 0, 0, RESULTS_PER_PAGE]);
+});
+
+/**
+ * Switches between displaying history data and synced tabs data for the page.
+ */
+window.addEventListener('switch-display', function(e) {
+ $('history-synced-device-manager').hidden =
+ e.detail.display != 'synced-tabs-button';
+ $('history-list').hidden = e.detail.display != 'history-button';
+});
+
+// Chrome Callbacks-------------------------------------------------------------
+
+/**
+ * Our history system calls this function with results from searches.
+ * @param {HistoryQuery} info An object containing information about the query.
+ * @param {!Array<HistoryEntry>} results A list of results.
+ */
+function historyResult(info, results) {
+ var listElem = $('history-list');
+ waitForUpgrade(listElem).then(function() {
+ var list = /** @type {HistoryListElement} */(listElem);
+ list.addNewResults(results, info.term);
+ if (info.finished)
+ list.disableResultLoading();
+ // TODO(tsergeant): Showing everything as soon as the list is ready is not
+ // ideal, as the sidebar can still pop in after. Fix this to show everything
+ // at once.
+ document.body.classList.remove('loading');
+ });
+}
+
+/**
+ * Called by the history backend after receiving results and after discovering
+ * the existence of other forms of browsing history.
+ * @param {boolean} hasSyncedResults Whether there are synced results.
+ * @param {boolean} includeOtherFormsOfBrowsingHistory Whether to include
+ * a sentence about the existence of other forms of browsing history.
+ */
+function showNotification(
+ hasSyncedResults, includeOtherFormsOfBrowsingHistory) {
+ // TODO(msramek): Implement the joint notification about web history and other
+ // forms of browsing history for the MD history page.
+}
+
+/**
+ * Receives the synced history data. An empty list means that either there are
+ * no foreign sessions, or tab sync is disabled for this profile.
+ * |isTabSyncEnabled| makes it possible to distinguish between the cases.
+ *
+ * @param {!Array<!ForeignSession>} sessionList Array of objects describing the
+ * sessions from other devices.
+ * @param {boolean} isTabSyncEnabled Is tab sync enabled for this profile?
+ */
+function setForeignSessions(sessionList, isTabSyncEnabled) {
+ // TODO(calamity): Add a 'no synced devices' message when sessions are empty.
+ $('history-side-bar').hidden = !isTabSyncEnabled;
+ var syncedDeviceElem = $('history-synced-device-manager');
+ waitForUpgrade(syncedDeviceElem).then(function() {
+ var syncedDeviceManager =
+ /** @type {HistorySyncedDeviceManagerElement} */(syncedDeviceElem);
+ if (isTabSyncEnabled)
+ syncedDeviceManager.setSyncedHistory(sessionList);
+ });
+}
+
+/**
+ * Called by the history backend when deletion was succesful.
+ */
+function deleteComplete() {
+ var historyList = /** @type {HistoryListElement} */($('history-list'));
+ var toolbar = /** @type {HistoryToolbarElement} */($('toolbar'));
+ historyList.removeDeletedHistory(toolbar.count);
+ toolbar.count = 0;
+}
+
+/**
+ * Called by the history backend when the deletion failed.
+ */
+function deleteFailed() {
+}
+
+/**
+ * Called when the history is deleted by someone else.
+ */
+function historyDeleted() {
+}
diff --git a/chromium/chrome/browser/resources/md_history/history_item.html b/chromium/chrome/browser/resources/md_history/history_item.html
new file mode 100644
index 00000000000..d576463789d
--- /dev/null
+++ b/chromium/chrome/browser/resources/md_history/history_item.html
@@ -0,0 +1,145 @@
+<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/iron-icon/iron-icon.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/iron-icons/iron-icons.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="chrome://resources/html/util.html">
+<link rel="import" href="chrome://history/shared_style.html">
+
+<dom-module id="history-item">
+ <template>
+ <style include="shared-style"></style>
+ <style>
+ :host {
+ @apply(--layout-center);
+ @apply(--layout-vertical);
+ padding: 0 24px;
+ }
+
+ #main-container {
+ background: #fff;
+ border-color: var(--card-border-color);
+ border-style: solid;
+ border-width: 0 1px;
+ max-width: var(--card-max-width);
+ min-width: var(--card-min-width);
+ width: 100%;
+ }
+
+ :host([is-card-start]) #main-container {
+ border-top-width: 1px;
+ }
+
+ :host([is-card-end]) #main-container {
+ border-bottom-width: 2px;
+ margin-bottom: 20px;
+ }
+
+ #date-accessed {
+ display: none;
+ }
+
+ :host([is-card-start]) #date-accessed {
+ display: flex;
+ }
+
+ #item-container {
+ @apply(--layout-center);
+ @apply(--layout-horizontal);
+ min-height: 40px;
+ }
+
+ :host([is-card-start]) #item-container {
+ padding-top: 8px;
+ }
+
+ :host([is-card-end]) #item-container {
+ padding-bottom: 8px;
+ }
+
+ #title-and-domain {
+ @apply(--layout-center);
+ @apply(--layout-flex);
+ @apply(--layout-horizontal);
+ min-height: 40px;
+ overflow: hidden;
+ }
+
+ paper-checkbox {
+ --paper-checkbox-checked-color: rgb(68, 136, 255);
+ --paper-checkbox-size: 16px;
+ --paper-checkbox-unchecked-color: #969696;
+ height: 16px;
+ margin: 0 16px 0 20px;
+ padding: 2px;
+ width: 16px;
+ }
+
+ #time-accessed {
+ color: #646464;
+ min-width: 96px;
+ }
+
+ #domain {
+ -webkit-margin-start: 16px;
+ color: #969696;
+ flex-shrink: 0;
+ }
+
+ #menu-button {
+ -webkit-margin-end: 12px;
+ -webkit-margin-start: 2px;
+ color: #969696;
+ height: 36px;
+ min-width: 36px;
+ width: 36px;
+ }
+
+ #bookmark-star {
+ --iron-icon-height: 16px;
+ --iron-icon-width: 16px;
+ -webkit-margin-end: 10px;
+ -webkit-margin-start: 20px;
+ color: rgb(68, 136, 255);
+ min-width: 16px;
+ visibility: hidden;
+ }
+
+ :host([starred]) #bookmark-star {
+ visibility: visible;
+ }
+
+ #time-gap-separator {
+ -webkit-border-start: 1px solid #888;
+ -webkit-margin-start: 77px;
+ height: 15px;
+ }
+ </style>
+ <div id="main-container">
+ <div id="date-accessed" class="card-title">
+ [[cardTitle_(numberOfItems, item.dateRelativeDay, searchTerm)]]
+ </div>
+ <div id="item-container">
+ <paper-checkbox id="checkbox" on-tap="onCheckboxSelected_"
+ checked="{{selected}}" disabled="[[selectionNotAllowed_()]]">
+ </paper-checkbox>
+ <span id="time-accessed">[[item.readableTimestamp]]</span>
+ <div class="website-icon" id="icon"></div>
+ <div id="title-and-domain">
+ <a href="[[item.url]]" id="title" class="website-title"></a>
+ <span id="domain">[[item.domain]]</span>
+ </div>
+ <iron-icon icon="star" id="bookmark-star"></iron-icon>
+ <paper-icon-button icon="more-vert" id="menu-button"
+ on-tap="onMenuButtonTap_">
+ </paper-icon-button>
+ </div>
+ <template is="dom-if" if="[[item.hasTimeGap]]">
+ <div id="time-gap-separator"></div>
+ </template>
+ </div>
+ </template>
+ <script src="chrome://history/history_item.js"></script>
+</dom-module>
diff --git a/chromium/chrome/browser/resources/md_history/history_item.js b/chromium/chrome/browser/resources/md_history/history_item.js
new file mode 100644
index 00000000000..f4d95df96c8
--- /dev/null
+++ b/chromium/chrome/browser/resources/md_history/history_item.js
@@ -0,0 +1,146 @@
+// 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-item',
+
+ properties: {
+ // Underlying HistoryEntry data for this item. Contains read-only fields
+ // from the history backend, as well as fields computed by history-list.
+ item: {
+ type: Object,
+ observer: 'showIcon_'
+ },
+
+ // True if the website is a bookmarked page.
+ starred: {
+ type: Boolean,
+ value: false,
+ reflectToAttribute: true
+ },
+
+ // Search term used to obtain this history-item.
+ searchTerm: {
+ type: String,
+ value: '',
+ },
+
+ selected: {
+ type: Boolean,
+ value: false,
+ notify: true
+ },
+
+ isCardStart: {
+ type: Boolean,
+ value: false,
+ reflectToAttribute: true
+ },
+
+ isCardEnd: {
+ type: Boolean,
+ value: false,
+ reflectToAttribute: true
+ },
+
+ numberOfItems: {
+ type: Number,
+ value: 0
+ }
+ },
+
+ observers: [
+ 'setSearchedTextToBold_(item.title, searchTerm)'
+ ],
+
+ /**
+ * When a history-item is selected the toolbar is notified and increases
+ * or decreases its count of selected items accordingly.
+ * @private
+ */
+ onCheckboxSelected_: function() {
+ this.fire('history-checkbox-select', {
+ countAddition: this.$.checkbox.checked ? 1 : -1
+ });
+ },
+
+ /**
+ * Fires a custom event when the menu button is clicked. Sends the details of
+ * the history item and where the menu should appear.
+ */
+ onMenuButtonTap_: function(e) {
+ this.fire('toggle-menu', {
+ target: Polymer.dom(e).localTarget,
+ itemIdentifier: {
+ url: this.item.url,
+ timestamps: this.item.time,
+ domain: this.item.domain
+ },
+ });
+
+ // Stops the 'tap' event from closing the menu when it opens.
+ e.stopPropagation();
+ },
+
+ /**
+ * Set the favicon image, based on the URL of the history item.
+ * @private
+ */
+ showIcon_: function() {
+ this.$.icon.style.backgroundImage =
+ getFaviconImageSet(this.item.url);
+ },
+
+ /**
+ * Updates the page title. If the result was from a search, highlights any
+ * occurrences of the search term in bold.
+ * @private
+ */
+ setSearchedTextToBold_: function() {
+ var i = 0;
+ var titleElem = this.$.title;
+ var titleText = this.item.title;
+
+ if (this.searchTerm == '' || this.searchTerm == null) {
+ titleElem.textContent = titleText;
+ return;
+ }
+
+ var re = new RegExp(quoteString(this.searchTerm), 'gim');
+ var match;
+ titleElem.textContent = '';
+ while (match = re.exec(titleText)) {
+ if (match.index > i)
+ titleElem.appendChild(document.createTextNode(
+ titleText.slice(i, match.index)));
+ i = re.lastIndex;
+ // Mark the highlighted text in bold.
+ var b = document.createElement('b');
+ b.textContent = titleText.substring(match.index, i);
+ titleElem.appendChild(b);
+ }
+ if (i < titleText.length)
+ titleElem.appendChild(
+ document.createTextNode(titleText.slice(i)));
+ },
+
+ selectionNotAllowed_: function() {
+ return !loadTimeData.getBoolean('allowDeletingHistory');
+ },
+
+ /**
+ * Generates the title for this history card.
+ * @param {number} numberOfItems The number of items in the card.
+ * @param {string} search The search term associated with these results.
+ * @private
+ */
+ cardTitle_: function(numberOfItems, historyDate, search) {
+ if (!search)
+ return this.item.dateRelativeDay;
+
+ var resultId = numberOfItems == 1 ? 'searchResult' : 'searchResults';
+ return loadTimeData.getStringF('foundSearchResults', numberOfItems,
+ loadTimeData.getString(resultId), search);
+ }
+});
diff --git a/chromium/chrome/browser/resources/md_history/history_list.html b/chromium/chrome/browser/resources/md_history/history_list.html
new file mode 100644
index 00000000000..59cb64c8712
--- /dev/null
+++ b/chromium/chrome/browser/resources/md_history/history_list.html
@@ -0,0 +1,61 @@
+<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-item/paper-item.html">
+<link rel="import" href="chrome://resources/cr_elements/cr_shared_menu/cr_shared_menu.html">
+<link rel="import" href="chrome://history/constants.html">
+<link rel="import" href="chrome://history/history_item.html">
+<link rel="import" href="chrome://history/shared_style.html">
+
+<dom-module id="history-list">
+ <template>
+ <style include="shared-style"></style>
+ <style>
+ :host {
+ display: flex;
+ flex-direction: column;
+ }
+
+ #infinite-list {
+ flex: 1;
+ padding-top: var(--first-card-padding-top);
+ }
+
+ paper-item {
+ -webkit-user-select: none;
+ cursor: pointer;
+ font: inherit;
+ }
+
+ paper-item:hover {
+ background: #eaeaea;
+ }
+ </style>
+ <div id="no-results" class="centered-message"
+ hidden$="{{hasResults(historyData.length)}}">
+ {{noResultsMessage_(searchTerm, loading_)}}
+ </div>
+ <iron-list items="{{historyData}}" as="item" id="infinite-list"
+ on-scroll="scrollHandler_"
+ hidden$="{{!hasResults(historyData.length)}}">
+ <template>
+ <history-item item="[[item]]"
+ starred="[[item.starred]]"
+ selected="{{item.selected}}"
+ is-card-start="[[item.isFirstItem]]"
+ is-card-end="[[item.isLastItem]]"
+ search-term="[[searchTerm]]"
+ number-of-items="[[historyData.length]]">
+ </history-item>
+ </template>
+ </iron-list>
+ <cr-shared-menu id="sharedMenu">
+ <paper-item id="menuMoreButton" on-tap="onMoreFromSiteTap_">
+ $i18n{moreFromSite}
+ </paper-item>
+ <paper-item id="menuRemoveButton" on-tap="onRemoveFromHistoryTap_">
+ $i18n{removeFromHistory}
+ </paper-item>
+ </cr-shared-menu>
+ </template>
+ <script src="chrome://history/history_list.js"></script>
+</dom-module>
diff --git a/chromium/chrome/browser/resources/md_history/history_list.js b/chromium/chrome/browser/resources/md_history/history_list.js
new file mode 100644
index 00000000000..791a9acbe0c
--- /dev/null
+++ b/chromium/chrome/browser/resources/md_history/history_list.js
@@ -0,0 +1,295 @@
+// 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-list',
+
+ properties: {
+ // An array of history entries in reverse chronological order.
+ historyData: {
+ type: Array
+ },
+
+ // The time of access of the last history item in historyData.
+ lastVisitedTime: {
+ type: Number,
+ value: 0
+ },
+
+ searchTerm: {
+ type: String,
+ value: ''
+ },
+
+ // True if there is a pending request to the backend.
+ loading_: {
+ type: Boolean,
+ value: true
+ },
+
+ resultLoadingDisabled_: {
+ type: Boolean,
+ value: false
+ },
+ },
+
+ listeners: {
+ 'infinite-list.scroll': 'closeMenu_',
+ 'tap': 'closeMenu_',
+ 'toggle-menu': 'toggleMenu_',
+ },
+
+ /**
+ * Closes the overflow menu.
+ * @private
+ */
+ closeMenu_: function() {
+ /** @type {CrSharedMenuElement} */(this.$.sharedMenu).closeMenu();
+ },
+
+ /**
+ * Mark the page as currently loading new data from the back-end.
+ */
+ setLoading: function() {
+ this.loading_ = true;
+ },
+
+ /**
+ * Opens the overflow menu unless the menu is already open and the same button
+ * is pressed.
+ * @param {{detail: {itemIdentifier: !Object}}} e
+ * @private
+ */
+ toggleMenu_: function(e) {
+ var target = e.detail.target;
+ /** @type {CrSharedMenuElement} */(this.$.sharedMenu).toggleMenu(
+ target, e.detail.itemIdentifier);
+ },
+
+ /** @private */
+ onMoreFromSiteTap_: function() {
+ var menu = /** @type {CrSharedMenuElement} */(this.$.sharedMenu);
+ this.fire('search-changed', {search: menu.itemData.domain});
+ menu.closeMenu();
+ },
+
+ /**
+ * Disables history result loading when there are no more history results.
+ */
+ disableResultLoading: function() {
+ this.resultLoadingDisabled_ = true;
+ },
+
+ /**
+ * Adds the newly updated history results into historyData. Adds new fields
+ * for each result.
+ * @param {!Array<!HistoryEntry>} historyResults The new history results.
+ * @param {string} searchTerm Search query used to find these results.
+ */
+ addNewResults: function(historyResults, searchTerm) {
+ this.loading_ = false;
+
+ if (this.searchTerm != searchTerm) {
+ if (this.historyData)
+ this.splice('historyData', 0, this.historyData.length);
+ this.searchTerm = searchTerm;
+ }
+
+ if (historyResults.length == 0)
+ return;
+
+ // Creates a copy of historyResults to prevent accidentally modifying this
+ // field.
+ var results = historyResults.slice();
+
+ var currentDate = results[0].dateRelativeDay;
+
+ // Resets the last history item for the currentDate if new history results
+ // for currentDate is loaded.
+ if (this.historyData && this.historyData.length > 0) {
+ var lastHistoryItem = this.historyData[this.historyData.length - 1];
+ if (lastHistoryItem && lastHistoryItem.dateRelativeDay == currentDate) {
+ this.set('historyData.' + (this.historyData.length - 1) +
+ '.isLastItem', false);
+ }
+ }
+
+ for (var i = 0; i < results.length; i++) {
+ // Sets the default values for these fields to prevent undefined types.
+ results[i].selected = false;
+ results[i].isLastItem = false;
+ results[i].isFirstItem = false;
+ results[i].needsTimeGap = this.needsTimeGap_(results, i);
+ results[i].readableTimestamp =
+ searchTerm == '' ? results[i].dateTimeOfDay : results[i].dateShort;
+
+ if (results[i].dateRelativeDay != currentDate) {
+ results[i - 1].isLastItem = true;
+ results[i].isFirstItem = true;
+ currentDate = results[i].dateRelativeDay;
+ }
+ }
+ results[i - 1].isLastItem = true;
+
+ if (!this.historyData || this.historyData.length == 0)
+ results[0].isFirstItem = true;
+
+ if (this.historyData) {
+ // If we have previously received data, push the new items onto the
+ // existing array.
+ results.unshift('historyData');
+ this.push.apply(this, results);
+ } else {
+ // The first time we receive data, use set() to ensure the iron-list is
+ // initialized correctly.
+ this.set('historyData', results);
+ }
+
+ this.lastVisitedTime = this.historyData[this.historyData.length - 1].time;
+ },
+
+ /**
+ * Cycle through each entry in historyData and set all items to be
+ * unselected.
+ * @param {number} overallItemCount The number of checkboxes selected.
+ */
+ unselectAllItems: function(overallItemCount) {
+ if (this.historyData === undefined)
+ return;
+
+ for (var i = 0; i < this.historyData.length; i++) {
+ if (this.historyData[i].selected) {
+ this.set('historyData.' + i + '.selected', false);
+ overallItemCount--;
+ if (overallItemCount == 0)
+ break;
+ }
+ }
+ },
+
+ /**
+ * Remove all selected items from the overall array so that they are also
+ * removed from view. Make sure that the card length and positioning is
+ * updated accordingly.
+ * @param {number} overallItemCount The number of items selected.
+ */
+ removeDeletedHistory: function(overallItemCount) {
+ for (var i = this.historyData.length - 1; i >= 0; i--) {
+ if (!this.historyData[i].selected)
+ continue;
+
+ // TODO: Change to using computed properties to recompute the first and
+ // last cards.
+
+ // Resets the first history item.
+ if (this.historyData[i].isFirstItem &&
+ (i + 1) < this.historyData.length &&
+ this.historyData[i].dateRelativeDay ==
+ this.historyData[i + 1].dateRelativeDay) {
+ this.set('historyData.' + (i + 1) + '.isFirstItem', true);
+ }
+
+ // Resets the last history item.
+ if (this.historyData[i].isLastItem && i > 0 &&
+ this.historyData[i].dateRelativeDay ==
+ this.historyData[i - 1].dateRelativeDay) {
+ this.set('historyData.' + (i - 1) + '.isLastItem', true);
+
+ if (this.historyData[i - 1].needsTimeGap)
+ this.set('historyData.' + (i - 1) + '.needsTimeGap', false);
+ }
+
+ // Makes sure that the time gap separators are preserved.
+ if (this.historyData[i].needsTimeGap && i > 0)
+ this.set('historyData.' + (i - 1) + '.needsTimeGap', true);
+
+ // Removes the selected item from historyData.
+ this.splice('historyData', i, 1);
+
+ overallItemCount--;
+ if (overallItemCount == 0)
+ break;
+ }
+ },
+
+ /**
+ * Based on which items are selected, collect an array of the info required
+ * for chrome.send('removeHistory', ...).
+ * @param {number} count The number of items that are selected.
+ * @return {Array<HistoryEntry>} toBeRemoved An array of objects which contain
+ * information on which history-items should be deleted.
+ */
+ getSelectedItems: function(count) {
+ var toBeRemoved = [];
+ for (var i = 0; i < this.historyData.length; i++) {
+ if (this.historyData[i].selected) {
+ toBeRemoved.push({
+ url: this.historyData[i].url,
+ timestamps: this.historyData[i].allTimestamps
+ });
+
+ count--;
+ if (count == 0)
+ break;
+ }
+ }
+ return toBeRemoved;
+ },
+
+ /**
+ * Called when the card manager is scrolled.
+ * @private
+ */
+ scrollHandler_: function() {
+ if (this.resultLoadingDisabled_)
+ return;
+
+ // Requests the next list of results when the scrollbar is near the bottom
+ // of the window.
+ var scrollOffset = 10;
+ var scrollElem = this.$['infinite-list'];
+
+ if (!this.loading_ && scrollElem.scrollHeight <=
+ scrollElem.scrollTop + scrollElem.clientHeight + scrollOffset) {
+ this.loading_ = true;
+ chrome.send('queryHistory',
+ [this.searchTerm, 0, 0, this.lastVisitedTime, RESULTS_PER_PAGE]);
+ }
+ },
+
+ /**
+ * Check whether the time difference between the given history item and the
+ * next one is large enough for a spacer to be required.
+ * @param {Array<HistoryEntry>} results A list of history results.
+ * @param {number} index The index number of the first item being compared.
+ * @return {boolean} Whether or not time gap separator is required.
+ * @private
+ */
+ needsTimeGap_: function(results, index) {
+ // TODO(tsergeant): Allow the final item from one batch of results to have a
+ // timegap once more results are added.
+ if (index == results.length - 1)
+ return false;
+
+ var currentItem = results[index];
+ var nextItem = results[index + 1];
+
+ if (this.searchTerm)
+ return currentItem.dateShort != nextItem.dateShort;
+
+ return currentItem.time - nextItem.time > BROWSING_GAP_TIME &&
+ currentItem.dateRelativeDay == nextItem.dateRelativeDay;
+ },
+
+ hasResults: function(historyDataLength) {
+ return historyDataLength > 0;
+ },
+
+ noResultsMessage_: function(searchTerm, isLoading) {
+ if (isLoading)
+ return '';
+ var messageId = searchTerm !== '' ? 'noSearchResults' : 'noResults';
+ return loadTimeData.getString(messageId);
+ }
+});
diff --git a/chromium/chrome/browser/resources/md_history/history_toolbar.html b/chromium/chrome/browser/resources/md_history/history_toolbar.html
new file mode 100644
index 00000000000..ea78ae2531d
--- /dev/null
+++ b/chromium/chrome/browser/resources/md_history/history_toolbar.html
@@ -0,0 +1,118 @@
+<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-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/cr_elements/cr_search_field/cr_search_field.html">
+<link rel="import" href="chrome://history/shared_style.html">
+
+<dom-module id="history-toolbar">
+ <template>
+ <style include="shared-style"></style>
+ <style>
+ :host {
+ background: rgb(63, 85, 102);
+ color: #fff;
+ height: 56px;
+ transition: background-color 150ms;
+ }
+
+ :host,
+ #items,
+ #main-content,
+ #button-container,
+ #toolbar-container {
+ @apply(--layout-center);
+ @apply(--layout-horizontal);
+ width: 100%;
+ }
+
+ :host([items-selected_]) {
+ background: rgb(68, 136, 255);
+ }
+
+ h1 {
+ @apply(--layout-flex);
+ font-size: 16px;
+ font-weight: 400;
+ padding-left: 24px;
+ }
+
+ #search-input {
+ -webkit-padding-end: 20px;
+ }
+
+ #items {
+ margin: 0 auto;
+ max-width: var(--card-max-width);
+ }
+
+ #number-selected {
+ @apply(--layout-flex);
+ }
+
+ paper-icon-button {
+ height: 36px;
+ margin: 0 24px 0 2px;
+ min-width: 36px;
+ width: 36px;
+ }
+
+ #centered-buttons {
+ flex: 0 1 var(--card-max-width);
+ }
+
+ paper-button {
+ pointer-events: auto;
+ }
+
+ .toolbar-overlay {
+ height: inherit;
+ left: 0;
+ pointer-events: none;
+ position: absolute;
+ top: 0;
+ }
+
+ #front-padding {
+ flex: 1 1 0;
+ min-width: 100px;
+ }
+
+ #back-padding {
+ flex: 1 1 0;
+ }
+ </style>
+ <div id="toolbar-container">
+ <div id="main-content" hidden$="[[itemsSelected_]]">
+ <h1 id="title">$i18n{title}</h1>
+ <cr-search-field id="search-input" label="$i18n{search}"
+ clear-label="$i18n{clearSearch}">
+ </cr-search-field>
+ </div>
+
+ <div id="items" hidden$="[[!itemsSelected_]]">
+ <paper-icon-button icon="clear" id="cancel-icon-button"
+ on-tap="onClearSelectionTap_"></paper-icon-button>
+ <div id="number-selected">[[numberOfItemsSelected_(count)]]</div>
+ <paper-button id="cancel-button" on-tap="onClearSelectionTap_">
+ $i18n{cancel}
+ </paper-button>
+ <paper-button id="delete-button" on-tap="onDeleteTap_">
+ $i18n{delete}
+ </paper-button>
+ </div>
+ </div>
+
+ <div id="button-container" class="toolbar-overlay">
+ <div id="front-padding"></div>
+ <div id="centered-buttons" hidden$="[[itemsSelected_]]">
+ <paper-button on-tap="onClearBrowsingDataTap_"
+ id="clear-browsing-data-button">
+ $i18n{clearBrowsingData}
+ </paper-button>
+ </div>
+ <div id="back-padding"></div>
+ </div>
+ </template>
+ <script src="chrome://history/history_toolbar.js"></script>
+</dom-module>
diff --git a/chromium/chrome/browser/resources/md_history/history_toolbar.js b/chromium/chrome/browser/resources/md_history/history_toolbar.js
new file mode 100644
index 00000000000..48189b8999f
--- /dev/null
+++ b/chromium/chrome/browser/resources/md_history/history_toolbar.js
@@ -0,0 +1,114 @@
+// 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.
+
+/**
+ * @constructor
+ * @implements {SearchFieldDelegate}
+ * @param {!HistoryToolbarElement} toolbar This history-toolbar.
+ */
+function ToolbarSearchFieldDelegate(toolbar) {
+ this.toolbar_ = toolbar;
+}
+
+ToolbarSearchFieldDelegate.prototype = {
+ /** @override */
+ onSearchTermSearch: function(searchTerm) {
+ this.toolbar_.onSearch(searchTerm);
+ }
+};
+
+Polymer({
+ is: 'history-toolbar',
+ properties: {
+ // Number of history items currently selected.
+ count: {
+ type: Number,
+ value: 0,
+ observer: 'changeToolbarView_'
+ },
+
+ // True if 1 or more history items are selected. When this value changes
+ // the background colour changes.
+ itemsSelected_: {
+ type: Boolean,
+ value: false,
+ reflectToAttribute: true
+ },
+
+ // The most recent term entered in the search field. Updated incrementally
+ // as the user types.
+ searchTerm: {
+ type: String,
+ value: ''
+ }
+ },
+
+ /**
+ * Changes the toolbar background color depending on whether any history items
+ * are currently selected.
+ * @private
+ */
+ changeToolbarView_: function() {
+ this.itemsSelected_ = this.count > 0;
+ },
+
+ /**
+ * When changing the search term externally, update the search field to
+ * reflect the new search term.
+ * @param {string} search
+ */
+ setSearchTerm: function(search) {
+ if (this.searchTerm == search)
+ return;
+ this.searchTerm = search;
+ var searchField = /** @type {SearchField} */(this.$['search-input']);
+ searchField.showAndFocus().then(function(showing) {
+ if (showing) searchField.setValue(search);
+ });
+ },
+
+ /**
+ * If the search term has changed reload for the new search.
+ */
+ onSearch: function(searchTerm) {
+ if (searchTerm != this.searchTerm) {
+ this.searchTerm = searchTerm;
+ this.fire('search-changed', {search: searchTerm});
+ }
+ },
+
+ attached: function() {
+ this.searchFieldDelegate_ = new ToolbarSearchFieldDelegate(this);
+ /** @type {SearchField} */(this.$['search-input'])
+ .setDelegate(this.searchFieldDelegate_);
+ },
+
+ onClearSelectionTap_: function() {
+ this.fire('unselect-all');
+ },
+
+ /**
+ * Relocates the user to the clear browsing data section of the settings page.
+ * @private
+ */
+ onClearBrowsingDataTap_: function() {
+ window.location.href = 'chrome://settings/clearBrowserData';
+ },
+
+ onDeleteTap_: function() {
+ this.fire('delete-selected');
+ },
+
+ /**
+ * If the user is a supervised user the delete button is not shown.
+ * @private
+ */
+ deletingAllowed_: function() {
+ return loadTimeData.getBoolean('allowDeletingHistory');
+ },
+
+ numberOfItemsSelected_: function(count) {
+ return count > 0 ? loadTimeData.getStringF('itemsSelected', count) : '';
+ }
+});
diff --git a/chromium/chrome/browser/resources/md_history/shared_style.html b/chromium/chrome/browser/resources/md_history/shared_style.html
new file mode 100644
index 00000000000..a18de8dbb48
--- /dev/null
+++ b/chromium/chrome/browser/resources/md_history/shared_style.html
@@ -0,0 +1,57 @@
+<dom-module id="shared-style">
+ <template>
+ <style>
+ :root {
+ --card-border-color: rgba(0, 0, 0, 0.14);
+ --card-max-width: 960px;
+ --card-min-width: 500px;
+ --first-card-padding-top: 40px;
+ }
+
+ [hidden] {
+ display: none !important;
+ }
+
+ .card-title {
+ @apply(--layout-center);
+ @apply(--layout-horizontal);
+ -webkit-padding-start: 20px;
+ background: #fafafa;
+ border-bottom: 1px solid var(--card-border-color);
+ border-radius: 2px 2px 0 0;
+ color: #333;
+ font-size: 14px;
+ font-weight: 500;
+ height: 48px;
+ }
+
+ .centered-message {
+ align-items: center;
+ color: #b4b4b4;
+ display: flex;
+ flex: 1;
+ font-size: 14px;
+ font-weight: 500;
+ justify-content: center;
+ }
+
+ .website-icon {
+ -webkit-margin-end: 16px;
+ height: 16px;
+ min-width: 16px;
+ }
+
+ .website-title {
+ color: #333;
+ overflow: hidden;
+ text-decoration: none;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ }
+
+ .website-title:hover {
+ text-decoration: underline;
+ }
+ </style>
+ </template>
+</dom-module>
diff --git a/chromium/chrome/browser/resources/md_history/side_bar.html b/chromium/chrome/browser/resources/md_history/side_bar.html
new file mode 100644
index 00000000000..f9a6faa9354
--- /dev/null
+++ b/chromium/chrome/browser/resources/md_history/side_bar.html
@@ -0,0 +1,46 @@
+<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-item/paper-item.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-ripple/paper-ripple.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-styles/color.html">
+
+<dom-module id="history-side-bar">
+ <template>
+ <style>
+ :host {
+ padding-top: 5px;
+ width: 200px;
+ }
+
+ paper-item {
+ -webkit-padding-start: 25px;
+ cursor: pointer;
+ font-size: 14px;
+ font-weight: 500;
+ }
+
+ paper-item.iron-selected {
+ color: var(--google-blue-500);
+ font-weight: 500;
+ }
+
+ paper-listbox {
+ -webkit-user-select: none;
+ background-color: transparent;
+ color: #5a5a5a;
+ }
+ </style>
+ <paper-listbox id="overflow-menu" selected="0" on-iron-select="onSelect_">
+ <paper-item id="history-button">
+ <div>$i18n{historyMenuItem}</div>
+ <paper-ripple></paper-ripple>
+ </paper-item>
+ <paper-item id="synced-tabs-button">
+ <div>$i18n{openTabsMenuItem}</div>
+ <paper-ripple></paper-ripple>
+ </paper-item>
+ </paper-listbox>
+ </template>
+ <script src="chrome://history/side_bar.js"></script>
+</dom-module>
diff --git a/chromium/chrome/browser/resources/md_history/side_bar.js b/chromium/chrome/browser/resources/md_history/side_bar.js
new file mode 100644
index 00000000000..02108615aad
--- /dev/null
+++ b/chromium/chrome/browser/resources/md_history/side_bar.js
@@ -0,0 +1,17 @@
+// 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-side-bar',
+
+ /**
+ * Handles menu selection changes.
+ * @param {Event} e
+ * @private
+ */
+ onSelect_: function(e) {
+ this.fire('unselect-all');
+ this.fire('switch-display', {display: e.detail.item.id});
+ },
+});
diff --git a/chromium/chrome/browser/resources/md_history/synced_device_card.html b/chromium/chrome/browser/resources/md_history/synced_device_card.html
new file mode 100644
index 00000000000..ee526bb17bf
--- /dev/null
+++ b/chromium/chrome/browser/resources/md_history/synced_device_card.html
@@ -0,0 +1,109 @@
+<link rel="import" href="chrome://resources/html/polymer.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-styles/shadow.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/iron-icons/iron-icons.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/iron-flex-layout.html">
+<link rel="import" href="chrome://resources/html/util.html">
+<link rel="import" href="chrome://history/shared_style.html">
+
+<dom-module id="history-synced-device-card">
+ <template>
+ <style include="shared-style"></style>
+ <style>
+ :host {
+ @apply(--layout-center);
+ @apply(--layout-vertical);
+ padding: 0 24px 20px;
+ }
+
+ #card-heading {
+ @apply(--layout-justified);
+ cursor: pointer;
+ }
+
+ #icon {
+ -webkit-margin-start: 20px;
+ }
+
+ #tab-item-list {
+ padding: 8px 0;
+ }
+
+ #open-tabs {
+ -webkit-margin-start: 20px;
+ color: rgb(102, 136, 238);
+ cursor: pointer;
+ }
+
+ #open-tabs:hover {
+ text-decoration: underline;
+ }
+
+ #last-update-time {
+ color: #969696;
+ }
+
+ #dropdown-indicator {
+ -webkit-margin-end: 12px;
+ max-width: 16px;
+ }
+
+ #collapse {
+ overflow: hidden;
+ }
+
+ #history-item-container {
+ background: #fff;
+ border: 1px solid var(--card-border-color);
+ border-bottom-width: 2px;
+ max-width: var(--card-max-width);
+ min-width: var(--card-min-width);
+ width: 100%;
+ }
+
+ #item-container {
+ @apply(--layout-center);
+ @apply(--layout-horizontal);
+ min-height: 40px;
+ }
+
+ #window-separator {
+ background-color: var(--card-border-color);
+ height: 1px;
+ margin: 5px auto;
+ width: 80%;
+ }
+ </style>
+ <div id="history-item-container">
+ <div class="card-title" id="card-heading" aria-expanded$="[[cardOpen_]]"
+ aria-controls="collapse" on-tap="toggleTabCard">
+ <div>
+ [[device]]
+ <span id="last-update-time">[[lastUpdateTime]]</span>
+ </div>
+ <iron-icon icon="expand-less" id="dropdown-indicator"></iron-icon>
+ </div>
+
+ <iron-collapse opened="{{cardOpen_}}" id="collapse">
+ <div id="tab-item-list">
+ <template is="dom-repeat" items="[[tabs]]" as="tab" id="tab-list">
+ <div id="item-container">
+ <div id="icon" class="website-icon"></div>
+ <a href="[[tab.url]]" class="website-title" title="[[tab.title]]">
+ [[tab.title]]
+ </a>
+ </div>
+ <template is="dom-if" if="[[tab.needsWindowSeparator]]">
+ <div id="window-separator"></div>
+ </template>
+ </template>
+ <div class="item-container">
+ <p on-tap="openAllTabs_" id="open-tabs">$i18n{openAll}</p>
+ </div>
+ </div>
+ </iron-collapse>
+ </div>
+ </template>
+ <script src="chrome://history/synced_device_card.js"></script>
+</dom-module>
diff --git a/chromium/chrome/browser/resources/md_history/synced_device_card.js b/chromium/chrome/browser/resources/md_history/synced_device_card.js
new file mode 100644
index 00000000000..dc577b9769f
--- /dev/null
+++ b/chromium/chrome/browser/resources/md_history/synced_device_card.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.
+
+Polymer({
+ is: 'history-synced-device-card',
+
+ properties: {
+ // Name of the synced device.
+ device: {
+ type: String,
+ value: ''
+ },
+
+ // When the device information was last updated.
+ lastUpdateTime: {
+ type: String,
+ value: ''
+ },
+
+ /**
+ * The list of tabs open for this device.
+ * @type {!Array<!ForeignSessionTab>}
+ */
+ tabs: {
+ type: Array,
+ value: function() { return []; },
+ observer: 'updateIcons_'
+ },
+
+ // Whether the card is open.
+ cardOpen_: {
+ type: Boolean,
+ value: true
+ },
+ },
+
+ /**
+ * Opens all the tabs displayed on the device in separate tabs.
+ * @private
+ */
+ openAllTabs_: function() {
+ // TODO(calamity): add a warning if an excessive number of tabs will open.
+ for (var i = 0; i < this.tabs.length; i++)
+ window.open(this.tabs[i].url, '_blank');
+ },
+
+ /**
+ * Toggles the dropdown display of synced tabs for each device card.
+ */
+ toggleTabCard: function() {
+ this.$.collapse.toggle();
+ this.$['dropdown-indicator'].icon =
+ this.$.collapse.opened ? 'expand-less' : 'expand-more';
+ },
+
+ /**
+ * When the synced tab information is set, the icon associated with the tab
+ * website is also set.
+ * @private
+ */
+ updateIcons_: function() {
+ this.async(function() {
+ var icons = Polymer.dom(this.root).querySelectorAll('.website-icon');
+
+ for (var i = 0; i < this.tabs.length; i++) {
+ icons[i].style.backgroundImage =
+ getFaviconImageSet(this.tabs[i].url);
+ }
+ });
+ }
+});
diff --git a/chromium/chrome/browser/resources/md_history/synced_device_manager.html b/chromium/chrome/browser/resources/md_history/synced_device_manager.html
new file mode 100644
index 00000000000..7f86a250aa8
--- /dev/null
+++ b/chromium/chrome/browser/resources/md_history/synced_device_manager.html
@@ -0,0 +1,26 @@
+<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-item/paper-item.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-menu/paper-menu.html">
+<link rel="import" href="chrome://resources/html/cr/ui/position_util.html">
+<link rel="import" href="chrome://history/shared_style.html">
+<link rel="import" href="chrome://history/synced_device_card.html">
+
+<dom-module id="history-synced-device-manager">
+ <style include="shared-style"></style>
+ <template>
+ <style>
+ :host {
+ overflow: auto;
+ padding-top: var(--first-card-padding-top);
+ }
+ </style>
+ <template is="dom-repeat" items="[[syncedDevices]]" as="syncedDevice">
+ <history-synced-device-card device="[[syncedDevice.device]]"
+ last-update-time="[[syncedDevice.lastUpdateTime]]"
+ tabs="[[syncedDevice.tabs]]">
+ </history-synced-device-card>
+ </template>
+ </template>
+ <script src="chrome://history/synced_device_manager.js"></script>
+</dom-module>
diff --git a/chromium/chrome/browser/resources/md_history/synced_device_manager.js b/chromium/chrome/browser/resources/md_history/synced_device_manager.js
new file mode 100644
index 00000000000..aab4aefccf8
--- /dev/null
+++ b/chromium/chrome/browser/resources/md_history/synced_device_manager.js
@@ -0,0 +1,76 @@
+// 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 {{device: string,
+ * lastUpdateTime: string,
+ * timestamp: number,
+ * tabs: !Array<!ForeignSessionTab>,
+ * tag: string}}
+ */
+var ForeignDeviceInternal;
+
+Polymer({
+ is: 'history-synced-device-manager',
+
+ properties: {
+ /**
+ * An array of synced devices with synced tab data.
+ * @type {!Array<!ForeignDeviceInternal>}
+ */
+ syncedDevices: {
+ type: Array,
+ value: function() { return []; }
+ }
+ },
+
+ /**
+ * @param {!ForeignSession} session
+ * @return {!ForeignDeviceInternal}
+ */
+ createInternalDevice_: function(session) {
+ var tabs = [];
+ for (var j = 0; j < session.windows.length; j++) {
+ var newTabs = session.windows[j].tabs;
+ if (newTabs.length == 0)
+ continue;
+
+ tabs = tabs.concat(newTabs);
+ tabs[tabs.length - 1].needsWindowSeparator = true;
+ }
+ return {
+ device: session.name,
+ lastUpdateTime: '– ' + session.modifiedTime,
+ timestamp: session.timestamp,
+ tabs: tabs,
+ tag: session.tag
+ };
+ },
+
+ /**
+ * Replaces the currently displayed synced tabs with |sessionList|. It is
+ * common for only a single session within the list to have changed, We try to
+ * avoid doing extra work in this case. The logic could be more intelligent
+ * about updating individual tabs rather than replacing whole sessions, but
+ * this approach seems to have acceptable performance.
+ * @param {!Array<!ForeignSession>} sessionList
+ */
+ setSyncedHistory: function(sessionList) {
+ // First, update any existing devices that have changed.
+ var updateCount = Math.min(sessionList.length, this.syncedDevices.length);
+ for (var i = 0; i < updateCount; i++) {
+ var oldDevice = this.syncedDevices[i];
+ if (oldDevice.tag != sessionList[i].tag ||
+ oldDevice.timestamp != sessionList[i].timestamp) {
+ this.splice(
+ 'syncedDevices', i, 1, this.createInternalDevice_(sessionList[i]));
+ }
+ }
+
+ // Then, append any new devices.
+ for (var i = updateCount; i < sessionList.length; i++) {
+ this.push('syncedDevices', this.createInternalDevice_(sessionList[i]));
+ }
+ }
+});
diff --git a/chromium/chrome/browser/resources/md_user_manager/compiled_resources2.gyp b/chromium/chrome/browser/resources/md_user_manager/compiled_resources2.gyp
new file mode 100644
index 00000000000..caf1a9222b5
--- /dev/null
+++ b/chromium/chrome/browser/resources/md_user_manager/compiled_resources2.gyp
@@ -0,0 +1,50 @@
+# 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': 'control_bar',
+ 'dependencies': [
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
+ 'profile_browser_proxy',
+ ],
+ 'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'create_profile',
+ 'dependencies': [
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:i18n_behavior',
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:load_time_data',
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:util',
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:web_ui_listener_behavior',
+ 'profile_browser_proxy',
+ ],
+ 'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'profile_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': 'supervised_user_learn_more',
+ 'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'user_manager_pages',
+ 'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'user_manager_tutorial',
+ 'dependencies': [
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:i18n_behavior',
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:util',
+ ],
+ 'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ ],
+}
diff --git a/chromium/chrome/browser/resources/md_user_manager/control_bar.css b/chromium/chrome/browser/resources/md_user_manager/control_bar.css
new file mode 100644
index 00000000000..3b2489e9827
--- /dev/null
+++ b/chromium/chrome/browser/resources/md_user_manager/control_bar.css
@@ -0,0 +1,37 @@
+/* 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. */
+
+#container {
+ padding-bottom: 12px;
+ padding-top: 12px;
+}
+
+paper-button {
+ border-radius: 2px;
+ color: var(--paper-grey-600);
+ font-weight: 500;
+ line-height: 32px;
+ margin: 0;
+ min-width: 52px;
+ padding: 0 16px;
+}
+
+#addUser {
+ margin: 0 8px;
+}
+
+#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;
+ left: 24px;
+ position: absolute;
+ top: 19px;
+}
+
+:host-context([dir='rtl']) #logo {
+ left: auto;
+ right: 24px;
+}
diff --git a/chromium/chrome/browser/resources/md_user_manager/control_bar.html b/chromium/chrome/browser/resources/md_user_manager/control_bar.html
new file mode 100644
index 00000000000..94591e35a39
--- /dev/null
+++ b/chromium/chrome/browser/resources/md_user_manager/control_bar.html
@@ -0,0 +1,22 @@
+<link rel="import" href="chrome://md-user-manager/profile_browser_proxy.html">
+<link rel="import" href="chrome://md-user-manager/shared_styles.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">
+
+<dom-module id="control-bar">
+ <!-- TODO(mahmadi): this format is deprecated. Change to the new
+ "shared styles" format. -->
+ <link rel="import" type="css" href="chrome://md-user-manager/control_bar.css">
+ <template>
+ <style include="shared-styles"></style>
+ <div id="container" class="layout horizontal end-justified">
+ <div id="logo"></div>
+ <paper-button id="launchGuest" on-tap="onLaunchGuestTap_"
+ i18n-content="browseAsGuest" hidden="[[!showGuest]]"></paper-button>
+ <paper-button id="addUser" on-tap="onAddUserTap_"
+ i18n-content="addUser" hidden="[[!showAddPerson]]"></paper-button>
+ </div>
+ </template>
+ <script src="chrome://md-user-manager/control_bar.js"></script>
+</dom-module>
diff --git a/chromium/chrome/browser/resources/md_user_manager/control_bar.js b/chromium/chrome/browser/resources/md_user_manager/control_bar.js
new file mode 100644
index 00000000000..3c2b6362923
--- /dev/null
+++ b/chromium/chrome/browser/resources/md_user_manager/control_bar.js
@@ -0,0 +1,58 @@
+// 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 'control-bar' is the horizontal bar at the bottom of the user
+ * manager screen.
+ */
+ Polymer({
+ is: 'control-bar',
+
+ properties: {
+ /**
+ * True if 'Browse as Guest' button is displayed.
+ * @type {boolean}
+ */
+ showGuest: {
+ type: Boolean,
+ value: false
+ },
+
+ /**
+ * True if 'Add Person' button is displayed.
+ * @type {boolean}
+ */
+ showAddPerson: {
+ type: Boolean,
+ value: false
+ },
+
+ /** @private {!signin.ProfileBrowserProxy} */
+ browserProxy_: Object
+ },
+
+ /** @override */
+ created: function() {
+ this.browserProxy_ = signin.ProfileBrowserProxyImpl.getInstance();
+ },
+
+ /**
+ * Handler for 'Browse as Guest' button click event.
+ * @param {!Event} event
+ * @private
+ */
+ onLaunchGuestTap_: function(event) {
+ this.browserProxy_.launchGuestUser();
+ },
+
+ /**
+ * Handler for 'Add Person' button click event.
+ * @param {!Event} event
+ * @private
+ */
+ onAddUserTap_: function(event) {
+ // Event is caught by user-manager-pages.
+ this.fire('change-page', {page: 'create-user-page'});
+ }
+});
diff --git a/chromium/chrome/browser/resources/md_user_manager/create_profile.css b/chromium/chrome/browser/resources/md_user_manager/create_profile.css
new file mode 100644
index 00000000000..f0e12a72f57
--- /dev/null
+++ b/chromium/chrome/browser/resources/md_user_manager/create_profile.css
@@ -0,0 +1,159 @@
+/* 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. */
+
+.container {
+ color: var(--paper-grey-800);
+ margin: 0 auto;
+ width: 624px;
+}
+
+#message-container {
+ background-color: var(--google-red-700);
+ color: white;
+ left: 0;
+ overflow: hidden;
+ padding: 10px 16px;
+ position: absolute;
+ right: 0;
+ top: 0;
+}
+
+#message-container iron-icon {
+ height: 20px;
+ width: 20px;
+}
+
+#message-container #message {
+ -webkit-margin-start: 16px;
+}
+
+#message-container #supervised-user-import-existing {
+ color: inherit;
+ text-decoration: underline;
+}
+
+#title-bar {
+ border-bottom: 1px solid rgba(0, 0, 0, .12);
+ font-size: 16px;
+ font-weight: 500;
+ padding: 104px 0 16px;
+}
+
+#nameInput,
+paper-dropdown-menu {
+ --paper-input-container: {
+ padding: 0;
+ };
+ --paper-input-container-input: {
+ color: inherit;
+ font-size: inherit;
+ };
+}
+
+#nameInput {
+ margin-bottom: 24px;
+ margin-top: 32px;
+ width: 300px;
+}
+
+paper-dropdown-menu {
+ margin-top: 12px;
+ width: 200px;
+}
+
+paper-menu {
+ --paper-menu: {
+ color: inherit;
+ padding: 0;
+ };
+ --paper-menu-selected-item: {
+ font-weight: normal;
+ }
+}
+
+paper-menu paper-item {
+ font-size: inherit;
+ min-height: 40px;
+}
+
+#icons #wrapper {
+ display: flex;
+ flex-wrap: wrap;
+ margin: -12px;
+}
+
+#icons paper-button {
+ background: var(--paper-grey-300);
+ border: 1px solid rgba(0, 0, 0, .12);
+ margin: 12px;
+ min-width: 0;
+ padding: 6px 4px;
+}
+
+#icons paper-button[active] {
+ border-color: var(--google-blue-500);
+}
+
+#icons paper-button:focus:not([active]) {
+ outline: 1px dotted #666;
+}
+
+#supervised-user-container {
+ margin-top: 24px;
+}
+
+#supervised-user-container paper-checkbox {
+ --paper-checkbox-label-spacing: 16px;
+ --paper-checkbox-size: 20px;
+}
+
+#supervised-user-container #learn-more-accounts {
+ -webkit-margin-start: 36px;
+}
+
+#supervised-user-container #learn-more {
+ display: block;
+ line-height: 20px;
+}
+
+#actions {
+ bottom: 16px;
+ display: flex;
+ position: absolute;
+ right: 16px;
+}
+
+:host-context([dir='rtl']) #actions {
+ left: 16px;
+ right: auto;
+}
+
+#actions paper-button {
+ border-radius: 2px;
+ font-weight: 500;
+ line-height: 32px;
+ margin: 0;
+ min-width: 52px;
+ padding: 0 16px;
+}
+
+#actions paper-spinner {
+ align-self: center;
+ height: 20px;
+ width: 20px;
+}
+
+#actions #cancel {
+ color: var(--paper-grey-600);
+}
+
+#actions #save {
+ -webkit-margin-start: 8px;
+ background: var(--google-blue-500);
+ color: white;
+}
+
+#actions #save[disabled] {
+ background: rgba(66, 133, 244, .5);
+}
diff --git a/chromium/chrome/browser/resources/md_user_manager/create_profile.html b/chromium/chrome/browser/resources/md_user_manager/create_profile.html
new file mode 100644
index 00000000000..d25395078b4
--- /dev/null
+++ b/chromium/chrome/browser/resources/md_user_manager/create_profile.html
@@ -0,0 +1,83 @@
+<link rel="import" href="chrome://md-user-manager/profile_browser_proxy.html">
+<link rel="import" href="chrome://md-user-manager/shared_styles.html">
+<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/i18n_behavior.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/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-checkbox/paper-checkbox.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-dropdown-menu/paper-dropdown-menu.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-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-spinner/paper-spinner.html">
+
+<dom-module id="create-profile">
+ <link rel="import" type="css"
+ href="chrome://md-user-manager/create_profile.css">
+ <link rel="import" type="css" href="chrome://resources/css/action_link.css">
+ <template>
+ <style include="shared-styles"></style>
+ <div id="message-container" hidden="[[!message_]]">
+ <iron-icon icon="warning"></iron-icon>
+ <span id="message" inner-h-t-m-l="[[message_]]"></span>
+ </div>
+ <div class="container">
+ <div id="title-bar" i18n-content="createProfileTitle"></div>
+ <paper-input id="nameInput" value="{{profileName_}}" pattern=".*\S.*"
+ no-label-float auto-validate>
+ </paper-input>
+ <div id="icons">
+ <div id="wrapper">
+ <template is="dom-repeat" items="[[availableIconUrls_]]">
+ <paper-button toggles on-tap="onIconTap_" data-icon-url$="[[item]]"
+ active="[[isActiveIcon_(item, profileIconUrl_)]]">
+ <img src="[[item]]">
+ </paper-button>
+ </template>
+ </div>
+ </div>
+ <template is="dom-if" if="[[isSignedIn_(signedInUsers_)]]">
+ <div id="supervised-user-container">
+ <paper-checkbox checked="{{isSupervised_}}">
+ [[i18n('manageProfilesSupervisedSignedInLabel')]]
+ </paper-checkbox>
+ <div id="learn-more-accounts">
+ <a id="learn-more" is="action-link" on-tap="onLearnMoreTap_">
+ [[i18n('learnMore')]]
+ </a>
+ <template is="dom-if" if="[[isSupervised_]]">
+ <paper-dropdown-menu no-label-float>
+ <paper-menu class="dropdown-content"
+ selected="{{signedInUserIndex_}}"
+ attr-for-selected="data-user-index">
+ <paper-item data-user-index$="[[NO_USER_SELECTED]]">
+ [[i18n('selectAnAccount')]]
+ </paper-item>
+ <template is="dom-repeat" items="[[signedInUsers_]]">
+ <paper-item data-user-index$="[[index]]">
+ [[item.username]]
+ </paper-item>
+ </template>
+ </paper-menu>
+ </paper-dropdown-menu>
+ </template>
+ </div>
+ </div>
+ </template>
+ <div id="actions">
+ <paper-spinner active="[[createInProgress_]]"></paper-spinner>
+ <paper-button id="cancel" on-tap="onCancelTap_" i18n-content="cancel">
+ </paper-button>
+ <paper-button id="save" on-tap="onSaveTap_"
+ i18n-content="createProfileConfirm"
+ disabled="[[isSaveDisabled_(createInProgress_, profileName_)]]">
+ </paper-button>
+ </div>
+ </div>
+ </template>
+ <script src="chrome://md-user-manager/create_profile.js"></script>
+</dom-module>
diff --git a/chromium/chrome/browser/resources/md_user_manager/create_profile.js b/chromium/chrome/browser/resources/md_user_manager/create_profile.js
new file mode 100644
index 00000000000..e7d0113315a
--- /dev/null
+++ b/chromium/chrome/browser/resources/md_user_manager/create_profile.js
@@ -0,0 +1,350 @@
+// 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 'create-profile' is a page that contains controls for creating
+ * a (optionally supervised) profile, including choosing a name, and an avatar.
+ */
+(function() {
+/**
+ * It means the sentinel menu item is selected.
+ * @const {number}
+ */
+var NO_USER_SELECTED = -1;
+
+Polymer({
+ is: 'create-profile',
+
+ behaviors: [
+ I18nBehavior,
+ WebUIListenerBehavior
+ ],
+
+ properties: {
+ /**
+ * The current profile name.
+ * @private {string}
+ */
+ profileName_: {
+ type: String,
+ value: ''
+ },
+
+ /**
+ * The list of available profile icon URLs.
+ * @private {!Array<string>}
+ */
+ availableIconUrls_: {
+ type: Array,
+ value: function() { return []; }
+ },
+
+ /**
+ * The currently selected profile icon URL. May be a data URL.
+ * @private {string}
+ */
+ profileIconUrl_: {
+ type: String,
+ value: ''
+ },
+
+ /**
+ * True if a profile is being created or imported.
+ * @private {boolean}
+ */
+ createInProgress_: {
+ type: Boolean,
+ value: false
+ },
+
+ /**
+ * The current error/warning message.
+ * @private {string}
+ */
+ message_: {
+ type: String,
+ value: ''
+ },
+
+ /**
+ * True if the new profile is a supervised profile.
+ * @private {boolean}
+ */
+ isSupervised_: {
+ type: Boolean,
+ value: false
+ },
+
+ /**
+ * The list of usernames and profile paths for currently signed-in users.
+ * @private {!Array<!SignedInUser>}
+ */
+ signedInUsers_: {
+ type: Array,
+ value: function() { return []; }
+ },
+
+ /**
+ * Index of the selected signed-in user.
+ * @private {number}
+ */
+ signedInUserIndex_: {
+ type: Number,
+ value: NO_USER_SELECTED
+ },
+
+ /** @private {!signin.ProfileBrowserProxy} */
+ browserProxy_: Object
+ },
+
+ /** @override */
+ created: function() {
+ this.browserProxy_ = signin.ProfileBrowserProxyImpl.getInstance();
+ },
+
+ /** @override */
+ ready: function() {
+ this.addWebUIListener(
+ 'create-profile-success', this.handleSuccess_.bind(this));
+ this.addWebUIListener(
+ 'create-profile-warning', this.handleMessage_.bind(this));
+ this.addWebUIListener(
+ 'create-profile-error', this.handleMessage_.bind(this));
+ this.addWebUIListener(
+ 'profile-icons-received', this.handleProfileIcons_.bind(this));
+ this.addWebUIListener(
+ 'profile-defaults-received', this.handleProfileDefaults_.bind(this));
+ this.addWebUIListener(
+ 'signedin-users-received', this.handleSignedInUsers_.bind(this));
+
+ this.browserProxy_.getAvailableIcons();
+ this.browserProxy_.getSignedInUsers();
+
+ // Alias on 'this' to use in html.
+ this.NO_USER_SELECTED = NO_USER_SELECTED;
+ },
+
+ /**
+ * Handler for when the profile icons are pushed from the browser.
+ * @param {!Array<string>} iconUrls
+ * @private
+ */
+ handleProfileIcons_: function(iconUrls) {
+ this.availableIconUrls_ = iconUrls;
+ this.profileIconUrl_ = iconUrls[0];
+ },
+
+ /**
+ * Handler for when the profile defaults are pushed from the browser.
+ * @param {ProfileInfo} profileInfo Default Info for the new profile.
+ * @private
+ */
+ handleProfileDefaults_: function(profileInfo) {
+ this.profileName_ = profileInfo.name;
+ },
+
+ /**
+ * Handler for when signed-in users are pushed from the browser.
+ * @param {!Array<!SignedInUser>} signedInUsers
+ * @private
+ */
+ handleSignedInUsers_: function(signedInUsers) {
+ this.signedInUsers_ = signedInUsers;
+ },
+
+ /**
+ * Returns the currently selected signed-in user.
+ * @return {(!SignedInUser|undefined)}
+ * @private
+ */
+ signedInUser_: function(signedInUserIndex) {
+ return this.signedInUsers_[signedInUserIndex];
+ },
+
+ /**
+ * Handler for the 'Learn More' link tap event.
+ * @param {!Event} event
+ * @private
+ */
+ onLearnMoreTap_: function(event) {
+ this.fire('change-page', {page: 'supervised-learn-more-page'});
+ },
+
+ /**
+ * Handler for the 'Save' button tap event.
+ * @param {!Event} event
+ * @private
+ */
+ onSaveTap_: function(event) {
+ this.createInProgress_ = true;
+
+ if (!this.isSupervised_) {
+ // The new profile is not supervised. Go ahead and create it.
+ this.createProfile_();
+ } else if (this.signedInUserIndex_ == NO_USER_SELECTED) {
+ // If the new profile is supervised, a custodian must be selected.
+ this.handleMessage_(this.i18n('custodianAccountNotSelectedError'));
+ this.createInProgress_ = false;
+ } else {
+ var signedInUser = this.signedInUser_(this.signedInUserIndex_);
+ this.browserProxy_.getExistingSupervisedUsers(
+ signedInUser.profilePath).then(
+ this.createProfileIfValidSupervisedUser_.bind(this),
+ /** @param {*} error */
+ function(error) { this.handleMessage_(error); }.bind(this));
+ }
+ },
+
+ /**
+ * Checks if the entered name matches name of an existing supervised user.
+ * If yes, the user is prompted to import the existing supervised user.
+ * If no, the new supervised profile gets created.
+ * @param {Array<SupervisedUser>} supervisedUsers The list of existing
+ * supervised users.
+ * @private
+ */
+ createProfileIfValidSupervisedUser_: function(supervisedUsers) {
+ for (var i = 0; i < supervisedUsers.length; ++i) {
+ if (supervisedUsers[i].name != this.profileName_)
+ continue;
+ // Check if another supervised user also exists with that name.
+ var nameIsUnique = true;
+ // Handling the case when multiple supervised users with the same
+ // name exist, but not all of them are on the device.
+ // If at least one is not imported, we want to offer that
+ // option to the user. This could happen due to a bug that allowed
+ // creating SUs with the same name (https://crbug.com/557445).
+ var allOnCurrentDevice = supervisedUsers[i].onCurrentDevice;
+ for (var j = i + 1; j < supervisedUsers.length; ++j) {
+ if (supervisedUsers[j].name == this.profileName_) {
+ nameIsUnique = false;
+ allOnCurrentDevice = allOnCurrentDevice &&
+ supervisedUsers[j].onCurrentDevice;
+ }
+ }
+
+ this.handleMessage_(allOnCurrentDevice ?
+ this.i18n('managedProfilesExistingLocalSupervisedUser') :
+ this.i18n('manageProfilesExistingSupervisedUser',
+ HTMLEscape(elide(this.profileName_, /* maxLength */ 50))));
+
+ this.createInProgress_ = false;
+ return;
+ }
+ // No existing supervised user's name matches the entered profile name.
+ // Continue with creating the new supervised profile.
+ this.createProfile_();
+ },
+
+ /**
+ * Creates the new profile.
+ * @private
+ */
+ createProfile_: function() {
+ var custodianProfilePath = '';
+ if (this.signedInUserIndex_ != NO_USER_SELECTED) {
+ custodianProfilePath =
+ this.signedInUser_(this.signedInUserIndex_).profilePath;
+ }
+
+ this.browserProxy_.createProfile(
+ this.profileName_, this.profileIconUrl_, this.isSupervised_,
+ custodianProfilePath);
+ },
+
+ /**
+ * Handler for the 'Cancel' button tap event.
+ * @param {!Event} event
+ * @private
+ */
+ onCancelTap_: function(event) {
+ if (this.createInProgress_) {
+ this.createInProgress_ = false;
+ this.browserProxy_.cancelCreateProfile();
+ } else {
+ this.fire('change-page', {page: 'user-pods-page'});
+ }
+ },
+
+ /**
+ * Handler for when the user clicks a new profile icon.
+ * @param {!Event} event
+ * @private
+ */
+ onIconTap_: function(event) {
+ var element = Polymer.dom(event).rootTarget;
+
+ if (element.nodeName == 'IMG')
+ this.profileIconUrl_ = element.src;
+ else if (element.dataset && element.dataset.iconUrl)
+ this.profileIconUrl_ = element.dataset.iconUrl;
+
+ // Button toggle state is controlled by the selected icon URL. Prevent
+ // tap events from changing the toggle state.
+ event.preventDefault();
+ },
+
+ /**
+ * Handles profile create/import success message pushed by the browser.
+ * @param {!ProfileInfo} profileInfo Details of the created/imported profile.
+ * @private
+ */
+ handleSuccess_: function(profileInfo) {
+ this.createInProgress_ = false;
+ this.fire('change-page', {page: 'user-pods-page'});
+ },
+
+ /**
+ * Handles profile create/import warning/error message pushed by the browser.
+ * @param {string} message An HTML warning/error message.
+ * @private
+ */
+ handleMessage_: function(message) {
+ this.createInProgress_ = false;
+ this.message_ = message;
+
+ // TODO(mahmadi): attach handler to '#supervised-user-import-existing'
+ // in order to import supervised user with the given name.
+
+ // TODO(mahmadi): attach handler to '#reauth' in order to re-authenticate
+ // custodian.
+ },
+
+ /**
+ * Computed binding determining which profile icon button is toggled on.
+ * @param {string} iconUrl icon URL of a given icon button.
+ * @param {string} profileIconUrl Currently selected icon URL.
+ * @return {boolean}
+ * @private
+ */
+ isActiveIcon_: function(iconUrl, profileIconUrl) {
+ return iconUrl == profileIconUrl;
+ },
+
+ /**
+ * Computed binding determining whether 'Save' button is disabled.
+ * @param {boolean} createInProgress Is create in progress?
+ * @param {string} profileName Profile Name.
+ * @return {boolean}
+ * @private
+ */
+ isSaveDisabled_: function(createInProgress, profileName) {
+ // TODO(mahmadi): Figure out a way to add 'paper-input-extracted' as a
+ // dependency and cast to PaperInputElement instead.
+ /** @type {{validate: function():boolean}} */
+ var nameInput = this.$.nameInput;
+ return createInProgress || !profileName || !nameInput.validate();
+ },
+
+ /**
+ * Computed binding that returns True if there are any signed-in users.
+ * @param {!Array<!SignedInUser>} signedInUsers signed-in users.
+ * @return {boolean}
+ * @private
+ */
+ isSignedIn_: function(signedInUsers) {
+ return signedInUsers.length > 0;
+ }
+});
+}());
diff --git a/chromium/chrome/browser/resources/downloads/throttled_icon_loader.html b/chromium/chrome/browser/resources/md_user_manager/profile_browser_proxy.html
index 4cbd4ebfebd..078c69a1d09 100644
--- a/chromium/chrome/browser/resources/downloads/throttled_icon_loader.html
+++ b/chromium/chrome/browser/resources/md_user_manager/profile_browser_proxy.html
@@ -1,3 +1,3 @@
<link rel="import" href="chrome://resources/html/assert.html">
<link rel="import" href="chrome://resources/html/cr.html">
-<script src="throttled_icon_loader.js"></script>
+<script src="chrome://md-user-manager/profile_browser_proxy.js"></script>
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
new file mode 100644
index 00000000000..b65f737ab84
--- /dev/null
+++ b/chromium/chrome/browser/resources/md_user_manager/profile_browser_proxy.js
@@ -0,0 +1,156 @@
+// 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 Helper object and related behavior that encapsulate messaging
+ * between JS and C++ for creating/importing profiles in the user-manager page.
+ */
+
+/** @typedef {{username: string, profilePath: string}} */
+var SignedInUser;
+
+/** @typedef {{name: string, filePath: string, isSupervised: boolean}} */
+var ProfileInfo;
+
+/** @typedef {{id: string,
+ * name: string,
+ * iconURL: string,
+ * onCurrentDevice: boolean}}
+ */
+var SupervisedUser;
+
+cr.define('signin', function() {
+ /** @interface */
+ function ProfileBrowserProxy() {}
+
+ ProfileBrowserProxy.prototype = {
+ /**
+ * Gets the available profile icons to choose from.
+ */
+ getAvailableIcons: function() {
+ assertNotReached();
+ },
+
+ /**
+ * Gets the current signed-in users.
+ */
+ getSignedInUsers: function() {
+ assertNotReached();
+ },
+
+ /**
+ * Launches the guest user.
+ */
+ launchGuestUser: function() {
+ assertNotReached();
+ },
+
+ /**
+ * Gets the list of existing supervised users.
+ * @param {string} profilePath Profile Path of the custodian.
+ * @return {Promise} A promise for the requested data.
+ * @private
+ */
+ getExistingSupervisedUsers: function(profilePath) {
+ assertNotReached();
+ },
+
+ /**
+ * Creates a profile.
+ * @param {string} profileName Name of the new profile.
+ * @param {string} profileIconUrl URL of the selected icon of the new
+ * profile.
+ * @param {boolean} isSupervised True if the new profile is supervised.
+ * @param {string} custodianProfilePath Profile path of the custodian if
+ * the new profile is supervised.
+ */
+ createProfile: function(profileName, profileIconUrl, isSupervised,
+ custodianProfilePath) {
+ assertNotReached();
+ },
+
+ /**
+ * Cancels creation of the new profile.
+ */
+ cancelCreateProfile: function() {
+ assertNotReached();
+ },
+
+ /**
+ * Initializes the UserManager
+ * @param {string} locationHash
+ */
+ initializeUserManager: function(locationHash) {
+ assertNotReached();
+ },
+
+ /**
+ * Launches the user with the given |profilePath|
+ * @param {string} profilePath Profile Path of the user.
+ */
+ launchUser: function(profilePath) {
+ assertNotReached();
+ }
+ };
+
+ /**
+ * @constructor
+ * @implements {signin.ProfileBrowserProxy}
+ */
+ function ProfileBrowserProxyImpl() {}
+
+ // The singleton instance_ is replaced with a test version of this wrapper
+ // during testing.
+ cr.addSingletonGetter(ProfileBrowserProxyImpl);
+
+ ProfileBrowserProxyImpl.prototype = {
+ /** @override */
+ getAvailableIcons: function() {
+ chrome.send('requestDefaultProfileIcons');
+ },
+
+ /** @override */
+ getSignedInUsers: function() {
+ chrome.send('requestSignedInProfiles');
+ },
+
+ /** @override */
+ launchGuestUser: function() {
+ chrome.send('launchGuest');
+ },
+
+ /** @override */
+ getExistingSupervisedUsers: function(profilePath) {
+ return cr.sendWithPromise('getExistingSupervisedUsers', profilePath);
+ },
+
+ /** @override */
+ createProfile: function(profileName, profileIconUrl, isSupervised,
+ custodianProfilePath) {
+ chrome.send('createProfile',
+ [profileName, profileIconUrl, false, isSupervised, '',
+ custodianProfilePath]);
+ },
+
+ /** @override */
+ cancelCreateProfile: function() {
+ chrome.send('cancelCreateProfile');
+ },
+
+ /** @override */
+ initializeUserManager: function(locationHash) {
+ chrome.send('userManagerInitialize', [locationHash]);
+ },
+
+ /** @override */
+ launchUser: function(profilePath) {
+ chrome.send('launchUser', [profilePath]);
+ }
+ };
+
+ return {
+ ProfileBrowserProxy: ProfileBrowserProxy,
+ ProfileBrowserProxyImpl: ProfileBrowserProxyImpl,
+ };
+});
diff --git a/chromium/chrome/browser/resources/md_user_manager/shared_styles.html b/chromium/chrome/browser/resources/md_user_manager/shared_styles.html
new file mode 100644
index 00000000000..28ab1f42621
--- /dev/null
+++ b/chromium/chrome/browser/resources/md_user_manager/shared_styles.html
@@ -0,0 +1,10 @@
+<dom-module id="shared-styles">
+ <template>
+ <style>
+ a {
+ color: var(--google-blue-700);
+ text-decoration: none;
+ }
+ </style>
+ </template>
+</dom-module>
diff --git a/chromium/chrome/browser/resources/md_user_manager/strings.html b/chromium/chrome/browser/resources/md_user_manager/strings.html
new file mode 100644
index 00000000000..b349971f093
--- /dev/null
+++ b/chromium/chrome/browser/resources/md_user_manager/strings.html
@@ -0,0 +1,2 @@
+<link rel="import" href="chrome://resources/html/load_time_data.html">
+<script src="chrome://md-user-manager/strings.js"></script>
diff --git a/chromium/chrome/browser/resources/md_user_manager/supervised_user_learn_more.css b/chromium/chrome/browser/resources/md_user_manager/supervised_user_learn_more.css
new file mode 100644
index 00000000000..0cb0fc80d1e
--- /dev/null
+++ b/chromium/chrome/browser/resources/md_user_manager/supervised_user_learn_more.css
@@ -0,0 +1,56 @@
+/* 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. */
+
+:host {
+ align-self: center;
+}
+
+#container {
+ color: var(--google-grey-800);
+ line-height: 20px;
+ width: 624px;
+}
+
+#title-area {
+ border-bottom: 1px solid rgba(0, 0, 0, .12);
+ font-size: 16px;
+ padding-bottom: 16px;
+}
+
+#title-area iron-icon {
+ --iron-icon-height: 20px;
+ --iron-icon-width: 20px;
+ color: var(--google-grey-500);
+}
+
+.content-area {
+ padding-top: 32px;
+ white-space: pre-wrap;
+ word-wrap: break-word;
+}
+
+#actions {
+ bottom: 16px;
+ position: absolute;
+ right: 16px;
+}
+
+:host-context([dir='rtl']) #actions {
+ left: 16px;
+ right: auto;
+}
+
+#actions paper-button {
+ border-radius: 2px;
+ font-weight: 500;
+ line-height: 32px;
+ margin: 0;
+ min-width: 52px;
+ padding: 0 16px;
+}
+
+#actions #done {
+ background: var(--google-blue-500);
+ color: white;
+}
diff --git a/chromium/chrome/browser/resources/md_user_manager/supervised_user_learn_more.html b/chromium/chrome/browser/resources/md_user_manager/supervised_user_learn_more.html
new file mode 100644
index 00000000000..e2abb463556
--- /dev/null
+++ b/chromium/chrome/browser/resources/md_user_manager/supervised_user_learn_more.html
@@ -0,0 +1,28 @@
+<link rel="import" href="chrome://md-user-manager/shared_styles.html">
+<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/iron-icon/iron-icon.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html">
+
+<dom-module id="supervised-user-learn-more">
+ <link rel="import" type="css"
+ href="chrome://md-user-manager/supervised_user_learn_more.css">
+ <template>
+ <style include="shared-styles"></style>
+ <div id="container">
+ <div id="title-area" class="horizontal justified layout">
+ <span id="title" i18n-content="supervisedUserLearnMoreTitle"></span>
+ <iron-icon icon="supervisor-account"></iron-icon>
+ </div>
+ <div class="content-area"
+ i18n-values=".innerHTML:supervisedUserLearnMoreText">
+ </div>
+ <div id="actions">
+ <paper-button id="done" on-tap="onDoneTap_"
+ i18n-content="supervisedUserLearnMoreDone">
+ </paper-button>
+ </div>
+ </div>
+ </template>
+ <script src="chrome://md-user-manager/supervised_user_learn_more.js"></script>
+</dom-module>
diff --git a/chromium/chrome/browser/resources/md_user_manager/supervised_user_learn_more.js b/chromium/chrome/browser/resources/md_user_manager/supervised_user_learn_more.js
new file mode 100644
index 00000000000..1a0093887ac
--- /dev/null
+++ b/chromium/chrome/browser/resources/md_user_manager/supervised_user_learn_more.js
@@ -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.
+
+/**
+ * @fileoverview 'supervised-user-learn-more' is a page that contains
+ * information about what a supervised user is, what happens when a supervised
+ * user is created, and a link to the help center for more information.
+ */
+Polymer({
+ is: 'supervised-user-learn-more',
+
+ /**
+ * Handler for the 'Done' button click event.
+ * @param {!Event} event
+ * @private
+ */
+ onDoneTap_: function(event) {
+ // Event is caught by user-manager-pages.
+ this.fire('change-page', {page: 'create-user-page'});
+ }
+});
diff --git a/chromium/chrome/browser/resources/md_user_manager/user_manager.html b/chromium/chrome/browser/resources/md_user_manager/user_manager.html
new file mode 100644
index 00000000000..6dd9fdc8b4d
--- /dev/null
+++ b/chromium/chrome/browser/resources/md_user_manager/user_manager.html
@@ -0,0 +1,47 @@
+<!doctype html>
+<html i18n-values="build:buildType;
+ dir:textdirection;
+ lang:language;
+ screen:screenType">
+<head>
+ <meta charset="utf-8">
+ <meta name="google" value="notranslate">
+ <title i18n-content="title"></title>
+
+ <link rel="stylesheet" href="../../../../ui/login/account_picker/screen_account_picker.css">
+ <link rel="stylesheet" href="../../../../ui/login/account_picker/user_pod_row.css">
+ <link rel="stylesheet" href="../../../../ui/login/bubble.css">
+ <link rel="stylesheet" href="../../../../ui/login/oobe.css">
+ <link rel="stylesheet" href="../../../../ui/login/screen_container.css">
+ <link rel="stylesheet" href="chrome://resources/css/text_defaults_md.css">
+
+ <link rel="import" href="chrome://md-user-manager/control_bar.html">
+ <link rel="import" href="chrome://md-user-manager/user_manager_pages.html">
+ <link rel="import" href="chrome://md-user-manager/user_manager_styles.html">
+ <link rel="import" href="chrome://md-user-manager/user_manager_tutorial.html">
+ <link rel="import" href="chrome://resources/html/cr/ui.html">
+ <link rel="import" href="chrome://resources/html/util.html">
+ <style is="custom-style" include="user-manager-styles"></style>
+</head>
+<body>
+ <user-manager-pages>
+ <div id="outer-container">
+ <user-manager-tutorial></user-manager-tutorial>
+ <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>
+ <control-bar id="login-header-bar"></control-bar>
+ <include src="../../../../ui/login/account_picker/user_pod_template.html">
+ </user-manager-pages>
+ <link rel="import" href="chrome://md-user-manager/strings.html">
+ <link rel="import" href="chrome://resources/html/i18n_template.html">
+ <script src="user_manager.js"></script>
+</body>
+</html>
diff --git a/chromium/chrome/browser/resources/md_user_manager/user_manager.js b/chromium/chrome/browser/resources/md_user_manager/user_manager.js
new file mode 100644
index 00000000000..caaf404f0a4
--- /dev/null
+++ b/chromium/chrome/browser/resources/md_user_manager/user_manager.js
@@ -0,0 +1,123 @@
+// 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 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="../../../../ui/login/account_picker/screen_account_picker.js">
+<include src="../../../../ui/login/account_picker/user_pod_row.js">
+
+
+cr.define('cr.ui', function() {
+ var DisplayManager = cr.ui.login.DisplayManager;
+
+ /**
+ * Manages initialization of screens, transitions, and error messages.
+ * @constructor
+ * @extends {DisplayManager}
+ */
+ function UserManager() {}
+
+ cr.addSingletonGetter(UserManager);
+
+ UserManager.prototype = {
+ __proto__: DisplayManager.prototype,
+ };
+
+ /**
+ * Initializes the UserManager.
+ */
+ UserManager.initialize = function() {
+ cr.ui.login.DisplayManager.initialize();
+ login.AccountPickerScreen.register();
+ cr.ui.Bubble.decorate($('bubble'));
+
+ signin.ProfileBrowserProxyImpl.getInstance().initializeUserManager(
+ window.location.hash);
+ };
+
+ /**
+ * Shows the given screen.
+ * @param {boolean} showGuest True if 'Browse as Guest' button should be
+ * displayed.
+ * @param {boolean} showAddPerson True if 'Add Person' button should be
+ * displayed.
+ */
+ UserManager.showUserManagerScreen = function(showGuest, showAddPerson) {
+ UserManager.getInstance().showScreen({id: 'account-picker',
+ data: {disableAddUser: false}});
+ // Hide control options if the user does not have the right permissions.
+ var controlBar = document.querySelector('control-bar');
+ controlBar.showGuest = showGuest;
+ controlBar.showAddPerson = showAddPerson;
+
+ // 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();});
+
+ if (window.location.hash == '#tutorial')
+ document.querySelector('user-manager-tutorial').startTutorial();
+ };
+
+ /**
+ * Open a new browser for the given profile.
+ * @param {string} profilePath The profile's path.
+ */
+ UserManager.launchUser = function(profilePath) {
+ signin.ProfileBrowserProxyImpl.getInstance().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 attempts 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();
+ };
+
+ // Export
+ return {
+ UserManager: UserManager
+ };
+});
+
+// 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', cr.ui.UserManager.initialize);
diff --git a/chromium/chrome/browser/resources/md_user_manager/user_manager_pages.css b/chromium/chrome/browser/resources/md_user_manager/user_manager_pages.css
new file mode 100644
index 00000000000..385e3ee3f79
--- /dev/null
+++ b/chromium/chrome/browser/resources/md_user_manager/user_manager_pages.css
@@ -0,0 +1,12 @@
+/* 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. */
+
+neon-animated-pages {
+ height: 100%;
+}
+
+neon-animated-pages > div {
+ display: flex;
+ justify-content: center;
+}
diff --git a/chromium/chrome/browser/resources/md_user_manager/user_manager_pages.html b/chromium/chrome/browser/resources/md_user_manager/user_manager_pages.html
new file mode 100644
index 00000000000..5ce6be90406
--- /dev/null
+++ b/chromium/chrome/browser/resources/md_user_manager/user_manager_pages.html
@@ -0,0 +1,35 @@
+<link rel="import" href="chrome://md-user-manager/create_profile.html">
+<link rel="import" href="chrome://md-user-manager/supervised_user_learn_more.html">
+<link rel="import" href="chrome://resources/html/polymer.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/neon-animation/animations/slide-from-left-animation.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/neon-animation/animations/slide-right-animation.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/neon-animation/neon-animated-pages.html">
+
+<dom-module id="user-manager-pages">
+ <link rel="import" type="css"
+ href="chrome://md-user-manager/user_manager_pages.css">
+ <template>
+ <neon-animated-pages id="animatedPages" attr-for-selected="id"
+ selected="[[selectedPage_]]" entry-animation="slide-from-left-animation"
+ exit-animation="slide-right-animation">
+ <div id="create-user-page">
+ <template is="dom-if" if="[[isPageVisible_(selectedPage_, 'create-user-page')]]" restamp>
+ <create-profile></create-profile>
+ </template>
+ </div>
+ <div id="user-pods-page">
+ <template is="dom-if" if="[[isPageVisible_(selectedPage_, 'user-pods-page')]]">
+ <content></content>
+ </template>
+ </div>
+ <div id="supervised-learn-more-page">
+ <template is="dom-if"
+ if="[[isPageVisible_(selectedPage_, 'supervised-learn-more-page')]]">
+ <supervised-user-learn-more></supervised-user-learn-more>
+ </template>
+ </div>
+ <content></content>
+ </neon-animated-pages>
+ </template>
+ <script src="chrome://md-user-manager/user_manager_pages.js"></script>
+</dom-module>
diff --git a/chromium/chrome/browser/resources/md_user_manager/user_manager_pages.js b/chromium/chrome/browser/resources/md_user_manager/user_manager_pages.js
new file mode 100644
index 00000000000..434f840f1df
--- /dev/null
+++ b/chromium/chrome/browser/resources/md_user_manager/user_manager_pages.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 'user-manager-pages' is the element that controls paging in the
+ * user manager screen.
+ */
+Polymer({
+ is: 'user-manager-pages',
+
+ properties: {
+ /**
+ * ID of the currently selected page.
+ * @private {string}
+ */
+ selectedPage_: {
+ type: String,
+ value: 'user-pods-page'
+ }
+ },
+
+ listeners: {
+ 'change-page': 'changePage_'
+ },
+
+ /**
+ * Changes the currently selected page.
+ * @param {Event} e The event containing ID of the selected page.
+ * @private
+ */
+ changePage_: function(e) {
+ this.selectedPage_ = e.detail.page;
+ },
+
+ /**
+ * Returns True if the given page should be visible.
+ * @param {string} selectedPage ID of the currently selected page.
+ * @param {string} page ID of the given page.
+ * @return {boolean}
+ */
+ isPageVisible_: function(selectedPage, page) {
+ return this.selectedPage_ == page;
+ }
+});
diff --git a/chromium/chrome/browser/resources/md_user_manager/user_manager_styles.html b/chromium/chrome/browser/resources/md_user_manager/user_manager_styles.html
new file mode 100644
index 00000000000..7b0785b4975
--- /dev/null
+++ b/chromium/chrome/browser/resources/md_user_manager/user_manager_styles.html
@@ -0,0 +1,217 @@
+<link rel="import" href="chrome://md-user-manager/shared_styles.html">
+
+<dom-module id="user-manager-styles">
+ <template>
+ <style include="shared-styles">
+ body {
+ background-color: #eee;
+ }
+
+ /* Overrides for the desktop user manager screen. */
+ #login-header-bar {
+ bottom: 0;
+ left: 0;
+ position: absolute;
+ right: 0;
+ }
+
+ #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: var(--paper-grey-600);
+ display: initial;
+ }
+
+ .pod.legacy-supervised .legacy-supervised-indicator {
+ -webkit-mask-image:
+ url(../../../../ui/webui/resources/images/supervisor_account.svg);
+ background-color: var(--google-blue-500);
+ display: initial;
+ }
+
+ .pod.child .child-indicator {
+ -webkit-mask-image:
+ url(../../../../ui/webui/resources/images/account_child_invert.svg);
+ background-color: var(--google-blue-500);
+ 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: var(--paper-grey-800);
+ 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: var(--google-grey-100);
+ 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 {
+ height: 30px;
+ }
+
+ .action-box-remove-user-warning .remove-warning-button:focus {
+ /* Override the default blue border inherited from
+ button.custom-appearance:focus. */
+ border: 1px solid transparent !important;
+ box-shadow: inset 0 0 0 1px #fff;
+ }
+ </style>
+ </template>
+</dom-module>
diff --git a/chromium/chrome/browser/resources/md_user_manager/user_manager_tutorial.css b/chromium/chrome/browser/resources/md_user_manager/user_manager_tutorial.css
new file mode 100644
index 00000000000..625d78dd9c6
--- /dev/null
+++ b/chromium/chrome/browser/resources/md_user_manager/user_manager_tutorial.css
@@ -0,0 +1,160 @@
+/* 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. */
+
+.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;
+}
+
+:host.single-pod #yourChrome,
+:host.single-pod #complete {
+ -webkit-margin-start: 30px;
+}
+
+#guests {
+ bottom: 20px;
+ left: auto;
+ margin: 0;
+ right: 100px;
+ top: auto;
+}
+
+:host-context([dir='rtl']) #guests {
+ left: 100px;
+ right: auto;
+}
+
+#friends,
+#notYou {
+ bottom: 20px;
+ left: auto;
+ margin: 0;
+ right: 20px;
+ top: auto;
+}
+
+:host-context([dir='rtl']) #friends,
+:host-context([dir='rtl']) #notYou {
+ left: 20px;
+ right: auto;
+}
+
+#notYou {
+ height: 100px;
+ width: 240px;
+}
+
+.slide-contents {
+ padding: 0 20px;
+ text-align: center;
+}
+
+.slide-title {
+ color: black;
+ font-size: 20px;
+ line-height: 20px;
+ margin: 30px 0;
+}
+
+.slide-text {
+ color: var(--google-grey-600);
+ 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;
+}
+
+.arrow-down {
+ border-left: 15px solid transparent;
+ border-right: 15px solid transparent;
+ border-top: 15px solid white;
+ bottom: -15px;
+ height: 0;
+ position: absolute;
+ right: 40px;
+ width: 0;
+}
+
+:host-context([dir='rtl']) .arrow-down {
+ left: 40px;
+ right: auto;
+}
+
+#guests .arrow-down {
+ right: 110px;
+}
+
+:host-context([dir='rtl']) #guests .arrow-down {
+ left: 110px;
+ right: auto;
+}
+
+.slide-image {
+ height: 182px;
+}
+
+#yourChrome .slide-image {
+ background-color: rgb(241, 202, 58);
+ background-image:
+ url(chrome://theme/IDR_ICON_USER_MANAGER_TUTORIAL_YOUR_CHROME);
+}
+
+#guests .slide-image {
+ background-color: rgb(90, 196, 144);
+ background-image: url(chrome://theme/IDR_ICON_USER_MANAGER_TUTORIAL_GUESTS);
+}
+
+#friends .slide-image {
+ background-color: var(--paper-light-blue-100);
+ background-image:
+ url(chrome://theme/IDR_ICON_USER_MANAGER_TUTORIAL_FRIENDS);
+}
+
+#complete .slide-image {
+ background-color: white;
+ background-image:
+ url(chrome://theme/IDR_ICON_USER_MANAGER_TUTORIAL_COMPLETE);
+}
+
+#notYou #dismiss {
+ position: absolute;
+ right: 5px;
+ top: 5px;
+}
+
+#notYou #slide-add-user {
+ margin-top: 10px;
+}
+
+:host-context([dir='rtl']) #notYou #dismiss {
+ left: 5px;
+ right: auto;
+}
diff --git a/chromium/chrome/browser/resources/md_user_manager/user_manager_tutorial.html b/chromium/chrome/browser/resources/md_user_manager/user_manager_tutorial.html
new file mode 100644
index 00000000000..25c81bc844c
--- /dev/null
+++ b/chromium/chrome/browser/resources/md_user_manager/user_manager_tutorial.html
@@ -0,0 +1,96 @@
+<link rel="import" href="chrome://md-user-manager/shared_styles.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-icon/iron-icon.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html">
+
+<dom-module id="user-manager-tutorial">
+ <link rel="import" type="css"
+ href="chrome://md-user-manager/user_manager_tutorial.css">
+ <link rel="import" type="css" href="chrome://resources/css/action_link.css">
+ <template>
+ <style include="shared-styles"></style>
+ <template is="dom-if" if="[[!hidden_]]">
+ <template is="dom-if"
+ if="[[!isStepHidden_(currentStep_, steps_.YOUR_CHROME)]]">
+ <div class="tutorial-slide" id="[[steps_.YOUR_CHROME]]">
+ <div class="slide-image"></div>
+ <div class="slide-contents">
+ <div class="slide-title">[[i18n('slideYourChromeTitle')]]</div>
+ <div class="slide-text">[[i18n('slideYourChromeText')]]</div>
+ </div>
+ <div class="slide-buttons">
+ <paper-button on-tap="onNextTap_" data-next$="[[steps_.GUESTS]]">
+ [[i18n('tutorialNext')]]
+ </paper-button>
+ </div>
+ </div>
+ </template>
+ <template is="dom-if"
+ if="[[!isStepHidden_(currentStep_, steps_.GUESTS)]]">
+ <div class="tutorial-slide" id="[[steps_.GUESTS]]">
+ <div class="slide-image"></div>
+ <div class="slide-contents">
+ <div class="slide-title">[[i18n('slideGuestsTitle')]]</div>
+ <div class="slide-text">[[i18n('slideGuestsText')]]</div>
+ </div>
+ <div class="slide-buttons">
+ <paper-button on-tap="onNextTap_" data-next$="[[steps_.FRIENDS]]">
+ [[i18n('tutorialNext')]]
+ </paper-button>
+ </div>
+ <div class="arrow-down"></div>
+ </div>
+ </template>
+ <template is="dom-if"
+ if="[[!isStepHidden_(currentStep_, steps_.FRIENDS)]]">
+ <div class="tutorial-slide" id="[[steps_.FRIENDS]]">
+ <div class="slide-image"></div>
+ <div class="slide-contents">
+ <div class="slide-title">[[i18n('slideFriendsTitle')]]</div>
+ <div class="slide-text">[[i18n('slideFriendsText')]]</div>
+ </div>
+ <div class="slide-buttons">
+ <paper-button on-tap="onNextTap_" data-next$="[[steps_.COMPLETE]]">
+ [[i18n('tutorialNext')]]
+ </paper-button>
+ </div>
+ <div class="arrow-down"></div>
+ </div>
+ </template>
+ <template is="dom-if"
+ if="[[!isStepHidden_(currentStep_, steps_.COMPLETE)]]">
+ <div class="tutorial-slide" id="[[steps_.COMPLETE]]">
+ <div class="slide-image"></div>
+ <div class="slide-contents">
+ <div class="slide-title">[[i18n('slideCompleteTitle')]]</div>
+ <div class="slide-text">[[i18n('slideCompleteText')]]</div>
+ </div>
+ <div class="slide-buttons">
+ <paper-button on-tap="onNextTap_" data-next$="[[steps_.NOT_YOU]]">
+ [[i18n('tutorialDone')]]
+ </paper-button>
+ </div>
+ </div>
+ </template>
+ <template is="dom-if" if="[[!isStepHidden_(currentStep_, 'notYou')]]">
+ <div class="tutorial-slide" id="notYou">
+ <iron-icon id="dismiss" icon="close" on-tap="onDissmissTap_">
+ </iron-icon>
+ <div class="slide-buttons">
+ <div class="slide-text">
+ [[i18n('slideCompleteUserNotFound')]]
+ </div>
+ <div id="slide-add-user">
+ <a id="addUser" is="action-link" on-tap="onAddUserTap_">
+ [[i18n('slideCompleteAddUser')]]
+ </a>
+ </div>
+ </div>
+ <div class="arrow-down"></div>
+ </div>
+ </template>
+ </template>
+ </template>
+ <script src="chrome://md-user-manager/user_manager_tutorial.js"></script>
+</dom-module>
diff --git a/chromium/chrome/browser/resources/md_user_manager/user_manager_tutorial.js b/chromium/chrome/browser/resources/md_user_manager/user_manager_tutorial.js
new file mode 100644
index 00000000000..10ca08a20a8
--- /dev/null
+++ b/chromium/chrome/browser/resources/md_user_manager/user_manager_tutorial.js
@@ -0,0 +1,118 @@
+// 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 'user-manager-tutorial' is the element that controls the
+ * tutorial steps for the user manager page.
+ */
+(function() {
+
+/** @enum {string} */
+var TutorialSteps = {
+ YOUR_CHROME: 'yourChrome',
+ FRIENDS: 'friends',
+ GUESTS: 'guests',
+ COMPLETE: 'complete',
+ NOT_YOU: 'notYou'
+};
+
+Polymer({
+ is: 'user-manager-tutorial',
+
+ behaviors: [
+ I18nBehavior,
+ ],
+
+ properties: {
+ /**
+ * True if the tutorial is currently hidden.
+ * @private {boolean}
+ */
+ hidden_: {
+ type: Boolean,
+ value: true
+ },
+
+ /**
+ * Current tutorial step ID.
+ * @type {string}
+ */
+ currentStep_: {
+ type: String,
+ value: ''
+ },
+
+ /**
+ * Enum values for the step IDs.
+ * @private {TutorialSteps}
+ */
+ steps_: {
+ readOnly: true,
+ type: Object,
+ value: TutorialSteps
+ }
+ },
+
+ /**
+ * Determines whether a given step is displaying.
+ * @param {string} currentStep Index of the current step
+ * @param {string} step Name of the given step
+ * @return {boolean}
+ * @private
+ */
+ isStepHidden_: function(currentStep, step) {
+ return currentStep != step;
+ },
+
+ /**
+ * Navigates to the next step.
+ * @param {!Event} event
+ * @private
+ */
+ onNextTap_: function(event) {
+ var element = Polymer.dom(event).rootTarget;
+ this.currentStep_ = element.dataset.next;
+ },
+
+ /**
+ * Handler for the link in the last step. Takes user to the create-profile
+ * page in order to add a new profile.
+ * @param {!Event} event
+ * @private
+ */
+ onAddUserTap_: function(event) {
+ this.onDissmissTap_();
+ // Event is caught by user-manager-pages.
+ this.fire('change-page', {page: 'create-user-page'});
+ },
+
+ /**
+ * Starts the tutorial.
+ */
+ startTutorial: function() {
+ this.currentStep_ = TutorialSteps.YOUR_CHROME;
+ this.hidden_ = false;
+
+ // If there's only one pod, show the steps to the side of the pod.
+ // Otherwise, center the steps and disable interacting with the pods
+ // while the tutorial is showing.
+ var podRow = /** @type {{focusPod: !function(), pods: !Array}} */
+ ($('pod-row'));
+
+ this.classList.toggle('single-pod', podRow.pods.length == 1);
+
+ podRow.focusPod(); // No focused pods.
+ $('inner-container').classList.add('disabled');
+ },
+
+ /**
+ * Ends the tutorial.
+ * @private
+ */
+ onDissmissTap_: function() {
+ $('inner-container').classList.remove('disabled');
+ this.hidden_ = true;
+ }
+});
+})();
diff --git a/chromium/chrome/browser/resources/media_router/compiled_resources.gyp b/chromium/chrome/browser/resources/media_router/compiled_resources.gyp
index 5b7abe5f47f..614b3699428 100644
--- a/chromium/chrome/browser/resources/media_router/compiled_resources.gyp
+++ b/chromium/chrome/browser/resources/media_router/compiled_resources.gyp
@@ -34,6 +34,7 @@
'../../../../third_party/polymer/v1_0/components-chromium/paper-toolbar/paper-toolbar-extracted.js',
'../../../../ui/webui/resources/js/cr.js',
'../../../../ui/webui/resources/js/compiled_resources.gyp:load_time_data',
+ '../../../../ui/webui/resources/js/promise_resolver.js',
'../../../../ui/webui/resources/js/util.js',
'media_router.js',
'media_router_data.js',
@@ -42,6 +43,7 @@
'elements/route_details/route_details.js',
'elements/media_router_header/media_router_header.js',
'elements/media_router_container/media_router_container.js',
+ 'elements/media_router_search_highlighter/media_router_search_highlighter.js',
],
'externs': [
'<(EXTERNS_DIR)/chrome_send.js',
diff --git a/chromium/chrome/browser/resources/media_router/elements/issue_banner/issue_banner.css b/chromium/chrome/browser/resources/media_router/elements/issue_banner/issue_banner.css
index b06922b84b9..9730fa99f82 100644
--- a/chromium/chrome/browser/resources/media_router/elements/issue_banner/issue_banner.css
+++ b/chromium/chrome/browser/resources/media_router/elements/issue_banner/issue_banner.css
@@ -22,14 +22,14 @@
}
#blocking-icon {
- color: rgb(219, 68, 55);
+ color: var(--google-red-500);
height: 75px;
padding-top: 24px;
width: 75px;
}
.non-blocking {
- background-color: rgb(66, 66, 66);
+ background-color: var(--paper-grey-800);
overflow: hidden;
padding: 16px;
}
diff --git a/chromium/chrome/browser/resources/media_router/elements/issue_banner/issue_banner.html b/chromium/chrome/browser/resources/media_router/elements/issue_banner/issue_banner.html
index d5f02adbcdb..193f1a74cdf 100644
--- a/chromium/chrome/browser/resources/media_router/elements/issue_banner/issue_banner.html
+++ b/chromium/chrome/browser/resources/media_router/elements/issue_banner/issue_banner.html
@@ -1,4 +1,4 @@
-<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.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/polymer/v1_0/paper-button/paper-button.html">
<dom-module name="issue-banner">
@@ -15,12 +15,12 @@
</div>
<div id="buttons">
<paper-button flat id="opt-button" class="button"
- on-click="onClickOptAction_"
+ on-tap="onClickOptAction_"
hidden$="[[computeOptionalActionHidden_(issue)]]">
<span>[[secondaryActionButtonText_]]</span>
</paper-button>
<paper-button flat id="default-button"
- class="button action" on-click="onClickDefaultAction_">
+ class="button action" on-tap="onClickDefaultAction_">
<span>[[defaultActionButtonText_]]</span>
</paper-button>
</div>
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 1d675fe4d91..99ccd760ff7 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
@@ -2,24 +2,19 @@
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file. */
-:root {
- --container-header-height: 52px;
-}
-
.active-sink {
- color: rgb(33, 150, 243);
+ color: var(--paper-blue-700);
}
.cast-mode-icon,
.sink-icon {
-webkit-padding-end: 12px;
- -webkit-padding-start: 16px;
- height: 16px;
- width: 16px;
+ -webkit-padding-start: var(--dialog-padding-start);
+ height: var(--non-navigation-icon-size);
+ width: var(--non-navigation-icon-size);
}
#cast-mode-list {
- margin-top: var(--container-header-height);
padding-bottom: 12px;
padding-top: 4px;
}
@@ -27,20 +22,19 @@
#container-header {
position: fixed;
width: 100%;
- z-index: 1;
}
#device-missing {
align-items: center;
background-color: white;
display: flex;
- height: 120px;
justify-content: center;
- margin-top: var(--container-header-height);
+ margin: 60px 0;
}
#device-missing a {
- color: rgba(33, 150, 243, 0.87);
+ color: var(--paper-blue-700);
+ margin: 8px 0;
text-decoration: none;
}
@@ -54,22 +48,30 @@
justify-content: flex-end;
}
-#first-run-flow {
- background-color: rgb(33, 150, 243);
- padding: 24px 16px 4px 16px;
- position: fixed;
- z-index: 1;
+#first-run-cloud-checkbox,
+#first-run-flow-cloud-pref,
+#first-run-text {
+ font-size: 1.0em;
+ line-height: 1.5em;
}
+#first-run-cloud-checkbox,
#first-run-text,
#first-run-title {
color: white;
padding-bottom: 24px;
}
-#first-run-text {
- font-size: 1.0em;
- line-height: 1.5em;
+#first-run-cloud-checkbox::shadow #checkboxLabel {
+ -webkit-padding-start: var(-dialog-padding-start);
+}
+
+#first-run-flow {
+ background-color: var(--paper-blue-700);
+ box-sizing: border-box;
+ padding: 24px 16px 4px 16px;
+ position: fixed;
+ width: 100%;
}
#first-run-flow a {
@@ -77,6 +79,11 @@
text-decoration: none;
}
+#first-run-flow-cloud-pref {
+ color: white;
+ display: flex;
+}
+
.first-run-learn-more {
font-weight: bold;
text-transform: uppercase;
@@ -87,15 +94,30 @@
}
#issue-banner {
- margin-top: var(--container-header-height);
width: 100%;
}
#issue-banner.non-blocking {
bottom: 0;
+ display: block;
margin-top: 0;
}
+#no-search-matches {
+ color: rgb(112, 112, 112);
+ display: block;
+ font-size: 1.2 em;
+ padding-bottom: 20px;
+ padding-top: 20px;
+ text-align: center;
+}
+
+paper-checkbox {
+ --paper-checkbox-checked-color: white;
+ --paper-checkbox-checkmark-color: var(--paper-blue-700);
+ --paper-checkbox-unchecked-color: white;
+}
+
paper-item {
cursor: pointer;
font-size: 1.0em;
@@ -118,18 +140,29 @@ paper-menu {
padding-top: 4px;
}
+#search-input-container {
+ flex-grow: 1;
+}
+
#searching-devices-spinner {
height: 30px;
width: 30px;
}
#share-screen-text {
- -webkit-padding-start: 16px;
- color: rgb(150, 150, 150);
+ -webkit-padding-start: var(--dialog-padding-start);
+ color: var(--paper-grey-600);
+ cursor: default;
+ font-weight: normal;
padding-bottom: 4px;
padding-top: 12px;
}
+#share-screen-text::after {
+ background-color: white;
+ font-weight: normal;
+}
+
.sink-content {
display: flex;
flex-direction: row;
@@ -138,24 +171,61 @@ paper-menu {
.sink-domain {
-webkit-padding-start: 6px;
- color: rgb(150, 150, 150);
+ color: var(--paper-grey-600);
+ /* TODO(crbug/589697): Handle overflow of very long domain names. */
+}
+
+#sink-list {
+ padding-bottom: 0;
+}
+
+.sink-name {
+ min-width: 10%;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+#sink-search.bottom {
+ padding-bottom: 16px;
+}
+
+/* Separate icon class is a consequence of box-sizing: border-box set by
+ * paper-icon-button. This should achieve the same dimensions as .sink-icon.
+ */
+#sink-search-icon {
+ -webkit-margin-start: 4px;
+ -webkit-padding-end: 12px;
+ -webkit-padding-start: 12px;
+}
+
+#sink-search-input {
+ --paper-input-container: {
+ margin: 8px 0;
+ padding: 0;
+ };
+ --paper-input-container-focus-color: rgb(33, 150, 243);
+ --paper-input-container-input: {
+ font-size: 12px;
+ };
+ --paper-input-container-label: {
+ font-size: 12px;
+ };
+ -webkit-margin-end: 31px;
+ box-sizing: border-box;
}
.sink-subtext {
- color: rgb(150, 150, 150);
+ color: var(--paper-grey-600);
padding-top: 8px;
}
.sink-text {
- -webkit-padding-end: 26px;
+ -webkit-padding-end: var(--dialog-padding-end);
+ display: inline-flex;
flex-direction: row;
+ flex-flow: row nowrap;
line-height: normal;
- overflow: hidden;
- text-overflow: ellipsis;
white-space: nowrap;
width: 250px;
}
-#route-details {
- margin-top: var(--container-header-height);
-}
diff --git a/chromium/chrome/browser/resources/media_router/elements/media_router_container/media_router_container.html b/chromium/chrome/browser/resources/media_router/elements/media_router_container/media_router_container.html
index cfafdac6db6..1c2d42a0b94 100644
--- a/chromium/chrome/browser/resources/media_router/elements/media_router_container/media_router_container.html
+++ b/chromium/chrome/browser/resources/media_router/elements/media_router_container/media_router_container.html
@@ -1,34 +1,54 @@
-<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.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/polymer/v1_0/iron-icons/av-icons.html">
<link rel="import" href="chrome://resources/polymer/v1_0/iron-icons/communication-icons.html">
<link rel="import" href="chrome://resources/polymer/v1_0/iron-icons/hardware-icons.html">
<link rel="import" href="chrome://resources/polymer/v1_0/iron-icons/iron-icons.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-input/paper-input.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-spinner/paper-spinner.html">
<link rel="import" href="../issue_banner/issue_banner.html">
<link rel="import" href="../media_router_header/media_router_header.html">
+<link rel="import" href="../media_router_search_highlighter/media_router_search_highlighter.html">
<link rel="import" href="../route_details/route_details.html">
+<link rel="import" href="../../icons/media_router_icons.html">
<dom-module id="media-router-container">
<link rel="import" type="css" href="../../media_router_common.css">
<link rel="import" type="css" href="media_router_container.css">
<template>
+ <div id="focus-placeholder" tabindex="0"></div>
<template is="dom-if"
if="[[computeShowFirstRunFlow_(showFirstRunFlow, currentView_)]]">
<div id="first-run-flow">
<div id="first-run-title">[[firstRunFlowTitle_]]</div>
<div id="first-run-text">
<span>[[firstRunFlowText_]]</span>
- <a href="[[firstRunFlowLearnMoreUrl]]">
+ <a href="[[firstRunFlowLearnMoreUrl]]" target="_blank">
<span class="first-run-learn-more">
[[firstRunFlowLearnMore_]]
</span>
</a>
</div>
+ <div id="first-run-flow-cloud-pref"
+ hidden$="[[!showFirstRunFlowCloudPref]]">
+ <div>
+ <paper-checkbox checked id="first-run-cloud-checkbox">
+ </paper-checkbox>
+ </div>
+ <div>
+ <span>[[firstRunFlowCloudPrefText_]]</span>
+ <a href="[[firstRunFlowCloudPrefLearnMoreUrl]]" target="_blank">
+ <span class="first-run-learn-more">
+ [[firstRunFlowLearnMore_]]
+ </span>
+ </a>
+ </div>
+ </div>
<div id="first-run-button-container">
<paper-button id="first-run-button" class="button"
- on-click="acknowledgeFirstRunFlow_">
+ on-tap="acknowledgeFirstRunFlow_">
<span>[[firstRunFlowButtonText_]]</span>
</paper-button>
</div>
@@ -41,95 +61,162 @@
tooltip="[[computeHeaderTooltip_(currentView_, headerTextTooltip)]]"
on-back-click="showSinkList_">
</media-router-header>
- <template is="dom-if" if="[[!computeCastModeListHidden_(currentView_)]]">
- <paper-menu id="cast-mode-list">
- <template is="dom-repeat" id="defaultCastModeList"
- items="[[computeDefaultCastModeList_(castModeList)]]">
- <paper-item on-click="onCastModeClick_">
- <iron-icon class="cast-mode-icon"
- icon="[[computeCastModeIcon_(item)]]">
- </iron-icon>
- <div><span>[[item.host]]</span></div>
- </paper-item>
- </template>
- <div id="share-screen-text"
- hidden$="[[computeShareScreenSubheadingHidden_(castModeList)]]">
- <span>[[shareYourScreenSubheadingText_]]</span>
+ <div id="content">
+ <template is="dom-if" if="[[!computeCastModeListHidden_(currentView_)]]">
+ <paper-menu id="cast-mode-list" role="presentation">
+ <template is="dom-repeat" id="defaultCastModeList"
+ items="[[computeDefaultCastModeList_(castModeList)]]">
+ <paper-item on-tap="onCastModeClick_">
+ <iron-icon class="cast-mode-icon"
+ icon="[[computeCastModeIcon_(item)]]">
+ </iron-icon>
+ <div><span>[[item.host]]</span></div>
+ </paper-item>
+ </template>
+ <div id="share-screen-text"
+ hidden$="[[computeShareScreenSubheadingHidden_(castModeList)]]">
+ <span>[[shareYourScreenSubheadingText_]]</span>
+ </div>
+ <template is="dom-repeat" id="nonDefaultCastModeList"
+ items="[[computeNonDefaultCastModeList_(castModeList)]]">
+ <paper-item on-tap="onCastModeClick_">
+ <iron-icon class="cast-mode-icon"
+ icon="[[computeCastModeIcon_(item)]]">
+ </iron-icon>
+ <div><span>[[item.description]]</span></div>
+ </paper-item>
+ </template>
+ </paper-menu>
+ </template>
+ <template is="dom-if"
+ if="[[!computeRouteDetailsHidden_(currentView_, issue)]]">
+ <route-details id="route-details" route="[[currentRoute_]]"
+ on-close-route-click="onCloseRouteClick_">
+ </route-details>
+ </template>
+ <div id="sink-list-view"
+ hidden$="[[computeSinkListViewHidden_(currentView_, issue)]]">
+ <div id="device-missing"
+ hidden$="[[computeDeviceMissingHidden_(sinksToShow_)]]">
+ <paper-spinner id="searching-devices-spinner" active
+ hidden$="[[computeSpinnerHidden_(justOpened_)]]">
+ </paper-spinner>
+ <a href="[[deviceMissingUrl]]" target="_blank"
+ hidden$="[[!computeSpinnerHidden_(justOpened_)]]">
+ [[deviceMissingText_]]
+ </a>
</div>
- <template is="dom-repeat" id="nonDefaultCastModeList"
- items="[[computeNonDefaultCastModeList_(castModeList)]]">
- <paper-item on-click="onCastModeClick_">
- <iron-icon class="cast-mode-icon"
- icon="[[computeCastModeIcon_(item)]]">
- </iron-icon>
- <div><span>[[item.description]]</span></div>
- </paper-item>
- </template>
- </paper-menu>
- </template>
- <template is="dom-if"
- if="[[!computeRouteDetailsHidden_(currentView_, issue)]]">
- <route-details id="route-details" route="[[currentRoute_]]"
- on-close-route-click="onCloseRouteClick_">
- </route-details>
- </template>
- <div id="sink-list-view"
- hidden$="[[computeSinkListViewHidden_(currentView_, issue)]]">
- <div id="device-missing"
- hidden$="[[!computeSinkListHidden_(sinksToShow_)]]">
- <paper-spinner id="searching-devices-spinner" active
- hidden$="[[computeSpinnerHidden_(justOpened_)]]">
- </paper-spinner>
- <a href="[[deviceMissingUrl]]">
- <span hidden$="[[!computeSpinnerHidden_(justOpened_)]]"
- >[[deviceMissingText_]]</span>
- </a>
- </div>
- <paper-menu id="sink-list"
- hidden$="[[computeSinkListHidden_(sinksToShow_)]]">
- <template is="dom-repeat" id="sinkList" items="[[sinksToShow_]]">
- <paper-item class="sink" on-click="onSinkClick_">
- <div class="sink-content">
- <div>
- <iron-icon icon="[[computeSinkIcon_(item)]]"
- hidden$="[[computeSinkIsLaunching_(currentLaunchingSinkId_, item.id)]]"
- class$="[[computeSinkIconClass_(item.id, sinkToRouteMap_)]]">
- </iron-icon>
- <template is="dom-if"
- if="[[computeSinkIsLaunching_(currentLaunchingSinkId_, item.id)]]">
- <paper-spinner class="sink-icon" active>
- </paper-spinner>
- </template>
- </div>
- <div>
- <div class="sink-text">
- <span dir="auto">[[item.name]]</span>
+ <paper-menu id="sink-list" role="presentation"
+ hidden$="[[computeSinkListHidden_(sinksToShow_, isUserSearching_)]]">
+ <template is="dom-repeat" id="sinkList" items="[[sinksToShow_]]">
+ <paper-item on-tap="onSinkClick_">
+ <div class="sink-content">
+ <div>
+ <iron-icon icon="[[computeSinkIcon_(item)]]"
+ hidden$="[[computeSinkIsLaunching_(currentLaunchingSinkId_, item.id)]]"
+ class$="[[computeSinkIconClass_(item.id, sinkToRouteMap_)]]">
+ </iron-icon>
<template is="dom-if"
- if="[[!computeSinkDomainHidden_(item)]]">
- <span class="sink-domain">
- [[item.domain]]
- </span>
+ if="[[computeSinkIsLaunching_(currentLaunchingSinkId_, item.id)]]">
+ <paper-spinner class="sink-icon" active>
+ </paper-spinner>
</template>
</div>
- <template is="dom-if"
- if="[[!computeSinkSubtextHidden_(item, sinkToRouteMap_)]]">
- <div class="sink-text sink-subtext">
- <span>[[computeSinkSubtext_(item, sinkToRouteMap_)]]</span>
+ <div>
+ <div class="sink-text">
+ <span dir="auto" class="sink-name" title="[[item.name]]">
+ [[item.name]]
+ </span>
+ <template is="dom-if"
+ if="[[!computeSinkDomainHidden_(item)]]">
+ <span class="sink-domain" title="[[item.domain]]">
+ [[item.domain]]
+ </span>
+ </template>
</div>
- </template>
+ <template is="dom-if"
+ if="[[!computeSinkSubtextHidden_(item, sinkToRouteMap_)]]">
+ <div class="sink-text sink-subtext">
+ <span>[[computeSinkSubtext_(item, sinkToRouteMap_)]]</span>
+ </div>
+ </template>
+ </div>
</div>
+ </paper-item>
+ </template>
+ </paper-menu>
+ <div id="sink-search" class$="[[computeSinkSearchClass_(currentView_)]]">
+ <div class="sink-content">
+ <div>
+ <paper-icon-button id="sink-search-icon" icon="search"
+ on-tap="searchButtonClick_" title="[[searchButtonTitle_]]">
+ </paper-icon-button>
</div>
- </paper-item>
+ <div id="search-input-container">
+ <paper-input id="sink-search-input" label="[[searchInputLabel_]]"
+ no-label-float value="{{searchInputText_}}">
+ </paper-input>
+ </div>
+ </div>
+ </div>
+ <template is="dom-if" if="[[isUserSearching_]]">
+ <div id="no-search-matches"
+ hidden$="[[computeNoMatchesHidden_(searchResultsToShow_, isUserSearching_)]]">
+ <span>[[searchNoMatchesText_]]</span>
+ </div>
+ <paper-menu id="search-results" selected="0" role="presentation"
+ hidden$="[[computeSearchResultsHidden_(isUserSearching_, searchResultsToShow_)]]">
+ <template is="dom-repeat" id="searchResults"
+ items="[[searchResultsToShow_]]">
+ <paper-item class="search-item" on-tap="onSinkClick_">
+ <div class="sink-content">
+ <div>
+ <iron-icon icon="[[computeSinkIcon_(item.sinkItem)]]"
+ hidden$="[[computeSinkIsLaunching_(currentLaunchingSinkId_, item.sinkItem.id)]]"
+ class$="[[computeSinkIconClass_(item.sinkItem.id, sinkToRouteMap_)]]">
+ </iron-icon>
+ <template is="dom-if"
+ if="[[computeSinkIsLaunching_(currentLaunchingSinkId_, item.sinkItem.id)]]">
+ <paper-spinner class="sink-icon" active>
+ </paper-spinner>
+ </template>
+ </div>
+ <div>
+ <div class="sink-text">
+ <media-router-search-highlighter class="sink-name"
+ data="[[computeSinkMatchingText_(item)]]"
+ title="[[item.sinkItem.name]]">
+ </media-router-search-highlighter>
+ <template is="dom-if"
+ if="[[!computeSinkDomainHidden_(item.sinkItem)]]">
+ <span class="sink-domain" title="[[item.sinkItem.domain]]">
+ [[item.sinkItem.domain]]
+ </span>
+ </template>
+ </div>
+ <template is="dom-if"
+ if="[[!computeSinkSubtextHidden_(item.sinkItem, sinkToRouteMap_)]]">
+ <div class="sink-text sink-subtext">
+ <span>
+ [[computeSinkSubtext_(item.sinkItem, sinkToRouteMap_)]]
+ </span>
+ </div>
+ </template>
+ </div>
+ </div>
+ </paper-item>
+ </template>
+ </paper-menu>
</template>
- </paper-menu>
+ </div>
+ <template is="dom-if"
+ if="[[computeIssueBannerShown_(currentView_, issue)]]">
+ <issue-banner id="issue-banner" issue="[[issue]]"
+ class$="[[computeIssueBannerClass_(issue)]]"
+ on-issue-action-tap="showSinkList_">
+ </issue-banner>
+ </template>
</div>
- <template is="dom-if"
- if="[[computeIssueBannerShown_(currentView_, issue)]]">
- <issue-banner id="issue-banner" issue="[[issue]]"
- class$="[[computeIssueBannerClass_(issue)]]"
- on-issue-action-click="showSinkList_">
- </issue-banner>
- </template>
</template>
<script src="media_router_container.js"></script>
</dom-module>
diff --git a/chromium/chrome/browser/resources/media_router/elements/media_router_container/media_router_container.js b/chromium/chrome/browser/resources/media_router/elements/media_router_container/media_router_container.js
index 8f38c9dc68e..12ae40f478c 100644
--- a/chromium/chrome/browser/resources/media_router/elements/media_router_container/media_router_container.js
+++ b/chromium/chrome/browser/resources/media_router/elements/media_router_container/media_router_container.js
@@ -53,7 +53,7 @@ Polymer({
currentView_: {
type: String,
value: null,
- observer: 'updateElementPositioning_',
+ observer: 'currentViewChanged_',
},
/**
@@ -119,6 +119,27 @@ Polymer({
},
/**
+ * The URL to open when the cloud services pref learn more link is clicked.
+ * @type {string}
+ */
+ firstRunFlowCloudPrefLearnMoreUrl: {
+ type: String,
+ value: '',
+ },
+
+ /**
+ * The text for the cloud services preference description in the first run
+ * flow.
+ * @private {string}
+ */
+ firstRunFlowCloudPrefText_: {
+ type: String,
+ readOnly: true,
+ value: loadTimeData.valueExists('firstRunFlowCloudPrefText') ?
+ loadTimeData.getString('firstRunFlowCloudPrefText') : '',
+ },
+
+ /**
* The URL to open when the first run flow learn more link is clicked.
* @type {string}
*/
@@ -163,11 +184,55 @@ Polymer({
/**
* The header text tooltip. This would be descriptive of the
* source origin, whether a host name, tab URL, etc.
- * @type {?string}
+ * @type {string}
*/
headerTextTooltip: {
type: String,
- value: null,
+ value: '',
+ },
+
+ /**
+ * Whether the search input is currently focused. This is used to prevent
+ * window focus/blur events from interfering with input-focus-dependent
+ * operations.
+ * @private {boolean}
+ */
+ isSearchFocused_: {
+ type: Boolean,
+ value: false,
+ },
+
+ /**
+ * Records the value of |isSearchFocused_| when a window blur event is
+ * received. This used to handle search focus edge cases. See
+ * |setSearchFocusHandlers_| for details.
+ * @private {boolean}
+ */
+ isSearchFocusedOnWindowBlur_: {
+ type: Boolean,
+ value: false,
+ },
+
+ /**
+ * Temporarily set when the window focus event handler needs to reset
+ * |isSearchFocused_| to the correct value but needs to know whether the
+ * search input focus handler will run. See |setSearchFocusHandlers_| for
+ * details.
+ * @private {boolean}
+ */
+ isSearchFocusedShouldBeSet_: {
+ type: Boolean,
+ value: false,
+ },
+
+ /**
+ * Whether the user is currently searching for a sink.
+ * @private {boolean}
+ */
+ isUserSearching_: {
+ type: Boolean,
+ value: false,
+ observer: 'isUserSearchingChanged_',
},
/**
@@ -233,6 +298,17 @@ Polymer({
},
/**
+ * Whether the next character input should cause a filter action metric to
+ * be sent.
+ * @type {boolean}
+ * @private
+ */
+ reportFilterOnInput_: {
+ type: Boolean,
+ value: false,
+ },
+
+ /**
* The list of current routes.
* @type {!Array<!media_router.Route>}
*/
@@ -252,6 +328,61 @@ Polymer({
},
/**
+ * Title text for the search button.
+ * @private {string}
+ */
+ searchButtonTitle_: {
+ type: String,
+ readOnly: true,
+ value: function() {
+ return loadTimeData.getString('searchButtonTitle');
+ },
+ },
+
+ /**
+ * Label text for the user search input.
+ * @private {string}
+ */
+ searchInputLabel_: {
+ type: String,
+ readOnly: true,
+ value: function() {
+ return loadTimeData.getString('searchInputLabel');
+ },
+ },
+
+ /**
+ * Search text entered by the user into the sink search input.
+ * @private {string}
+ */
+ searchInputText_: {
+ type: String,
+ value: '',
+ observer: 'searchInputTextChanged_',
+ },
+
+ /**
+ * Text to display when a user search returns no matches.
+ * @private {string}
+ */
+ searchNoMatchesText_: {
+ type: String,
+ readOnly: true,
+ value: function() {
+ return loadTimeData.getString('searchNoMatches');
+ },
+ },
+
+ /**
+ * Sinks to display that match |searchInputText_|.
+ * @private {!Array<!media_router.Sink>}
+ */
+ searchResultsToShow_: {
+ type: Array,
+ value: [],
+ },
+
+ /**
* The header text when the cast mode list is shown.
* @private {string}
*/
@@ -276,6 +407,15 @@ Polymer({
},
/**
+ * Whether to show the user domain of sinks associated with identity.
+ * @type {boolean}
+ */
+ showDomain: {
+ type: Boolean,
+ value: false,
+ },
+
+ /**
* Whether to show the first run flow.
* @type {boolean}
*/
@@ -286,6 +426,15 @@ Polymer({
},
/**
+ * Whether to show the cloud preference setting in the first run flow.
+ * @type {boolean}
+ */
+ showFirstRunFlowCloudPref: {
+ type: Boolean,
+ value: false,
+ },
+
+ /**
* The cast mode shown to the user. Initially set to auto mode. (See
* media_router.CastMode documentation for details on auto mode.)
* This value may be changed in one of the following ways:
@@ -351,7 +500,9 @@ Polymer({
},
listeners: {
- 'arrow-drop-click': 'toggleCastModeHidden_',
+ 'focus': 'onFocus_',
+ 'header-height-changed': 'updateElementPositioning_',
+ 'header-or-arrow-click': 'toggleCastModeHidden_',
'mouseleave': 'onMouseLeave_',
'mouseenter': 'onMouseEnter_',
},
@@ -362,6 +513,15 @@ Polymer({
ready: function() {
this.elementReadyTimeMs_ = performance.now();
+
+ // If this is not on a Mac platform, remove the placeholder. See
+ // onFocus_() for more details. ready() is only called once, so no need
+ // to check if the placeholder exist before removing.
+ if (!cr.isMac)
+ this.$$('#focus-placeholder').remove();
+
+ document.addEventListener('keydown', this.onKeydown_.bind(this));
+ this.setSearchFocusHandlers_();
this.showSinkList_();
},
@@ -385,8 +545,16 @@ Polymer({
* @private
*/
acknowledgeFirstRunFlow_: function() {
+ // Only set |userOptedIntoCloudServices| if the user was shown the cloud
+ // services preferences option.
+ var userOptedIntoCloudServices = this.showFirstRunFlowCloudPref ?
+ this.$$('#first-run-cloud-checkbox').checked : undefined;
+ this.fire('acknowledge-first-run-flow', {
+ optedIntoCloudServices: userOptedIntoCloudServices,
+ });
+
this.showFirstRunFlow = false;
- this.fire('acknowledge-first-run-flow');
+ this.showFirstRunFlowCloudPref = false;
},
/**
@@ -433,6 +601,64 @@ Polymer({
},
/**
+ * Compares two search match objects for sorting. Earlier and longer matches
+ * are prioritized.
+ *
+ * @param {!{sinkItem: !media_router.Sink,
+ * substrings: Array<!Array<number>>}} resultA
+ * Parameters in |resultA|:
+ * sinkItem - sink object.
+ * substrings - start-end index pairs of substring matches.
+ * @param {!{sinkItem: !media_router.Sink,
+ * substrings: Array<!Array<number>>}} resultB
+ * Parameters in |resultB|:
+ * sinkItem - sink object.
+ * substrings - start-end index pairs of substring matches.
+ * @return {number} -1 if |resultA| should come before |resultB|, 1 if
+ * |resultB| should come before |resultA|, and 0 if they are considered
+ * equal.
+ */
+ compareSearchMatches_: function(resultA, resultB) {
+ var substringsA = resultA.substrings;
+ var substringsB = resultB.substrings;
+ var numberSubstringsA = substringsA.length;
+ var numberSubstringsB = substringsB.length;
+
+ if (numberSubstringsA == 0 && numberSubstringsB == 0) {
+ return 0;
+ } else if (numberSubstringsA == 0) {
+ return 1;
+ } else if (numberSubstringsB == 0) {
+ return -1;
+ }
+
+ var loopMax = Math.min(numberSubstringsA, numberSubstringsB);
+ for (var i = 0; i < loopMax; ++i) {
+ var [matchStartA, matchEndA] = substringsA[i];
+ var [matchStartB, matchEndB] = substringsB[i];
+
+ if (matchStartA < matchStartB) {
+ return -1;
+ } else if (matchStartA > matchStartB) {
+ return 1;
+ }
+
+ if (matchEndA > matchEndB) {
+ return -1;
+ } else if (matchEndA < matchEndB) {
+ return 1;
+ }
+ }
+
+ if (numberSubstringsA > numberSubstringsB) {
+ return -1;
+ } else if (numberSubstringsA < numberSubstringsB) {
+ return 1;
+ }
+ return 0;
+ },
+
+ /**
* If |allSinks| supports only a single cast mode, returns that cast mode.
* Otherwise, returns AUTO_MODE. Only called if |userHasSelectedCastMode_| is
* |false|.
@@ -500,6 +726,15 @@ Polymer({
},
/**
+ * @param {!Array<!media_router.Sink>} sinksToShow The list of sinks.
+ * @return {boolean} Whether or not to hide the 'devices missing' message.
+ * @private
+ */
+ computeDeviceMissingHidden_: function(sinksToShow) {
+ return sinksToShow.length != 0;
+ },
+
+ /**
* @param {?media_router.MediaRouterView} view The current view.
* @param {?media_router.Issue} issue The current issue.
* @return {boolean} Whether or not to hide the header.
@@ -527,6 +762,7 @@ Polymer({
return this.currentRoute_ ?
this.sinkMap_[this.currentRoute_.sinkId].name : '';
case media_router.MediaRouterView.SINK_LIST:
+ case media_router.MediaRouterView.FILTER:
return this.headerText;
default:
return '';
@@ -574,6 +810,18 @@ Polymer({
},
/**
+ * @param {!Array<!media_router.Sink>} searchResultsToShow The sinks currently
+ * matching the search text.
+ * @param {boolean} isUserSearching Whether the user is searching for sinks.
+ * @return {boolean} Whether or not the 'no matches' message is hidden.
+ * @private
+ */
+ computeNoMatchesHidden_: function(searchResultsToShow, isUserSearching) {
+ return !isUserSearching || this.searchInputText_.length == 0 ||
+ searchResultsToShow.length != 0;
+ },
+
+ /**
* @param {!Array<!media_router.CastMode>} castModeList The current list of
* cast modes.
* @return {!Array<!media_router.CastMode>} The list of non-default cast
@@ -598,6 +846,53 @@ Polymer({
},
/**
+ * Computes an array of substring indices that mark where substrings of
+ * |searchString| occur in |sinkName|.
+ *
+ * @param {string} searchString Search string entered by user.
+ * @param {string} sinkName Sink name being filtered.
+ * @return {Array<!Array<number>>} Array of substring start-end (inclusive)
+ * index pairs if every character in |searchString| was matched, in order,
+ * in |sinkName|. Otherwise it returns null.
+ * @private
+ */
+ computeSearchMatches_: function(searchString, sinkName) {
+ var i = 0;
+ var matchStart = -1;
+ var matchEnd = -1;
+ var matchPairs = [];
+ for (var j = 0; i < searchString.length && j < sinkName.length; ++j) {
+ if (searchString[i].toLocaleLowerCase() ==
+ sinkName[j].toLocaleLowerCase()) {
+ if (matchStart == -1) {
+ matchStart = j;
+ }
+ ++i;
+ } else if (matchStart != -1) {
+ matchEnd = j - 1;
+ matchPairs.push([matchStart, matchEnd]);
+ matchStart = -1;
+ }
+ }
+ if (matchStart != -1) {
+ matchEnd = j - 1;
+ matchPairs.push([matchStart, matchEnd]);
+ }
+ return (i == searchString.length) ? matchPairs : null;
+ },
+
+ /**
+ * Computes whether the search results list should be hidden.
+ * @param {boolean} isUserSearching Whether the user is searching for sinks.
+ * @param {!Array<!media_router.Sink>} searchResultsToShow The sinks currently
+ * @return {boolean} Whether the search results list should be hidden.
+ * @private
+ */
+ computeSearchResultsHidden_: function(isUserSearching, searchResultsToShow) {
+ return !isUserSearching || searchResultsToShow.length == 0;
+ },
+
+ /**
* @param {!Array<!media_router.CastMode>} castModeList The current list of
* cast modes.
* @return {boolean} Whether or not to hide the share screen subheading text.
@@ -629,7 +924,7 @@ Polymer({
computeSinkIcon_: function(sink) {
switch (sink.iconType) {
case media_router.SinkIconType.CAST:
- return 'hardware:tv';
+ return 'media-router:chromecast';
case media_router.SinkIconType.CAST_AUDIO:
return 'hardware:speaker';
case media_router.SinkIconType.CAST_AUDIO_GROUP:
@@ -637,7 +932,7 @@ Polymer({
case media_router.SinkIconType.GENERIC:
return 'hardware:tv';
case media_router.SinkIconType.HANGOUT:
- return 'communication:message';
+ return 'media-router:hangout';
default:
return 'hardware:tv';
}
@@ -667,11 +962,12 @@ Polymer({
/**
* @param {!Array<!media_router.Sink>} sinksToShow The list of sinks.
+ * @param {boolean} isUserSearching Whether the user is searching for sinks.
* @return {boolean} Whether or not to hide the sink list.
* @private
*/
- computeSinkListHidden_: function(sinksToShow) {
- return sinksToShow.length == 0;
+ computeSinkListHidden_: function(sinksToShow, isUserSearching) {
+ return sinksToShow.length == 0 || isUserSearching;
},
/**
@@ -681,7 +977,8 @@ Polymer({
* @private
*/
computeSinkListViewHidden_: function(view, issue) {
- return view != media_router.MediaRouterView.SINK_LIST ||
+ return (view != media_router.MediaRouterView.SINK_LIST &&
+ view != media_router.MediaRouterView.FILTER) ||
(!!issue && issue.isBlocking);
},
@@ -692,9 +989,65 @@ Polymer({
* @private
*/
computeSinkDomainHidden_: function(sink) {
- // TODO(amp): Check the domain of Chrome profile identity and only show the
- // sink domain if it doesn't match the profile domain. crbug.com/570797
- return this.isEmptyOrWhitespace_(sink.domain);
+ return !this.showDomain || this.isEmptyOrWhitespace_(sink.domain);
+ },
+
+ /**
+ * Computes which portions of a sink name, if any, should be highlighted when
+ * displayed in the filter view. Any substrings matching the search text
+ * should be highlighted.
+ *
+ * The order the strings are combined is plainText[0] highlightedText[0]
+ * plainText[1] highlightedText[1] etc.
+ *
+ * @param {!{sinkItem: !media_router.Sink,
+ * substrings: !Array<!Array<number>>}} matchedItem
+ * Parameters in matchedItem:
+ * sinkItem - Original !media_router.Sink from the sink list.
+ * substrings - List of index pairs denoting substrings of sinkItem.name
+ * that match |searchInputText_|.
+ * @return {!{highlightedText: !Array<string>, plainText: !Array<string>}}
+ * highlightedText - Array of strings that should be displayed highlighted.
+ * plainText - Array of strings that should be displayed normally.
+ * @private
+ */
+ computeSinkMatchingText_: function(matchedItem) {
+ if (!matchedItem.substrings) {
+ return {highlightedText: [null], plainText: [matchedItem.sinkItem.name]};
+ }
+ var lastMatchIndex = -1;
+ var nameIndex = 0;
+ var sinkName = matchedItem.sinkItem.name;
+ var highlightedText = [];
+ var plainText = [];
+ for (var i = 0; i < matchedItem.substrings.length; ++i) {
+ var [matchStart, matchEnd] = matchedItem.substrings[i];
+ if (lastMatchIndex + 1 < matchStart) {
+ plainText.push(sinkName.substring(lastMatchIndex + 1, matchStart));
+ } else {
+ plainText.push(null);
+ }
+ highlightedText.push(sinkName.substring(matchStart, matchEnd + 1));
+ lastMatchIndex = matchEnd;
+ }
+ if (lastMatchIndex + 1 < sinkName.length) {
+ highlightedText.push(null);
+ plainText.push(sinkName.substring(lastMatchIndex + 1));
+ }
+ return {highlightedText: highlightedText, plainText: plainText};
+ },
+
+ /**
+ * Computes the CSS class for #sink-search depending on whether it is the
+ * first or last item in the list, as indicated by |currentView|.
+ * @param {?media_router.MediaRouterView} currentView The current view of the
+ * dialog.
+ * @return {string} The CSS that correctly sets the padding of #sink-search
+ * for the current view.
+ * @private
+ */
+ computeSinkSearchClass_: function(currentView) {
+ return (currentView == media_router.MediaRouterView.FILTER) ? '' : 'bottom';
},
/**
@@ -739,12 +1092,59 @@ Polymer({
},
/**
+ * Updates element positioning when the view changes and possibly triggers
+ * reporting of a user filter action. If there is no filter text, it defers
+ * the reporting until some text is entered, but otherwise it reports the
+ * filter action here.
+ * @param {?media_router.MediaRouterView} currentView The current view of the
+ * dialog.
+ * @private
+ */
+ currentViewChanged_: function(currentView) {
+ if (currentView == media_router.MediaRouterView.FILTER) {
+ this.reportFilterOnInput_ = true;
+ this.maybeReportFilter_();
+ }
+ this.updateElementPositioning_();
+ },
+
+ /**
+ * Filters all sinks based on fuzzy matching to the currently entered search
+ * text.
+ * @param {string} searchInputText The currently entered search text.
+ * @private
+ */
+ filterSinks_: function(searchInputText) {
+ if (searchInputText.length == 0) {
+ this.searchResultsToShow_ = this.sinksToShow_.map(function(item) {
+ return {sinkItem: item, substrings: null};
+ });
+ return;
+ }
+ this.isUserSearching_ = true;
+
+ var searchResultsToShow = [];
+ for (var i = 0; i < this.sinksToShow_.length; ++i) {
+ var matchSubstrings = this.computeSearchMatches_(
+ searchInputText,
+ this.sinksToShow_[i].name);
+ if (!matchSubstrings) {
+ continue;
+ }
+ searchResultsToShow.push({sinkItem: this.sinksToShow_[i],
+ substrings: matchSubstrings});
+ }
+ searchResultsToShow.sort(this.compareSearchMatches_);
+ this.searchResultsToShow_ = searchResultsToShow;
+ },
+
+ /**
* Helper function to locate the CastMode object with the given type in
* castModeList.
*
* @param {number} castModeType Type of cast mode to look for.
- * @return {?media_router.CastMode} CastMode object with the given type in
- * castModeList, or undefined if not found.
+ * @return {media_router.CastMode|undefined} CastMode object with the given
+ * type in castModeList, or undefined if not found.
*/
findCastModeByType_: function(castModeType) {
return this.castModeList.find(function(element, index, array) {
@@ -764,6 +1164,33 @@ Polymer({
},
/**
+ * Updates sink list when user is searching.
+ * @param {boolean} isUserSearching Whether the user is searching for sinks.
+ */
+ isUserSearchingChanged_: function(isUserSearching) {
+ if (isUserSearching) {
+ this.currentView_ = media_router.MediaRouterView.FILTER;
+ this.updateElementPositioning_();
+ this.filterSinks_(this.searchInputText_);
+ } else {
+ this.currentView_ = media_router.MediaRouterView.SINK_LIST;
+ }
+ },
+
+ /**
+ * Reports a user filter action if |searchInputText_| is not empty and the
+ * filter action hasn't been reported since the view changed to the filter
+ * view.
+ * @private
+ */
+ maybeReportFilter_: function() {
+ if (this.reportFilterOnInput_ && this.searchInputText_.length != 0) {
+ this.reportFilterOnInput_ = false;
+ this.fire('report-filter');
+ }
+ },
+
+ /**
* Updates |currentView_| if the dialog had just opened and there's
* only one local route.
*/
@@ -788,18 +1215,33 @@ Polymer({
},
/**
- * Updates |currentView_| if there is a new blocking issue.
+ * Updates |currentView_| if there is a new blocking issue or a blocking
+ * issue is resolved. Clears any pending route creation properties if the
+ * issue corresponds with |pendingCreatedRouteId_|.
*
- * @param {?media_router.Issue} issue The new issue.
+ * @param {?media_router.Issue} issue The new issue, or null if the
+ * blocking issue was resolved.
* @private
*/
maybeShowIssueView_: function(issue) {
- if (!!issue && issue.isBlocking) {
- this.currentView_ = media_router.MediaRouterView.ISSUE;
- } else {
- this.async(function() {
+ if (!!issue) {
+ if (issue.isBlocking) {
+ this.currentView_ = media_router.MediaRouterView.ISSUE;
+ } else if (this.currentView_ == media_router.MediaRouterView.SINK_LIST) {
+ // Make space for the non-blocking issue in the sink list.
this.updateElementPositioning_();
- });
+ }
+ } else {
+ // Switch back to the sink list if the issue was cleared. If the previous
+ // issue was non-blocking, this would be a no-op. It is expected that
+ // the only way to clear an issue is by user action; the IssueManager
+ // (C++ side) does not clear issues in the UI.
+ this.currentView_ = media_router.MediaRouterView.SINK_LIST;
+ }
+
+ if (!!this.pendingCreatedRouteId_ && !!issue &&
+ issue.routeId == this.pendingCreatedRouteId_) {
+ this.resetRouteCreationProperties_(false);
}
},
@@ -884,21 +1326,91 @@ Polymer({
*
* @param {string} sinkId The ID of the sink to which the Media Route was
* creating a route.
- * @param {string} routeId The ID of the newly created route for the sink if
- * succeeded; empty otherwise.
+ * @param {?media_router.Route} route The newly created route that
+ * corresponds to the sink if route creation succeeded; null otherwise.
+ * @param {boolean} isForDisplay Whether or not |route| is for display.
*/
- onCreateRouteResponseReceived: function(sinkId, routeId) {
- // Check that |sinkId| exists and corresponds to |currentLaunchingSinkId_|.
- if (!this.sinkMap_[sinkId] || this.currentLaunchingSinkId_ != sinkId)
- return;
-
+ onCreateRouteResponseReceived: function(sinkId, route, isForDisplay) {
// The provider will handle sending an issue for a failed route request.
- if (this.isEmptyOrWhitespace_(routeId)) {
+ if (!route) {
this.resetRouteCreationProperties_(false);
+ this.fire('report-resolved-route', {
+ outcome: media_router.MediaRouterRouteCreationOutcome.FAILURE_NO_ROUTE
+ });
return;
}
- this.pendingCreatedRouteId_ = routeId;
+ // Check that |sinkId| exists and corresponds to |currentLaunchingSinkId_|.
+ if (!this.sinkMap_[sinkId] || this.currentLaunchingSinkId_ != sinkId) {
+ this.fire('report-resolved-route', {
+ outcome:
+ media_router.MediaRouterRouteCreationOutcome.FAILURE_INVALID_SINK
+ });
+ return;
+ }
+
+ // Regardless of whether the route is for display, it was resolved
+ // successfully.
+ this.fire('report-resolved-route', {
+ outcome: media_router.MediaRouterRouteCreationOutcome.SUCCESS
+ });
+
+ if (isForDisplay) {
+ this.showRouteDetails_(route);
+ this.startTapTimer_();
+ this.resetRouteCreationProperties_(true);
+ } else {
+ this.pendingCreatedRouteId_ = route.id;
+ }
+ },
+
+ /**
+ * Called when a focus event is triggered.
+ *
+ * @param {!Event} event The event object.
+ * @private
+ */
+ onFocus_: function(event) {
+ // If the focus event was automatically fired by Polymer, remove focus from
+ // the element. This prevents unexpected focusing when the dialog is
+ // initially loaded. This only happens on mac.
+ if (cr.isMac && !event.sourceCapabilities) {
+ // Adding a focus placeholder element is part of the workaround for
+ // handling unexpected focusing, which only happens once on dialog open.
+ // Since the placeholder is focus-enabled as denoted by its tabindex
+ // value, the focus will not appear in other elements.
+ var placeholder = this.$$('#focus-placeholder');
+ // Check that the placeholder is the currently focused element. In some
+ // tests, other elements are non-user-triggered focused.
+ if (placeholder && this.shadowRoot.activeElement == placeholder) {
+ event.path[0].blur();
+ // Remove the placeholder since we have no more use for it.
+ placeholder.remove();
+ }
+ }
+ },
+
+ /**
+ * Called when a keydown event is fired.
+ * @param {!Event} e Keydown event object for the event.
+ */
+ onKeydown_: function(e) {
+ // The ESC key may be pressed with a combination of other keys. It is
+ // handled on the C++ side instead of the JS side on non-mac platforms,
+ // which uses toolkit-views. Handle the expected behavior on all platforms
+ // here.
+ if (e.keyCode == media_router.KEYCODE_ESC && !e.shiftKey &&
+ !e.ctrlKey && !e.altKey && !e.metaKey) {
+ // When searching, allow ESC as a mechanism to leave the filter view.
+ if (this.isUserSearching_) {
+ this.showSinkList_();
+ e.preventDefault();
+ } else {
+ this.fire('close-dialog', {
+ pressEscToClose: true,
+ });
+ }
+ }
},
/**
@@ -920,20 +1432,16 @@ Polymer({
},
/**
- * Handles timeout of previous create route attempt.
- */
- onNotifyRouteCreationTimeout: function() {
- this.resetRouteCreationProperties_(false);
- },
-
- /**
* Called when a sink is clicked.
*
* @param {!Event} event The event object.
* @private
*/
onSinkClick_: function(event) {
- this.showOrCreateRoute_(this.$.sinkList.itemForElement(event.target));
+ var clickedSink = (this.isUserSearching_) ?
+ this.$$('#searchResults').itemForElement(event.target).sinkItem :
+ this.$.sinkList.itemForElement(event.target);
+ this.showOrCreateRoute_(clickedSink);
this.fire('sink-click', {index: event['model'].index});
},
@@ -1025,6 +1533,9 @@ Polymer({
}, this);
this.rebuildSinksToShow_();
+ if (this.isUserSearching_) {
+ this.filterSinks_(this.searchInputText_);
+ }
},
/**
@@ -1043,6 +1554,91 @@ Polymer({
},
/**
+ * Responds to a click on the search button by toggling sink filtering.
+ */
+ searchButtonClick_: function() {
+ // Redundancy needed because focus() only fires event if input is not
+ // already focused. In the case that user typed text, hit escape, then
+ // clicks the search button, a focus event will not fire and so its event
+ // handler from ready() will not run.
+ this.isUserSearching_ = true;
+ this.$$('#sink-search-input').focus();
+ },
+
+ /**
+ * Sets various focus and blur event handlers to handle |isSearchFocused_| and
+ * showing search results when the input is focused.
+ * @private
+ */
+ setSearchFocusHandlers_: function() {
+ var search = this.$['sink-search-input'];
+
+ // The window can see a blur event for two important cases: the window is
+ // actually losing focus or keyboard focus is wrapping from the end of the
+ // document to the beginning. To handle both cases, we save the state of
+ // |isSearchFocused_| during the window blur event.
+ //
+ // The corresponding window focus event can do nothing if |isSearchFocused_|
+ // was false during the blur event. If the search input is gaining focus now
+ // it will work correctly. There are two cases when the input had focus
+ // during the window blur event: the input still has focus and the input
+ // lost focus. These cases are handled by the logic around
+ // |isSearchFocusedShouldBeSet_| and |isSearchFocused_|.
+ //
+ // Because the window focus event will always happen first, it doesn't know
+ // whether the input focus handler will later run or not. If it is not going
+ // to run, then |isSearchFocused_| should be set to |false|, otherwise it
+ // should be |true|. So the window focus handler just sets
+ // |isSearchFocused_| to |false| and makes a note in
+ // |isSearchFocusedShouldBeSet_| that |isSearchFocused_| should actually be
+ // set to true if the search focus handler runs. The |setTimeout| in the
+ // window focus handler clears this note as soon as all focus event handlers
+ // have run.
+ window.addEventListener('blur', function() {
+ this.isSearchFocusedOnWindowBlur_ = this.isSearchFocused_;
+ }.bind(this));
+ window.addEventListener('focus', function() {
+ if (this.isSearchFocusedOnWindowBlur_) {
+ this.isSearchFocusedOnWindowBlur_ = false;
+ this.isSearchFocusedShouldBeSet_ = true;
+ this.isSearchFocused_ = false;
+ setTimeout(function() {
+ this.isSearchFocusedShouldBeSet_ = false;
+ }.bind(this));
+ }
+ }.bind(this));
+ search.addEventListener('blur', function() {
+ // This lets normal blur cases work as expected, but doesn't get in the
+ // way of the window blur handler capturing the "current" state. This is
+ // the case because this will be run after all the blur handlers are done.
+ setTimeout(function() { this.isSearchFocused_ = false; }.bind(this));
+ }.bind(this));
+ search.addEventListener('focus', function() {
+ if (this.isSearchFocusedShouldBeSet_) {
+ this.isSearchFocused_ = true;
+ }
+ if (!this.isSearchFocused_) {
+ this.isSearchFocused_ = true;
+ this.isUserSearching_ = true;
+ }
+ }.bind(this));
+ },
+
+ /**
+ * Filters the sink list when the input text changes and shows the search
+ * results if |searchInputText| is not empty.
+ * @param {string} searchInputText The currently entered search text.
+ * @private
+ */
+ searchInputTextChanged_: function(searchInputText) {
+ this.filterSinks_(searchInputText);
+ if (searchInputText.length != 0) {
+ this.isUserSearching_ = true;
+ this.maybeReportFilter_();
+ }
+ },
+
+ /**
* Updates the shown cast mode, and updates the header text fields
* according to the cast mode. If |castMode| type is AUTO, then set
* |userHasSelectedCastMode_| to false.
@@ -1055,7 +1651,7 @@ Polymer({
this.shownCastModeValue_ = castMode.type;
this.headerText = castMode.description;
- this.headerTextTooltip = castMode.host;
+ this.headerTextTooltip = castMode.host || '';
if (castMode.type == media_router.CastModeType.AUTO)
this.userHasSelectedCastMode_ = false;
},
@@ -1124,6 +1720,7 @@ Polymer({
*/
showSinkList_: function() {
this.currentView_ = media_router.MediaRouterView.SINK_LIST;
+ this.isUserSearching_ = false;
},
/**
@@ -1135,7 +1732,9 @@ Polymer({
startTapTimer_: function() {
var id = setTimeout(function() {
if (!this.mouseIsPositionedOverDialog_)
- this.fire('close-dialog');
+ this.fire('close-dialog', {
+ pressEscToClose: false,
+ });
}.bind(this), 3000 /* 3 seconds */);
},
@@ -1147,7 +1746,7 @@ Polymer({
toggleCastModeHidden_: function() {
if (this.currentView_ == media_router.MediaRouterView.CAST_MODE_LIST) {
this.showSinkList_();
- } else {
+ } else if (this.currentView_ == media_router.MediaRouterView.SINK_LIST) {
this.showCastModeList_();
this.fire('navigate-to-cast-mode-list');
}
@@ -1168,13 +1767,18 @@ Polymer({
var issueHeight = this.$$('#issue-banner') &&
this.$$('#issue-banner').style.display != 'none' ?
this.$$('#issue-banner').offsetHeight : 0;
+ var searchHeight = this.$$('#sink-search').offsetHeight;
this.$['container-header'].style.marginTop = firstRunFlowHeight + 'px';
- this.$['sink-list-view'].style.marginTop =
+ this.$['content'].style.marginTop =
firstRunFlowHeight + headerHeight + 'px';
this.$['sink-list'].style.maxHeight =
this.dialogHeight_ - headerHeight - firstRunFlowHeight -
- issueHeight + 'px';
+ issueHeight - searchHeight + 'px';
+ var searchResults = this.$$('#search-results');
+ if (searchResults) {
+ searchResults.style.maxHeight = this.$['sink-list'].style.maxHeight;
+ }
});
},
diff --git a/chromium/chrome/browser/resources/media_router/elements/media_router_header/media_router_header.css b/chromium/chrome/browser/resources/media_router/elements/media_router_header/media_router_header.css
index 22fee5d50e9..8e58a07b6b9 100644
--- a/chromium/chrome/browser/resources/media_router/elements/media_router_header/media_router_header.css
+++ b/chromium/chrome/browser/resources/media_router/elements/media_router_header/media_router_header.css
@@ -6,48 +6,54 @@
flex-grow: 1;
}
-#arrow-drop-icon::shadow #icon {
- height: 20px;
- width: 20px;
+#arrow-drop-icon {
+ height: var(--navigation-icon-button-size);
+ width: var(--navigation-icon-button-size);
}
-#back-button::shadow #icon {
- height: 20px;
- width: 20px;
+#back-button {
+ height: var(--navigation-icon-button-size);
+ width: var(--navigation-icon-button-size);
}
#back-button-container {
- -webkit-padding-end: 12px;
+ -webkit-padding-end: 4px;
}
#close-button {
-webkit-margin-start: auto;
-}
-
-#close-button::shadow #icon {
- height: 15px;
- width: 15px;
+ height: 31px;
+ width: 31px;
}
#close-button-container {
+ -webkit-margin-start: auto;
-webkit-padding-end: 16px;
-webkit-padding-start: 24px;
}
+#header-and-arrow-container {
+ display: flex;
+ height: 36px;
+ overflow: hidden;
+ white-space: nowrap;
+}
+
#header-text {
-webkit-padding-end: 4px;
color: white;
font-size: 1.175em;
- margin: 0;
+ margin: 8px 0 0 0;
+ overflow: hidden;
+ text-overflow: ellipsis;
}
paper-icon-button {
- display: inline;
+ display: inline-block;
}
paper-toolbar {
-webkit-padding-start: 8px;
- height: 52px;
}
paper-toolbar::shadow .toolbar-tools {
@@ -55,18 +61,24 @@ paper-toolbar::shadow .toolbar-tools {
}
paper-toolbar.cast-mode-list {
- background-color: rgb(0, 150, 136);
+ background-color: var(--paper-teal-500);
}
paper-toolbar.filter {
- background-color: rgb(103, 58, 183);
+ background-color: var(--paper-deep-purple-500);
}
paper-toolbar.issue {
- background-color: rgb(219, 68, 55);
+ background-color: var(--google-red-500);
}
paper-toolbar.route-details,
paper-toolbar.sink-list {
- background-color: rgb(33, 150, 243);
+ background-color: var(--paper-blue-700);
+}
+
+#user-email-container {
+ -webkit-padding-start: 12px;
+ font-size: 0.917em;
+ padding-bottom: 12px;
}
diff --git a/chromium/chrome/browser/resources/media_router/elements/media_router_header/media_router_header.html b/chromium/chrome/browser/resources/media_router/elements/media_router_header/media_router_header.html
index 1947cb1abfa..2be6c2eeed4 100644
--- a/chromium/chrome/browser/resources/media_router/elements/media_router_header/media_router_header.html
+++ b/chromium/chrome/browser/resources/media_router/elements/media_router_header/media_router_header.html
@@ -1,30 +1,38 @@
-<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.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="chrome://resources/polymer/v1_0/paper-toolbar/paper-toolbar.html">
<dom-module name="media-router-header">
<link rel="import" type="css" href="../../media_router_common.css">
<link rel="import" type="css" href="media_router_header.css">
<template>
- <paper-toolbar class$="[[view]]">
+ <paper-toolbar id="header-toolbar" class$="[[view]]">
<div id="back-button-container">
<paper-icon-button id="back-button" icon="[[arrowDropIcon_]]"
- on-click="onBackButtonClick_"
+ on-tap="onBackButtonClick_" title="[[backButtonTitle_]]"
hidden$="[[computeBackButtonHidden_(view)]]">
</paper-icon-button>
</div>
- <span id="header-text" title="[[tooltip]]">[[headingText]]</span>
- <div id="arrow-drop-container">
- <paper-icon-button icon="[[computeArrowDropIcon_(view)]]"
- id="arrow-drop-icon" on-click="onArrowDropClick_"
- disabled$="[[arrowDropIconDisabled]]"
- hidden$="[[computeArrowDropIconHidden_(view)]]">
- </paper-icon-button>
+ <div id="header-and-arrow-container" on-tap="onHeaderOrArrowClick_">
+ <span id="header-text" title="[[tooltip]]">
+ [[headingText]]</span>
+ <div id="arrow-drop-container">
+ <paper-icon-button icon="[[computeArrowDropIcon_(view)]]"
+ id="arrow-drop-icon" disabled$="[[arrowDropIconDisabled]]"
+ hidden$="[[computeArrowDropIconHidden_(view)]]"
+ title="[[computeArrowDropTitle_(view)]]">
+ </paper-icon-button>
+ </div>
</div>
<div id="close-button-container">
<paper-icon-button icon="close" id="close-button"
- on-click="onCloseButtonClick_">
+ on-tap="onCloseButtonClick_" title="[[closeButtonTitle_]]">
</paper-icon-button>
</div>
+ <template is="dom-if" if="[[showEmail]]">
+ <div id="user-email-container" class="bottom fit">
+ <span>[[userEmail]]</span>
+ </div>
+ </template>
</paper-toolbar>
</template>
<script src="media_router_header.js"></script>
diff --git a/chromium/chrome/browser/resources/media_router/elements/media_router_header/media_router_header.js b/chromium/chrome/browser/resources/media_router/elements/media_router_header/media_router_header.js
index 3e9ea19c5e6..fba24a5cb16 100644
--- a/chromium/chrome/browser/resources/media_router/elements/media_router_header/media_router_header.js
+++ b/chromium/chrome/browser/resources/media_router/elements/media_router_header/media_router_header.js
@@ -27,6 +27,30 @@ Polymer({
},
/**
+ * Title text for the back button.
+ * @private {string}
+ */
+ backButtonTitle_: {
+ type: String,
+ readOnly: true,
+ value: function() {
+ return loadTimeData.getString('backButtonTitle');
+ },
+ },
+
+ /**
+ * Title text for the close button.
+ * @private {string}
+ */
+ closeButtonTitle_: {
+ type: String,
+ readOnly: true,
+ value: function() {
+ return loadTimeData.getString('closeButtonTitle');
+ },
+ },
+
+ /**
* The header text to show.
* @type {string}
*/
@@ -36,12 +60,33 @@ Polymer({
},
/**
- * The current view that this header should reflect.
- * @type {?media_router.MediaRouterView}
+ * The height of the header when it shows the user email.
+ * @private {number}
*/
- view: {
- type: String,
- value: null,
+ headerWithEmailHeight_: {
+ type: Number,
+ readOnly: true,
+ value: 62,
+ },
+
+ /**
+ * The height of the header when it doesn't show the user email.
+ * @private {number}
+ */
+ headerWithoutEmailHeight_: {
+ type: Number,
+ readOnly: true,
+ value: 52,
+ },
+
+ /**
+ * Whether to show the user email in the header.
+ * @type {boolean}
+ */
+ showEmail: {
+ type: Boolean,
+ value: false,
+ observer: 'maybeChangeHeaderHeight_',
},
/**
@@ -52,6 +97,29 @@ Polymer({
type: String,
value: '',
},
+
+ /**
+ * The user email if they are signed in.
+ * @type {string}
+ */
+ userEmail: {
+ type: String,
+ value: '',
+ },
+
+ /**
+ * The current view that this header should reflect.
+ * @type {?media_router.MediaRouterView}
+ */
+ view: {
+ type: String,
+ value: null,
+ observer: 'updateHeaderCursorStyle_',
+ },
+ },
+
+ listeners: {
+ 'focus': 'onFocus_',
},
attached: function() {
@@ -82,20 +150,34 @@ Polymer({
/**
* @param {?media_router.MediaRouterView} view The current view.
+ * @return {string} The title text for the arrow drop button.
+ * @private
+ */
+ computeArrowDropTitle_: function(view) {
+ return view == media_router.MediaRouterView.CAST_MODE_LIST ?
+ loadTimeData.getString('viewDeviceListButtonTitle') :
+ loadTimeData.getString('viewCastModeListButtonTitle');
+ },
+
+ /**
+ * @param {?media_router.MediaRouterView} view The current view.
* @return {boolean} Whether or not the back button should be hidden.
* @private
*/
computeBackButtonHidden_: function(view) {
- return view != media_router.MediaRouterView.ROUTE_DETAILS;
+ return view != media_router.MediaRouterView.ROUTE_DETAILS &&
+ view != media_router.MediaRouterView.FILTER;
},
/**
- * Handles a click on the arrow button by firing an arrow-click event.
- *
+ * Returns whether given string is undefined, null, empty, or whitespace only.
+ * @param {?string} str String to be tested.
+ * @return {boolean} |true| if the string is undefined, null, empty, or
+ * whitespace.
* @private
*/
- onArrowDropClick_: function() {
- this.fire('arrow-drop-click');
+ isEmptyOrWhitespace_: function(str) {
+ return str === undefined || str === null || (/^\s*$/).test(str);
},
/**
@@ -113,6 +195,63 @@ Polymer({
* @private
*/
onCloseButtonClick_: function() {
- this.fire('close-button-click');
+ this.fire('close-dialog', {
+ pressEscToClose: false,
+ });
+ },
+
+ /**
+ * Handles a click on the arrow button by firing an arrow-click event.
+ *
+ * @private
+ */
+ onHeaderOrArrowClick_: function() {
+ if (this.view == media_router.MediaRouterView.SINK_LIST ||
+ this.view == media_router.MediaRouterView.CAST_MODE_LIST) {
+ this.fire('header-or-arrow-click');
+ }
+ },
+
+ /**
+ * Updates header height to accomodate email text. This is called on changes
+ * to |showEmail| and will return early if the value has not changed.
+ *
+ * @param {boolean} newValue The new value of |showEmail|.
+ * @param {boolean} oldValue The previous value of |showEmail|.
+ * @private
+ */
+ maybeChangeHeaderHeight_: function(newValue, oldValue) {
+ if (!!oldValue == !!newValue) {
+ return;
+ }
+
+ // Ensures conditional templates are stamped.
+ this.async(function() {
+ var currentHeight = this.offsetHeight;
+
+ this.$$('#header-toolbar').style.height =
+ this.showEmail && !this.isEmptyOrWhitespace_(this.userEmail) ?
+ this.headerWithEmailHeight_ + 'px' :
+ this.headerWithoutEmailHeight_ + 'px';
+
+ // Only fire if height actually changed.
+ if (currentHeight != this.offsetHeight) {
+ this.fire('header-height-changed');
+ }
+ });
+ },
+
+ /**
+ * Updates the cursor style for the header text when the view changes. When
+ * the drop arrow is also shown, the header text is also clickable.
+ *
+ * @param {?media_router.MediaRouterView} view The current view.
+ * @private
+ */
+ updateHeaderCursorStyle_: function(view) {
+ this.$$('#header-text').style.cursor =
+ view == media_router.MediaRouterView.SINK_LIST ||
+ view == media_router.MediaRouterView.CAST_MODE_LIST ?
+ 'pointer' : 'auto';
},
});
diff --git a/chromium/chrome/browser/resources/ntp4/guest_tab.css b/chromium/chrome/browser/resources/media_router/elements/media_router_search_highlighter/media_router_search_highlighter.css
index b3912c8c22f..39b1c2f334c 100644
--- a/chromium/chrome/browser/resources/ntp4/guest_tab.css
+++ b/chromium/chrome/browser/resources/media_router/elements/media_router_search_highlighter/media_router_search_highlighter.css
@@ -1,7 +1,7 @@
-/* Copyright 2013 The Chromium Authors. All rights reserved.
+/* 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. */
-a {
- color: rgb(51, 103, 214);
+.highlight {
+ font-weight: bold;
}
diff --git a/chromium/chrome/browser/resources/media_router/elements/media_router_search_highlighter/media_router_search_highlighter.html b/chromium/chrome/browser/resources/media_router/elements/media_router_search_highlighter/media_router_search_highlighter.html
new file mode 100644
index 00000000000..dbb9334ae99
--- /dev/null
+++ b/chromium/chrome/browser/resources/media_router/elements/media_router_search_highlighter/media_router_search_highlighter.html
@@ -0,0 +1,8 @@
+<link rel="import" href="chrome://resources/html/polymer.html">
+<dom-module id="media-router-search-highlighter">
+ <link rel="import" type="css" href="media_router_search_highlighter.css">
+ <template>
+ <span id="text" dir="auto"></span>
+ </template>
+</dom-module>
+<script src="media_router_search_highlighter.js"></script>
diff --git a/chromium/chrome/browser/resources/media_router/elements/media_router_search_highlighter/media_router_search_highlighter.js b/chromium/chrome/browser/resources/media_router/elements/media_router_search_highlighter/media_router_search_highlighter.js
new file mode 100644
index 00000000000..317907f2843
--- /dev/null
+++ b/chromium/chrome/browser/resources/media_router/elements/media_router_search_highlighter/media_router_search_highlighter.js
@@ -0,0 +1,81 @@
+// 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.
+
+// This Polymer element displays text that needs sections of it highlighted.
+// This is useful, for example, for displaying which portions of a string were
+// matched by some filter text.
+Polymer({
+ is: 'media-router-search-highlighter',
+
+ properties: {
+ /**
+ * The text that this element should display, split it into highlighted and
+ * normal text. The displayed text will alternate between plainText and
+ * highlightedText.
+ *
+ * Example: You have a sink with the name 'living room'.
+ * When your seach text is 'living', the resulting arrays will be:
+ * plainText: [null, ' room'], highlightedText: ['living', null]
+ *
+ * When your search text is 'room', the resulting arrays will be:
+ * plainText: ['living ', null], highlightedText: [null, 'room']
+ *
+ * null corresponds to an empty string when the arrays are being combined.
+ * So both examples reproduce the text 'living room', but with different
+ * words highlighted.
+ * @type {{highlightedText: !Array<?string>, plainText: !Array<?string>}}
+ */
+ data: {
+ type: Object,
+ value: null,
+ observer: 'dataChanged_',
+ },
+
+ /**
+ * The text that this element is displaying as a plain string. The primary
+ * purpose for this property is to make getting this element's textContent
+ * easy for testing.
+ * @type {?string}
+ */
+ text: {
+ type: String,
+ value: null,
+ readOnly: true,
+ notify: false,
+ },
+ },
+
+ /**
+ * Update the element text if |data| changes.
+ *
+ * The order the strings are combined is plainText[0] highlightedText[0]
+ * plainText[1] highlightedText[1] etc.
+ *
+ * @param {{highlightedText: !Array<?string>, plainText: !Array<?string>}}
+ * data
+ * Parameters in |data|:
+ * highlightedText - Array of strings that should be displayed highlighted.
+ * plainText - Array of strings that should be displayed normally.
+ */
+ dataChanged_: function(data) {
+ if (!data || !data.highlightedText || !data.plainText) {
+ return;
+ }
+
+ var text = '';
+ for (var i = 0; i < data.highlightedText.length; ++i) {
+ if (data.plainText[i]) {
+ text +=
+ HTMLEscape(/** @type {!string} */ (data.plainText[i]));
+ }
+ if (data.highlightedText[i]) {
+ text += '<span class="highlight">' +
+ HTMLEscape(/** @type {!string} */ (data.highlightedText[i])) +
+ '</span>';
+ }
+ }
+ this.$.text.innerHTML = text;
+ this._setText(this.$.text.textContent);
+ },
+});
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 7b9411ddbbb..a1801c3ec5e 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
@@ -9,10 +9,6 @@
width: 100%;
}
-#join-route-button {
- @apply(--layout-flex);
-}
-
#route-action-buttons {
@apply(--layout-horizontal);
@apply(--layout-end-justified);
@@ -31,9 +27,15 @@
}
#route-information {
+ -webkit-padding-end: var(--dialog-padding-end);
-webkit-padding-start: 44px;
background-color: white;
font-size: 1.2em;
+ line-height: 1.5em;
margin-top: 16px;
overflow: hidden;
}
+
+#start-casting-to-route-button {
+ @apply(--layout-flex);
+}
diff --git a/chromium/chrome/browser/resources/media_router/elements/route_details/route_details.html b/chromium/chrome/browser/resources/media_router/elements/route_details/route_details.html
index 041b60a5a44..a60128320c8 100644
--- a/chromium/chrome/browser/resources/media_router/elements/route_details/route_details.html
+++ b/chromium/chrome/browser/resources/media_router/elements/route_details/route_details.html
@@ -1,4 +1,4 @@
-<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
+<link rel="import" href="chrome://resources/html/polymer.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html">
<dom-module id="route-details">
<link rel="import" type="css" href="../../media_router_common.css">
@@ -12,14 +12,14 @@
</extensionview>
<div id="route-action-buttons" class="layout">
<paper-button flat class="route-button button"
- id="join-route-button"
+ id="start-casting-to-route-button"
hidden$="[[!route.canJoin]]"
- on-click="joinRoute_">
- <span>[[joinButtonText_]]</span>
+ on-tap="startCastingToRoute_">
+ <span>[[startCastingButtonText_]]</span>
</paper-button>
<paper-button flat class="route-button button"
id="close-route-button"
- on-click="closeRoute_">
+ on-tap="closeRoute_">
<span>[[stopCastingButtonText_]]</span>
</paper-button>
<div>
diff --git a/chromium/chrome/browser/resources/media_router/elements/route_details/route_details.js b/chromium/chrome/browser/resources/media_router/elements/route_details/route_details.js
index 39a4e86d87b..64a50fbd97d 100644
--- a/chromium/chrome/browser/resources/media_router/elements/route_details/route_details.js
+++ b/chromium/chrome/browser/resources/media_router/elements/route_details/route_details.js
@@ -28,13 +28,13 @@ Polymer({
},
/**
- * The text for the join button.
+ * The text for the start casting button.
* @private {string}
*/
- joinButtonText_: {
+ startCastingButtonText_: {
type: String,
readOnly: true,
- value: loadTimeData.getString('joinButton'),
+ value: loadTimeData.getString('startCastingButton'),
},
/**
@@ -44,9 +44,7 @@ Polymer({
stopCastingButtonText_: {
type: String,
readOnly: true,
- value: function() {
- return loadTimeData.getString('stopCastingButton');
- },
+ value: function() { return loadTimeData.getString('stopCastingButton'); },
},
/**
@@ -72,13 +70,13 @@ Polymer({
},
/**
- * Fires a join-route-click event. This is called when the button to join
- * the current route is clicked.
+ * Fires a start-casting-to-route-click event. This is called when the button
+ * to start casting to the current route is clicked.
*
* @private
*/
- joinRoute_: function() {
- this.fire('join-route-click', {route: this.route});
+ startCastingToRoute_: function() {
+ this.fire('start-casting-to-route-click', {route: this.route});
},
/**
diff --git a/chromium/chrome/browser/resources/media_router/externs.js b/chromium/chrome/browser/resources/media_router/externs.js
index 5821b32cbbb..c81db5b89b9 100644
--- a/chromium/chrome/browser/resources/media_router/externs.js
+++ b/chromium/chrome/browser/resources/media_router/externs.js
@@ -13,3 +13,9 @@ var performance = {};
* @return {number}
*/
performance.now = function() {};
+
+/** @interface */
+var InputDeviceCapabilities;
+
+/** @type {?InputDeviceCapabilities} */
+Event.prototype.sourceCapabilities;
diff --git a/chromium/chrome/browser/resources/media_router/icons/media_router_icons.html b/chromium/chrome/browser/resources/media_router/icons/media_router_icons.html
new file mode 100644
index 00000000000..bb2d4628eaf
--- /dev/null
+++ b/chromium/chrome/browser/resources/media_router/icons/media_router_icons.html
@@ -0,0 +1,10 @@
+<link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/iron-iconset-svg/iron-iconset-svg.html">
+<iron-iconset-svg name="media-router" size="24">
+<svg><defs>
+ <!-- copy of third_party/polymer/v1_0/components-chromium/iron-icons/hardware-icons.html hardware:tv icon -->
+ <g id="chromecast"><path d="M21 3H3c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h5v2h8v-2h5c1.1 0 1.99-.9 1.99-2L23 5c0-1.1-.9-2-2-2zm0 14H3V5h18v12z"></path></g>
+ <!-- copy of third_party/polymer/v1_0/components-chromium/iron-icons/hardware-icons.html communication:message icon -->
+ <g id="hangout"><path d="M20 2H4c-1.1 0-1.99.9-1.99 2L2 22l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm-2 12H6v-2h12v2zm0-3H6V9h12v2zm0-3H6V6h12v2z"></path></g>
+</defs></svg>
+</iron-iconset-svg>
diff --git a/chromium/chrome/browser/resources/media_router/media_router.css b/chromium/chrome/browser/resources/media_router/media_router.css
index c2aca5e29ab..f0fffb5b19b 100644
--- a/chromium/chrome/browser/resources/media_router/media_router.css
+++ b/chromium/chrome/browser/resources/media_router/media_router.css
@@ -10,6 +10,7 @@ body {
#media-router-container {
-webkit-margin-start: 1px;
+ background-color: white;
box-shadow: 0 3px 4px 0 rgba(0, 0, 0, 0.14),
0 1px 8px 0 rgba(0, 0, 0, 0.12),
0 3px 3px -2px rgba(0, 0, 0, 0.4);
diff --git a/chromium/chrome/browser/resources/media_router/media_router.html b/chromium/chrome/browser/resources/media_router/media_router.html
index f0f3ffa6796..027ff7d0fd9 100644
--- a/chromium/chrome/browser/resources/media_router/media_router.html
+++ b/chromium/chrome/browser/resources/media_router/media_router.html
@@ -4,19 +4,17 @@
<meta charset="utf-8">
<title i18n-content="mediaRouterTitle"></title>
- <script src="chrome://resources/js/polymer_config.js"></script>
- <script src="chrome://resources/js/cr.js"></script>
- <script src="chrome://resources/js/load_time_data.js"></script>
- <script src="chrome://resources/js/util.js"></script>
- <script src="chrome://media-router/strings.js"></script>
- <script src="chrome://media-router/media_router.js"></script>
-
<link rel="stylesheet" href="chrome://resources/css/roboto.css">
<link rel="stylesheet" href="media_router.css">
+ <link rel="import" href="chrome://resources/html/cr.html">
+ <link rel="import" href="chrome://resources/html/load_time_data.html">
+ <link rel="import" href="chrome://resources/html/util.html">
+ <script src="chrome://media-router/strings.js"></script>
+ <script src="chrome://media-router/media_router.js"></script>
<link rel="import" href="chrome://media-router/elements/media_router_container/media_router_container.html">
</head>
<body>
<media-router-container id="media-router-container"></media-router-container>
- <script src="chrome://resources/js/i18n_template.js"></script>
+ <link rel="import" href="chrome://resources/html/i18n_template.html">
</body>
</html>
diff --git a/chromium/chrome/browser/resources/media_router/media_router.js b/chromium/chrome/browser/resources/media_router/media_router.js
index 7a0535264b6..916a427fe6a 100644
--- a/chromium/chrome/browser/resources/media_router/media_router.js
+++ b/chromium/chrome/browser/resources/media_router/media_router.js
@@ -9,10 +9,6 @@
cr.define('media_router', function() {
'use strict';
- // The ESC key maps to keycode '27'.
- // @const {number}
- var KEYCODE_ESC = 27;
-
/**
* The media-router-container element. Initialized after polymer is ready.
* @type {?MediaRouterContainerElement}
@@ -28,22 +24,24 @@ cr.define('media_router', function() {
container = /** @type {!MediaRouterContainerElement} */
($('media-router-container'));
- media_router.ui.setContainer(container);
+
+ media_router.ui.setElements(container,
+ /** @type {!MediaRouterHeaderElement} */
+ (container.$['container-header']));
container.addEventListener('acknowledge-first-run-flow',
onAcknowledgeFirstRunFlow);
container.addEventListener('back-click', onNavigateToSinkList);
container.addEventListener('cast-mode-selected', onCastModeSelected);
- container.addEventListener('close-button-click', onCloseDialogEvent);
- container.addEventListener('close-dialog', onCloseDialogEvent);
+ container.addEventListener('close-dialog', onCloseDialog);
container.addEventListener('close-route-click', onCloseRouteClick);
container.addEventListener('create-route', onCreateRoute);
container.addEventListener('issue-action-click', onIssueActionClick);
- container.addEventListener('join-route-click', onJoinRouteClick);
container.addEventListener('navigate-sink-list-to-details',
onNavigateToDetails);
container.addEventListener('navigate-to-cast-mode-list',
onNavigateToCastMode);
+ container.addEventListener('report-filter', onFilter);
container.addEventListener('report-initial-action', onInitialAction);
container.addEventListener('report-initial-action-close',
onInitialActionClose);
@@ -51,16 +49,14 @@ cr.define('media_router', function() {
container.addEventListener('report-sink-click-time',
onSinkClickTimeReported);
container.addEventListener('report-sink-count', onSinkCountReported);
+ container.addEventListener('report-resolved-route',
+ onReportRouteCreationOutcome);
container.addEventListener('show-initial-state', onShowInitialState);
container.addEventListener('sink-click', onSinkClick);
+ container.addEventListener('start-casting-to-route-click',
+ onStartCastingToRouteClick);
- // Pressing the ESC key closes the dialog.
- document.addEventListener('keydown', function(e) {
- if (e.keyCode == KEYCODE_ESC) {
- container.maybeReportUserFirstAction(
- media_router.MediaRouterUserAction.CLOSE);
- }
- });
+ window.addEventListener('blur', onWindowBlur);
}
/**
@@ -81,19 +77,44 @@ cr.define('media_router', function() {
* Updates the preference that the user has seen the first run flow.
* Called when the user clicks on the acknowledgement button on the first run
* flow.
+ *
+ * @param {!Event} event
+ * Parameters in |event|.detail:
+ * optedIntoCloudServices - whether or not the user opted into cloud
+ * services.
*/
- function onAcknowledgeFirstRunFlow() {
- media_router.browserApi.acknowledgeFirstRunFlow();
+ function onAcknowledgeFirstRunFlow(event) {
+ /** @type {{optedIntoCloudServices: boolean}} */
+ var detail = event.detail;
+ media_router.browserApi.acknowledgeFirstRunFlow(
+ detail.optedIntoCloudServices);
}
/**
* Closes the dialog.
- * Called when the user clicks the close button on the dialog.
+ * Called when the user clicks the close button on the dialog. Reports
+ * whether the user closed the dialog via the ESC key.
+ *
+ * @param {!Event} event
+ * Parameters in |event|.detail:
+ * pressEscToClose - whether or not the user pressed ESC to close the
+ * dialog.
*/
- function onCloseDialogEvent() {
+ function onCloseDialog(event) {
+ /** @type {{pressEscToClose: boolean}} */
+ var detail = event.detail;
container.maybeReportUserFirstAction(
media_router.MediaRouterUserAction.CLOSE);
- media_router.browserApi.closeDialog();
+ media_router.browserApi.closeDialog(detail.pressEscToClose);
+ }
+
+ /**
+ * Reports when the user uses the filter input to filter the sink list. This
+ * is reported at most once each time the user enters the filter view, and
+ * only if text is actually entered in the filter input.
+ */
+ function onFilter() {
+ media_router.browserApi.reportFilter();
}
/**
@@ -176,14 +197,14 @@ cr.define('media_router', function() {
}
/**
- * Joins a route.
- * Called when the user requests to join a media route.
+ * Starts casting to an existing route.
+ * Called when the user requests to start casting to a media route.
*
* @param {!Event} event
* Parameters in |event|.detail:
- * route - route to join.
+ * route - The route to connect to if possible.
*/
- function onJoinRouteClick(event) {
+ function onStartCastingToRouteClick(event) {
/** @type {{route: !media_router.Route}} */
var detail = event.detail;
media_router.browserApi.joinRoute(detail.route);
@@ -232,6 +253,23 @@ cr.define('media_router', function() {
}
/**
+ * Reports success or the type of failure for route creation response.
+ * Called when the route is resolved; either the route creation was a success
+ * or if there was no route or the route's corresponding sink is invalid;
+ * either the sink does not exist or was not the sink we were looking for.
+ *
+ * @param {!Event} event
+ * Parameters in |event|.detail:
+ * outcome - the outcome of a create route response.
+ *
+ */
+ function onReportRouteCreationOutcome(event) {
+ /** @type {{outcome: number}} */
+ var detail = event.detail;
+ media_router.browserApi.reportRouteCreationOutcome(detail.outcome);
+ }
+
+ /**
* Reports the initial state of the dialog after it is opened.
* Called after initial data is populated.
*
@@ -287,6 +325,13 @@ cr.define('media_router', function() {
media_router.browserApi.reportSinkCount(detail.sinkCount);
}
+ /**
+ * Reports when the user clicks outside the dialog.
+ */
+ function onWindowBlur() {
+ media_router.browserApi.reportBlur();
+ }
+
return {
initialize: initialize,
};
diff --git a/chromium/chrome/browser/resources/media_router/media_router_common.css b/chromium/chrome/browser/resources/media_router/media_router_common.css
index 1d51985930d..767fd1ed896 100644
--- a/chromium/chrome/browser/resources/media_router/media_router_common.css
+++ b/chromium/chrome/browser/resources/media_router/media_router_common.css
@@ -2,12 +2,19 @@
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file. */
+:root {
+ --dialog-padding-end: 26px;
+ --dialog-padding-start: 16px;
+ --navigation-icon-button-size: 36px;
+ --non-navigation-icon-size: 16px;
+}
+
.button {
- color: rgb(33, 150, 243);
+ color: var(--paper-blue-700);
cursor: pointer;
text-align: center;
}
[hidden] {
display: none !important;
-} \ No newline at end of file
+}
diff --git a/chromium/chrome/browser/resources/media_router/media_router_data.js b/chromium/chrome/browser/resources/media_router/media_router_data.js
index f28ccd5db9c..15b07e726c7 100644
--- a/chromium/chrome/browser/resources/media_router/media_router_data.js
+++ b/chromium/chrome/browser/resources/media_router/media_router_data.js
@@ -24,6 +24,23 @@ media_router.CastModeType = {
};
/**
+ * The ESC key maps to keycode '27'.
+ * @const {number}
+ */
+media_router.KEYCODE_ESC = 27;
+
+/**
+ * This corresponds to the C++ MediaRouterMetrics
+ * MediaRouterRouteCreationOutcome.
+ * @enum {number}
+ */
+media_router.MediaRouterRouteCreationOutcome = {
+ SUCCESS: 0,
+ FAILURE_NO_ROUTE: 1,
+ FAILURE_INVALID_SINK: 2,
+};
+
+/**
* This corresponds to the C++ MediaRouterMetrics MediaRouterUserAction.
* @enum {number}
*/
@@ -103,7 +120,7 @@ cr.define('media_router', function() {
* @param {string} message The issue message.
* @param {number} defaultActionType The type of default action.
* @param {?number} secondaryActionType The type of optional action.
- * @param {?string} mediaRouteId The route ID to which this issue
+ * @param {?string} routeId The route ID to which this issue
* pertains. If not set, this is a global issue.
* @param {boolean} isBlocking True if this issue blocks other UI.
* @param {?number} helpPageId The numeric help center ID.
@@ -111,7 +128,7 @@ cr.define('media_router', function() {
* @struct
*/
var Issue = function(id, title, message, defaultActionType,
- secondaryActionType, mediaRouteId, isBlocking,
+ secondaryActionType, routeId, isBlocking,
helpPageId) {
/** @type {string} */
this.id = id;
@@ -129,7 +146,7 @@ cr.define('media_router', function() {
this.secondaryActionType = secondaryActionType;
/** @type {?string} */
- this.mediaRouteId = mediaRouteId;
+ this.routeId = routeId;
/** @type {boolean} */
this.isBlocking = isBlocking;
diff --git a/chromium/chrome/browser/resources/media_router/media_router_ui_interface.js b/chromium/chrome/browser/resources/media_router/media_router_ui_interface.js
index 91ee850b30c..a19cf3c874e 100644
--- a/chromium/chrome/browser/resources/media_router/media_router_ui_interface.js
+++ b/chromium/chrome/browser/resources/media_router/media_router_ui_interface.js
@@ -10,23 +10,20 @@ cr.define('media_router.ui', function() {
// The media-router-container element.
var container = null;
- /**
- * Handles timeout of previous create route attempt.
- */
- function onNotifyRouteCreationTimeout() {
- container.onNotifyRouteCreationTimeout();
- }
+ // The media-router-header element.
+ var header = null;
/**
* Handles response of previous create route attempt.
*
* @param {string} sinkId The ID of the sink to which the Media Route was
* creating a route.
- * @param {string} routeId The ID of the newly created route that corresponds
- * to the sink if route creation succeeded; empty otherwise.
+ * @param {?media_router.Route} route The newly created route that
+ * corresponds to the sink if route creation succeeded; null otherwise.
+ * @param {boolean} isForDisplay Whether or not |route| is for display.
*/
- function onCreateRouteResponseReceived(sinkId, routeId) {
- container.onCreateRouteResponseReceived(sinkId, routeId);
+ function onCreateRouteResponseReceived(sinkId, route, isForDisplay) {
+ container.onCreateRouteResponseReceived(sinkId, route, isForDisplay);
}
/**
@@ -39,41 +36,71 @@ cr.define('media_router.ui', function() {
}
/**
- * Sets |container|.
+ * Sets |container| and |header|.
*
* @param {!MediaRouterContainerElement} mediaRouterContainer
+ * @param {!MediaRouterHeaderElement} mediaRouterHeader
*/
- function setContainer(mediaRouterContainer) {
+ function setElements(mediaRouterContainer, mediaRouterHeader) {
container = mediaRouterContainer;
+ header = mediaRouterHeader;
}
/**
- * Populates the WebUI with data obtained from Media Router.
+ * Populates the WebUI with data obtained about the first run flow.
*
- * @param {{firstRunFlowLearnMoreUrl: string,
- * deviceMissingUrl: string,
- * sinks: !Array<!media_router.Sink>,
- * routes: !Array<!media_router.Route>,
- * castModes: !Array<!media_router.CastMode>,
- * wasFirstRunFlowAcknowledged: boolean}} data
+ * @param {{firstRunFlowCloudPrefLearnMoreUrl: string,
+ * firstRunFlowLearnMoreUrl: string,
+ * wasFirstRunFlowAcknowledged: boolean,
+ * showFirstRunFlowCloudPref: boolean}} data
* Parameters in data:
+ * firstRunFlowCloudPrefLearnMoreUrl - url to open when the cloud services
+ * pref learn more link is clicked.
* firstRunFlowLearnMoreUrl - url to open when the first run flow learn
* more link is clicked.
- * deviceMissingUrl - url to be opened on "Device missing?" clicked.
- * sinks - list of sinks to be displayed.
- * routes - list of routes that are associated with the sinks.
- * castModes - list of available cast modes.
* wasFirstRunFlowAcknowledged - true if first run flow was previously
* acknowledged by user.
+ * showFirstRunFlowCloudPref - true if the cloud pref option should be
+ * shown.
*/
- function setInitialData(data) {
+ function setFirstRunFlowData(data) {
+ container.firstRunFlowCloudPrefLearnMoreUrl =
+ data['firstRunFlowCloudPrefLearnMoreUrl'];
container.firstRunFlowLearnMoreUrl =
data['firstRunFlowLearnMoreUrl'];
+ container.showFirstRunFlowCloudPref =
+ data['showFirstRunFlowCloudPref'];
+ // Some users acknowledged the first run flow before the cloud prefs
+ // setting was implemented. These users will see the first run flow
+ // again.
+ container.showFirstRunFlow = !data['wasFirstRunFlowAcknowledged'] ||
+ container.showFirstRunFlowCloudPref;
+ }
+
+ /**
+ * Populates the WebUI with data obtained from Media Router.
+ *
+ * @param {{deviceMissingUrl: string,
+ * sinksAndIdentity: {
+ * sinks: !Array<!media_router.Sink>,
+ * showEmail: boolean,
+ * userEmail: string,
+ * showDomain: boolean,
+ * userDomain: string
+ * },
+ * routes: !Array<!media_router.Route>,
+ * castModes: !Array<!media_router.CastMode>}} data
+ * Parameters in data:
+ * deviceMissingUrl - url to be opened on "Device missing?" clicked.
+ * sinksAndIdentity - list of sinks to be displayed and user identity.
+ * routes - list of routes that are associated with the sinks.
+ * castModes - list of available cast modes.
+ */
+ function setInitialData(data) {
container.deviceMissingUrl = data['deviceMissingUrl'];
container.castModeList = data['castModes'];
- container.allSinks = data['sinks'];
+ this.setSinkListAndIdentity(data['sinksAndIdentity']);
container.routeList = data['routes'];
- container.showFirstRunFlow = !data['wasFirstRunFlowAcknowledged'];
container.maybeShowRouteDetailsOnOpen();
media_router.browserApi.onInitialDataReceived();
}
@@ -98,12 +125,27 @@ cr.define('media_router.ui', function() {
}
/**
- * Sets the list of discovered sinks.
+ * Sets the list of discovered sinks along with properties of whether to hide
+ * identity of the user email and domain.
*
- * @param {!Array<!media_router.Sink>} sinkList
+ * @param {{sinks: !Array<!media_router.Sink>,
+ * showEmail: boolean,
+ * userEmail: string,
+ * showDomain: boolean,
+ * userDomain: string,}} data
+ * Parameters in data:
+ * sinks - list of sinks to be displayed.
+ * showEmail - true if the user email should be shown.
+ * userEmail - email of the user if the user is signed in.
+ * showDomain - true if the user domain should be shown.
+ * userDomain - domain of the user if the user is signed in.
*/
- function setSinkList(sinkList) {
- container.allSinks = sinkList;
+ function setSinkListAndIdentity(data) {
+ container.allSinks = data['sinks'];
+ container.showDomain = data['showDomain'];
+ container.userDomain = data['userDomain'];
+ header.showEmail = data['showEmail'];
+ header.userEmail = data['userEmail'];
}
/**
@@ -116,14 +158,14 @@ cr.define('media_router.ui', function() {
}
return {
- onNotifyRouteCreationTimeout: onNotifyRouteCreationTimeout,
onCreateRouteResponseReceived: onCreateRouteResponseReceived,
setCastModeList: setCastModeList,
- setContainer: setContainer,
+ setElements: setElements,
+ setFirstRunFlowData: setFirstRunFlowData,
setInitialData: setInitialData,
setIssue: setIssue,
setRouteList: setRouteList,
- setSinkList: setSinkList,
+ setSinkListAndIdentity: setSinkListAndIdentity,
updateMaxHeight: updateMaxHeight,
};
});
@@ -134,9 +176,12 @@ cr.define('media_router.browserApi', function() {
/**
* Indicates that the user has acknowledged the first run flow.
+ *
+ * @param {boolean} optedIntoCloudServices Whether or not the user opted into
+ * cloud services.
*/
- function acknowledgeFirstRunFlow() {
- chrome.send('acknowledgeFirstRunFlow');
+ function acknowledgeFirstRunFlow(optedIntoCloudServices) {
+ chrome.send('acknowledgeFirstRunFlow', [optedIntoCloudServices]);
}
/**
@@ -153,9 +198,12 @@ cr.define('media_router.browserApi', function() {
/**
* Closes the dialog.
+ *
+ * @param {boolean} pressEscToClose Whether the user pressed ESC to close the
+ * dialog.
*/
- function closeDialog() {
- chrome.send('closeDialog');
+ function closeDialog(pressEscToClose) {
+ chrome.send('closeDialog', [pressEscToClose]);
}
/**
@@ -184,6 +232,13 @@ cr.define('media_router.browserApi', function() {
}
/**
+ * Reports when the user clicks outside the dialog.
+ */
+ function reportBlur() {
+ chrome.send('reportBlur');
+ }
+
+ /**
* Reports the index of the selected sink.
*
* @param {number} sinkIndex
@@ -193,6 +248,13 @@ cr.define('media_router.browserApi', function() {
}
/**
+ * Reports that the user used the filter input.
+ */
+ function reportFilter() {
+ chrome.send('reportFilter');
+ }
+
+ /**
* Reports the initial dialog view.
*
* @param {string} view
@@ -229,6 +291,15 @@ cr.define('media_router.browserApi', function() {
}
/**
+ * Reports the outcome of a create route response.
+ *
+ * @param {number} outcome
+ */
+ function reportRouteCreationOutcome(outcome) {
+ chrome.send('reportRouteCreationOutcome', [outcome]);
+ }
+
+ /**
* Reports the cast mode that the user selected.
*
* @param {number} castModeType
@@ -293,12 +364,15 @@ cr.define('media_router.browserApi', function() {
closeRoute: closeRoute,
joinRoute: joinRoute,
onInitialDataReceived: onInitialDataReceived,
+ reportBlur: reportBlur,
reportClickedSinkIndex: reportClickedSinkIndex,
+ reportFilter: reportFilter,
reportInitialAction: reportInitialAction,
reportInitialState: reportInitialState,
reportNavigateToView: reportNavigateToView,
- reportSelectedCastMode: reportSelectedCastMode,
reportRouteCreation: reportRouteCreation,
+ reportRouteCreationOutcome: reportRouteCreationOutcome,
+ reportSelectedCastMode: reportSelectedCastMode,
reportSinkCount: reportSinkCount,
reportTimeToClickSink: reportTimeToClickSink,
reportTimeToInitialActionClose: reportTimeToInitialActionClose,
diff --git a/chromium/chrome/browser/resources/memory_internals/OWNERS b/chromium/chrome/browser/resources/memory_internals/OWNERS
deleted file mode 100644
index 08086df063e..00000000000
--- a/chromium/chrome/browser/resources/memory_internals/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-peria@chromium.org
diff --git a/chromium/chrome/browser/resources/memory_internals/extension_view.css b/chromium/chrome/browser/resources/memory_internals/extension_view.css
deleted file mode 100644
index 24d2a25176e..00000000000
--- a/chromium/chrome/browser/resources/memory_internals/extension_view.css
+++ /dev/null
@@ -1,22 +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. */
-
-#extension-view .extension-id {
- text-align: right;
- width: 4em;
-}
-
-#extension-view .extension-info {
- text-align: left;
-}
-
-#extension-view .extension-memory {
- border-left: 1px solid rgb(181, 198, 222);
- text-align: right;
- width: 7em;
-}
-
-#extension-template {
- display: none;
-}
diff --git a/chromium/chrome/browser/resources/memory_internals/extension_view.html b/chromium/chrome/browser/resources/memory_internals/extension_view.html
deleted file mode 100644
index 154f12b99e0..00000000000
--- a/chromium/chrome/browser/resources/memory_internals/extension_view.html
+++ /dev/null
@@ -1,14 +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. -->
-<h2>Extensions</h2>
-<table class="list" id="extension-view">
- <tr class="header bottom">
- <th class="extension-id">PID
- <th class="extension-info">Name
- <th class="extension-memory">Private Memory [KB]
- <tr id="extension-template">
- <td class="extension-id">
- <td class="extension-info">
- <td class="extension-memory">
-</table>
diff --git a/chromium/chrome/browser/resources/memory_internals/list.css b/chromium/chrome/browser/resources/memory_internals/list.css
deleted file mode 100644
index 5c9a1267cc4..00000000000
--- a/chromium/chrome/browser/resources/memory_internals/list.css
+++ /dev/null
@@ -1,27 +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. */
-
-table.list {
- border-spacing: 2px;
- width: 100%;
-}
-
-table.list tr:nth-child(odd) td {
- background: rgb(239, 243, 255);
-}
-
-table.list td {
- padding: 0.35em 0.5em 0;
- vertical-align: top;
-}
-
-table.list .header th {
- padding: 0.35em 0.5em 0;
- vertical-align: bottom;
-}
-
-table.list .bottom th,
-table.list th.bottom {
- border-bottom: 1px solid rgb(181, 198, 222);
-}
diff --git a/chromium/chrome/browser/resources/memory_internals/memory_internals.css b/chromium/chrome/browser/resources/memory_internals/memory_internals.css
deleted file mode 100644
index fd6ef69ff89..00000000000
--- a/chromium/chrome/browser/resources/memory_internals/memory_internals.css
+++ /dev/null
@@ -1,39 +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. */
-
-body {
- font-size: 70%;
- margin: 0;
- min-width: 45em;
- padding: 0.75em;
-}
-
-h1 {
- color: rgb(74, 142, 230);
- font-size: 110%;
- font-weight: bold;
- letter-spacing: -1px;
- margin: 0;
- padding: 0;
-}
-
-h2 {
- border-top: 1px solid rgb(58, 117, 189);
- color: rgb(58, 117, 189);
- font-size: 110%;
- font-weight: normal;
- letter-spacing: -1px;
- margin: 20px 0 0 -38px;
- padding: 0.5em 1em 0.5em 38px;
-}
-
-a {
- color: black;
-}
-
-#json {
- display: none;
- height: 100px;
- width: 100%;
-}
diff --git a/chromium/chrome/browser/resources/memory_internals/memory_internals.html b/chromium/chrome/browser/resources/memory_internals/memory_internals.html
deleted file mode 100644
index 94a8ea89413..00000000000
--- a/chromium/chrome/browser/resources/memory_internals/memory_internals.html
+++ /dev/null
@@ -1,23 +0,0 @@
-<!doctype html>
-<!-- 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. -->
-<link rel="stylesheet" href="chrome://resources/css/text_defaults.css">
-<link rel="stylesheet" href="memory_internals.css">
-<link rel="stylesheet" href="list.css">
-<link rel="stylesheet" href="extension_view.css">
-<link rel="stylesheet" href="snapshot_view.css">
-
-<script src="chrome://memory-internals/memory_internals.js"></script>
-<script src="chrome://resources/js/util.js"></script>
-
-<h1>Memory Internals</h1>
-<div id="buttons">
- <button id="button-update">Update</button>
-</div>
-
-<h2>JSON</h2>
-<textarea id="json" readonly></textarea>
-
-<include src="snapshot_view.html">
-<include src="extension_view.html">
diff --git a/chromium/chrome/browser/resources/memory_internals/memory_internals.js b/chromium/chrome/browser/resources/memory_internals/memory_internals.js
deleted file mode 100644
index 5a1d310c636..00000000000
--- a/chromium/chrome/browser/resources/memory_internals/memory_internals.js
+++ /dev/null
@@ -1,172 +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.
-
-var g_main_view = null;
-
-/**
- * This class is the root view object of the page.
- */
-var MainView = (function() {
- 'use strict';
-
- /**
- * @constructor
- */
- function MainView() {
- $('button-update').onclick = function() {
- chrome.send('update');
- };
- };
-
- MainView.prototype = {
- /**
- * Receiving notification to display memory snapshot.
- * @param {Object} Information about memory in JSON format.
- */
- onSetSnapshot: function(browser) {
- $('json').textContent = JSON.stringify(browser);
- $('json').style.display = 'block';
-
- $('os-value').textContent = browser['os'] + ' (' +
- browser['os_version'] + ')';
- $('uptime-value').textContent =
- secondsToHMS(Math.floor(browser['uptime'] / 1000));
-
- this.updateSnapshot(browser['processes']);
- this.updateExtensions(browser['extensions']);
- },
-
- /**
- * Update process information table.
- * @param {Object} processes information about memory.
- */
- updateSnapshot: function(processes) {
- // Remove existing processes.
- var size = $('snapshot-view').getElementsByClassName('process').length;
- for (var i = 0; i < size; ++i) {
- $('snapshot-view').deleteRow(-1);
- }
-
- var template = $('process-template').childNodes;
- // Add processes.
- for (var p in processes) {
- var process = processes[p];
-
- var row = $('snapshot-view').insertRow(-1);
- // We skip |template[0]|, because it is a (invalid) Text object.
- for (var i = 1; i < template.length; ++i) {
- var value = '---';
- switch (template[i].className) {
- case 'process-id':
- value = process['pid'];
- break;
- case 'process-info':
- value = process['type'];
- if (process['type'].match(/^Tab/) && 'history' in process) {
- // Append each tab's history.
- for (var j = 0; j < process['history'].length; ++j) {
- value += '<dl><dt>History ' + j + ':' +
- JoinLinks(process['history'][j]) + '</dl>';
- }
- } else {
- value += '<br>' + process['titles'].join('<br>');
- }
- break;
- case 'process-memory-private':
- value = process['memory_private'];
- break;
- case 'process-memory-v8':
- if (process['v8_alloc'] !== undefined) {
- value = process['v8_used'] + '<br>/ ' + process['v8_alloc'];
- }
- break;
- }
- var col = row.insertCell(-1);
- col.innerHTML = value;
- col.className = template[i].className;
- }
- row.setAttribute('class', 'process');
- }
- },
-
- /**
- * Update extension information table.
- * @param {Object} extensions information about memory.
- */
- updateExtensions: function(extensions) {
- // Remove existing information.
- var size =
- $('extension-view').getElementsByClassName('extension').length;
- for (var i = 0; i < size; ++i) {
- $('extension-view').deleteRow(-1);
- }
-
- var template = $('extension-template').childNodes;
- for (var id in extensions) {
- var extension = extensions[id];
-
- var row = $('extension-view').insertRow(-1);
- // We skip |template[0]|, because it is a (invalid) Text object.
- for (var i = 1; i < template.length; ++i) {
- var value = '---';
- switch (template[i].className) {
- case 'extension-id':
- value = extension['pid'];
- break;
- case 'extension-info':
- value = extension['titles'].join('<br>');
- break;
- case 'extension-memory':
- value = extension['memory_private'];
- break;
- }
- var col = row.insertCell(-1);
- col.innerHTML = value;
- col.className = template[i].className;
- }
- row.setAttribute('class', 'extension');
- }
- }
- };
-
- function JoinLinks(tab) {
- var line = '';
- for (var l in tab['history']) {
- var history = tab['history'][l];
- var title = (history['title'] == '') ? history['url'] : history['title'];
- var url = '<a href="' + history['url'] + '">' + HTMLEscape(title) +
- '</a> (' + secondsToHMS(history['time']) + ' ago)';
- if (l == tab['index']) {
- url = '<strong>' + url + '</strong>';
- }
- line += '<dd>' + url;
- }
- return line;
- };
-
- /**
- * Produces a readable string int the format '<HH> hours <MM> min. <SS> sec.'
- * representing the amount of time provided as the number of seconds.
- * @param {number} totalSeconds The total amount of seconds.
- * @return {string} The formatted HH hours/hours MM min. SS sec. string
- */
- function secondsToHMS(totalSeconds) {
- totalSeconds = Number(totalSeconds);
- var hour = Math.floor(totalSeconds / 3600);
- var min = Math.floor(totalSeconds % 3600 / 60);
- var sec = Math.floor(totalSeconds % 60);
- return (hour > 0 ? (hour + (hour > 1 ? ' hours ' : ' hour ')) : '') +
- (min > 0 ? (min + ' min. ') : '') +
- (sec + ' sec. ');
- }
-
- return MainView;
-})();
-
-/**
- * Initialize everything once we have access to chrome://memory-internals.
- */
-document.addEventListener('DOMContentLoaded', function() {
- g_main_view = new MainView();
-});
diff --git a/chromium/chrome/browser/resources/memory_internals/snapshot_view.css b/chromium/chrome/browser/resources/memory_internals/snapshot_view.css
deleted file mode 100644
index db86eeced8e..00000000000
--- a/chromium/chrome/browser/resources/memory_internals/snapshot_view.css
+++ /dev/null
@@ -1,41 +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. */
-
-#snapshot-view .process-id {
- text-align: right;
- width: 4em;
-}
-
-#snapshot-view .process-info {
- text-align: left;
-}
-
-#snapshot-view dl {
- margin: 0;
- padding: 0;
-}
-
-#snapshot-view dl dd {
- margin-left: 1em;
-}
-
-#snapshot-view .process-memory {
- border-left: 1px solid rgb(181, 198, 222);
- width: 13em;
-}
-
-#snapshot-view .process-memory-private {
- border-left: 1px solid rgb(181, 198, 222);
- text-align: right;
- width: 6em;
-}
-
-#snapshot-view .process-memory-v8 {
- text-align: right;
- width: 7em;
-}
-
-#process-template {
- display: none;
-}
diff --git a/chromium/chrome/browser/resources/memory_internals/snapshot_view.html b/chromium/chrome/browser/resources/memory_internals/snapshot_view.html
deleted file mode 100644
index b6f31984e3c..00000000000
--- a/chromium/chrome/browser/resources/memory_internals/snapshot_view.html
+++ /dev/null
@@ -1,21 +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. -->
-<h2>Processes</h2>
-<div id="os-view">OS: <span id="os-value">unknown</span></div>
-<div id="uptime-view">Uptime: <span id="uptime-value">unknown</span></div>
-
-<table class="list" id="snapshot-view">
- <tr class="header">
- <th rowspan="2" class="process-id bottom">PID
- <th rowspan="2" class="process-info bottom">Name
- <th colspan="2" class="process-memory">Memory [KB]
- <tr class="header bottom">
- <th class="process-memory-private">Private
- <th class="process-memory-v8">V8<br>Used / Alloc
- <tr id="process-template">
- <td class="process-id">
- <td class="process-info">
- <td class="process-memory-private">
- <td class="process-memory-v8">
-</table>
diff --git a/chromium/chrome/browser/resources/memory_internals_resources.grd b/chromium/chrome/browser/resources/memory_internals_resources.grd
deleted file mode 100644
index 4d10d966326..00000000000
--- a/chromium/chrome/browser/resources/memory_internals_resources.grd
+++ /dev/null
@@ -1,15 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<grit latest_public_release="0" current_release="1">
- <outputs>
- <output filename="grit/memory_internals_resources.h" type="rc_header">
- <emit emit_type='prepend'></emit>
- </output>
- <output filename="memory_internals_resources.pak" type="data_package" />
- </outputs>
- <release seq="1">
- <includes>
- <include name="IDR_MEMORY_INTERNALS_MEMORY_INTERNALS_HTML" file="memory_internals/memory_internals.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" />
- <include name="IDR_MEMORY_INTERNALS_MEMORY_INTERNALS_JS" file="memory_internals/memory_internals.js" flattenhtml="true" type="BINDATA" />
- </includes>
- </release>
-</grit>
diff --git a/chromium/chrome/browser/resources/net_internals/alt_svc_view.html b/chromium/chrome/browser/resources/net_internals/alt_svc_view.html
new file mode 100644
index 00000000000..876725fa028
--- /dev/null
+++ b/chromium/chrome/browser/resources/net_internals/alt_svc_view.html
@@ -0,0 +1,22 @@
+<div id=alt-svc-view-tab-content class=content-box>
+ <h4>Alternate Service Mappings</h4>
+ <div id=alt-svc-view-alternate-protocol-mappings>
+ <div jsdisplay="altSvcMappings.length == 0">None</div>
+ <div jsdisplay="altSvcMappings.length != 0">
+ <table class="styled-table">
+ <thead>
+ <tr>
+ <th>Host</th>
+ <th>Alternative Service</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr jsselect="altSvcMappings">
+ <td jscontent="host_port_pair"></td>
+ <td jscontent="alternative_service"></td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+ </div>
+</div>
diff --git a/chromium/chrome/browser/resources/net_internals/alt_svc_view.js b/chromium/chrome/browser/resources/net_internals/alt_svc_view.js
new file mode 100644
index 00000000000..91bc82e9f71
--- /dev/null
+++ b/chromium/chrome/browser/resources/net_internals/alt_svc_view.js
@@ -0,0 +1,61 @@
+// 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.
+
+/**
+ * This view displays the Alt-Svc mappings.
+ */
+var AltSvcView = (function() {
+ 'use strict';
+
+ // We inherit from DivView.
+ var superClass = DivView;
+
+ /**
+ * @constructor
+ */
+ function AltSvcView() {
+ assertFirstConstructorCall(AltSvcView);
+
+ // Call superclass's constructor.
+ superClass.call(this, AltSvcView.MAIN_BOX_ID);
+
+ g_browser.addAltSvcMappingsObserver(this, true);
+ }
+
+ AltSvcView.TAB_ID = 'tab-handle-alt-svc';
+ AltSvcView.TAB_NAME = 'Alt-Svc';
+ AltSvcView.TAB_HASH = '#alt-svc';
+
+ // IDs for special HTML elements in alt_svc_view.html
+ AltSvcView.MAIN_BOX_ID = 'alt-svc-view-tab-content';
+ AltSvcView.ALTERNATE_PROTOCOL_MAPPINGS_ID =
+ 'alt-svc-view-alternate-protocol-mappings';
+
+ cr.addSingletonGetter(AltSvcView);
+
+ AltSvcView.prototype = {
+ // Inherit the superclass's methods.
+ __proto__: superClass.prototype,
+
+ onLoadLogFinish: function(data) {
+ // TODO(rch): Remove the check for spdyAlternateProtocolMappings after
+ // M53 (It was renamed to altSvcMappings in M50).
+ return this.onAltSvcMappingsChanged(data.altSvcMappings ||
+ data.spdyAlternateProtocolMappings);
+ },
+
+ /**
+ * Displays the alternate service mappings.
+ */
+ onAltSvcMappingsChanged: function(altSvcMappings) {
+ if (!altSvcMappings)
+ return false;
+ var input = new JsEvalContext({altSvcMappings: altSvcMappings});
+ jstProcess(input, $(AltSvcView.ALTERNATE_PROTOCOL_MAPPINGS_ID));
+ return true;
+ }
+ };
+
+ return AltSvcView;
+})();
diff --git a/chromium/chrome/browser/resources/net_internals/browser_bridge.js b/chromium/chrome/browser/resources/net_internals/browser_bridge.js
index 85e6bdc9dc5..4e48bbcfa8c 100644
--- a/chromium/chrome/browser/resources/net_internals/browser_bridge.js
+++ b/chromium/chrome/browser/resources/net_internals/browser_bridge.js
@@ -49,8 +49,8 @@ var BrowserBridge = (function() {
this.addNetInfoPollableDataHelper('spdySessionInfo',
'onSpdySessionInfoChanged');
this.addNetInfoPollableDataHelper('spdyStatus', 'onSpdyStatusChanged');
- this.addNetInfoPollableDataHelper('spdyAlternateProtocolMappings',
- 'onSpdyAlternateProtocolMappingsChanged');
+ this.addNetInfoPollableDataHelper('altSvcMappings',
+ 'onAltSvcMappingsChanged');
this.addNetInfoPollableDataHelper('quicInfo', 'onQuicInfoChanged');
this.addNetInfoPollableDataHelper('sdchInfo', 'onSdchInfoChanged');
this.addNetInfoPollableDataHelper('httpCacheInfo',
@@ -485,15 +485,13 @@ var BrowserBridge = (function() {
},
/**
- * Adds a listener of the AlternateProtocolMappings. |observer| will be
+ * Adds a listener of the altSvcMappings. |observer| will be
* called back when data is received, through:
*
- * observer.onSpdyAlternateProtocolMappingsChanged(
- * spdyAlternateProtocolMappings)
+ * observer.onAltSvcMappingsChanged(altSvcMappings)
*/
- addSpdyAlternateProtocolMappingsObserver: function(observer,
- ignoreWhenUnchanged) {
- this.pollableDataHelpers_.spdyAlternateProtocolMappings.addObserver(
+ addAltSvcMappingsObserver: function(observer, ignoreWhenUnchanged) {
+ this.pollableDataHelpers_.altSvcMappings.addObserver(
observer, ignoreWhenUnchanged);
},
diff --git a/chromium/chrome/browser/resources/net_internals/index.html b/chromium/chrome/browser/resources/net_internals/index.html
index 5cf974e2e0e..00b350f1ea9 100644
--- a/chromium/chrome/browser/resources/net_internals/index.html
+++ b/chromium/chrome/browser/resources/net_internals/index.html
@@ -14,7 +14,6 @@ found in the LICENSE file.
<link rel="stylesheet" href="main.css">
<link rel="stylesheet" href="status_view.css">
<link rel="stylesheet" href="events_view.css">
- <link rel="stylesheet" href="waterfall_view.css">
<link rel="stylesheet" href="timeline_view.css">
<link rel="stylesheet" href="chromeos_view.css">
<script src="chrome://resources/js/util.js"></script>
@@ -30,6 +29,7 @@ found in the LICENSE file.
<include src="proxy_view.html">
<include src="dns_view.html">
<include src="sockets_view.html">
+ <include src="alt_svc_view.html">
<include src="spdy_view.html">
<include src="quic_view.html">
<include src="http_cache_view.html">
@@ -41,7 +41,6 @@ found in the LICENSE file.
<include src="capture_view.html">
<include src="hsts_view.html">
<include src="events_view.html">
- <include src="waterfall_view.html">
<include src="timeline_view.html">
<include src="sdch_view.html">
<include src="chromeos_view.html">
diff --git a/chromium/chrome/browser/resources/net_internals/index.js b/chromium/chrome/browser/resources/net_internals/index.js
index 55b9abf7a76..d614267a695 100644
--- a/chromium/chrome/browser/resources/net_internals/index.js
+++ b/chromium/chrome/browser/resources/net_internals/index.js
@@ -27,8 +27,6 @@
<include src="source_filter_parser.js">
<include src="source_row.js">
<include src="events_view.js">
-<include src="waterfall_view.js">
-<include src="waterfall_row.js">
<include src="details_view.js">
<include src="source_entry.js">
<include src="horizontal_scrollbar_view.js">
@@ -42,6 +40,7 @@
<include src="quic_view.js">
<include src="socket_pool_wrapper.js">
<include src="sockets_view.js">
+<include src="alt_svc_view.js">
<include src="spdy_view.js">
<include src="modules_view.js">
<include src="prerender_view.js">
diff --git a/chromium/chrome/browser/resources/net_internals/main.css b/chromium/chrome/browser/resources/net_internals/main.css
index 5f80612a418..b8a005c0c30 100644
--- a/chromium/chrome/browser/resources/net_internals/main.css
+++ b/chromium/chrome/browser/resources/net_internals/main.css
@@ -9,6 +9,10 @@
box-sizing: border-box;
}
+body {
+ overflow: hidden; /* Prevents scroll bar flickering on resize. */
+}
+
ul {
padding-left: 2em;
}
diff --git a/chromium/chrome/browser/resources/net_internals/main.js b/chromium/chrome/browser/resources/net_internals/main.js
index 7c5d6551b5f..0034a981d73 100644
--- a/chromium/chrome/browser/resources/net_internals/main.js
+++ b/chromium/chrome/browser/resources/net_internals/main.js
@@ -187,10 +187,10 @@ var MainView = (function() {
addTab(ImportView);
addTab(ProxyView);
addTab(EventsView);
- addTab(WaterfallView);
addTab(TimelineView);
addTab(DnsView);
addTab(SocketsView);
+ addTab(AltSvcView);
addTab(SpdyView);
addTab(QuicView);
addTab(SdchView);
diff --git a/chromium/chrome/browser/resources/net_internals/quic_view.html b/chromium/chrome/browser/resources/net_internals/quic_view.html
index df6d9432a19..9ee0590fa7c 100644
--- a/chromium/chrome/browser/resources/net_internals/quic_view.html
+++ b/chromium/chrome/browser/resources/net_internals/quic_view.html
@@ -1,13 +1,7 @@
<div id=quic-view-tab-content class=content-box>
<ul style='margin-top:0'>
<li>QUIC Enabled: <span jscontent="!!quic_enabled"></span></li>
- <!-- "alternative_service_probability_threshold" is used since release 44,
- see https://crrev.com/1091283007.
- "alternate_protocol_probability_threshold" is here to support importing
- netlog json files from earlier browsers.
- TODO(bnc): Deprecate around 2016 January. --!>
- <li>Alternative Service Probability Threshold: <span jscontent="$this.alternative_service_probability_threshold || $this.alternate_protocol_probability_threshold"></span></li>
- <li>Origin To Force QUIC On: <span jscontent="origin_to_force_quic_on"></span></li>
+ <li>Origins To Force QUIC On: <span jscontent="origins_to_force_quic_on"></span></li>
<li>Connection options: <span jscontent="connection_options"></span></li>
<li>Consistent Port Selection Enabled: <span jscontent="!!enable_quic_port_selection"></span></li>
<li>Load Server Info Timeout Multiplier: <span jscontent="$this.load_server_info_timeout_srtt_multiplier"></span></li>
@@ -20,6 +14,7 @@
<li>Store Server Configs In Properties File: <span jscontent="!!store_server_configs_in_properties"></span></li>
<li>Idle Connection Timeout In Seconds: <span jscontent="$this.idle_connection_timeout_seconds"></span></li>
<li>Disable PreConnect If 0RTT: <span jscontent="$this.disable_preconnect_if_0rtt"></span></li>
+ <li>Disable QUIC On Timeout With Open Streams: <span jscontent="$this.disable_quic_on_timeout_with_open_streams"></span></li>
<li jsdisplay="$this.disabled_reason && disabled_reason.length > 0">QUIC dynamically disabled: <span jscontent="disabled_reason"></span></li>
</ul>
diff --git a/chromium/chrome/browser/resources/net_internals/spdy_view.html b/chromium/chrome/browser/resources/net_internals/spdy_view.html
index ca314769b60..dd1bc166ef1 100644
--- a/chromium/chrome/browser/resources/net_internals/spdy_view.html
+++ b/chromium/chrome/browser/resources/net_internals/spdy_view.html
@@ -1,6 +1,11 @@
<div id=spdy-view-tab-content class=content-box>
<ul id=spdy-view-status style='margin-top:0'>
- <li>HTTP/2 Enabled: <span jscontent="spdy_enabled"></span></li>
+ <!-- "enable_http2" and "enable_spdy31" are used since release 50, see
+ https://crrev.com/1651123002. "spdy_enabled" is here to support
+ importing netlog json files from earlier browsers.
+ TODO(bnc): Deprecate around 2016 July. -->
+ <li>HTTP/2 Enabled: <span jscontent="$this.enable_http2 == undefined ? $this.spdy_enabled : $this.enable_http2"></span></li>
+ <li>SPDY/3.1 Enabled: <span jscontent="$this.enable_spdy31 == undefined ? $this.spdy_enabled : $this.enable_spdy31"></span></li>
<!-- "use_alternative_service" is used here since release 46, see
https://crrev.com/1268313004. "use_alternate_protocols" is here to
support importing netlog json files from earlier browsers.
@@ -74,25 +79,4 @@
</p>
</div>
</div>
-
- <h4>Alternative Service Mappings</h4>
- <div id=spdy-view-alternate-protocol-mappings>
- <div jsdisplay="spdyAlternateProtocolMappings.length == 0">None</div>
- <div jsdisplay="spdyAlternateProtocolMappings.length != 0">
- <table class="styled-table">
- <thead>
- <tr>
- <th>Host</th>
- <th>Alternative Service</th>
- </tr>
- </thead>
- <tbody>
- <tr jsselect="spdyAlternateProtocolMappings">
- <td jscontent="host_port_pair"></td>
- <td jscontent="alternative_service"></td>
- </tr>
- </tbody>
- </table>
- </div>
- </div>
</div>
diff --git a/chromium/chrome/browser/resources/net_internals/spdy_view.js b/chromium/chrome/browser/resources/net_internals/spdy_view.js
index e7146807e29..797aeda7a25 100644
--- a/chromium/chrome/browser/resources/net_internals/spdy_view.js
+++ b/chromium/chrome/browser/resources/net_internals/spdy_view.js
@@ -23,7 +23,6 @@ var SpdyView = (function() {
g_browser.addSpdySessionInfoObserver(this, true);
g_browser.addSpdyStatusObserver(this, true);
- g_browser.addSpdyAlternateProtocolMappingsObserver(this, true);
}
SpdyView.TAB_ID = 'tab-handle-spdy';
@@ -34,8 +33,6 @@ var SpdyView = (function() {
SpdyView.MAIN_BOX_ID = 'spdy-view-tab-content';
SpdyView.STATUS_ID = 'spdy-view-status';
SpdyView.SESSION_INFO_ID = 'spdy-view-session-info';
- SpdyView.ALTERNATE_PROTOCOL_MAPPINGS_ID =
- 'spdy-view-alternate-protocol-mappings';
cr.addSingletonGetter(SpdyView);
@@ -45,9 +42,7 @@ var SpdyView = (function() {
onLoadLogFinish: function(data) {
return this.onSpdySessionInfoChanged(data.spdySessionInfo) &&
- this.onSpdyStatusChanged(data.spdyStatus) &&
- this.onSpdyAlternateProtocolMappingsChanged(
- data.spdyAlternateProtocolMappings);
+ this.onSpdyStatusChanged(data.spdyStatus);
},
/**
@@ -71,19 +66,6 @@ var SpdyView = (function() {
var input = new JsEvalContext(spdyStatus);
jstProcess(input, $(SpdyView.STATUS_ID));
return true;
- },
-
- /**
- * Displays information on the SPDY alternate protocol mappings.
- */
- onSpdyAlternateProtocolMappingsChanged: function(
- spdyAlternateProtocolMappings) {
- if (!spdyAlternateProtocolMappings)
- return false;
- var input = new JsEvalContext(
- {spdyAlternateProtocolMappings: spdyAlternateProtocolMappings});
- jstProcess(input, $(SpdyView.ALTERNATE_PROTOCOL_MAPPINGS_ID));
- return true;
}
};
diff --git a/chromium/chrome/browser/resources/net_internals/waterfall_row.js b/chromium/chrome/browser/resources/net_internals/waterfall_row.js
deleted file mode 100644
index 6e6abe511bf..00000000000
--- a/chromium/chrome/browser/resources/net_internals/waterfall_row.js
+++ /dev/null
@@ -1,406 +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.
-
-var WaterfallRow = (function() {
- 'use strict';
-
- /**
- * A WaterfallRow represents the row corresponding to a single SourceEntry
- * displayed by the EventsWaterfallView. All times are relative to the
- * "base time" (Time of first event from any source).
- *
- * @constructor
- */
-
- // TODO(viona):
- // -Support nested events.
- // -Handle updating length when an event is stalled.
- function WaterfallRow(parentView, sourceEntry) {
- this.parentView_ = parentView;
- this.sourceEntry_ = sourceEntry;
-
- this.description_ = sourceEntry.getDescription();
-
- this.createRow_();
- }
-
- // Offset of popup from mouse location.
- var POPUP_OFFSET_FROM_CURSOR = 25;
-
- WaterfallRow.prototype = {
- onSourceUpdated: function() {
- this.updateRow();
- },
-
- updateRow: function() {
- var scale = this.parentView_.getScaleFactor();
- // In some cases, the REQUEST_ALIVE event has been received, while the
- // URL Request to start the job has not been received. In that case, the
- // description obtained is incorrect. The following fixes that.
- if (this.description_ == '') {
- this.sourceCell_.innerHTML = '';
- this.description_ = this.sourceEntry_.getDescription();
- addTextNode(this.sourceCell_, this.description_);
- }
-
- this.rowCell_.innerHTML = '';
-
- var matchingEventPairs =
- WaterfallRow.findUrlRequestEvents(this.sourceEntry_);
-
- // Creates the spacing in the beginning to show start time.
- var sourceStartTicks = this.getStartTicks();
- var frontNode = addNode(this.rowCell_, 'div');
- frontNode.classList.add('waterfall-view-padding');
- setNodeWidth(frontNode, sourceStartTicks * scale);
-
- var barCell = addNode(this.rowCell_, 'div');
- barCell.classList.add('waterfall-view-bar');
-
- if (this.sourceEntry_.isError()) {
- barCell.classList.add('error');
- }
-
- var currentEnd = sourceStartTicks;
-
- for (var i = 0; i < matchingEventPairs.length; ++i) {
- var event = matchingEventPairs[i];
- var startTicks =
- timeutil.convertTimeTicksToRelativeTime(event.startEntry.time);
- var endTicks =
- timeutil.convertTimeTicksToRelativeTime(event.endEntry.time);
- event.eventType = event.startEntry.type;
- event.startTime = startTicks;
- event.endTime = endTicks;
- event.eventDuration = event.endTime - event.startTime;
-
- // Handles the spaces between events.
- if (currentEnd < event.startTime) {
- var eventDuration = event.startTime - currentEnd;
- var padNode = this.createNode_(
- barCell, eventDuration, this.sourceTypeString_, 'source');
- }
-
- // Creates event bars.
- var eventNode = this.createNode_(
- barCell, event.eventDuration, EventTypeNames[event.eventType],
- event);
- currentEnd = event.startTime + event.eventDuration;
- }
-
- // Creates a bar for the part after the last event.
- var endTime = this.getEndTicks();
- if (endTime > currentEnd) {
- var endDuration = endTime - currentEnd;
- var endNode = this.createNode_(
- barCell, endDuration, this.sourceTypeString_, 'source');
- }
- },
-
- getStartTicks: function() {
- return timeutil.convertTimeTicksToRelativeTime(
- this.sourceEntry_.getStartTicks());
- },
-
- getEndTicks: function() {
- return timeutil.convertTimeTicksToRelativeTime(
- this.sourceEntry_.getEndTicks());
- },
-
- clearPopup_: function(parentNode) {
- parentNode.innerHTML = '';
- },
-
- createPopup_: function(parentNode, event, eventType, duration, mouse) {
- var newPopup = addNode(parentNode, 'div');
- newPopup.classList.add('waterfall-view-popup');
-
- var popupList = addNode(newPopup, 'ul');
- popupList.classList.add('waterfall-view-popup-list');
-
- popupList.style.maxWidth =
- $(WaterfallView.MAIN_BOX_ID).offsetWidth * 0.5 + 'px';
-
- this.createPopupItem_(
- popupList, 'Has Error', this.sourceEntry_.isError());
-
- this.createPopupItem_(popupList, 'Event Type', eventType);
-
- if (event != 'source') {
- this.createPopupItem_(
- popupList, 'Event Duration', duration.toFixed(0) + 'ms');
- this.createPopupItem_(
- popupList, 'Event Start Time', event.startTime + 'ms');
- this.createPopupItem_(
- popupList, 'Event End Time', event.endTime + 'ms');
- }
- this.createPopupItem_(popupList, 'Source Duration',
- this.getEndTicks() - this.getStartTicks() + 'ms');
- this.createPopupItem_(popupList, 'Source Start Time',
- this.getStartTicks() + 'ms');
- this.createPopupItem_(popupList, 'Source End Time',
- this.getEndTicks() + 'ms');
- this.createPopupItem_(
- popupList, 'Source ID', this.sourceEntry_.getSourceId());
- var urlListItem = this.createPopupItem_(
- popupList, 'Source Description', this.description_);
-
- urlListItem.classList.add('waterfall-view-popup-list-url-item');
-
- // Fixes cases where the popup appears 'off-screen'.
- var popupLeft = mouse.pageX - newPopup.offsetWidth;
- if (popupLeft < 0) {
- popupLeft = mouse.pageX;
- }
- newPopup.style.left = popupLeft +
- $(WaterfallView.MAIN_BOX_ID).scrollLeft -
- $(WaterfallView.BAR_TABLE_ID).offsetLeft + 'px';
-
- var popupTop = mouse.pageY - newPopup.offsetHeight -
- POPUP_OFFSET_FROM_CURSOR;
- if (popupTop < 0) {
- popupTop = mouse.pageY;
- }
- newPopup.style.top = popupTop +
- $(WaterfallView.MAIN_BOX_ID).scrollTop -
- $(WaterfallView.BAR_TABLE_ID).offsetTop + 'px';
- },
-
- createPopupItem_: function(parentPopup, key, popupInformation) {
- var popupItem = addNode(parentPopup, 'li');
- addTextNode(popupItem, key + ': ' + popupInformation);
- return popupItem;
- },
-
- createRow_: function() {
- // Create a row.
- var tr = addNode($(WaterfallView.BAR_TBODY_ID), 'tr');
- tr.classList.add('waterfall-view-table-row');
-
- // Creates the color bar.
-
- var rowCell = addNode(tr, 'td');
- rowCell.classList.add('waterfall-view-row');
- this.rowCell_ = rowCell;
-
- this.sourceTypeString_ = this.sourceEntry_.getSourceTypeString();
-
- var infoTr = addNode($(WaterfallView.INFO_TBODY_ID), 'tr');
- infoTr.classList.add('waterfall-view-information-row');
-
- var idCell = addNode(infoTr, 'td');
- idCell.classList.add('waterfall-view-id-cell');
- var idValue = this.sourceEntry_.getSourceId();
- var idLink = addNodeWithText(idCell, 'a', idValue);
- idLink.href = '#events&s=' + idValue;
-
- var sourceCell = addNode(infoTr, 'td');
- sourceCell.classList.add('waterfall-view-url-cell');
- addTextNode(sourceCell, this.description_);
- this.sourceCell_ = sourceCell;
-
- this.updateRow();
- },
-
- // Generates nodes.
- createNode_: function(parentNode, duration, eventTypeString, event) {
- var linkNode = addNode(parentNode, 'a');
- linkNode.href = '#events&s=' + this.sourceEntry_.getSourceId();
-
- var scale = this.parentView_.getScaleFactor();
- var newNode = addNode(linkNode, 'div');
- setNodeWidth(newNode, duration * scale);
- newNode.classList.add(eventTypeToCssClass_(eventTypeString));
- newNode.classList.add('waterfall-view-bar-component');
- newNode.addEventListener(
- 'mouseover',
- this.createPopup_.bind(this, newNode, event, eventTypeString,
- duration),
- true);
- newNode.addEventListener(
- 'mouseout', this.clearPopup_.bind(this, newNode), true);
- return newNode;
- },
- };
-
- /**
- * Identifies source dependencies and extracts events of interest for use in
- * inlining in URL Request bars.
- * Created as static function for testing purposes.
- */
- WaterfallRow.findUrlRequestEvents = function(sourceEntry) {
- var eventPairs = [];
- if (!sourceEntry) {
- return eventPairs;
- }
-
- // One level down from URL Requests.
-
- var httpStreamJobSources = findDependenciesOfType_(
- sourceEntry, EventType.HTTP_STREAM_REQUEST_BOUND_TO_JOB);
-
- var httpTransactionReadHeadersPairs = findEntryPairsFromSourceEntries_(
- [sourceEntry], EventType.HTTP_TRANSACTION_READ_HEADERS);
- eventPairs = eventPairs.concat(httpTransactionReadHeadersPairs);
-
- var proxyServicePairs = findEntryPairsFromSourceEntries_(
- httpStreamJobSources, EventType.PROXY_SERVICE);
- eventPairs = eventPairs.concat(proxyServicePairs);
-
- if (httpStreamJobSources.length > 0) {
- for (var i = 0; i < httpStreamJobSources.length; ++i) {
- // Two levels down from URL Requests.
-
- var socketSources = findDependenciesOfType_(
- httpStreamJobSources[i], EventType.SOCKET_POOL_BOUND_TO_SOCKET);
-
- // TODO(mmenke): Some of these may be nested in the PROXY_SERVICE
- // event, resulting in incorrect display, since nested
- // events aren't handled.
- var hostResolverImplRequestPairs = findEntryPairsByType_(
- httpStreamJobSources[i], EventType.HOST_RESOLVER_IMPL_REQUEST);
- eventPairs = eventPairs.concat(hostResolverImplRequestPairs);
-
- // Truncate times of connection events such that they don't occur before
- // the HTTP_STREAM_JOB event or the PROXY_SERVICE event.
- // TODO(mmenke): The last HOST_RESOLVER_IMPL_REQUEST may still be a
- // problem.
- var minTime = httpStreamJobSources[i].getLogEntries()[0].time;
- if (proxyServicePairs.length > 0)
- minTime = proxyServicePairs[0].endEntry.time;
- // Convert to number so comparisons will be numeric, not string,
- // comparisons.
- minTime = Number(minTime);
-
- var tcpConnectPairs = findEntryPairsFromSourceEntries_(
- socketSources, EventType.TCP_CONNECT);
-
- var sslConnectPairs = findEntryPairsFromSourceEntries_(
- socketSources, EventType.SSL_CONNECT);
-
- var connectionPairs = tcpConnectPairs.concat(sslConnectPairs);
-
- // Truncates times of connection events such that they are shown after a
- // proxy service event.
- for (var k = 0; k < connectionPairs.length; ++k) {
- var eventPair = connectionPairs[k];
- var eventInRange = false;
- if (eventPair.startEntry.time >= minTime) {
- eventInRange = true;
- } else if (eventPair.endEntry.time > minTime) {
- eventInRange = true;
- // Should not modify original object.
- eventPair.startEntry = shallowCloneObject(eventPair.startEntry);
- // Need to have a string, for consistency.
- eventPair.startEntry.time = minTime + '';
- }
- if (eventInRange) {
- eventPairs.push(eventPair);
- }
- }
- }
- }
- eventPairs.sort(function(a, b) {
- return a.startEntry.time - b.startEntry.time;
- });
- return eventPairs;
- };
-
- function eventTypeToCssClass_(eventType) {
- return eventType.toLowerCase().replace(/_/g, '-');
- }
-
- /**
- * Finds all events of input type from the input list of Source Entries.
- * Returns an ordered list of start and end log entries.
- */
- function findEntryPairsFromSourceEntries_(sourceEntryList, eventType) {
- var eventPairs = [];
- for (var i = 0; i < sourceEntryList.length; ++i) {
- var sourceEntry = sourceEntryList[i];
- if (sourceEntry) {
- var entries = sourceEntry.getLogEntries();
- var matchingEventPairs = findEntryPairsByType_(entries, eventType);
- eventPairs = eventPairs.concat(matchingEventPairs);
- }
- }
- return eventPairs;
- }
-
- /**
- * Finds all events of input type from the input list of log entries.
- * Returns an ordered list of start and end log entries.
- */
- function findEntryPairsByType_(entries, eventType) {
- var matchingEventPairs = [];
- var startEntry = null;
- for (var i = 0; i < entries.length; ++i) {
- var currentEntry = entries[i];
- if (eventType != currentEntry.type) {
- continue;
- }
- if (currentEntry.phase == EventPhase.PHASE_BEGIN) {
- startEntry = currentEntry;
- }
- if (startEntry && currentEntry.phase == EventPhase.PHASE_END) {
- var event = {
- startEntry: startEntry,
- endEntry: currentEntry,
- };
- matchingEventPairs.push(event);
- startEntry = null;
- }
- }
- return matchingEventPairs;
- }
-
- /**
- * Returns an ordered list of SourceEntries that are dependencies for
- * events of the given type.
- */
- function findDependenciesOfType_(sourceEntry, eventType) {
- var sourceEntryList = [];
- if (sourceEntry) {
- var eventList = findEventsInSourceEntry_(sourceEntry, eventType);
- for (var i = 0; i < eventList.length; ++i) {
- var foundSourceEntry = findSourceEntryFromEvent_(eventList[i]);
- if (foundSourceEntry) {
- sourceEntryList.push(foundSourceEntry);
- }
- }
- }
- return sourceEntryList;
- }
-
- /**
- * Returns an ordered list of events from the given sourceEntry with the
- * given type.
- */
- function findEventsInSourceEntry_(sourceEntry, eventType) {
- var entries = sourceEntry.getLogEntries();
- var events = [];
- for (var i = 0; i < entries.length; ++i) {
- var currentEntry = entries[i];
- if (currentEntry.type == eventType) {
- events.push(currentEntry);
- }
- }
- return events;
- }
-
- /**
- * Follows the event to obtain the sourceEntry that is the source
- * dependency.
- */
- function findSourceEntryFromEvent_(event) {
- if (!('params' in event) || !('source_dependency' in event.params)) {
- return undefined;
- } else {
- var id = event.params.source_dependency.id;
- return SourceTracker.getInstance().getSourceEntry(id);
- }
- }
-
- return WaterfallRow;
-})();
diff --git a/chromium/chrome/browser/resources/net_internals/waterfall_view.css b/chromium/chrome/browser/resources/net_internals/waterfall_view.css
deleted file mode 100644
index d30721bb722..00000000000
--- a/chromium/chrome/browser/resources/net_internals/waterfall_view.css
+++ /dev/null
@@ -1,178 +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.
- */
-
-#waterfall-view-controls {
- background-color: #FFF;
- border-color: #000;
- border-style: solid;
- border-width: 1px;
- padding-left: 5px;
- position: fixed;
- top: 40px;
- /* Displays above time bar and information tables. */
- z-index: 3;
-}
-
-#waterfall-view-time-bar-table {
- border-collapse: collapse;
- border-spacing: 0;
- position: absolute;
- /* Displays above main tab and under information table. */
- z-index: 1;
-}
-
-#waterfall-view-information-table {
- background-color: #FFF;
- border-collapse: collapse;
- border-spacing: 0;
- left: 0;
- overflow: hidden;
- position: fixed;
- /* Displays above time bar table. */
- z-index: 2;
-}
-
-.waterfall-view-information-row {
- height: 25px;
- margin: 0;
- padding: 0;
- white-space: nowrap;
-}
-
-.waterfall-view-url-cell {
- display: inline-block;
- font-size: 15px;
- height: 25px;
- overflow: hidden;
- padding-bottom: 0;
- padding-top: 0;
- text-overflow: ellipsis;
- white-space: nowrap;
- width: 250px;
-}
-
-.waterfall-view-id-cell {
- display: inline-block;
- font-size: 15px;
- height: 25px;
- min-width: 30px;
- overflow: hidden;
- padding-bottom: 0;
- padding-left: 5px;
- padding-right: 2px;
- padding-top: 0;
-}
-
-.waterfall-view-table-row {
- white-space: nowrap;
-}
-
-.waterfall-view-row {
- height: 25px;
- padding: 0;
-}
-
-.waterfall-view-row * {
- display: inline-block;
- padding-top: 0;
-}
-
-.waterfall-view-bar-component {
- height: 15px;
-}
-
-.waterfall-view-popup {
- display: inline-block;
- position: absolute;
- /* Displays above info table and controls */
- z-index: 4;
-}
-
-.waterfall-view-popup-list {
- background-color: rgba(255, 255, 255, 0.8);
- border-color: #000;
- border-style: solid;
- border-width: 2px;
- color: #000;
- padding-right: 1em;
-}
-
-.waterfall-view-popup-list > li {
- display: list-item;
-}
-.waterfall-view-popup-list-url-item {
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
-}
-
-.waterfall-view-bar.error {
- border-color: rgba(255, 0, 0, 0.8);
- border-style: solid;
- border-width: 1px;
- height: 18px;
-}
-
-.waterfall-view-row .http-stream-request {
- background: -webkit-linear-gradient(top, #EEE, rgba(0, 0, 0, 0.5));
-}
-
-.waterfall-view-row .http-stream-request-bound-to-job {
- background: -webkit-linear-gradient(top, #EEE, rgba(200, 200, 200, 0.5));
-}
-
-.waterfall-view-row .http-transaction-read-headers {
- background: -webkit-linear-gradient(top, #EEE, rgba(255, 0, 0, 0.5));
-}
-
-.waterfall-view-row .url-request {
- background: -webkit-linear-gradient(top, #EEE, rgba(0, 0, 255, 0.5));
-}
-
-.waterfall-view-row .http-stream-job {
- background: -webkit-linear-gradient(top, #EEE, rgba(0, 255, 0, 0.5));
-}
-
-.waterfall-view-row .proxy-service {
- background: -webkit-linear-gradient(top, #EEE, rgba(122, 122, 0, 0.5));
-}
-
-.waterfall-view-row .socket-pool-connect-job {
- background: -webkit-linear-gradient(top, #EEE, rgba(0, 122, 122, 0.5));
-}
-
-.waterfall-view-row .host-resolver-impl-request {
- background: -webkit-linear-gradient(top, #EEE, rgba(122, 0, 122, 0.5));
-}
-
-.waterfall-view-row .socket {
- background: -webkit-linear-gradient(top, #EEE, rgba(122, 178, 0, 0.5));
-}
-
-.waterfall-view-row .tcp-connect {
- background: -webkit-linear-gradient(top, #EEE, rgba(0, 178, 122, 0.5));
-}
-
-.waterfall-view-row .ssl-connect {
- background: -webkit-linear-gradient(top, #EEE, rgba(55, 122, 178, 0.5));
-}
-
-.waterfall-view-time-scale-row {
- white-space: nowrap;
-}
-
-.waterfall-view-time-scale {
- border-color: #000;
- border-left-style: solid;
- border-width: 1px;
- box-sizing: border-box;
- display: inline-block;
- height: 15px;
-}
-
-/* Colors every fifth bar red. */
-.waterfall-view-time-scale-special {
- border-color: rgb(255, 0, 0);
-}
diff --git a/chromium/chrome/browser/resources/net_internals/waterfall_view.html b/chromium/chrome/browser/resources/net_internals/waterfall_view.html
deleted file mode 100644
index fbbca322d1a..00000000000
--- a/chromium/chrome/browser/resources/net_internals/waterfall_view.html
+++ /dev/null
@@ -1,31 +0,0 @@
-<!-- =============== Events Waterfall View ================= -->
-<div id=waterfall-view-tab-content class=content-box>
- <div>
- <div id=waterfall-view-controls>
- Start Time: <input id=waterfall-view-start-input type=number min=0 value=0>
- End Time: <input id=waterfall-view-end-input type=number min=0>
- <input id=waterfall-view-adjust-to-window type=button value="Fit Range in Window">
- </div>
- <p>
- <!-- Table that displays time bars -->
- <table id=waterfall-view-time-bar-table>
- <thead>
- <tr id=waterfall-view-table-header>
- <td id=waterfall-view-time-scale-labels></td>
- </tr>
- </thead>
- <!-- Events Waterfall table body: This is where request rows go into -->
- <tbody id=waterfall-view-time-bar-tbody></tbody>
- </table>
- <!-- Fixed table that contains the id and url information. -->
- <table id=waterfall-view-information-table>
- <thead id=waterfall-view-information-thead>
- <tr>
- <td class=waterfall-view-id-cell id=waterfall-view-id-header>ID</td>
- <td class=waterfall-view-url-cell id=waterfall-view-url-header>URL</td>
- </tr>
- </thead>
- <tbody id=waterfall-view-information-tbody></tbody>
- </table>
- </div>
-</div>
diff --git a/chromium/chrome/browser/resources/net_internals/waterfall_view.js b/chromium/chrome/browser/resources/net_internals/waterfall_view.js
deleted file mode 100644
index 928730ba8d4..00000000000
--- a/chromium/chrome/browser/resources/net_internals/waterfall_view.js
+++ /dev/null
@@ -1,283 +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.
-
-// TODO(viona): Write a README document/instructions.
-
-/** This view displays the event waterfall. */
-var WaterfallView = (function() {
- 'use strict';
-
- // We inherit from DivView.
- var superClass = DivView;
-
- /**
- * @constructor
- */
- function WaterfallView() {
- assertFirstConstructorCall(WaterfallView);
-
- // Call superclass's constructor.
- superClass.call(this, WaterfallView.MAIN_BOX_ID);
-
- SourceTracker.getInstance().addSourceEntryObserver(this);
-
- // For adjusting the range of view.
- $(WaterfallView.SCALE_ID).addEventListener(
- 'click', this.setStartEndTimes_.bind(this), true);
-
- $(WaterfallView.MAIN_BOX_ID).addEventListener(
- 'mousewheel', this.scrollToZoom_.bind(this), true);
-
- $(WaterfallView.MAIN_BOX_ID).addEventListener(
- 'scroll', this.scrollInfoTable_.bind(this), true);
-
- this.initializeSourceList_();
-
- window.onload = this.scrollInfoTable_();
- }
-
- WaterfallView.TAB_ID = 'tab-handle-waterfall';
- WaterfallView.TAB_NAME = 'Waterfall';
- WaterfallView.TAB_HASH = '#waterfall';
-
- // IDs for special HTML elements in events_waterfall_view.html.
- WaterfallView.MAIN_BOX_ID = 'waterfall-view-tab-content';
- WaterfallView.BAR_TABLE_ID = 'waterfall-view-time-bar-table';
- WaterfallView.BAR_TBODY_ID = 'waterfall-view-time-bar-tbody';
- WaterfallView.SCALE_ID = 'waterfall-view-adjust-to-window';
- WaterfallView.TIME_SCALE_HEADER_ID = 'waterfall-view-time-scale-labels';
- WaterfallView.TIME_RANGE_ID = 'waterfall-view-time-range-submit';
- WaterfallView.START_TIME_ID = 'waterfall-view-start-input';
- WaterfallView.END_TIME_ID = 'waterfall-view-end-input';
- WaterfallView.INFO_TABLE_ID = 'waterfall-view-information-table';
- WaterfallView.INFO_TBODY_ID = 'waterfall-view-information-tbody';
- WaterfallView.CONTROLS_ID = 'waterfall-view-controls';
- WaterfallView.ID_HEADER_ID = 'waterfall-view-id-header';
- WaterfallView.URL_HEADER_ID = 'waterfall-view-url-header';
-
- // The number of units mouse wheel deltas increase for each tick of the
- // wheel.
- var MOUSE_WHEEL_UNITS_PER_CLICK = 120;
-
- // Amount we zoom for one vertical tick of the mouse wheel, as a ratio.
- var MOUSE_WHEEL_ZOOM_RATE = 1.25;
- // Amount we scroll for one horizontal tick of the mouse wheel, in pixels.
- var MOUSE_WHEEL_SCROLL_RATE = MOUSE_WHEEL_UNITS_PER_CLICK;
-
- cr.addSingletonGetter(WaterfallView);
-
- WaterfallView.prototype = {
- // Inherit the superclass's methods.
- __proto__: superClass.prototype,
-
- /**
- * Creates new WaterfallRows for URL Requests when the sourceEntries are
- * updated if they do not already exist.
- * Updates pre-existing WaterfallRows that correspond to updated sources.
- */
- onSourceEntriesUpdated: function(sourceEntries) {
- for (var i = 0; i < sourceEntries.length; ++i) {
- var sourceEntry = sourceEntries[i];
- var id = sourceEntry.getSourceId();
- if (sourceEntry.getSourceType() == EventSourceType.URL_REQUEST) {
- var row = this.sourceIdToRowMap_[id];
- if (!row) {
- var newRow = new WaterfallRow(this, sourceEntry);
- this.sourceIdToRowMap_[id] = newRow;
- } else {
- row.onSourceUpdated();
- }
- }
- }
- this.scrollInfoTable_();
- this.positionBarTable_();
- this.updateTimeScale_(this.scaleFactor_);
- },
-
- onAllSourceEntriesDeleted: function() {
- this.initializeSourceList_();
- },
-
- onLoadLogFinish: function(data) {
- return true;
- },
-
- getScaleFactor: function() {
- return this.scaleFactor_;
- },
-
- setGeometry: function(left, top, width, height) {
- superClass.prototype.setGeometry.call(this, left, top, width, height);
- this.scrollInfoTable_();
- },
-
- show: function(isVisible) {
- superClass.prototype.show.call(this, isVisible);
- if (isVisible) {
- this.scrollInfoTable_();
- }
- },
-
- /**
- * Initializes the list of source entries. If source entries are already
- * being displayed, removes them all in the process.
- */
- initializeSourceList_: function() {
- this.sourceIdToRowMap_ = {};
- $(WaterfallView.BAR_TBODY_ID).innerHTML = '';
- $(WaterfallView.INFO_TBODY_ID).innerHTML = '';
- this.scaleFactor_ = 0.1;
- },
-
- /**
- * Changes scroll position of the window such that horizontally, everything
- * within the specified range fits into the user's viewport.
- */
- adjustToWindow_: function(windowStart, windowEnd) {
- var waterfallLeft = $(WaterfallView.INFO_TABLE_ID).offsetWidth +
- $(WaterfallView.INFO_TABLE_ID).offsetLeft +
- $(WaterfallView.ID_HEADER_ID).offsetWidth;
- var maxWidth = $(WaterfallView.MAIN_BOX_ID).offsetWidth - waterfallLeft;
- var totalDuration = 0;
- if (windowEnd != -1) {
- totalDuration = windowEnd - windowStart;
- } else {
- for (var id in this.sourceIdToRowMap_) {
- var row = this.sourceIdToRowMap_[id];
- var rowDuration = row.getEndTicks();
- if (totalDuration < rowDuration && !row.hide) {
- totalDuration = rowDuration;
- }
- }
- }
- if (totalDuration <= 0) {
- return;
- }
- this.scaleAll_(maxWidth / totalDuration);
- $(WaterfallView.MAIN_BOX_ID).scrollLeft =
- windowStart * this.scaleFactor_;
- },
-
- /** Updates the time tick indicators. */
- updateTimeScale_: function(scaleFactor) {
- var timePerTick = 1;
- var minTickDistance = 20;
-
- $(WaterfallView.TIME_SCALE_HEADER_ID).innerHTML = '';
-
- // Holder provides environment to prevent wrapping.
- var timeTickRow = addNode($(WaterfallView.TIME_SCALE_HEADER_ID), 'div');
- timeTickRow.classList.add('waterfall-view-time-scale-row');
-
- var availableWidth = $(WaterfallView.BAR_TBODY_ID).clientWidth;
- var tickDistance = scaleFactor * timePerTick;
-
- while (tickDistance < minTickDistance) {
- timePerTick = timePerTick * 10;
- tickDistance = scaleFactor * timePerTick;
- }
-
- var tickCount = availableWidth / tickDistance;
- for (var i = 0; i < tickCount; ++i) {
- var timeCell = addNode(timeTickRow, 'div');
- setNodeWidth(timeCell, tickDistance);
- timeCell.classList.add('waterfall-view-time-scale');
- timeCell.title = i * timePerTick + ' to ' +
- (i + 1) * timePerTick + ' ms';
- // Red marker for every 5th bar.
- if (i % 5 == 0) {
- timeCell.classList.add('waterfall-view-time-scale-special');
- }
- }
- },
-
- /**
- * Scales all existing rows by scaleFactor.
- */
- scaleAll_: function(scaleFactor) {
- this.scaleFactor_ = scaleFactor;
- for (var id in this.sourceIdToRowMap_) {
- var row = this.sourceIdToRowMap_[id];
- row.updateRow();
- }
- this.updateTimeScale_(scaleFactor);
- },
-
- scrollToZoom_: function(event) {
- // To use scrolling to control zoom, hold down the alt key and scroll.
- if ('wheelDelta' in event && event.altKey) {
- event.preventDefault();
- var zoomFactor = Math.pow(MOUSE_WHEEL_ZOOM_RATE,
- event.wheelDeltaY / MOUSE_WHEEL_UNITS_PER_CLICK);
-
- var waterfallLeft = $(WaterfallView.ID_HEADER_ID).offsetWidth +
- $(WaterfallView.URL_HEADER_ID).offsetWidth;
- var oldCursorPosition = event.pageX +
- $(WaterfallView.MAIN_BOX_ID).scrollLeft;
- var oldCursorPositionInTable = oldCursorPosition - waterfallLeft;
-
- this.scaleAll_(this.scaleFactor_ * zoomFactor);
-
- // Shifts the view when scrolling. newScroll could be less than 0 or
- // more than the maximum scroll position, but both cases are handled
- // by the inbuilt scrollLeft implementation.
- var newScroll =
- oldCursorPositionInTable * zoomFactor - event.pageX + waterfallLeft;
- $(WaterfallView.MAIN_BOX_ID).scrollLeft = newScroll;
- }
- },
-
- /**
- * Positions the bar table such that it is in line with the right edge of
- * the info table.
- */
- positionBarTable_: function() {
- var offsetLeft = $(WaterfallView.INFO_TABLE_ID).offsetWidth +
- $(WaterfallView.INFO_TABLE_ID).offsetLeft;
- $(WaterfallView.BAR_TABLE_ID).style.left = offsetLeft + 'px';
- },
-
- /**
- * Moves the info table when the page is scrolled vertically, ensuring that
- * the correct information is displayed on the page, and that no elements
- * are blocked unnecessarily.
- */
- scrollInfoTable_: function(event) {
- $(WaterfallView.INFO_TABLE_ID).style.top =
- $(WaterfallView.MAIN_BOX_ID).offsetTop +
- $(WaterfallView.BAR_TABLE_ID).offsetTop -
- $(WaterfallView.MAIN_BOX_ID).scrollTop + 'px';
-
- if ($(WaterfallView.INFO_TABLE_ID).offsetHeight >
- $(WaterfallView.MAIN_BOX_ID).clientHeight) {
- var scroll = $(WaterfallView.MAIN_BOX_ID).scrollTop;
- var bottomClip =
- $(WaterfallView.MAIN_BOX_ID).clientHeight -
- $(WaterfallView.BAR_TABLE_ID).offsetTop +
- $(WaterfallView.MAIN_BOX_ID).scrollTop;
- // Clips the information table such that it does not cover the scroll
- // bars or the controls bar.
- $(WaterfallView.INFO_TABLE_ID).style.clip = 'rect(' + scroll +
- 'px auto ' + bottomClip + 'px auto)';
- }
- },
-
- /** Parses user input, then calls adjustToWindow to shift that into view. */
- setStartEndTimes_: function() {
- var windowStart = parseInt($(WaterfallView.START_TIME_ID).value);
- var windowEnd = parseInt($(WaterfallView.END_TIME_ID).value);
- if ($(WaterfallView.END_TIME_ID).value == '') {
- windowEnd = -1;
- }
- if ($(WaterfallView.START_TIME_ID).value == '') {
- windowStart = 0;
- }
- this.adjustToWindow_(windowStart, windowEnd);
- },
-
-
- };
-
- return WaterfallView;
-})();
diff --git a/chromium/chrome/browser/resources/ntp4/compiled_resources.gyp b/chromium/chrome/browser/resources/ntp4/compiled_resources.gyp
index 8b2b37c8e10..4f9b08eef76 100644
--- a/chromium/chrome/browser/resources/ntp4/compiled_resources.gyp
+++ b/chromium/chrome/browser/resources/ntp4/compiled_resources.gyp
@@ -13,8 +13,8 @@
'../../../../ui/webui/resources/js/event_tracker.js',
'../../../../ui/webui/resources/js/load_time_data.js',
'../../../../ui/webui/resources/js/parse_html_subset.js',
+ '../../../../ui/webui/resources/js/promise_resolver.js',
'../../../../ui/webui/resources/js/util.js',
- '../../../../ui/webui/resources/js/cr.js',
'../../../../ui/webui/resources/js/cr/event_target.js',
'../../../../ui/webui/resources/js/cr/ui.js',
'../../../../ui/webui/resources/js/cr/ui/bubble.js',
diff --git a/chromium/chrome/browser/resources/ntp4/guest_tab.html b/chromium/chrome/browser/resources/ntp4/guest_tab.html
index 704140ab1ef..15b74f042cb 100644
--- a/chromium/chrome/browser/resources/ntp4/guest_tab.html
+++ b/chromium/chrome/browser/resources/ntp4/guest_tab.html
@@ -3,8 +3,7 @@
<head>
<meta charset="utf-8">
<title i18n-content="title"></title>
-<link rel="stylesheet" href="chrome://resources/css/text_defaults.css">
-<link rel="stylesheet" href="guest_tab.css">
+<link rel="stylesheet" href="chrome://resources/css/text_defaults_md.css">
<link rel="stylesheet" href="incognito_and_guest_tab.css">
</head>
<body>
@@ -13,7 +12,7 @@
<p>
<span i18n-content="guestTabDescription"></span>
</p>
- <a i18n-content="learnMore" i18n-values=".href:learnMoreLink"></a>
+ <a class="learn-more-button" i18n-content="learnMore" i18n-values=".href:learnMoreLink"></a>
</div>
</body>
<script src="chrome://resources/js/cr.js"></script>
diff --git a/chromium/chrome/browser/resources/ntp4/incognito_and_guest_tab.css b/chromium/chrome/browser/resources/ntp4/incognito_and_guest_tab.css
index 90e52d921d9..567f7192f41 100644
--- a/chromium/chrome/browser/resources/ntp4/incognito_and_guest_tab.css
+++ b/chromium/chrome/browser/resources/ntp4/incognito_and_guest_tab.css
@@ -5,32 +5,48 @@
* Incognito and guest mode NTP shared CSS.
*/
+body {
+ font-size: 85%;
+}
+
h1 {
font-size: 200%;
font-weight: 300;
- margin-bottom: 1.33em;
+ margin-bottom: .77em;
}
p {
line-height: 1.5;
- margin-bottom: 2em;
+ margin: .588em 0;
text-align: start;
}
a {
- font-size: 108.3%;
- text-decoration: none;
- text-transform: uppercase;
+ color: rgb(51, 103, 214);
}
a:hover {
text-decoration: underline;
}
+/* 'Learn More' button styled like a Material Design text button.
+ * TODO(edwardjung): Switch styled links to actual text buttons.
+ */
+.learn-more-button {
+ color: rgb(66, 133, 244);
+ display: inline-block;
+ font-size: 92.8%;
+ font-weight: 500;
+ margin-top: 1.98em;
+ padding: 10.5px 12px;
+ text-decoration: none;
+ text-transform: uppercase;
+}
+
.content {
box-sizing: border-box;
margin: 3.5em auto 0;
- max-width: 420px;
+ max-width: 480px;
min-width: 240px;
padding: 30px 35px;
text-align: center;
diff --git a/chromium/chrome/browser/resources/ntp4/incognito_tab.css b/chromium/chrome/browser/resources/ntp4/incognito_tab.css
index 6994b2cb0ac..67bd8c9d471 100644
--- a/chromium/chrome/browser/resources/ntp4/incognito_tab.css
+++ b/chromium/chrome/browser/resources/ntp4/incognito_tab.css
@@ -19,11 +19,14 @@ body {
}
h1 {
- margin-top: 1em;
+ margin-top: .88em;
+ opacity: .8;
}
-a {
- color: rgb(3, 169, 244);
- display: inline-block;
- padding: 10.5px 12px;
+p {
+ opacity: .8;
+}
+
+.learn-more-button {
+ color: rgb(123, 170, 247);
}
diff --git a/chromium/chrome/browser/resources/ntp4/incognito_tab.html b/chromium/chrome/browser/resources/ntp4/incognito_tab.html
index 4b19819a5d3..fc50f7771af 100644
--- a/chromium/chrome/browser/resources/ntp4/incognito_tab.html
+++ b/chromium/chrome/browser/resources/ntp4/incognito_tab.html
@@ -29,7 +29,7 @@ document.write('<link id="incognitothemecss" rel="stylesheet" ' +
<span i18n-content="incognitoTabWarning"></span>
</p>
</span>
- <a i18n-content="learnMore" i18n-values=".href:learnMoreLink"></a>
+ <a class="learn-more-button" i18n-content="learnMore" i18n-values=".href:learnMoreLink"></a>
</div>
</body>
<script src="chrome://resources/js/cr.js"></script>
diff --git a/chromium/chrome/browser/resources/ntp4/new_incognito_tab_theme.css b/chromium/chrome/browser/resources/ntp4/new_incognito_tab_theme.css
index 496b95b99f8..62ec0921507 100644
--- a/chromium/chrome/browser/resources/ntp4/new_incognito_tab_theme.css
+++ b/chromium/chrome/browser/resources/ntp4/new_incognito_tab_theme.css
@@ -5,21 +5,21 @@
html {
background-attachment: fixed;
- background-color: ${colorBackground};
- background-position: ${backgroundBarDetached};
- background-repeat: ${backgroundTiling};
+ background-color: $i18n{colorBackground};
+ background-position: $i18n{backgroundBarDetached};
+ background-repeat: $i18n{backgroundTiling};
height: 100%;
overflow: auto;
}
html[hascustombackground='true'] {
- background-image: url(chrome://theme/IDR_THEME_NTP_BACKGROUND?${themeId});
+ background-image: url(chrome://theme/IDR_THEME_NTP_BACKGROUND?$i18n{themeId});
}
html[bookmarkbarattached='true'] {
- background-position: ${backgroundBarAttached};
+ background-position: $i18n{backgroundBarAttached};
}
#attribution-img {
- content: url(chrome://theme/IDR_THEME_NTP_ATTRIBUTION?${themeId});
+ content: url(chrome://theme/IDR_THEME_NTP_ATTRIBUTION?$i18n{themeId});
}
diff --git a/chromium/chrome/browser/resources/ntp4/new_tab.css b/chromium/chrome/browser/resources/ntp4/new_tab.css
index 1be1e0c0577..43dd42dcf27 100644
--- a/chromium/chrome/browser/resources/ntp4/new_tab.css
+++ b/chromium/chrome/browser/resources/ntp4/new_tab.css
@@ -24,57 +24,6 @@ body {
display: none !important;
}
-#notification-container {
- -webkit-transition: opacity 200ms;
- bottom: 31px;
- display: block;
- float: left;
- position: relative;
- text-align: start;
- z-index: 15;
-}
-
-html[dir='rtl'] #notification-container {
- float: right;
-}
-
-#notification-container.card-changed {
- -webkit-transition: none;
- opacity: 0;
-}
-
-#notification-container.inactive {
- -webkit-transition: opacity 200ms;
- opacity: 0;
-}
-
-#notification {
- display: inline-block;
- font-weight: bold;
- white-space: nowrap;
-}
-
-#notification > * {
- display: inline-block;
- white-space: normal;
-}
-
-#notification > div > div,
-#notification > div {
- display: inline-block;
-}
-
-/* NOTE: This is in the probable case that we start stuffing 16x16 data URI'd
- * icons in the promo notification responses. */
-#notification > span > img {
- margin-bottom: -3px;
-}
-
-#notification .close-button {
- -webkit-margin-start: 8px; /* Matching value in TilePage#repositionTile_. */
- vertical-align: top;
-}
-
.close-button {
background: no-repeat;
background-color: transparent;
@@ -183,15 +132,6 @@ html[dir='rtl'] #attribution {
position: relative;
}
-#promo-bubble-anchor {
- height: 1px;
- left: 0;
- position: absolute;
- top: 4px;
- visibility: hidden;
- width: 32px;
-}
-
.starting-up * {
-webkit-transition: none !important;
}
diff --git a/chromium/chrome/browser/resources/ntp4/new_tab.html b/chromium/chrome/browser/resources/ntp4/new_tab.html
index 4cb27594882..ba71ff01d54 100644
--- a/chromium/chrome/browser/resources/ntp4/new_tab.html
+++ b/chromium/chrome/browser/resources/ntp4/new_tab.html
@@ -32,7 +32,6 @@
<script src="../../../../ui/webui/resources/js/action_link.js"></script>
<script src="../../../../ui/webui/resources/js/event_tracker.js"></script>
-<script src="../../../../ui/webui/resources/js/parse_html_subset.js"></script>
<script src="../../../../ui/webui/resources/js/util.js"></script>
<script src="../../../../ui/webui/resources/js/cr.js"></script>
@@ -63,15 +62,6 @@
</head>
<body>
- <div id="notification-container" class="inactive" hidden>
- <div id="notification">
- <span></span>
- <div id="notificationLinks"></div>
- <button class="close-button custom-appearance" class="custom-appearance">
- </button>
- </div>
- </div>
-
<div id="card-slider-frame">
<button id="page-switcher-start" class="page-switcher custom-appearance"
tabindex="2" hidden>‹
@@ -103,7 +93,6 @@
<div id="footer-content">
<div id="logo-img">
<img alt="" src="chrome://theme/IDR_PRODUCT_LOGO">
- <div id="promo-bubble-anchor"></div>
</div>
<ul id="dot-list">
diff --git a/chromium/chrome/browser/resources/ntp4/new_tab.js b/chromium/chrome/browser/resources/ntp4/new_tab.js
index d219ad73b56..43e25f75629 100644
--- a/chromium/chrome/browser/resources/ntp4/new_tab.js
+++ b/chromium/chrome/browser/resources/ntp4/new_tab.js
@@ -3,9 +3,9 @@
// found in the LICENSE file.
/**
- * @fileoverview New tab page
- * This is the main code for the new tab page used by touch-enabled Chrome
- * browsers. For now this is still a prototype.
+ * @fileoverview New tab page 4
+ * This is the main code for a previous version of the Chrome NTP ("NTP4").
+ * Some parts of this are still used for the chrome://apps page.
*/
// Use an anonymous function to enable strict mode just for this file (which
@@ -20,20 +20,6 @@ cr.define('ntp', function() {
var newTabView;
/**
- * The 'notification-container' element.
- * @type {!Element|undefined}
- */
- var notificationContainer;
-
- /**
- * If non-null, an info bubble for showing messages to the user. It points at
- * the Most Visited label, and is used to draw more attention to the
- * navigation dot UI.
- * @type {!cr.ui.Bubble|undefined}
- */
- var promoBubble;
-
- /**
* If non-null, an bubble confirming that the user has signed into sync. It
* points at the login status at the top of the page.
* @type {!cr.ui.Bubble|undefined}
@@ -63,16 +49,6 @@ cr.define('ntp', function() {
var DEFAULT_TRANSITION_TIME = 500;
/**
- * See description for these values in ntp_stats.h.
- * @enum {number}
- */
- var NtpFollowAction = {
- CLICKED_TILE: 11,
- CLICKED_OTHER_NTP_PANE: 12,
- OTHER: 13
- };
-
- /**
* Creates a NewTabView object. NewTabView extends PageListView with
* new tab UI specific logics.
* @constructor
@@ -94,17 +70,9 @@ cr.define('ntp', function() {
pageSwitcherStart, pageSwitcherEnd);
}
- NewTabView.prototype = {
- __proto__: ntp.PageListView.prototype,
-
- /** @override */
- appendTilePage: function(page, title, titleIsEditable, opt_refNode) {
- ntp.PageListView.prototype.appendTilePage.apply(this, arguments);
-
- if (promoBubble)
- window.setTimeout(promoBubble.reposition.bind(promoBubble), 0);
- }
- };
+ // TODO(dbeam): NewTabView is now the only extender of PageListView; these
+ // classes should be merged.
+ NewTabView.prototype = {__proto__: ntp.PageListView.prototype};
/**
* Invoked at startup once the DOM is available to initialize the app.
@@ -127,10 +95,6 @@ cr.define('ntp', function() {
newTabView = new NewTabView();
- notificationContainer = getRequiredElement('notification-container');
- notificationContainer.addEventListener(
- 'webkitTransitionEnd', onNotificationTransitionEnd);
-
if (!loadTimeData.getBoolean('showWebStoreIcon')) {
var webStoreIcon = $('chrome-web-store-link');
// Not all versions of the NTP have a footer, so this may not exist.
@@ -170,30 +134,6 @@ cr.define('ntp', function() {
shouldShowLoginBubble = true;
}
- if (loadTimeData.valueExists('bubblePromoText')) {
- promoBubble = new cr.ui.Bubble;
- promoBubble.anchorNode = getRequiredElement('promo-bubble-anchor');
- promoBubble.arrowLocation = cr.ui.ArrowLocation.BOTTOM_START;
- promoBubble.bubbleAlignment = cr.ui.BubbleAlignment.ENTIRELY_VISIBLE;
- promoBubble.deactivateToDismissDelay = 2000;
- promoBubble.content = parseHtmlSubset(
- loadTimeData.getString('bubblePromoText'), ['BR']);
-
- var bubbleLink = promoBubble.querySelector('a');
- if (bubbleLink) {
- bubbleLink.addEventListener('click', function(e) {
- chrome.send('bubblePromoLinkClicked');
- });
- }
-
- promoBubble.handleCloseEvent = function() {
- promoBubble.hide();
- chrome.send('bubblePromoClosed');
- };
- promoBubble.show();
- chrome.send('bubblePromoViewed');
- }
-
$('login-container').addEventListener('click', showSyncLoginUI);
if (loadTimeData.getBoolean('shouldShowSyncLogin'))
chrome.send('initializeSyncLogin');
@@ -205,30 +145,6 @@ cr.define('ntp', function() {
newTabView.cardSlider.currentCardValue.navigationDot.classList.add(
'selected');
- if (loadTimeData.valueExists('notificationPromoText')) {
- var promoText = loadTimeData.getString('notificationPromoText');
- var tags = ['IMG'];
- var attrs = {
- src: function(node, value) {
- return node.tagName == 'IMG' &&
- /^data\:image\/(?:png|gif|jpe?g)/.test(value);
- },
- };
-
- var promo = parseHtmlSubset(promoText, tags, attrs);
- var promoLink = promo.querySelector('a');
- if (promoLink) {
- promoLink.addEventListener('click', function(e) {
- chrome.send('notificationPromoLinkClicked');
- });
- }
-
- showNotification(promo, [], function() {
- chrome.send('notificationPromoClosed');
- }, 60000);
- chrome.send('notificationPromoViewed');
- }
-
cr.dispatchSimpleEvent(document, 'ntpLoaded', true, true);
document.documentElement.classList.remove('starting-up');
@@ -345,125 +261,6 @@ cr.define('ntp', function() {
}
/**
- * Timeout ID.
- * @type {number}
- */
- var notificationTimeout = 0;
-
- /**
- * Shows the notification bubble.
- * @param {string|Node} message The notification message or node to use as
- * message.
- * @param {Array<{text: string, action: function()}>} links An array of
- * records describing the links in the notification. Each record should
- * have a 'text' attribute (the display string) and an 'action' attribute
- * (a function to run when the link is activated).
- * @param {Function=} opt_closeHandler The callback invoked if the user
- * manually dismisses the notification.
- * @param {number=} opt_timeout
- */
- function showNotification(message, links, opt_closeHandler, opt_timeout) {
- window.clearTimeout(notificationTimeout);
-
- var span = document.querySelector('#notification > span');
- if (typeof message == 'string') {
- span.textContent = message;
- } else {
- span.textContent = ''; // Remove all children.
- span.appendChild(message);
- }
-
- var linksBin = $('notificationLinks');
- linksBin.textContent = '';
- for (var i = 0; i < links.length; i++) {
- var link = new ActionLink;
- link.textContent = links[i].text;
- link.action = links[i].action;
- link.onclick = function() {
- this.action();
- hideNotification();
- };
- linksBin.appendChild(link);
- }
-
- function closeFunc(e) {
- if (opt_closeHandler)
- opt_closeHandler();
- hideNotification();
- }
-
- document.querySelector('#notification button').onclick = closeFunc;
- document.addEventListener('dragstart', closeFunc);
-
- notificationContainer.hidden = false;
- showNotificationOnCurrentPage();
-
- newTabView.cardSlider.frame.addEventListener(
- 'cardSlider:card_change_ended', onCardChangeEnded);
-
- var timeout = opt_timeout || 10000;
- notificationTimeout = window.setTimeout(hideNotification, timeout);
- }
-
- /**
- * Hide the notification bubble.
- */
- function hideNotification() {
- notificationContainer.classList.add('inactive');
-
- newTabView.cardSlider.frame.removeEventListener(
- 'cardSlider:card_change_ended', onCardChangeEnded);
- }
-
- /**
- * Happens when 1 or more consecutive card changes end.
- * @param {Event} e The cardSlider:card_change_ended event.
- */
- function onCardChangeEnded(e) {
- // If we ended on the same page as we started, ignore.
- if (newTabView.cardSlider.currentCardValue.notification)
- return;
-
- // Hide the notification the old page.
- notificationContainer.classList.add('card-changed');
-
- showNotificationOnCurrentPage();
- }
-
- /**
- * Move and show the notification on the current page.
- */
- function showNotificationOnCurrentPage() {
- var page = newTabView.cardSlider.currentCardValue;
- doWhenAllSectionsReady(function() {
- if (page != newTabView.cardSlider.currentCardValue)
- return;
-
- // NOTE: This moves the notification to inside of the current page.
- page.notification = notificationContainer;
-
- // Reveal the notification and instruct it to hide itself if ignored.
- notificationContainer.classList.remove('inactive');
-
- // Gives the browser time to apply this rule before we remove it (causing
- // a transition).
- window.setTimeout(function() {
- notificationContainer.classList.remove('card-changed');
- }, 0);
- });
- }
-
- /**
- * When done fading out, set hidden to true so the notification can't be
- * tabbed to or clicked.
- * @param {Event} e The webkitTransitionEnd event.
- */
- function onNotificationTransitionEnd(e) {
- if (notificationContainer.classList.contains('inactive'))
- notificationContainer.hidden = true;
- }
-
- /**
* Set the dominant color for a node. This will be called in response to
* getFaviconDominantColor. The node represented by |id| better have a setter
* for stripeColor.
@@ -644,12 +441,10 @@ cr.define('ntp', function() {
getCardSlider: getCardSlider,
onLoad: onLoad,
leaveRearrangeMode: leaveRearrangeMode,
- NtpFollowAction: NtpFollowAction,
saveAppPageName: saveAppPageName,
setAppToBeHighlighted: setAppToBeHighlighted,
setBookmarkBarAttached: setBookmarkBarAttached,
setFaviconDominantColor: setFaviconDominantColor,
- showNotification: showNotification,
themeChanged: themeChanged,
updateLogin: updateLogin
};
diff --git a/chromium/chrome/browser/resources/ntp4/new_tab_theme.css b/chromium/chrome/browser/resources/ntp4/new_tab_theme.css
index 64742909ab3..f5a66984bd8 100644
--- a/chromium/chrome/browser/resources/ntp4/new_tab_theme.css
+++ b/chromium/chrome/browser/resources/ntp4/new_tab_theme.css
@@ -1,88 +1,88 @@
-/* Copyright (c) 2012 The Chromium Authors. All rights reserved.
+/* Copyright 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. */
html {
background-attachment: fixed;
- background-color: ${colorBackground};
- background-image: url(chrome://theme/IDR_THEME_NTP_BACKGROUND?${themeId});
- background-position: ${backgroundBarDetached};
- background-repeat: ${backgroundTiling};
+ background-color: $i18n{colorBackground};
+ background-image: url(chrome://theme/IDR_THEME_NTP_BACKGROUND?$i18n{themeId});
+ background-position: $i18n{backgroundBarDetached};
+ background-repeat: $i18n{backgroundTiling};
}
#attribution {
- left: ${leftAlignAttribution};
- right: ${rightAlignAttribution};
- text-align: ${textAlignAttribution};
- display: ${displayAttribution};
+ left: $i18n{leftAlignAttribution};
+ right: $i18n{rightAlignAttribution};
+ text-align: $i18n{textAlignAttribution};
+ display: $i18n{displayAttribution};
}
#attribution-img {
- content: url(chrome://theme/IDR_THEME_NTP_ATTRIBUTION?${themeId});
+ content: url(chrome://theme/IDR_THEME_NTP_ATTRIBUTION?$i18n{themeId});
}
html[bookmarkbarattached='true'] {
- background-position: ${backgroundBarAttached};
+ background-position: $i18n{backgroundBarAttached};
}
body {
- color: ${colorTextRgba};
+ color: $i18n{colorTextRgba};
height: 100%;
overflow: auto;
}
#attribution,
[is='action-link'] {
- color: ${colorTextLight};
+ color: $i18n{colorTextLight};
}
[is='action-link']:active {
- color: ${colorTextRgba};
+ color: $i18n{colorTextRgba};
}
.page-switcher {
- color: rgba(${colorText}, 0.5);
+ color: rgba($i18n{colorText}, 0.5);
}
.page-switcher:hover,
.page-switcher:focus,
.page-switcher.drag-target {
- background-color: rgba(${colorText}, 0.06);
+ background-color: rgba($i18n{colorText}, 0.06);
}
/* Only change the background to a gradient when a promo is showing. */
.showing-login-area #page-switcher-end:hover,
.showing-login-area #page-switcher-end:focus,
.showing-login-area #page-switcher-end.drag-target {
- background: linear-gradient(top,
- rgba(${colorText}, 0) 0,
- rgba(${colorText}, .01) 60px,
- rgba(${colorText}, .06) 183px);
+ background: linear-gradient(
+ rgba($i18n{colorText}, 0) 0,
+ rgba($i18n{colorText}, .01) 60px,
+ rgba($i18n{colorText}, .06) 183px);
}
.tile-page-scrollbar {
- background-color: ${colorTextLight};
+ background-color: $i18n{colorTextLight};
}
/* Footer *********************************************************************/
#footer-border {
- background: linear-gradient(left,
- rgba(${colorSectionBorder}, 0.2),
- rgba(${colorSectionBorder}, 0.3) 20%,
- rgba(${colorSectionBorder}, 0.3) 80%,
- rgba(${colorSectionBorder}, 0.2));
+ background: linear-gradient(to left,
+ rgba($i18n{colorSectionBorder}, 0.2),
+ rgba($i18n{colorSectionBorder}, 0.3) 20%,
+ rgba($i18n{colorSectionBorder}, 0.3) 80%,
+ rgba($i18n{colorSectionBorder}, 0.2));
}
.dot input:focus {
- background-color: ${colorBackground};
+ background-color: $i18n{colorBackground};
}
.thumbnail-wrapper {
/* This shows through at the (rounded) thumbnail's corners. */
- background-color: ${colorSectionBorder};
+ background-color: $i18n{colorSectionBorder};
}
.filler .thumbnail {
- border-color: ${colorBackground};
+ border-color: $i18n{colorBackground};
}
diff --git a/chromium/chrome/browser/resources/ntp4/page_list_view.js b/chromium/chrome/browser/resources/ntp4/page_list_view.js
index 69027b966ae..efb31fe47c3 100644
--- a/chromium/chrome/browser/resources/ntp4/page_list_view.js
+++ b/chromium/chrome/browser/resources/ntp4/page_list_view.js
@@ -108,14 +108,8 @@ cr.define('ntp', function() {
trash: undefined,
/**
- * The type of page that is currently shown. The value is a numerical ID.
- * @type {number}
- */
- shownPage: 0,
-
- /**
- * The index of the page that is currently shown, within the page type.
- * For example if the third Apps page is showing, this will be 2.
+ * The index of the page that is currently shown. For example if the third
+ * page is showing, this will be 2.
* @type {number}
*/
shownPageIndex: 0,
@@ -166,7 +160,6 @@ cr.define('ntp', function() {
if (this.pageSwitcherEnd)
ntp.initializePageSwitcher(this.pageSwitcherEnd);
- this.shownPage = loadTimeData.getInteger('shown_page_type');
this.shownPageIndex = loadTimeData.getInteger('shown_page_index');
// TODO(dbeam): remove showApps and everything that says if (apps).
@@ -450,8 +443,7 @@ cr.define('ntp', function() {
app.replaceAppData(appData);
} else if (opt_highlight) {
page.insertAndHighlightApp(appData);
- this.setShownPage_(loadTimeData.getInteger('apps_page_id'),
- appData.page_index);
+ this.setShownPage_(appData.page_index);
} else {
page.insertApp(appData, false);
}
@@ -488,11 +480,11 @@ cr.define('ntp', function() {
/**
* Updates the hidden state of the app launcher promo based on the page
* shown and load data content.
+ * @private
*/
updateAppLauncherPromoHiddenState_: function() {
$('app-launcher-promo').hidden =
- !loadTimeData.getBoolean('showAppLauncherPromo') ||
- this.shownPage != loadTimeData.getInteger('apps_page_id');
+ !loadTimeData.getBoolean('showAppLauncherPromo');
},
/**
@@ -504,8 +496,7 @@ cr.define('ntp', function() {
this.tilePages.length - 1));
this.cardSlider.setCards(Array.prototype.slice.call(this.tilePages),
pageNo);
- if (this.shownPage == loadTimeData.getInteger('apps_page_id') &&
- loadTimeData.getBoolean('showApps')) {
+ if (loadTimeData.getBoolean('showApps')) {
this.cardSlider.selectCardByValue(
this.appsPages[Math.min(this.shownPageIndex,
this.appsPages.length - 1)]);
@@ -632,12 +623,11 @@ cr.define('ntp', function() {
// Don't change shownPage until startup is done (and page changes actually
// reflect user actions).
if (!this.isStartingUp_()) {
- if (page.classList.contains('apps-page')) {
- this.setShownPage_(loadTimeData.getInteger('apps_page_id'),
- this.getAppsPageIndex(page));
- } else {
+ // TODO(dbeam): is this ever false?
+ if (page.classList.contains('apps-page'))
+ this.setShownPage_(this.getAppsPageIndex(page));
+ else
console.error('unknown page selected');
- }
}
// Update the active dot
@@ -650,15 +640,13 @@ cr.define('ntp', function() {
/**
* Saves/updates the newly selected page to open when first loading the NTP.
- * @param {number} shownPage The new shown page type.
* @param {number} shownPageIndex The new shown page index.
* @private
*/
- setShownPage_: function(shownPage, shownPageIndex) {
+ setShownPage_: function(shownPageIndex) {
assert(shownPageIndex >= 0);
- this.shownPage = shownPage;
this.shownPageIndex = shownPageIndex;
- chrome.send('pageSelected', [this.shownPage, this.shownPageIndex]);
+ chrome.send('pageSelected', [this.shownPageIndex]);
this.updateAppLauncherPromoHiddenState_();
},
diff --git a/chromium/chrome/browser/resources/ntp4/tile_page.css b/chromium/chrome/browser/resources/ntp4/tile_page.css
index 81f43227056..52fd059e1f9 100644
--- a/chromium/chrome/browser/resources/ntp4/tile_page.css
+++ b/chromium/chrome/browser/resources/ntp4/tile_page.css
@@ -127,10 +127,6 @@
-webkit-transition: margin-bottom 200ms;
}
-.animating-tile-page #notification-container {
- -webkit-transition: margin 200ms, opacity 200ms;
-}
-
@-webkit-keyframes bounce {
0% {
-webkit-transform: scale(0, 0);
diff --git a/chromium/chrome/browser/resources/ntp4/tile_page.js b/chromium/chrome/browser/resources/ntp4/tile_page.js
index 6cda72cff2e..8a3cc3db65e 100644
--- a/chromium/chrome/browser/resources/ntp4/tile_page.js
+++ b/chromium/chrome/browser/resources/ntp4/tile_page.js
@@ -500,25 +500,6 @@ cr.define('ntp', function() {
},
/**
- * The notification content of this tile (if any, otherwise null).
- * @type {!HTMLElement}
- */
- get notification() {
- return this.topMargin_.nextElementSibling.id == 'notification-container' ?
- this.topMargin_.nextElementSibling : null;
- },
- /**
- * The notification content of this tile (if any, otherwise null).
- * @type {!HTMLElement}
- */
- set notification(node) {
- assert(node instanceof HTMLElement, '|node| isn\'t an HTMLElement!');
- // NOTE: Implicitly removes from DOM if |node| is inside it.
- this.content_.insertBefore(node, this.topMargin_.nextElementSibling);
- this.positionNotification_();
- },
-
- /**
* Fetches the size, in pixels, of the padding-top of the tile contents.
* @type {number}
*/
@@ -968,7 +949,6 @@ cr.define('ntp', function() {
this.classList.add('animating-tile-page');
this.heightChanged_();
- this.positionNotification_();
this.repositionTiles_();
},
@@ -1044,35 +1024,6 @@ cr.define('ntp', function() {
},
/**
- * Position the notification if there's one showing.
- */
- positionNotification_: function() {
- var notification = this.notification;
- if (!notification || notification.hidden)
- return;
-
- // Update the horizontal position.
- var animatedLeftMargin = this.getAnimatedLeftMargin_();
- notification.style.WebkitMarginStart = animatedLeftMargin + 'px';
- var leftOffset = (this.layoutValues_.leftMargin - animatedLeftMargin) *
- (isRTL() ? -1 : 1);
- notification.style.WebkitTransform = 'translateX(' + leftOffset + 'px)';
-
- // Update the allowable widths of the text.
- var buttonWidth = notification.querySelector('button').offsetWidth + 8;
- notification.querySelector('span').style.maxWidth =
- this.layoutValues_.gridWidth - buttonWidth + 'px';
-
- // This makes sure the text doesn't condense smaller than the narrow size
- // of the grid (e.g. when a user makes the window really small).
- notification.style.minWidth =
- this.gridValues_.narrowWidth - buttonWidth + 'px';
-
- // Update the top position.
- notification.style.marginTop = -notification.offsetHeight + 'px';
- },
-
- /**
* Handles final setup that can only happen after |this| is inserted into
* the page.
* @private
diff --git a/chromium/chrome/browser/resources/omnibox/omnibox.js b/chromium/chrome/browser/resources/omnibox/omnibox.js
index 8631c277cff..292052952e6 100644
--- a/chromium/chrome/browser/resources/omnibox/omnibox.js
+++ b/chromium/chrome/browser/resources/omnibox/omnibox.js
@@ -21,7 +21,7 @@ define('main', [
'mojo/public/js/core',
'mojo/public/js/connection',
'chrome/browser/ui/webui/omnibox/omnibox.mojom',
- 'content/public/renderer/service_provider',
+ 'content/public/renderer/frame_service_registry',
], function(bindings, core, connection, browser, serviceProvider) {
'use strict';
diff --git a/chromium/chrome/browser/resources/options/autofill_edit_address_overlay.js b/chromium/chrome/browser/resources/options/autofill_edit_address_overlay.js
index 43049212de4..c9e5440f7fb 100644
--- a/chromium/chrome/browser/resources/options/autofill_edit_address_overlay.js
+++ b/chromium/chrome/browser/resources/options/autofill_edit_address_overlay.js
@@ -301,12 +301,12 @@ cr.define('options', function() {
var customInputElements = {addrLines: 'textarea'};
- for (var i in components) {
+ for (var i = 0; i < components.length; i++) {
var row = document.createElement('div');
row.classList.add('input-group', 'settings-row');
content.appendChild(row);
- for (var j in components[i]) {
+ for (var j = 0; j < components[i].length; j++) {
if (components[i][j].field == 'country')
continue;
diff --git a/chromium/chrome/browser/resources/options/autofill_options.css b/chromium/chrome/browser/resources/options/autofill_options.css
index 815c58c4079..dd131a6c52e 100644
--- a/chromium/chrome/browser/resources/options/autofill_options.css
+++ b/chromium/chrome/browser/resources/options/autofill_options.css
@@ -7,7 +7,7 @@
}
#autofill-options list {
- min-height: 172px;
+ height: 192px; /* This is the min-height for lists from WebUI.*/
}
.autofill-list-item {
@@ -38,7 +38,7 @@
#autofill-add-address,
#autofill-add-creditcard {
- margin: 5px 5px;
+ margin: 5px 0;
}
#autofill-options .list-inline-button {
@@ -56,3 +56,13 @@
.hides-on-hover {
display: none;
}
+
+.settings-list + .autofill-section-header {
+ margin-top: 20px;
+}
+
+#autofill-options .autofill-section-header {
+ display: flex;
+ justify-content: space-between;
+ margin-bottom: 5px;
+} \ No newline at end of file
diff --git a/chromium/chrome/browser/resources/options/autofill_options.html b/chromium/chrome/browser/resources/options/autofill_options.html
index cf33636bb89..ab3931bf41f 100644
--- a/chromium/chrome/browser/resources/options/autofill_options.html
+++ b/chromium/chrome/browser/resources/options/autofill_options.html
@@ -2,22 +2,21 @@
<div class="close-button"></div>
<h1 i18n-content="autofillOptionsPage"></h1>
<div class="content-area">
- <h3 i18n-content="autofillAddresses"></h3>
+ <div class="autofill-section-header">
+ <h3 i18n-content="autofillAddresses"></h3>
+ <button id="autofill-add-address" i18n-content="autofillAddAddress">
+ </button>
+ </div>
<div class="settings-list">
<list id="address-list"></list>
- <div>
- <button id="autofill-add-address" i18n-content="autofillAddAddress">
- </button>
- </div>
</div>
-
- <h3 i18n-content="autofillCreditCards"></h3>
+ <div class="autofill-section-header">
+ <h3 i18n-content="autofillCreditCards"></h3>
+ <button id="autofill-add-creditcard" i18n-content="autofillAddCreditCard">
+ </button>
+ </div>
<div class="settings-list">
<list id="creditcard-list"></list>
- <div>
- <button id="autofill-add-creditcard"
- i18n-content="autofillAddCreditCard"></button>
- </div>
</div>
</div>
diff --git a/chromium/chrome/browser/resources/options/browser_options.html b/chromium/chrome/browser/resources/options/browser_options.html
index 51a79e68208..7f73b07bea4 100644
--- a/chromium/chrome/browser/resources/options/browser_options.html
+++ b/chromium/chrome/browser/resources/options/browser_options.html
@@ -7,7 +7,7 @@
<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">
<include src="secondary_user_banner.html">
- <section>
+ <section id="network-section-cros">
<div id="network-section-header" class="section-header">
<h3 i18n-content="sectionTitleInternet"></h3>
<span class="controlled-setting-indicator" plural></span>
@@ -102,7 +102,7 @@
</if>
</section>
<if expr="chromeos">
- <section>
+ <section id="device-section">
<h3 i18n-content="sectionTitleDevice"></h3>
<div>
<span i18n-content="deviceGroupDescription"></span>
@@ -137,7 +137,7 @@
</div>
</section>
</if>
- <section>
+ <section id="search-section">
<h3 i18n-content="sectionTitleSearch"></h3>
<div id="search-section-content">
<span id="default-search-engine-label"
@@ -221,6 +221,22 @@
</div>
</div>
</section>
+<if expr="chromeos">
+ <section id="android-apps-section" hidden>
+ <h3 i18n-content="androidAppsTitle"></h3>
+ <div class="checkbox controlled-setting-with-label">
+ <label>
+ <input id="android-apps-enabled" pref="arc.enabled"
+ metric="Options_AndroidApps" type="checkbox">
+ <span>
+ <span i18n-content="androidAppsEnabled"></span>
+ <span class="controlled-setting-indicator"
+ pref="arc.enabled"></span>
+ </span>
+ </label>
+ </div>
+ </section>
+</if>
<section id="sync-users-section" guest-visibility="hidden">
<h3 i18n-content="sectionTitleUsers"></h3>
<if expr="chromeos">
@@ -283,7 +299,7 @@
<div id="advanced-settings" hidden>
<div id="advanced-settings-container">
<if expr="chromeos">
- <section>
+ <section id="date-time-section">
<h3 i18n-content="datetimeTitle"></h3>
<div class="option-control-table">
<div guest-visibility="disabled">
@@ -525,7 +541,7 @@
</div>
</div>
</section>
-</if> <!-- chromeos -->
+</if>
<section id="passwords-and-autofill-section">
<h3 i18n-content="passwordsAndAutofillGroupName"></h3>
<div class="checkbox controlled-setting-with-label">
@@ -613,7 +629,7 @@
<button id="fontSettingsCustomizeFontsButton"
i18n-content="fontSettingsCustomizeFontsButton"></button>
</div>
- <div class="settings-row">
+ <div class="settings-row" guest-visibility="disabled">
<label class="web-content-select-label">
<span i18n-content="defaultZoomFactorLabel"></span>
<select id="defaultZoomFactor" dataType="double"></select>
@@ -727,7 +743,7 @@
</div>
</div>
</section>
- <section>
+ <section id="certificates-section">
<h3 i18n-content="advancedSectionTitleCertificates"></h3>
<div>
<if expr="use_nss_certs or is_win or is_macosx">
@@ -772,7 +788,7 @@
<include src="startup_section.html">
</if>
-<section>
+<section id="a11y-section">
<h3 i18n-content="accessibilityTitle"></h3>
<div>
@@ -939,7 +955,7 @@
pref="settings.a11y.autoclick_delay_ms"></span>
</div>
</div>
- <div class="option_name" id="accessibility_onscreen_keyboard">
+ <div class="option-name" id="accessibility_onscreen_keyboard">
<div class="checkbox controlled-setting-with-label">
<label>
<input pref="settings.a11y.virtual_keyboard" type="checkbox"
@@ -952,6 +968,73 @@
</label>
</div>
</div>
+ <div id="experimental-accessibility-features" hidden>
+ <div class="option-name">
+ <div class="checkbox controlled-setting-with-label">
+ <label>
+ <input pref="settings.a11y.caret_highlight" type="checkbox"
+ metric="Options_AccessibilityCaretHighlight">
+ <span>
+ <span i18n-content="accessibilityCaretHighlight"></span>
+ <span class="controlled-setting-indicator"
+ pref="settings.a11y.caret_highlight"></span>
+ </span>
+ </label>
+ </div>
+ </div>
+ <div class="option-name">
+ <div class="checkbox controlled-setting-with-label">
+ <label>
+ <input pref="settings.a11y.cursor_highlight" type="checkbox"
+ metric="Options_AccessibilityCursorHighlight">
+ <span>
+ <span i18n-content="accessibilityCursorHighlight"></span>
+ <span class="controlled-setting-indicator"
+ pref="settings.a11y.cursor_highlight"></span>
+ </span>
+ </label>
+ </div>
+ </div>
+ <div class="option-name">
+ <div class="checkbox controlled-setting-with-label">
+ <label>
+ <input pref="settings.a11y.focus_highlight" type="checkbox"
+ metric="Options_AccessibilityFocusHighlight">
+ <span>
+ <span i18n-content="accessibilityFocusHighlight"></span>
+ <span class="controlled-setting-indicator"
+ pref="settings.a11y.focus_highlight"></span>
+ </span>
+ </label>
+ </div>
+ </div>
+ <div class="option-name">
+ <div class="checkbox controlled-setting-with-label">
+ <label>
+ <input pref="settings.a11y.select_to_speak" type="checkbox"
+ metric="Options_AccessibilitySelectToSpeak">
+ <span>
+ <span i18n-content="accessibilitySelectToSpeak"></span>
+ <span class="controlled-setting-indicator"
+ pref="settings.a11y.select_to_speak"></span>
+ </span>
+ </label>
+ </div>
+ </div>
+ <div class="option-name">
+ <div class="checkbox controlled-setting-with-label">
+ <label>
+ <input pref="settings.a11y.switch_access" type="checkbox"
+ metric="Options_AccessibilitySwitchAccess">
+ <span>
+ <span i18n-content="accessibilitySwitchAccess"></span>
+ <span class="controlled-setting-indicator"
+ pref="settings.a11y.switch_access"></span>
+ </span>
+ </label>
+ </div>
+ </div>
+ </div>
</div>
</if>
diff --git a/chromium/chrome/browser/resources/options/browser_options.js b/chromium/chrome/browser/resources/options/browser_options.js
index bb646e6a8e9..b35d0047b71 100644
--- a/chromium/chrome/browser/resources/options/browser_options.js
+++ b/chromium/chrome/browser/resources/options/browser_options.js
@@ -38,6 +38,18 @@ options.ExtensionData;
*/
options.Profile;
+/**
+ * Device policy SystemTimezoneAutomaticDetection values.
+ * @enum {number}
+ * @const
+ */
+options.AutomaticTimezoneDetectionType = {
+ USERS_DECIDE: 0,
+ DISABLED: 1,
+ IP_ONLY: 2,
+ SEND_WIFI_ACCESS_POINTS: 3,
+};
+
cr.define('options', function() {
var OptionsPage = options.OptionsPage;
var Page = cr.ui.pageManager.Page;
@@ -118,6 +130,18 @@ cr.define('options', function() {
systemTimezoneIsManaged_: false,
/**
+ * True if system timezone detection is managed by policy.
+ * @private {boolean}
+ */
+ systemTimezoneAutomaticDetectionIsManaged_: false,
+
+ /**
+ * This is the value of SystemTimezoneAutomaticDetection policy.
+ * @private {number}
+ */
+ systemTimezoneAutomaticDetectionValue_: 0,
+
+ /**
* Cached bluetooth adapter state.
* @private {?chrome.bluetooth.AdapterState}
*/
@@ -200,7 +224,7 @@ cr.define('options', function() {
} else if (cr.isChromeOS) {
SyncSetupOverlay.showSetupUI();
} else {
- SyncSetupOverlay.startSignIn('access-point-settings');
+ SyncSetupOverlay.startSignIn(false /* creatingSupervisedUser */);
}
};
$('customize-sync').onclick = function(event) {
@@ -728,6 +752,8 @@ cr.define('options', function() {
Preferences.getInstance().addEventListener(
$('accessibility-autoclick-check').getAttribute('pref'),
updateDelayDropdown);
+ $('experimental-accessibility-features').hidden =
+ !loadTimeData.getBoolean('enableExperimentalAccessibilityFeatures');
}
// Display management section (CrOS only).
@@ -1477,7 +1503,7 @@ cr.define('options', function() {
else
$('profiles-manage').title = '';
$('profiles-delete').disabled = !profilesList.canDeleteItems ||
- (!hasSelection && !hasSingleProfile);
+ !hasSelection;
if (OptionsPage.isSettingsApp()) {
$('profiles-app-list-switch').disabled = !hasSelection ||
selectedProfile.isCurrentProfile;
@@ -1679,17 +1705,37 @@ cr.define('options', function() {
* @private
*/
updateTimezoneSectionState_: function() {
+ var self = this;
+ $('resolve-timezone-by-geolocation')
+ .onclick = function(event) {
+ self.resolveTimezoneByGeolocation_ = event.currentTarget.checked;
+ };
if (this.systemTimezoneIsManaged_) {
- $('resolve-timezone-by-geolocation-selection').disabled = true;
- $('resolve-timezone-by-geolocation').onclick = function(event) {};
+ $('resolve-timezone-by-geolocation').disabled = true;
+ $('resolve-timezone-by-geolocation').checked = false;
+ } else if (this.systemTimezoneAutomaticDetectionIsManaged_) {
+ if (this.systemTimezoneAutomaticDetectionValue_ ==
+ options.AutomaticTimezoneDetectionType.USERS_DECIDE) {
+ $('resolve-timezone-by-geolocation').disabled = false;
+ $('resolve-timezone-by-geolocation')
+ .checked = this.resolveTimezoneByGeolocation_;
+ $('timezone-value-select')
+ .disabled = this.resolveTimezoneByGeolocation_;
+ } else {
+ $('resolve-timezone-by-geolocation').disabled = true;
+ $('resolve-timezone-by-geolocation')
+ .checked =
+ (this.systemTimezoneAutomaticDetectionValue_ !=
+ options.AutomaticTimezoneDetectionType.DISABLED);
+ $('timezone-value-select').disabled = true;
+ }
} else {
this.enableElementIfPossible_(
- getRequiredElement('resolve-timezone-by-geolocation-selection'));
- $('resolve-timezone-by-geolocation').onclick = function(event) {
- $('timezone-value-select').disabled = event.currentTarget.checked;
- };
+ getRequiredElement('resolve-timezone-by-geolocation'));
$('timezone-value-select').disabled =
this.resolveTimezoneByGeolocation_;
+ $('resolve-timezone-by-geolocation')
+ .checked = this.resolveTimezoneByGeolocation_;
}
},
@@ -1705,6 +1751,20 @@ cr.define('options', function() {
},
/**
+ * This is called from chromium code when system timezone detection
+ * "managed" state is changed. Enables or disables dependent settings.
+ * @param {boolean} managed Is true when system timezone autodetection is
+ * managed by enterprise policy. False otherwize.
+ * @param {options.AutomaticTimezoneDetectionType} value Current value of
+ * SystemTimezoneAutomaticDetection device policy.
+ */
+ setSystemTimezoneAutomaticDetectionManaged_: function(managed, value) {
+ this.systemTimezoneAutomaticDetectionIsManaged_ = managed;
+ this.systemTimezoneAutomaticDetectionValue_ = value;
+ this.updateTimezoneSectionState_();
+ },
+
+ /**
* This is Preferences event listener, which is called when
* kResolveTimezoneByGeolocation preference is changed.
* Enables or disables dependent settings.
@@ -1735,12 +1795,17 @@ cr.define('options', function() {
/**
* Enables or disables the Chrome OS display settings button and overlay.
+ * @param {boolean} uiEnabled
+ * @param {boolean} unifiedEnabled
+ * @param {boolean} mirroredEnabled
* @private
*/
- enableDisplaySettings_: function(enabled, showUnifiedDesktop) {
+ enableDisplaySettings_: function(
+ uiEnabled, unifiedEnabled, mirroredEnabled) {
if (cr.isChromeOS) {
- $('display-options').disabled = !enabled;
- DisplayOptions.getInstance().setEnabled(enabled, showUnifiedDesktop);
+ $('display-options').disabled = !uiEnabled;
+ DisplayOptions.getInstance().setEnabled(
+ uiEnabled, unifiedEnabled, mirroredEnabled);
}
},
@@ -1797,7 +1862,8 @@ cr.define('options', function() {
*/
setNetworkPredictionValue_: function(pref) {
var checkbox = $('networkPredictionOptions');
- checkbox.disabled = pref.disabled;
+ checkbox.disabled = pref.disabled ||
+ loadTimeData.getBoolean('profileIsGuest');
checkbox.checked = (pref.value != NetworkPredictionOptions.NEVER);
},
@@ -2247,6 +2313,7 @@ cr.define('options', function() {
'setProfilesInfo',
'setSpokenFeedbackCheckboxState',
'setSystemTimezoneManaged',
+ 'setSystemTimezoneAutomaticDetectionManaged',
'setThemesResetButtonEnabled',
'setVirtualKeyboardCheckboxState',
'setupPageZoomSelector',
@@ -2317,6 +2384,16 @@ cr.define('options', function() {
}
button.textContent = loadTimeData.getString(strId);
};
+
+ /**
+ * Shows Android Apps settings when they are available.
+ * (Chrome OS only).
+ */
+ BrowserOptions.showAndroidAppsSection = function() {
+ var section = $('android-apps-section');
+ if (section)
+ section.hidden = false;
+ };
}
// Export
diff --git a/chromium/chrome/browser/resources/options/clear_browser_data_history_notice_overlay.html b/chromium/chrome/browser/resources/options/clear_browser_data_history_notice_overlay.html
new file mode 100644
index 00000000000..5de4a326bf0
--- /dev/null
+++ b/chromium/chrome/browser/resources/options/clear_browser_data_history_notice_overlay.html
@@ -0,0 +1,13 @@
+<div id="clear-browser-data-history-notice" class="page" hidden>
+ <h1 i18n-content="clearBrowserDataHistoryNoticeTitle"></h1>
+ <div class="content-area">
+ <p i18n-values=".innerHTML:clearBrowserDataHistoryNotice"></p>
+ </div>
+ <div class="action-area">
+ <div class="button-strip">
+ <button id="clear-browser-data-history-notice-ok" class="default-button"
+ i18n-content="clearBrowserDataHistoryNoticeOk">
+ </button>
+ </div>
+ </div>
+</div>
diff --git a/chromium/chrome/browser/resources/options/clear_browser_data_history_notice_overlay.js b/chromium/chrome/browser/resources/options/clear_browser_data_history_notice_overlay.js
new file mode 100644
index 00000000000..a96f20f139c
--- /dev/null
+++ b/chromium/chrome/browser/resources/options/clear_browser_data_history_notice_overlay.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 A popup that may be shown on top of the Clear Browsing Data
+ * overlay after the deletion finished.
+ */
+
+cr.define('options', function() {
+ /** @const */ var Page = cr.ui.pageManager.Page;
+ /** @const */ var PageManager = cr.ui.pageManager.PageManager;
+
+ /**
+ * A notice to be shown atop of the Clear Browsing Data overlay after
+ * the deletion of browsing history, informing the user that other forms
+ * of browsing history are still available.
+ * @constructor
+ * @extends {cr.ui.pageManager.Page}
+ */
+ function ClearBrowserDataHistoryNotice() {
+ Page.call(this, 'clearBrowserDataHistoryNotice',
+ loadTimeData.getString('clearBrowserDataOverlayTabTitle'),
+ 'clear-browser-data-history-notice');
+ }
+
+ cr.addSingletonGetter(ClearBrowserDataHistoryNotice);
+
+ ClearBrowserDataHistoryNotice.prototype = {
+ __proto__: Page.prototype,
+
+ /** @override */
+ initializePage: function() {
+ $('clear-browser-data-history-notice-ok').onclick = function() {
+ // Close this popup, and the Clear Browsing Data overlay below it.
+ PageManager.closeOverlay();
+ ClearBrowserDataOverlay.dismiss();
+ };
+ },
+ };
+
+ return {
+ ClearBrowserDataHistoryNotice: ClearBrowserDataHistoryNotice
+ };
+});
diff --git a/chromium/chrome/browser/resources/options/clear_browser_data_overlay.css b/chromium/chrome/browser/resources/options/clear_browser_data_overlay.css
index fca5b8d57f8..f18d8534469 100644
--- a/chromium/chrome/browser/resources/options/clear_browser_data_overlay.css
+++ b/chromium/chrome/browser/resources/options/clear_browser_data_overlay.css
@@ -48,10 +48,35 @@ input[type=checkbox]:not(:checked) ~ .clear-browser-data-counter {
display: none;
}
+#some-stuff-remains-footer {
+ display: block;
+}
+
#some-stuff-remains-footer > p {
- margin: 0;
+ -webkit-padding-start: 33px;
}
#some-stuff-remains-footer button {
padding: 0;
}
+
+#clear-browser-data-history-footer {
+ background: url(googleg.svg) left no-repeat;
+ margin: 0 0 0.8em 0;
+ min-height: 16px;
+}
+
+#clear-browser-data-general-footer {
+ background: url(info.svg) left no-repeat;
+ margin: 0;
+ min-height: 18px;
+}
+
+html[dir='rtl'] #clear-browser-data-history-footer,
+html[dir='rtl'] #clear-browser-data-general-footer {
+ background-position: right center;
+}
+
+#clear-browser-data-history-notice {
+ width: 300px;
+}
diff --git a/chromium/chrome/browser/resources/options/clear_browser_data_overlay.html b/chromium/chrome/browser/resources/options/clear_browser_data_overlay.html
index f3cb5c9c05f..3ddd1537b48 100644
--- a/chromium/chrome/browser/resources/options/clear_browser_data_overlay.html
+++ b/chromium/chrome/browser/resources/options/clear_browser_data_overlay.html
@@ -107,7 +107,9 @@
</div>
</div>
<div id="some-stuff-remains-footer" class="gray-bottom-bar">
- <p>
+ <p id="clear-browser-data-history-footer"
+ i18n-values=".innerHTML:clearBrowserDataHistoryFooter" hidden></p>
+ <p id="clear-browser-data-general-footer">
<span><!--This is filled by JavaScript--></span>
<a id="clear-browser-data-footer-learn-more-link" hidden
target="_blank" i18n-content="learnMore"
diff --git a/chromium/chrome/browser/resources/options/clear_browser_data_overlay.js b/chromium/chrome/browser/resources/options/clear_browser_data_overlay.js
index 5ad1a89d761..91c1812f105 100644
--- a/chromium/chrome/browser/resources/options/clear_browser_data_overlay.js
+++ b/chromium/chrome/browser/resources/options/clear_browser_data_overlay.js
@@ -100,9 +100,11 @@ cr.define('options', function() {
* clear browsing data dialog and warns that the deletion may be synced.
* @param {boolean} simple Whether to use a simple support string.
* @param {boolean} syncing Whether the user uses Sync.
+ * @param {boolean} showHistoryFooter Whether to show an additional footer
+ * about other forms of browsing history.
* @private
*/
- createFooter_: function(simple, syncing) {
+ createFooter_: function(simple, syncing, showHistoryFooter) {
// The localized string is of the form "Saved [content settings] and
// {search engines} will not be cleared and may reflect your browsing
// habits.", or of the form "Some settings that may reflect browsing
@@ -166,15 +168,19 @@ cr.define('options', function() {
$('clear-browser-data-old-learn-more-link').hidden = simple;
$('clear-browser-data-footer-learn-more-link').hidden = !simple;
$('flash-storage-settings').hidden = simple;
+ $('clear-browser-data-history-footer').hidden = !showHistoryFooter;
},
/**
* Shows or hides the sync warning based on whether the user uses Sync.
* @param {boolean} syncing Whether the user uses Sync.
+ * @param {boolean} showHistoryFooter Whether the user syncs history
+ * and conditions are met to show an additional history footer.
* @private
*/
- updateSyncWarning_: function(syncing) {
+ updateSyncWarningAndHistoryFooter_: function(syncing, showHistoryFooter) {
$('clear-browser-data-sync-warning').hidden = !syncing;
+ $('clear-browser-data-history-footer').hidden = !showHistoryFooter;
},
/**
@@ -283,12 +289,16 @@ cr.define('options', function() {
ClearBrowserDataOverlay.getInstance().updateCounter_(pref_name, text);
};
- ClearBrowserDataOverlay.createFooter = function(simple, syncing) {
- ClearBrowserDataOverlay.getInstance().createFooter_(simple, syncing);
+ ClearBrowserDataOverlay.createFooter = function(
+ simple, syncing, showHistoryFooter) {
+ ClearBrowserDataOverlay.getInstance().createFooter_(
+ simple, syncing, showHistoryFooter);
};
- ClearBrowserDataOverlay.updateSyncWarning = function(syncing) {
- ClearBrowserDataOverlay.getInstance().updateSyncWarning_(syncing);
+ ClearBrowserDataOverlay.updateSyncWarningAndHistoryFooter = function(
+ syncing, showHistoryFooter) {
+ ClearBrowserDataOverlay.getInstance().updateSyncWarningAndHistoryFooter_(
+ syncing, showHistoryFooter);
};
ClearBrowserDataOverlay.setClearing = function(clearing) {
@@ -303,13 +313,17 @@ cr.define('options', function() {
$('clear-browser-data-info-banner').innerText = text;
};
- ClearBrowserDataOverlay.doneClearing = function() {
+ ClearBrowserDataOverlay.doneClearing = function(showHistoryNotice) {
// The delay gives the user some feedback that the clearing
// actually worked. Otherwise the dialog just vanishes instantly in most
// cases.
window.setTimeout(function() {
ClearBrowserDataOverlay.setClearing(false);
- ClearBrowserDataOverlay.dismiss();
+
+ if (showHistoryNotice)
+ PageManager.showPageByName('clearBrowserDataHistoryNotice');
+ else
+ ClearBrowserDataOverlay.dismiss();
}, 200);
};
diff --git a/chromium/chrome/browser/resources/options/compiled_resources.gyp b/chromium/chrome/browser/resources/options/compiled_resources.gyp
index 242ff673ebb..ba84fb7d451 100644
--- a/chromium/chrome/browser/resources/options/compiled_resources.gyp
+++ b/chromium/chrome/browser/resources/options/compiled_resources.gyp
@@ -39,6 +39,7 @@
'../../../../ui/webui/resources/js/event_tracker.js',
'../../../../ui/webui/resources/js/load_time_data.js',
'../../../../ui/webui/resources/js/parse_html_subset.js',
+ '../../../../ui/webui/resources/js/promise_resolver.js',
'../../../../ui/webui/resources/js/util.js',
'../../../../chrome/browser/resources/chromeos/keyboard/keyboard_utils.js',
],
diff --git a/chromium/chrome/browser/resources/options/content_settings.html b/chromium/chrome/browser/resources/options/content_settings.html
index df9393cf3cf..e7b2dfb43aa 100644
--- a/chromium/chrome/browser/resources/options/content_settings.html
+++ b/chromium/chrome/browser/resources/options/content_settings.html
@@ -338,56 +338,6 @@
</div>
</div>
</section>
- <!-- Fullscreen filter -->
- <section id="fullscreen-section">
- <h3 i18n-content="fullscreenTabLabel"></h3>
- <div class="settings-row">
- <button class="exceptions-list-button" contentType="fullscreen"
- i18n-content="manageExceptions"></button>
- </div>
- </section>
- <!-- Mouse Lock filter -->
- <section id="mouselock-section">
- <h3 i18n-content="mouselockTabLabel"></h3>
- <div id="mouselock-global-settings">
- <div class="radio">
- <label>
- <input type="radio" name="mouselock" value="allow">
- <span>
- <span i18n-content="mouselockAllow"></span>
- <span class="controlled-setting-indicator"
- content-setting="mouselock" value="allow"></span>
- </span>
- </label>
- </div>
- <div class="radio">
- <label>
- <input type="radio" name="mouselock" value="ask">
- <span>
- <span i18n-content="mouselockAsk"></span>
- <span class="controlled-setting-indicator"
- content-setting="mouselock" value="ask"></span>
- </span>
- </label>
- </div>
- <div class="radio">
- <label>
- <input type="radio" name="mouselock" value="block">
- <span>
- <span i18n-content="mouselockBlock"></span>
- <span class="controlled-setting-indicator"
- content-setting="mouselock" value="block"></span>
- </span>
- </label>
- </div>
- </div>
- <div>
- <div class="settings-row">
- <button class="exceptions-list-button" contentType="mouselock"
- i18n-content="manageExceptions"></button>
- </div>
- </div>
- </section>
<if expr="chromeos or is_win">
<!-- Protected Content filter -->
<section guest-visibility="disabled">
@@ -646,6 +596,28 @@
</div>
</div>
</section>
+ <!-- Background sync -->
+ <section>
+ <h3 i18n-content="backgroundSyncHeader"></h3>
+ <div>
+ <div class="radio">
+ <label>
+ <input type="radio" name="background-sync" value="allow">
+ <span i18n-content="backgroundSyncAllow"></span>
+ </label>
+ </div>
+ <div class="radio">
+ <label>
+ <input type="radio" name="background-sync" value="block">
+ <span i18n-content="backgroundSyncBlock"></span>
+ </label>
+ </div>
+ <div class="settings-row">
+ <button class="exceptions-list-button" contentType="background-sync"
+ i18n-content="manageExceptions"></button>
+ </div>
+ </div>
+ </section>
<!-- Page zoom levels -->
<section id="page-zoom-levels">
<h3 i18n-content="zoomlevelsHeader"></h3>
@@ -656,6 +628,58 @@
</div>
</div>
</section>
+ <!-- Fullscreen filter -->
+ <section id="fullscreen-section">
+ <h3 i18n-content="fullscreenTabLabel"></h3>
+ <p id="fullscreen-deprecated" i18n-content="fullscreenDeprecated"></p>
+ <div class="settings-row">
+ <button class="exceptions-list-button" contentType="fullscreen"
+ i18n-content="manageExceptions"></button>
+ </div>
+ </section>
+ <!-- Mouse Lock filter -->
+ <section id="mouselock-section">
+ <h3 i18n-content="mouselockTabLabel"></h3>
+ <p id="mouselock-deprecated" i18n-content="mouselockDeprecated"></p>
+ <div id="mouselock-global-settings">
+ <div class="radio">
+ <label>
+ <input type="radio" name="mouselock" value="allow">
+ <span>
+ <span i18n-content="mouselockAllow"></span>
+ <span class="controlled-setting-indicator"
+ content-setting="mouselock" value="allow"></span>
+ </span>
+ </label>
+ </div>
+ <div class="radio">
+ <label>
+ <input type="radio" name="mouselock" value="ask">
+ <span>
+ <span i18n-content="mouselockAsk"></span>
+ <span class="controlled-setting-indicator"
+ content-setting="mouselock" value="ask"></span>
+ </span>
+ </label>
+ </div>
+ <div class="radio">
+ <label>
+ <input type="radio" name="mouselock" value="block">
+ <span>
+ <span i18n-content="mouselockBlock"></span>
+ <span class="controlled-setting-indicator"
+ content-setting="mouselock" value="block"></span>
+ </span>
+ </label>
+ </div>
+ </div>
+ <div>
+ <div class="settings-row">
+ <button class="exceptions-list-button" contentType="mouselock"
+ i18n-content="manageExceptions"></button>
+ </div>
+ </div>
+ </section>
</div>
<div class="action-area">
<div class="button-strip">
diff --git a/chromium/chrome/browser/resources/options/content_settings.js b/chromium/chrome/browser/resources/options/content_settings.js
index e00d6a9efad..33cac98257f 100644
--- a/chromium/chrome/browser/resources/options/content_settings.js
+++ b/chromium/chrome/browser/resources/options/content_settings.js
@@ -19,21 +19,6 @@ cr.define('options', function() {
/** @const */ var Page = cr.ui.pageManager.Page;
/** @const */ var PageManager = cr.ui.pageManager.PageManager;
- // Lookup table to generate the i18n strings.
- /** @const */ var permissionsLookup = {
- 'cookies': 'cookies',
- 'images': 'images',
- 'javascript': 'javascript',
- 'keygen': 'keygen',
- 'location': 'location',
- 'media-stream-camera': 'mediaStreamCamera',
- 'media-stream-mic': 'mediaStreamMic',
- 'multiple-automatic-downloads': 'multipleAutomaticDownloads',
- 'notifications': 'notifications',
- 'plugins': 'plugins',
- 'popups': 'popups',
- };
-
//////////////////////////////////////////////////////////////////////////////
// ContentSettings class:
@@ -117,14 +102,6 @@ cr.define('options', function() {
*/
ContentSettings.setContentFilterSettingsValue = function(dict) {
for (var group in dict) {
- var settingLabel = $(group + '-default-string');
- if (settingLabel) {
- var value = dict[group].value;
- var valueId =
- permissionsLookup[group] + value[0].toUpperCase() + value.slice(1);
- settingLabel.textContent = loadTimeData.getString(valueId);
- }
-
var managedBy = dict[group].managedBy;
var controlledBy = managedBy == 'policy' || managedBy == 'extension' ?
managedBy : null;
@@ -228,9 +205,14 @@ cr.define('options', function() {
/**
* Shows/hides parts of the fullscreen and mouselock sections.
+ * @param {boolean} deprecationVisible Whether to show (or hide) the
+ * deprecation warning labels.
* @param {boolean} globalsVisible Whether to show (or hide) global settings.
*/
- ContentSettings.setExclusiveAccessVisible = function(globalsVisible) {
+ ContentSettings.setExclusiveAccessVisible = function(
+ deprecationVisible, globalsVisible) {
+ $('fullscreen-deprecated').hidden = !deprecationVisible;
+ $('mouselock-deprecated').hidden = !deprecationVisible;
$('mouselock-global-settings').hidden = !globalsVisible;
};
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 bd4db34661d..4a16f4cfd87 100644
--- a/chromium/chrome/browser/resources/options/content_settings_exceptions_area.html
+++ b/chromium/chrome/browser/resources/options/content_settings_exceptions_area.html
@@ -156,6 +156,9 @@
<list mode="otr"></list>
</div>
</div>
+ <div contentType="background-sync">
+ <list mode="normal"></list>
+ </div>
<div contentType="zoomlevels">
<list mode="normal"></list>
<div>
diff --git a/chromium/chrome/browser/resources/options/googleg.svg b/chromium/chrome/browser/resources/options/googleg.svg
new file mode 100644
index 00000000000..7a1ad34425d
--- /dev/null
+++ b/chromium/chrome/browser/resources/options/googleg.svg
@@ -0,0 +1,7 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="16px" height="16px" viewBox="0 0 16 16">
+ <path fill="#4285F4" d="M14.72 8.16c0-.46-.05-.81-.11-1.16H8v2.4h3.97c-.1.62-.52 1.59-1.45 2.26v1.64h2.12c1.32-1.21 2.08-3.01 2.08-5.14z"/>
+ <path fill="#34A853" d="M8 15c1.89 0 3.47-.63 4.63-1.69l-2.12-1.64c-.6.43-1.42.75-2.51.75-1.89 0-3.48-1.24-4.08-2.96H1.75v1.69C2.9 13.43 5.26 15 8 15z"/>
+ <path fill="#FBBC05" d="M3.92 9.45C3.77 9 3.66 8.51 3.66 8s.1-1 .26-1.45V4.86H1.75C1.27 5.81 1 6.87 1 8s.27 2.19.75 3.14l2.17-1.69z"/>
+ <path fill="#EA4335" d="M8 3.58c1.36 0 2.27.58 2.79 1.08l1.9-1.83C11.47 1.69 9.89 1 8 1 5.26 1 2.9 2.57 1.75 4.86l2.17 1.69C4.52 4.83 6.11 3.58 8 3.58z"/>
+ <path fill="none" d="M1 1h14v14H1z"/>
+</svg>
diff --git a/chromium/chrome/browser/resources/options/info.svg b/chromium/chrome/browser/resources/options/info.svg
new file mode 100644
index 00000000000..e76e2476640
--- /dev/null
+++ b/chromium/chrome/browser/resources/options/info.svg
@@ -0,0 +1,4 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="18px" height="18px" viewBox="0 0 48 48" fill="#757575">
+ <path d="M0 0h48v48H0z" fill="none"/>
+ <path d="M24 4C12.95 4 4 12.95 4 24s8.95 20 20 20 20-8.95 20-20S35.05 4 24 4zm2 30h-4V22h4v12zm0-16h-4v-4h4v4z"/>
+</svg>
diff --git a/chromium/chrome/browser/resources/options/language_list.js b/chromium/chrome/browser/resources/options/language_list.js
index 1030a0ac70e..24467e0a02a 100644
--- a/chromium/chrome/browser/resources/options/language_list.js
+++ b/chromium/chrome/browser/resources/options/language_list.js
@@ -389,13 +389,12 @@ cr.define('options', function() {
*/
load_: function(languageCodes) {
// Preserve the original selected index. See comments below.
- var originalSelectedIndex = (this.selectionModel ?
- this.selectionModel.selectedIndex : -1);
+ var originalSelectedIndex = this.selectionModel.selectedIndex;
this.dataModel = new ArrayDataModel(languageCodes);
if (originalSelectedIndex >= 0 &&
originalSelectedIndex < this.dataModel.length) {
// Restore the original selected index if the selected index is
- // valid after the data model is loaded. This is neeeded to keep
+ // valid after the data model is loaded. This is needed to keep
// the selected language after the languge is added or removed.
this.selectionModel.selectedIndex = originalSelectedIndex;
// The lead index should be updated too.
diff --git a/chromium/chrome/browser/resources/options/language_options.html b/chromium/chrome/browser/resources/options/language_options.html
index bf3c4a82df0..a0c774ba1be 100644
--- a/chromium/chrome/browser/resources/options/language_options.html
+++ b/chromium/chrome/browser/resources/options/language_options.html
@@ -47,9 +47,6 @@
<span i18n-content="useThisForSpellChecking"></span>
</label>
</div>
- <button id="spellcheck-language-button"
- i18n-content="useThisForSpellChecking">
- </button>
<span id="spellcheck-language-message" hidden></span>
<span id="language-options-dictionary-downloading-message"
i18n-content="downloadingDictionary" hidden>
diff --git a/chromium/chrome/browser/resources/options/language_options.js b/chromium/chrome/browser/resources/options/language_options.js
index e954815562c..4117c5c1dd8 100644
--- a/chromium/chrome/browser/resources/options/language_options.js
+++ b/chromium/chrome/browser/resources/options/language_options.js
@@ -102,10 +102,10 @@ cr.define('options', function() {
/**
* Map from language code to spell check dictionary download status for that
* language.
- * @type {Array}
+ * @type {!Object}
* @private
*/
- spellcheckDictionaryDownloadStatus_: [],
+ spellcheckDictionaryDownloadStatus_: {},
/**
* Number of times a spell check dictionary download failed.
@@ -165,15 +165,6 @@ cr.define('options', function() {
*/
enableTranslate_: false,
- /**
- * Returns true if the enable-multilingual-spellchecker flag is set.
- * @return {boolean}
- * @private
- */
- isMultilingualSpellcheckerEnabled_: function() {
- return loadTimeData.getBoolean('enableMultilingualSpellChecker');
- },
-
/** @override */
initializePage: function() {
Page.prototype.initializePage.call(this);
@@ -244,25 +235,15 @@ cr.define('options', function() {
if (!(cr.isMac || cr.isChromeOS)) {
// Handle spell check enable/disable.
- if (!this.isMultilingualSpellcheckerEnabled_()) {
- Preferences.getInstance().addEventListener(
- ENABLE_SPELL_CHECK_PREF, this.updateEnableSpellCheck_.bind(this));
- }
- $('enable-spellcheck-container').hidden =
- this.isMultilingualSpellcheckerEnabled_();
+ Preferences.getInstance().addEventListener(
+ ENABLE_SPELL_CHECK_PREF, this.updateEnableSpellCheck_.bind(this));
}
// Handle clicks on "Use this language for spell checking" button.
if (!cr.isMac) {
- if (this.isMultilingualSpellcheckerEnabled_()) {
- $('spellcheck-language-checkbox').addEventListener(
- 'change',
- this.handleSpellCheckLanguageCheckboxClick_.bind(this));
- } else {
- $('spellcheck-language-button').addEventListener(
- 'click',
- this.handleSpellCheckLanguageButtonClick_.bind(this));
- }
+ $('spellcheck-language-checkbox').addEventListener(
+ 'change',
+ this.handleSpellCheckLanguageCheckboxClick_.bind(this));
}
if (cr.isChromeOS) {
@@ -284,6 +265,10 @@ cr.define('options', function() {
if (loadTimeData.getBoolean('enableLanguageOptionsImeMenu'))
$('language-options-ime-menu-template').hidden = false;
+ // Updates the initial checked state of the check box.
+ Preferences.getInstance().addEventListener(
+ ACTIVATE_IME_MENU_PREF, this.updateImeMenuCheckbox_.bind(this));
+
// Listen to check on 'activate-ime-menu' checkbox.
var checkboxImeMenu = $('activate-ime-menu');
checkboxImeMenu.addEventListener('click',
@@ -639,7 +624,6 @@ cr.define('options', function() {
updateSpellCheckLanguageControls_: function(languageCode) {
assert(languageCode);
var spellCheckLanguageSection = $('language-options-spellcheck');
- var spellCheckLanguageButton = $('spellcheck-language-button');
var spellCheckLanguageCheckboxContainer =
$('spellcheck-language-checkbox-container');
var spellCheckLanguageCheckbox = $('spellcheck-language-checkbox');
@@ -653,7 +637,6 @@ cr.define('options', function() {
spellCheckLanguageSection.hidden = false;
spellCheckLanguageMessage.hidden = true;
- spellCheckLanguageButton.hidden = true;
spellCheckLanguageCheckboxContainer.hidden = true;
dictionaryDownloadInProgress.hidden = true;
dictionaryDownloadFailed.hidden = true;
@@ -671,25 +654,10 @@ cr.define('options', function() {
}
var isUsedForSpellchecking = languageCode in this.spellCheckLanguages_;
- var isLanguageDownloaded =
- !(languageCode in this.spellcheckDictionaryDownloadStatus_);
-
- if (this.isMultilingualSpellcheckerEnabled_()) {
- spellCheckLanguageCheckbox.languageCode = languageCode;
- spellCheckLanguageCheckbox.checked = isUsedForSpellchecking;
- spellCheckLanguageCheckboxContainer.hidden = false;
- } else if (isUsedForSpellchecking) {
- if (isLanguageDownloaded) {
- spellCheckLanguageMessage.textContent =
- loadTimeData.getString('isUsedForSpellChecking');
- spellCheckLanguageMessage.hidden = false;
- }
- } else {
- spellCheckLanguageButton.textContent =
- loadTimeData.getString('useThisForSpellChecking');
- spellCheckLanguageButton.hidden = false;
- spellCheckLanguageButton.languageCode = languageCode;
- }
+
+ spellCheckLanguageCheckbox.languageCode = languageCode;
+ spellCheckLanguageCheckbox.checked = isUsedForSpellchecking;
+ spellCheckLanguageCheckboxContainer.hidden = false;
switch (this.spellcheckDictionaryDownloadStatus_[languageCode]) {
case DOWNLOAD_STATUS.IN_PROGRESS:
@@ -708,7 +676,6 @@ cr.define('options', function() {
Object.keys(this.spellCheckLanguages_).length == 0;
var usesSystemSpellchecker = !$('enable-spellcheck-container');
var isSpellcheckingEnabled = usesSystemSpellchecker ||
- this.isMultilingualSpellcheckerEnabled_() ||
$('enable-spellcheck').checked;
$('edit-custom-dictionary-button').hidden =
areNoLanguagesSelected || !isSpellcheckingEnabled;
@@ -971,14 +938,13 @@ cr.define('options', function() {
},
/**
- * Handles browse.enable_spellchecking change.
+ * Handles browser.enable_spellchecking change.
* @param {Event} e Change event.
* @private
*/
updateEnableSpellCheck_: function(e) {
var value = !$('enable-spellcheck').checked;
- var languageControl = $(this.isMultilingualSpellcheckerEnabled_() ?
- 'spellcheck-language-checkbox' : 'spellcheck-language-button');
+ var languageControl = $('spellcheck-language-checkbox');
languageControl.disabled = value;
if (!cr.isMac)
$('edit-custom-dictionary-button').hidden = value;
@@ -1028,23 +994,6 @@ cr.define('options', function() {
},
/**
- * Handles spellCheckLanguageButton click.
- * @param {Event} e Click event.
- * @private
- */
- handleSpellCheckLanguageButtonClick_: function(e) {
- var languageCode = e.currentTarget.languageCode;
- // Save the preference.
- Preferences.setListPref(SPELL_CHECK_DICTIONARIES_PREF,
- [languageCode], true);
-
- // The spellCheckLanguageChange argument is only used for logging.
- chrome.send('spellCheckLanguageChange', [languageCode]);
- chrome.send('coreOptionsUserMetricsAction',
- ['Options_Languages_SpellCheck']);
- },
-
- /**
* Updates the spellcheck.dictionaries preference with the currently
* selected language codes.
* @param {Event} e Click event. e.currentTarget represents the "Use this
@@ -1450,6 +1399,15 @@ cr.define('options', function() {
checkbox.checked, true);
}
},
+
+ /**
+ * Updates the activate-ime-menu check box's checked state.
+ * @param {Event} e Change event.
+ * @private
+ */
+ updateImeMenuCheckbox_: function(e) {
+ $('activate-ime-menu').checked = e.value.value;
+ },
};
/**
diff --git a/chromium/chrome/browser/resources/options/manage_profile_overlay.js b/chromium/chrome/browser/resources/options/manage_profile_overlay.js
index 874021e7a95..851c76f18d0 100644
--- a/chromium/chrome/browser/resources/options/manage_profile_overlay.js
+++ b/chromium/chrome/browser/resources/options/manage_profile_overlay.js
@@ -95,7 +95,7 @@ cr.define('options', function() {
$('create-profile-supervised-sign-in-link').onclick =
function(event) {
- SyncSetupOverlay.startSignIn('access-point-supervised-user');
+ SyncSetupOverlay.startSignIn(true /* creatingSupervisedUser */);
};
$('create-profile-supervised-sign-in-again-link').onclick =
diff --git a/chromium/chrome/browser/resources/options/options.html b/chromium/chrome/browser/resources/options/options.html
index e6e1ee2bc50..6d62f0026c7 100644
--- a/chromium/chrome/browser/resources/options/options.html
+++ b/chromium/chrome/browser/resources/options/options.html
@@ -148,6 +148,7 @@
<include src="alert_overlay.html">
<include src="autofill_edit_address_overlay.html">
<include src="autofill_edit_creditcard_overlay.html">
+ <include src="clear_browser_data_history_notice_overlay.html">
<include src="content_settings_exceptions_area.html">
<include src="cookies_view.html">
<include src="handler_options.html">
diff --git a/chromium/chrome/browser/resources/options/options.js b/chromium/chrome/browser/resources/options/options.js
index d331855fe56..bbfbf474eab 100644
--- a/chromium/chrome/browser/resources/options/options.js
+++ b/chromium/chrome/browser/resources/options/options.js
@@ -10,6 +10,7 @@ var AutofillOptions = options.AutofillOptions;
var AutomaticSettingsResetBanner = options.AutomaticSettingsResetBanner;
var BrowserOptions = options.BrowserOptions;
var ClearBrowserDataOverlay = options.ClearBrowserDataOverlay;
+var ClearBrowserDataHistoryNotice = options.ClearBrowserDataHistoryNotice;
var ConfirmDialog = options.ConfirmDialog;
var ContentSettingsExceptionsArea =
options.contentSettings.ContentSettingsExceptionsArea;
@@ -87,6 +88,9 @@ function load() {
BrowserOptions.getInstance(),
[$('privacyClearDataButton')]);
PageManager.registerOverlay(
+ ClearBrowserDataHistoryNotice.getInstance(),
+ ClearBrowserDataOverlay.getInstance());
+ PageManager.registerOverlay(
new ConfirmDialog(
'doNotTrackConfirm',
loadTimeData.getString('doNotTrackConfirmOverlayTabTitle'),
diff --git a/chromium/chrome/browser/resources/options/options_bundle.js b/chromium/chrome/browser/resources/options/options_bundle.js
index 8a72e0dc702..e1b6e3bf533 100644
--- a/chromium/chrome/browser/resources/options/options_bundle.js
+++ b/chromium/chrome/browser/resources/options/options_bundle.js
@@ -32,6 +32,9 @@
<include src="chromeos/accounts_user_list.js">
<include src="chromeos/accounts_user_name_edit.js">
<include src="chromeos/consumer_management_overlay.js">
+<include src="chromeos/display_layout.js">
+<include src="chromeos/display_layout_manager.js">
+<include src="chromeos/display_layout_manager_multi.js">
<include src="chromeos/display_options.js">
<include src="chromeos/display_overscan.js">
<include src="chromeos/keyboard_overlay.js">
@@ -74,6 +77,7 @@ var CertificateImportErrorOverlay = options.CertificateImportErrorOverlay;
<include src="browser_options_profile_list.js">
<include src="browser_options_startup_page_list.js">
<include src="clear_browser_data_overlay.js">
+<include src="clear_browser_data_history_notice_overlay.js">
<include src="confirm_dialog.js">
<include src="content_settings.js">
<include src="content_settings_exceptions_area.js">
diff --git a/chromium/chrome/browser/resources/options/password_manager.html b/chromium/chrome/browser/resources/options/password_manager.html
index 77ded2c088f..3e2584572b7 100644
--- a/chromium/chrome/browser/resources/options/password_manager.html
+++ b/chromium/chrome/browser/resources/options/password_manager.html
@@ -4,7 +4,7 @@
<div class="content-area">
<div id="auto-signin-block" class="checkbox" hidden>
<label>
- <input pref="profile.password_manager_auto_signin" type="checkbox">
+ <input pref="credentials_enable_autosignin" type="checkbox">
<span i18n-content="autoSigninTitle"></span>
</label>
<div class="setting-extra-description">
diff --git a/chromium/chrome/browser/resources/options/password_manager.js b/chromium/chrome/browser/resources/options/password_manager.js
index 3e501727ff7..a6ee22c8f03 100644
--- a/chromium/chrome/browser/resources/options/password_manager.js
+++ b/chromium/chrome/browser/resources/options/password_manager.js
@@ -165,6 +165,42 @@ cr.define('options', function() {
},
/**
+ * 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);
+ 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;
+ }
+ if (urlLink.offsetWidth <= cellWidth)
+ continue;
+ urlLink.textContent = '…' + urlLink.textContent.substring(1);
+ while (urlLink.offsetWidth > cellWidth)
+ urlLink.textContent = '…' + urlLink.textContent.substring(2);
+ }
+ },
+
+ /**
* Updates the data model for the saved passwords list with the values from
* |entries|.
* @param {!Array} entries The list of saved password data.
@@ -176,9 +212,9 @@ cr.define('options', function() {
var query = this.lastQuery_;
var filter = function(entry, index, list) {
// Search both shown URL and username.
- var shownUrl = entry[options.passwordManager.SHOWN_URL_FIELD];
+ var shownOrigin = entry[options.passwordManager.SHOWN_ORIGIN_FIELD];
var username = entry[options.passwordManager.USERNAME_FIELD];
- if (shownUrl.toLowerCase().indexOf(query.toLowerCase()) >= 0 ||
+ if (shownOrigin.toLowerCase().indexOf(query.toLowerCase()) >= 0 ||
username.toLowerCase().indexOf(query.toLowerCase()) >= 0) {
// Keep the original index so we can delete correctly. See also
// deleteItemAtIndex() in password_manager_list.js that uses this.
@@ -191,6 +227,9 @@ cr.define('options', function() {
}
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_);
},
/**
@@ -201,6 +240,9 @@ cr.define('options', function() {
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_);
},
/**
diff --git a/chromium/chrome/browser/resources/options/password_manager_list.css b/chromium/chrome/browser/resources/options/password_manager_list.css
index d3ac26af07a..43f7d607304 100644
--- a/chromium/chrome/browser/resources/options/password_manager_list.css
+++ b/chromium/chrome/browser/resources/options/password_manager_list.css
@@ -43,7 +43,7 @@ input.inactive-item {
}
#saved-passwords-list .url,
-#saved-passwords-list .name {
+#password-exceptions-list .url {
-webkit-user-select: text;
}
@@ -71,22 +71,3 @@ input.inactive-item {
overflow: hidden;
text-overflow: ellipsis;
}
-
-/* To elide URLs from the left, sets unicode-bidi=bidi-override and
- * direction=rtl. */
-.left-elided-url {
- direction: rtl;
- unicode-bidi: bidi-override;
-}
-
-/* RTL direction in left-elided-url changes text-align to right, but URLs for
- * left-to-right locales should still be left aligned.
- * Since the direction is changed to RTL, the icon is at the end (i.e. left),
- * but not at the start. So, swaps start and end margin/padding. */
-html[dir='ltr'] .left-elided-url {
- -webkit-margin-end: 7px;
- -webkit-margin-start: 0;
- -webkit-padding-end: 26px;
- -webkit-padding-start: 3px;
- text-align: left;
-} \ No newline at end of file
diff --git a/chromium/chrome/browser/resources/options/password_manager_list.js b/chromium/chrome/browser/resources/options/password_manager_list.js
index 58bd5efce0d..e30894ea7f0 100644
--- a/chromium/chrome/browser/resources/options/password_manager_list.js
+++ b/chromium/chrome/browser/resources/options/password_manager_list.js
@@ -10,9 +10,10 @@ cr.define('options.passwordManager', function() {
// The following constants should be synchronized with the constants in
// chrome/browser/ui/webui/options/password_manager_handler.cc.
- /** @const */ var ORIGIN_FIELD = 'origin';
- /** @const */ var SHOWN_URL_FIELD = 'shownUrl';
+ /** @const */ var URL_FIELD = 'url';
+ /** @const */ var SHOWN_ORIGIN_FIELD = 'shownOrigin';
/** @const */ var IS_ANDROID_URI_FIELD = 'isAndroidUri';
+ /** @const */ var IS_CLICKABLE_FIELD = 'isClickable';
/** @const */ var IS_SECURE_FIELD = 'isSecure';
/** @const */ var USERNAME_FIELD = 'username';
/** @const */ var PASSWORD_FIELD = 'password';
@@ -42,15 +43,15 @@ cr.define('options.passwordManager', function() {
}
/**
- * Returns title for password's origin. If the origin is Android URI, returns
- * the origin as it is. Removes the scheme if the url is insecure and removes
- * trailing punctuation symbols.
+ * Returns title for password's origin. If the origin is not clickable,
+ * returns the origin as it is. For clickable origins, removes the scheme if
+ * the url is insecure and removes trailing punctuation symbols.
* @param {Object} item A dictionary of data on the list item.
* @return {string} The title for password's origin.
*/
function getTitleForPasswordOrigin(item) {
var title = item.url;
- if (item.isAndroidUri)
+ if (!item.isClickable)
return title;
if (!item.isSecure) {
var ind = title.indexOf('://');
@@ -58,39 +59,61 @@ cr.define('options.passwordManager', function() {
title = title.substring(ind + 3);
}
}
- // Since the direction is switched to RTL, punctuation symbols appear on the
- // left side, that is wrong. So, just remove trailing punctuation symbols.
- title = title.replace(/[^A-Za-z0-9]+$/, '');
return title;
}
/**
- * Helper function that creates an HTML element for displaying the origin of
- * saved password.
+ * Helper function that creates an HTML element for displaying the link to
+ * the origin of saved password.
* @param {Object} item A dictionary of data on the list item.
* @param {Element} urlDiv div-element that will enclose the created
* element.
- * @return {Element} The element for displaying password origin.
+ * @return {Element} The element for displaying the link to the origin.
*/
function createUrlLink(item, urlDiv) {
var urlLink;
- if (!item.isAndroidUri) {
+ if (item.isClickable) {
urlLink = item.ownerDocument.createElement('a');
urlLink.href = item.url;
urlLink.setAttribute('target', '_blank');
- urlLink.textContent = item.shownUrl.split('').reverse().join('');
-
- urlDiv.classList.add('left-elided-url');
+ urlLink.dir = 'ltr';
} else {
urlLink = item.ownerDocument.createElement('span');
- urlLink.textContent = item.shownUrl;
}
+ urlLink.textContent = item.shownOrigin;
urlLink.addEventListener('focus', function() {
item.handleFocus();
}.bind(item));
return urlLink;
}
+ /**
+ * Helper function that creates an HTML element for displaying the origin of
+ * saved password. It also sets some properties in |item|.
+ * @param {Object} item A dictionary of data on the list item.
+ * @return {Element} The element for displaying the origin of saved password.
+ */
+ function createUrlDiv(item) {
+ var urlDiv = cr.doc.createElement('div');
+ urlDiv.className = 'favicon-cell url';
+ urlDiv.setAttribute('title', getTitleForPasswordOrigin(item));
+ urlDiv.style.backgroundImage = getFaviconImageSet(
+ 'origin/' + item.url, 16);
+
+ item.urlLink = createUrlLink(item, urlDiv);
+ urlDiv.appendChild(item.urlLink);
+
+ if (item.isAndroidUri && item.isClickable) {
+ item.androidUriSuffix = cr.doc.createElement('span');
+ item.androidUriSuffix.textContent =
+ loadTimeData.getString('androidUriSuffix');
+ urlDiv.appendChild(item.androidUriSuffix);
+ }
+
+ item.urlDiv = urlDiv;
+ return urlDiv;
+ }
+
PasswordListItem.prototype = {
__proto__: DeletableItem.prototype,
@@ -99,16 +122,7 @@ cr.define('options.passwordManager', function() {
DeletableItem.prototype.decorate.call(this);
// The URL of the site.
- var urlDiv = this.ownerDocument.createElement('div');
- urlDiv.className = 'favicon-cell url';
- urlDiv.setAttribute('title', getTitleForPasswordOrigin(this));
- urlDiv.style.backgroundImage = getFaviconImageSet(
- 'origin/' + this.url, 16);
-
- this.urlLink = createUrlLink(this, urlDiv);
- urlDiv.appendChild(this.urlLink);
-
- this.contentElement.appendChild(urlDiv);
+ this.contentElement.appendChild(createUrlDiv(this));
// The stored username.
var usernameDiv = this.ownerDocument.createElement('div');
@@ -262,81 +276,68 @@ cr.define('options.passwordManager', function() {
},
/**
- * Get and set the URL for the entry.
+ * Get the URL for the entry.
* @type {string}
*/
get url() {
- return this.dataItem[ORIGIN_FIELD];
- },
- set url(url) {
- this.dataItem[ORIGIN_FIELD] = url;
+ return this.dataItem[URL_FIELD];
},
/**
- * Get and set the shown url for the entry.
+ * Get the shown origin for the entry.
* @type {string}
*/
- get shownUrl() {
- return this.dataItem[SHOWN_URL_FIELD];
- },
- set shownUrl(shownUrl) {
- this.dataItem[SHOWN_URL_FIELD] = shownUrl;
+ get shownOrigin() {
+ return this.dataItem[SHOWN_ORIGIN_FIELD];
},
/**
- * Get and set whether the origin is Android URI.
+ * Get whether the origin is Android URI.
* @type {boolean}
*/
get isAndroidUri() {
return this.dataItem[IS_ANDROID_URI_FIELD];
},
- set isAndroidUri(isAndroidUri) {
- this.dataItem[IS_ANDROID_URI_FIELD] = isAndroidUri;
+
+ /**
+ * Get whether the origin is clickable.
+ * @type {boolean}
+ */
+ get isClickable() {
+ return this.dataItem[IS_CLICKABLE_FIELD];
},
/**
- * Get and set whether the origin uses secure scheme.
+ * Get whether the origin uses secure scheme.
* @type {boolean}
*/
get isSecure() {
return this.dataItem[IS_SECURE_FIELD];
},
- set isSecure(isSecure) {
- this.dataItem[IS_SECURE_FIELD] = isSecure;
- },
/**
- * Get and set the username for the entry.
+ * Get the username for the entry.
* @type {string}
*/
get username() {
return this.dataItem[USERNAME_FIELD];
},
- set username(username) {
- this.dataItem[USERNAME_FIELD] = username;
- },
/**
- * Get and set the password for the entry.
+ * Get the password for the entry.
* @type {string}
*/
get password() {
return this.dataItem[PASSWORD_FIELD];
},
- set password(password) {
- this.dataItem[PASSWORD_FIELD] = password;
- },
/**
- * Get and set the federation for the entry.
+ * Get the federation for the entry.
* @type {string}
*/
get federation() {
return this.dataItem[FEDERATION_FIELD];
},
- set federation(federation) {
- this.dataItem[FEDERATION_FIELD] = federation;
- },
};
/**
@@ -364,16 +365,7 @@ cr.define('options.passwordManager', function() {
DeletableItem.prototype.decorate.call(this);
// The URL of the site.
- var urlDiv = this.ownerDocument.createElement('div');
- urlDiv.className = 'favicon-cell url';
- urlDiv.setAttribute('title', getTitleForPasswordOrigin(this));
- urlDiv.style.backgroundImage = getFaviconImageSet(
- 'origin/' + this.url, 16);
-
- this.urlLink = createUrlLink(this, urlDiv);
- urlDiv.appendChild(this.urlLink);
-
- this.contentElement.appendChild(urlDiv);
+ this.contentElement.appendChild(createUrlDiv(this));
},
/** @override */
@@ -402,44 +394,40 @@ cr.define('options.passwordManager', function() {
* @type {string}
*/
get url() {
- return this.dataItem[ORIGIN_FIELD];
- },
- set url(url) {
- this.dataItem[ORIGIN_FIELD] = url;
+ return this.dataItem[URL_FIELD];
},
/**
- * Get and set the shown url for the entry.
+ * Get the shown origin for the entry.
* @type {string}
*/
- get shownUrl() {
- return this.dataItem[SHOWN_URL_FIELD];
- },
- set shownUrl(shownUrl) {
- this.dataItem[SHOWN_URL_FIELD] = shownUrl;
+ get shownOrigin() {
+ return this.dataItem[SHOWN_ORIGIN_FIELD];
},
/**
- * Get and set whether the origin is Android URI.
+ * Get whether the origin is Android URI.
* @type {boolean}
*/
get isAndroidUri() {
return this.dataItem[IS_ANDROID_URI_FIELD];
},
- set isAndroidUri(isAndroidUri) {
- this.dataItem[IS_ANDROID_URI_FIELD] = isAndroidUri;
+
+ /**
+ * Get whether the origin is clickable.
+ * @type {boolean}
+ */
+ get isClickable() {
+ return this.dataItem[IS_CLICKABLE_FIELD];
},
/**
- * Get and set whether the origin uses secure scheme.
+ * Get whether the origin uses secure scheme.
* @type {boolean}
*/
get isSecure() {
return this.dataItem[IS_SECURE_FIELD];
},
- set isSecure(isSecure) {
- this.dataItem[IS_SECURE_FIELD] = isSecure;
- },
};
/**
@@ -462,9 +450,6 @@ cr.define('options.passwordManager', function() {
/** @override */
decorate: function() {
DeletableItemList.prototype.decorate.call(this);
- Preferences.getInstance().addEventListener(
- 'profile.password_manager_allow_show_passwords',
- this.onPreferenceChanged_.bind(this));
this.addEventListener('focus', this.onFocus_.bind(this));
},
@@ -556,8 +541,10 @@ cr.define('options.passwordManager', function() {
PasswordExceptionsListItem: PasswordExceptionsListItem,
PasswordsList: PasswordsList,
PasswordExceptionsList: PasswordExceptionsList,
- ORIGIN_FIELD: ORIGIN_FIELD,
- SHOWN_URL_FIELD: SHOWN_URL_FIELD,
+ URL_FIELD: URL_FIELD,
+ SHOWN_ORIGIN_FIELD: SHOWN_ORIGIN_FIELD,
+ IS_ANDROID_URI_FIELD: IS_ANDROID_URI_FIELD,
+ IS_CLICKABLE_FIELD: IS_CLICKABLE_FIELD,
IS_SECURE_FIELD: IS_SECURE_FIELD,
USERNAME_FIELD: USERNAME_FIELD,
PASSWORD_FIELD: PASSWORD_FIELD,
diff --git a/chromium/chrome/browser/resources/options/search_page.js b/chromium/chrome/browser/resources/options/search_page.js
index 6cd5ff85dd2..c561a0cccbb 100644
--- a/chromium/chrome/browser/resources/options/search_page.js
+++ b/chromium/chrome/browser/resources/options/search_page.js
@@ -2,6 +2,55 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+/**
+ * Section IDs use for metrics. The integer values should match up with the
+ * |SettingsSections| in histograms.xml.
+ * @type {Object<string, number>}
+ */
+var SettingsSections = {
+ 'None': 0,
+ 'Unknown': 1,
+ 'network-section-cros': 2,
+ 'proxy-section': 3,
+ 'appearance-section': 4,
+ 'device-section': 5,
+ 'search-section': 6,
+ 'sync-users-section': 7,
+ 'set-default-browser-section': 8,
+ 'date-time-section': 9,
+ 'device-control-section': 10,
+ 'privacy-section': 11,
+ 'bluetooth-devices': 12,
+ 'passwords-and-autofill-section': 13,
+ 'easy-unlock-section': 14,
+ 'web-content-section': 15,
+ 'network-section': 16,
+ 'languages-section': 17,
+ 'downloads-section': 18,
+ 'certificates-section': 19,
+ 'cloudprint-options-mdns': 20,
+ 'a11y-section': 21,
+ 'factory-reset-section': 22,
+ 'system-section': 23,
+ 'reset-profile-settings-section': 24,
+ 'sync-section': 25,
+ 'startup-section': 26,
+ 'mouselock-section': 27,
+ 'page-zoom-levels': 28,
+ 'status-section': 29,
+ 'main-section': 30,
+ 'pointer-section-touchpad': 31,
+ 'pointer-section-mouse': 32,
+ 'prefs-blocked-languages': 33,
+ 'prefs-language-blacklist': 34,
+ 'prefs-site-blacklist': 35,
+ 'prefs-whitelists': 36,
+ 'prefs-supported-languages': 37,
+ 'prefs-cld-version': 38,
+ 'prefs-cld-data-source': 39,
+ 'prefs-dump': 40,
+};
+
cr.define('options', function() {
/** @const */ var Page = cr.ui.pageManager.Page;
/** @const */ var PageManager = cr.ui.pageManager.PageManager;
@@ -254,8 +303,8 @@ cr.define('options', function() {
}
var pagesToSearch = this.getSearchablePages_();
- for (var key in pagesToSearch) {
- var page = pagesToSearch[key];
+ for (var i = 0; i < pagesToSearch.length; i++) {
+ var page = pagesToSearch[i];
if (!active)
page.visible = false;
@@ -342,8 +391,8 @@ cr.define('options', function() {
this.removeSearchBubbles_();
var pagesToSearch = this.getSearchablePages_();
- for (var key in pagesToSearch) {
- var page = pagesToSearch[key];
+ for (var i = 0; i < pagesToSearch.length; i++) {
+ var page = pagesToSearch[i];
var elements = page.pageDiv.querySelectorAll('section');
for (var i = 0, node; node = elements[i]; i++) {
node.classList.add('search-hidden');
@@ -353,6 +402,7 @@ cr.define('options', function() {
var bubbleControls = [];
var pageMatchesForMetrics = 0;
var subpageMatchesForMetrics = 0;
+ var sectionMatchesForMetrics = {};
// Generate search text by applying lowercase and escaping any characters
// that would be problematic for regular expressions.
@@ -363,8 +413,8 @@ cr.define('options', function() {
if (searchText.length) {
// Search all top-level sections for anchored string matches.
- for (var key in pagesToSearch) {
- var page = pagesToSearch[key];
+ for (var i = 0; i < pagesToSearch.length; i++) {
+ var page = pagesToSearch[i];
var elements =
page.pageDiv.querySelectorAll('section');
for (var i = 0, node; node = elements[i]; i++) {
@@ -373,6 +423,9 @@ cr.define('options', function() {
if (!node.hidden) {
foundMatches = true;
pageMatchesForMetrics += 1;
+ var section = SettingsSections[node.id] ||
+ SettingsSections['Unknown'];
+ sectionMatchesForMetrics[section] = section;
}
}
}
@@ -382,8 +435,8 @@ cr.define('options', function() {
// we need to make visible.
var subPagesToSearch = this.getSearchableSubPages_();
var control, node;
- for (var key in subPagesToSearch) {
- var page = subPagesToSearch[key];
+ for (var i = 0; i < subPagesToSearch.length; i++) {
+ var page = subPagesToSearch[i];
if (this.highlightMatches_(regExp, page.pageDiv)) {
this.revealAssociatedSections_(page);
@@ -410,7 +463,17 @@ cr.define('options', function() {
if (!foundMatches) {
chrome.metricsPrivate.recordSmallCount(
'Settings.SearchLengthNoMatch', text.length);
+ chrome.metricsPrivate.recordSmallCount(
+ 'Settings.SearchSections', SettingsSections['None']);
+ } else {
+ for (var section in sectionMatchesForMetrics) {
+ var sectionId = sectionMatchesForMetrics[section];
+ assert(sectionId !== undefined);
+ chrome.metricsPrivate.recordSmallCount(
+ 'Settings.SearchSections', sectionId);
+ }
}
+
chrome.metricsPrivate.recordUserAction('Settings.Searching');
chrome.metricsPrivate.recordSmallCount(
'Settings.SearchLength', text.length);
diff --git a/chromium/chrome/browser/resources/options/sync_setup_overlay.js b/chromium/chrome/browser/resources/options/sync_setup_overlay.js
index 50a297a373e..59332d260bf 100644
--- a/chromium/chrome/browser/resources/options/sync_setup_overlay.js
+++ b/chromium/chrome/browser/resources/options/sync_setup_overlay.js
@@ -842,10 +842,11 @@ cr.define('options', function() {
/**
* Starts the signin process for the user. Does nothing if the user is
* already signed in.
+ * @param {boolean} creatingSupervisedUser
* @private
*/
- startSignIn_: function(accessPoint) {
- chrome.send('SyncSetupStartSignIn', [accessPoint]);
+ startSignIn_: function(creatingSupervisedUser) {
+ chrome.send('SyncSetupStartSignIn', [creatingSupervisedUser]);
},
/**
diff --git a/chromium/chrome/browser/resources/pdf/elements/viewer-bookmark/viewer-bookmark.js b/chromium/chrome/browser/resources/pdf/elements/viewer-bookmark/viewer-bookmark.js
index 7905ea4ec34..9d6399070e7 100644
--- a/chromium/chrome/browser/resources/pdf/elements/viewer-bookmark/viewer-bookmark.js
+++ b/chromium/chrome/browser/resources/pdf/elements/viewer-bookmark/viewer-bookmark.js
@@ -65,6 +65,8 @@
onClick: function() {
if (this.bookmark.hasOwnProperty('page'))
this.fire('change-page', {page: this.bookmark.page});
+ else if (this.bookmark.hasOwnProperty('uri'))
+ this.fire('navigate', {uri: this.bookmark.uri, newtab: true});
},
onEnter_: function(e) {
diff --git a/chromium/chrome/browser/resources/pdf/elements/viewer-pdf-toolbar/viewer-pdf-toolbar.html b/chromium/chrome/browser/resources/pdf/elements/viewer-pdf-toolbar/viewer-pdf-toolbar.html
index 7e3df10d583..dfe225d2c53 100644
--- a/chromium/chrome/browser/resources/pdf/elements/viewer-pdf-toolbar/viewer-pdf-toolbar.html
+++ b/chromium/chrome/browser/resources/pdf/elements/viewer-pdf-toolbar/viewer-pdf-toolbar.html
@@ -2,8 +2,8 @@
<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/iron-icons/image-icons.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/animations/slide-down-animation.html">
<link rel="import" href="chrome://resources/polymer/v1_0/neon-animation/animations/slide-up-animation.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/neon-animation/animations/transform-animation.html">
<link rel="import" href="chrome://resources/polymer/v1_0/neon-animation/neon-animation-runner-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-progress/paper-progress.html">
diff --git a/chromium/chrome/browser/resources/pdf/elements/viewer-pdf-toolbar/viewer-pdf-toolbar.js b/chromium/chrome/browser/resources/pdf/elements/viewer-pdf-toolbar/viewer-pdf-toolbar.js
index 143a0127c3d..009aa4e026f 100644
--- a/chromium/chrome/browser/resources/pdf/elements/viewer-pdf-toolbar/viewer-pdf-toolbar.js
+++ b/chromium/chrome/browser/resources/pdf/elements/viewer-pdf-toolbar/viewer-pdf-toolbar.js
@@ -53,8 +53,10 @@
value: function() {
return {
'entry': {
- name: 'slide-down-animation',
+ name: 'transform-animation',
node: this,
+ transformFrom: 'translateY(-100%)',
+ transformTo: 'translateY(0%)',
timing: {
easing: 'cubic-bezier(0, 0, 0.2, 1)',
duration: 250
diff --git a/chromium/chrome/browser/resources/pdf/pdf.js b/chromium/chrome/browser/resources/pdf/pdf.js
index 4ea2b064ea0..dab584d9d0b 100644
--- a/chromium/chrome/browser/resources/pdf/pdf.js
+++ b/chromium/chrome/browser/resources/pdf/pdf.js
@@ -237,6 +237,10 @@ function PDFViewer(browserApi) {
this.viewport_.goToPage(e.detail.page);
}.bind(this));
+ document.body.addEventListener('navigate', function(e) {
+ this.navigator_.navigate(e.detail.uri, e.detail.newtab);
+ }.bind(this));
+
this.toolbarManager_ =
new ToolbarManager(window, this.toolbar_, this.zoomToolbar_);
diff --git a/chromium/chrome/browser/resources/plugin_metadata/plugins_chromeos.json b/chromium/chrome/browser/resources/plugin_metadata/plugins_chromeos.json
index 86c4bae45ed..a920c7e0c99 100644
--- a/chromium/chrome/browser/resources/plugin_metadata/plugins_chromeos.json
+++ b/chromium/chrome/browser/resources/plugin_metadata/plugins_chromeos.json
@@ -1,5 +1,5 @@
{
- "x-version": 2,
+ "x-version": 3,
"google-talk": {
"mime_types": [
],
@@ -36,7 +36,7 @@
"versions": [
{
"version": "0",
- "status": "up_to_date",
+ "status": "fully_trusted",
"comment": "Google Chrome PDF has no version information."
}
],
@@ -49,8 +49,8 @@
"versions": [
{
"version": "0",
- "status": "up_to_date",
- "comment": "Chrome PDF Viewer has no version information."
+ "status": "fully_trusted",
+ "comment": "Chromium PDF Viewer has no version information."
}
],
"name": "Chromium PDF Viewer",
diff --git a/chromium/chrome/browser/resources/plugin_metadata/plugins_linux.json b/chromium/chrome/browser/resources/plugin_metadata/plugins_linux.json
index 1bb4dac3582..35dbf1052b5 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": 11,
+ "x-version": 12,
"google-talk": {
"mime_types": [
],
@@ -117,7 +117,7 @@
"versions": [
{
"version": "0",
- "status": "up_to_date",
+ "status": "fully_trusted",
"comment": "Google Chrome PDF has no version information."
}
],
@@ -130,8 +130,8 @@
"versions": [
{
"version": "0",
- "status": "up_to_date",
- "comment": "Chrome PDF Viewer has no version information."
+ "status": "fully_trusted",
+ "comment": "Chromium PDF Viewer has no version information."
}
],
"name": "Chromium PDF Viewer",
diff --git a/chromium/chrome/browser/resources/plugin_metadata/plugins_mac.json b/chromium/chrome/browser/resources/plugin_metadata/plugins_mac.json
index ad658f74973..853ad38c0bd 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": 17,
+ "x-version": 18,
"google-talk": {
"mime_types": [
],
@@ -277,8 +277,8 @@
"versions": [
{
"version": "0",
- "status": "up_to_date",
- "comment": "Chrome PDF Viewer has no version information."
+ "status": "fully_trusted",
+ "comment": "Google Chrome PDF Viewer has no version information."
}
],
"name": "Chrome PDF Viewer",
@@ -290,8 +290,8 @@
"versions": [
{
"version": "0",
- "status": "up_to_date",
- "comment": "Chrome PDF Viewer has no version information."
+ "status": "fully_trusted",
+ "comment": "Chromium PDF Viewer has no version information."
}
],
"name": "Chromium PDF Viewer",
diff --git a/chromium/chrome/browser/resources/plugin_metadata/plugins_win.json b/chromium/chrome/browser/resources/plugin_metadata/plugins_win.json
index 68ee094ba8a..3c8870a051b 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": 26,
+ "x-version": 27,
"google-talk": {
"mime_types": [
],
@@ -339,8 +339,8 @@
"versions": [
{
"version": "0",
- "status": "up_to_date",
- "comment": "Chrome PDF Viewer has no version information."
+ "status": "fully_trusted",
+ "comment": "Google Chrome PDF Viewer has no version information."
}
],
"name": "Chrome PDF Viewer",
@@ -352,8 +352,8 @@
"versions": [
{
"version": "0",
- "status": "up_to_date",
- "comment": "Chrome PDF Viewer has no version information."
+ "status": "fully_trusted",
+ "comment": "Chromium PDF Viewer has no version information."
}
],
"name": "Chromium PDF Viewer",
diff --git a/chromium/chrome/browser/resources/plugins.html b/chromium/chrome/browser/resources/plugins.html
index 92e92992db0..3dbd463b5e1 100644
--- a/chromium/chrome/browser/resources/plugins.html
+++ b/chromium/chrome/browser/resources/plugins.html
@@ -71,13 +71,13 @@
</span>
<a jsdisplay="critical" jsvalues=".href:update_url"
i18n-content="pluginDownload">DOWNLOAD UPDATE</a>
- <span jsdisplay="enabledMode == 'disabledByUser'"
+ <span jsdisplay="enabled_mode == 'disabledByUser'"
i18n-content="pluginDisabled">(DISABLED)</span>
- <span jsdisplay="enabledMode == 'disabledByPolicy'"
+ <span jsdisplay="enabled_mode == 'disabledByPolicy'"
i18n-content="pluginDisabledByPolicy">(DISABLED_BY_POLICY)</span>
- <span jsdisplay="enabledMode == 'enabledByPolicy'"
+ <span jsdisplay="enabled_mode == 'enabledByPolicy'"
i18n-content="pluginEnabledByPolicy">(ENABLED_BY_POLICY)</span>
- <span jsdisplay="enabledMode == 'managedByPolicy'"
+ <span jsdisplay="enabled_mode == 'managedByPolicy'"
i18n-content="pluginGroupManagedByPolicy">(MANAGED_BY_POLICY)</span>
<div jsdisplay="shouldDisplayPluginDescription($this)">
<span dir="ltr" jsvalues=".innerHTML:description">
@@ -119,29 +119,29 @@
<div><table><tr>
<td class="plugin-details-label">&nbsp;</td>
<td>
- <span jsdisplay="enabledMode == 'disabledByPolicy'"
+ <span jsdisplay="enabled_mode == 'disabledByPolicy'"
i18n-content="pluginDisabledByPolicy">(DISABLED_BY_POLICY)</span>
- <span jsdisplay="enabledMode == 'enabledByPolicy'"
+ <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="enabledMode == 'enabledByUser'"
+ jsdisplay="enabled_mode == 'enabledByUser'"
href="#"
i18n-content="disable"
>DISABLE</a>
<a
class="enable-plugin-link"
jsvalues=".path:path"
- jsdisplay="enabledMode == 'disabledByUser'"
+ jsdisplay="enabled_mode == 'disabledByUser'"
href="#"
i18n-content="enable"
>ENABLE</a>
</span>
</td>
</tr></table></div>
- <table><tr jsdisplay="mimeTypes.length > 0">
+ <table><tr jsdisplay="mime_types.length > 0">
<td class="plugin-details-label"
i18n-content="pluginMimeTypes">MIME_TYPES:</td>
<td><table width="100%" class="mime-types">
@@ -153,14 +153,14 @@
<td i18n-content="pluginMimeTypesFileExtensions"
>FILE_EXTENSIONS</td>
</tr>
- <tr jsselect="mimeTypes">
+ <tr jsselect="mime_types">
<td><span dir="ltr"
- jscontent="mimeType"></span></td>
+ jscontent="mime_type"></span></td>
<td><span dir="ltr"
jsvalues=".innerHTML:description"></span></td>
- <td><table jsdisplay="fileExtensions.length > 0"
+ <td><table jsdisplay="file_extensions.length > 0"
class="hlisting">
- <tr><td jsselect="fileExtensions">
+ <tr><td jsselect="file_extensions">
<span dir="ltr" jscontent="'.' + $this">
</td></tr>
</table></td>
@@ -176,14 +176,14 @@
<a
class="disable-group-link"
jsvalues=".path:name"
- jsdisplay="enabledMode == 'enabledByUser'"
+ jsdisplay="enabled_mode == 'enabledByUser'"
href="#"
i18n-content="disable"
>DISABLE</a>
<a
class="enable-group-link"
jsvalues=".path:name"
- jsdisplay="enabledMode == 'disabledByUser'"
+ jsdisplay="enabled_mode == 'disabledByUser'"
href="#"
i18n-content="enable"
>ENABLE</a>
@@ -191,7 +191,7 @@
<input
class="always-allow" type="checkbox"
jsvalues=
- ".identifier:id; id:id + '-always-allowed'; .checked:alwaysAllowed; disabled:!isPluginEnabled($this)">
+ ".identifier:id; id:id + '-always-allowed'; .checked:always_allowed; disabled:isPluginTrusted($this) || !isPluginEnabled($this)">
<label jsvalues="for:id + '-always-allowed'"
i18n-content="alwaysAllowed"></label>
</div>
diff --git a/chromium/chrome/browser/resources/plugins.js b/chromium/chrome/browser/resources/plugins.js
index 6b19cee625b..3301f2f8525 100644
--- a/chromium/chrome/browser/resources/plugins.js
+++ b/chromium/chrome/browser/resources/plugins.js
@@ -5,7 +5,7 @@
/**
* Takes the |pluginsData| input argument which represents data about the
* currently installed/running plugins and populates the html jstemplate with
- * that data. It expects an object structure like the above.
+ * that data.
* @param {Object} pluginsData Detailed info about installed plugins. Same
* expected format as returnPluginsData().
*/
@@ -16,24 +16,19 @@ function renderTemplate(pluginsData) {
jstProcess(input, output);
}
+// Keeps track of whether details have been made visible (expanded) or not.
+var tmiModeExpanded = false;
+
/**
- * Asks the C++ PluginsDOMHandler to get details about the installed plugins and
- * return detailed data about the configuration. The PluginsDOMHandler should
- * reply to returnPluginsData() (below).
+ * @param {boolean} showDetails
*/
-function requestPluginsData() {
- chrome.send('requestPluginsData');
- chrome.send('getShowDetails');
-}
-
-function loadShowDetailsFromPrefs(show_details) {
- tmiModeExpanded = show_details;
- $('collapse').style.display =
- show_details ? 'inline' : 'none';
- $('expand').style.display =
- show_details ? 'none' : 'inline';
-
- document.body.className = show_details ? 'show-in-tmi-mode' : 'hide-tmi-mode';
+function loadShowDetailsFromPrefs(showDetails) {
+ tmiModeExpanded = showDetails;
+ // TODO(dpapad): Use setAttribute()/removeAttribute() with 'hidden' instead of
+ // style.display.
+ $('collapse').style.display = showDetails ? 'inline' : 'none';
+ $('expand').style.display = showDetails ? 'none' : 'inline';
+ document.body.className = showDetails ? 'show-in-tmi-mode' : 'hide-tmi-mode';
}
/**
@@ -50,63 +45,48 @@ function loadShowDetailsFromPrefs(show_details) {
* version: 'version',
* update_url: 'http://update/',
* critical: true,
- * enabled: true,
- * identifier: 'plugin-name',
+ * enabled_mode: 'enabledByUser',
+ * id: 'plugin-name',
+ * always_allowed: false,
* plugin_files: [
* {
- * path: '/blahblah/blahblah/MyCrappyPlugin.plugin',
- * name: 'MyCrappyPlugin',
- * version: '1.2.3',
- * description: 'My crappy plugin',
- * mimeTypes: [
- * { description: 'Foo Media',
- * fileExtensions: ['foo'],
- * mimeType: 'application/x-my-foo' },
- * { description: 'Bar Stuff',
- * fileExtensions: ['bar', 'baz'],
- * mimeType: 'application/my-bar' }
+ * path: '/foo/bar/baz/MyPlugin.plugin',
+ * name: 'MyPlugin',
+ * version: '1.2,3'
+ * description: 'My plugin',
+ * type: 'BROWSER PLUGIN',
+ * mime_types: [
+ * {
+ * description: 'Foo Media',
+ * file_extensions: ['pdf'],
+ * mime_type: 'application/x-my-foo'
+ * },
+ * {
+ * description: 'Bar Stuff',
+ * file_extensions: ['bar', 'baz'],
+ * mime_type: 'application/my-bar'
+ * }
* ],
- * enabledMode: 'enabledByUser'
+ * enabled_mode: 'enabledByUser',
* },
* {
* path: '/tmp/MyFirst.plugin',
* name: 'MyFirstPlugin',
* version: '3.14r15926',
* description: 'My first plugin',
- * mimeTypes: [
- * { description: 'New Guy Media',
- * fileExtensions: ['mfp'],
- * mimeType: 'application/x-my-first' }
- * ],
- * enabledMode: 'enabledByPolicy'
- * },
- * {
- * path: '/foobar/baz/YourGreatPlugin.plugin',
- * name: 'YourGreatPlugin',
- * version: '4.5',
- * description: 'Your great plugin',
- * mimeTypes: [
- * { description: 'Baz Stuff',
- * fileExtensions: ['baz'],
- * mimeType: 'application/x-your-baz' }
+ * type: 'BROWSER PLUGIN',
+ * mime_types: [
+ * {
+ * description: 'New Guy Media',
+ * file_extensions: ['mfp'],
+ * mime_type: 'application/x-my-first'
+ * },
* ],
- * enabledMode: 'disabledByUser'
+ * enabled_mode: 'disabledByUser',
* },
- * {
- * path: '/foobiz/bar/HisGreatPlugin.plugin',
- * name: 'HisGreatPlugin',
- * version: '1.2',
- * description: 'His great plugin',
- * mimeTypes: [
- * { description: 'More baz Stuff',
- * fileExtensions: ['bor'],
- * mimeType: 'application/x-his-bor' }
- * ],
- * enabledMode: 'disabledByPolicy'
- * }
- * ]
- * }
- * ]
+ * ],
+ * },
+ * ],
* }
*/
function returnPluginsData(pluginsData) {
@@ -200,14 +180,12 @@ function returnPluginsData(pluginsData) {
* rather than a single plugin.
*/
function handleEnablePlugin(node, enable, isGroup) {
- // Tell the C++ PluginsDOMHandler to enable/disable the plugin.
- chrome.send('enablePlugin', [String(node.path), String(enable),
- String(isGroup)]);
+ if (isGroup)
+ browserProxy.setPluginGroupEnabled(node.path, enable);
+ else
+ browserProxy.setPluginEnabled(node.path, enable);
}
-// Keeps track of whether details have been made visible (expanded) or not.
-var tmiModeExpanded = false;
-
/*
* Toggles visibility of details.
*/
@@ -222,11 +200,11 @@ function toggleTmiMode() {
document.body.className =
tmiModeExpanded ? 'show-tmi-mode' : 'hide-tmi-mode';
- chrome.send('saveShowDetailsToPrefs', [String(tmiModeExpanded)]);
+ browserProxy.saveShowDetailsToPrefs(tmiModeExpanded);
}
function handleSetPluginAlwaysAllowed(el) {
- chrome.send('setPluginAlwaysAllowed', [el.identifier, el.checked]);
+ browserProxy.setPluginAlwaysAllowed(el.identifier, el.checked);
}
/**
@@ -259,18 +237,108 @@ function shouldDisplayPluginDescription(plugin) {
* @return {boolean} Whether the plugin is enabled.
*/
function isPluginEnabled(plugin) {
- return plugin.enabledMode == 'enabledByUser' ||
- plugin.enabledMode == 'enabledByPolicy';
+ return plugin.enabled_mode == 'enabledByUser' ||
+ plugin.enabled_mode == 'enabledByPolicy';
}
-// Unfortunately, we don't have notifications for plugin (list) status changes
-// (yet), so in the meanwhile just update regularly.
-setInterval(requestPluginsData, 30000);
+/**
+ * @param {Object} plugin An object containing the information about a plugin.
+ * See returnPluginsData() for the format of this object.
+ * @return {boolean} Whether the plugin is fully trusted.
+ */
+function isPluginTrusted(plugin) {
+ return plugin.trusted == 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 reference to the stub here such that it is not garbage
+// collected, which causes the pipe to close and future calls from C++ to JS to
+// get dropped.
+var pluginsPageStub = null;
+
+var browserProxy = null;
+// Exposed globally such that the tests can make direct calls on it.
+var pageProxy = null;
+
+function initializeProxies() {
+ return importModules([
+ 'mojo/public/js/bindings',
+ 'mojo/public/js/core',
+ 'mojo/public/js/connection',
+ 'chrome/browser/ui/webui/plugins/plugins.mojom',
+ 'content/public/renderer/frame_service_registry',
+ ]).then(function(modules) {
+ var bindings = modules[0];
+ var core = modules[1];
+ var connection = modules[2];
+ var pluginsMojom = modules[3];
+ var serviceProvider = modules[4];
+
+ browserProxy = connection.bindHandleToProxy(
+ serviceProvider.connectToService(
+ pluginsMojom.PluginsHandlerMojo.name),
+ pluginsMojom.PluginsHandlerMojo);
+
+ // Connect pipe handle to JS code.
+ var pipe = core.createMessagePipe();
+ pluginsPageStub = connection.bindHandleToStub(
+ pipe.handle0, pluginsMojom.PluginsPageMojo);
-// Get data and have it displayed upon loading.
-document.addEventListener('DOMContentLoaded', requestPluginsData);
+ pageProxy = {
+ __proto__: pluginsMojom.PluginsPageMojo.stubClass.prototype,
+ onPluginsUpdated: function(plugins) {
+ returnPluginsData({plugins: plugins});
+ },
+ };
+
+ bindings.StubBindings(pluginsPageStub).delegate = pageProxy;
+ // Send pipe handle to C++.
+ browserProxy.setClientPage(pipe.handle1);
+ });
+}
+
+/**
+ * Overriden by tests to give them a chance to setup a fake Mojo browser proxy
+ * before any other code executes.
+ * @return {!Promise} A promise firing once necessary setup has been completed.
+ */
+var setupFn = setupFn || function() { return Promise.resolve(); };
+
+function main() {
+ setupFn().then(function() {
+ // Add handlers to static HTML elements.
+ $('collapse').onclick = toggleTmiMode;
+ $('expand').onclick = toggleTmiMode;
+ $('details-link').onclick = toggleTmiMode;
+ return initializeProxies();
+ }).then(function() {
+ return browserProxy.getShowDetails();
+ }).then(function(response) {
+ // Set the |tmiModeExpanded| first otherwise the UI flickers when
+ // returnPlignsData executes.
+ loadShowDetailsFromPrefs(response.show_details);
+ return browserProxy.getPluginsData();
+ }).then(function(pluginsData) {
+ returnPluginsData(pluginsData);
+
+ // Unfortunately, we don't have notifications for plugin (list) status
+ // changes (yet), so in the meanwhile just update regularly.
+ setInterval(function() {
+ browserProxy.getPluginsData().then(returnPluginsData);
+ }, 30000);
+ });
+}
-// Add handlers to static HTML elements.
-$('collapse').onclick = toggleTmiMode;
-$('expand').onclick = toggleTmiMode;
-$('details-link').onclick = toggleTmiMode;
+document.addEventListener('DOMContentLoaded', main);
diff --git a/chromium/chrome/browser/resources/popular_sites_internals.css b/chromium/chrome/browser/resources/popular_sites_internals.css
index 1e509657e4d..ee4c1d4225e 100644
--- a/chromium/chrome/browser/resources/popular_sites_internals.css
+++ b/chromium/chrome/browser/resources/popular_sites_internals.css
@@ -43,3 +43,6 @@ html {
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
index e287b84da61..97b3a311fea 100644
--- a/chromium/chrome/browser/resources/popular_sites_internals.html
+++ b/chromium/chrome/browser/resources/popular_sites_internals.html
@@ -48,13 +48,33 @@ found in the LICENSE file.
</table>
</div>
- <div id="sites" class="section">
+ <div class="section">
+ <h2>Info</h2>
+ <table class="section-details">
+ <tr>
+ <td class="detail">Country</td>
+ <td class="value" jscontent="country"></td>
+ </tr>
+ <tr>
+ <td class="detail">Version</td>
+ <td class="value" jscontent="version"></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>
diff --git a/chromium/chrome/browser/resources/popular_sites_internals.js b/chromium/chrome/browser/resources/popular_sites_internals.js
index d68e8f9b14c..96f470d1302 100644
--- a/chromium/chrome/browser/resources/popular_sites_internals.js
+++ b/chromium/chrome/browser/resources/popular_sites_internals.js
@@ -16,6 +16,14 @@ cr.define('chrome.popular_sites_internals', function() {
$('submit-download').addEventListener('click', submitDownload);
+ function viewJson(event) {
+ $('json-value').textContent = '';
+ chrome.send('viewJson');
+ event.preventDefault();
+ }
+
+ $('view-json').addEventListener('click', viewJson);
+
chrome.send('registerForEvents');
}
@@ -24,7 +32,13 @@ cr.define('chrome.popular_sites_internals', function() {
}
function receiveSites(sites) {
- jstProcess(new JsEvalContext(sites), $('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.
@@ -32,6 +46,7 @@ cr.define('chrome.popular_sites_internals', function() {
initialize: initialize,
receiveDownloadResult: receiveDownloadResult,
receiveSites: receiveSites,
+ receiveJson: receiveJson,
};
});
diff --git a/chromium/chrome/browser/resources/print_preview/compiled_resources.gyp b/chromium/chrome/browser/resources/print_preview/compiled_resources.gyp
index f54c04cdf02..2f0576586b0 100644
--- a/chromium/chrome/browser/resources/print_preview/compiled_resources.gyp
+++ b/chromium/chrome/browser/resources/print_preview/compiled_resources.gyp
@@ -14,6 +14,7 @@
'../../../../ui/webui/resources/js/cr/ui/focus_outline_manager.js',
'../../../../ui/webui/resources/js/event_tracker.js',
'../../../../ui/webui/resources/js/load_time_data.js',
+ '../../../../ui/webui/resources/js/promise_resolver.js',
'../../../../ui/webui/resources/js/util.js',
],
'externs': ['<(EXTERNS_DIR)/chrome_send.js'],
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 86465a5a46c..ef00b686462 100644
--- a/chromium/chrome/browser/resources/print_preview/data/destination_store.js
+++ b/chromium/chrome/browser/resources/print_preview/data/destination_store.js
@@ -341,10 +341,14 @@ cr.define('print_preview', function() {
var mediaSize = capabilities.printer.media_size;
if (mediaSize) {
var mediaDisplayNames = {
- 'ISO_A4': 'A4',
+ 'ISO_A0': 'A0',
+ 'ISO_A1': 'A1',
+ 'ISO_A2': 'A2',
'ISO_A3': 'A3',
- 'NA_LETTER': 'Letter',
+ '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++) {
diff --git a/chromium/chrome/browser/resources/print_preview/data/ticket_items/page_range.js b/chromium/chrome/browser/resources/print_preview/data/ticket_items/page_range.js
index bbb3f8229a2..db20e71f1f7 100644
--- a/chromium/chrome/browser/resources/print_preview/data/ticket_items/page_range.js
+++ b/chromium/chrome/browser/resources/print_preview/data/ticket_items/page_range.js
@@ -35,8 +35,9 @@ cr.define('print_preview.ticket_items', function() {
/** @override */
wouldValueBeValid: function(value) {
- return null != pageRangeTextToPageRanges(
+ var result = pageRangeTextToPageRanges(
value, this.getDocumentInfoInternal().pageCount);
+ return result instanceof Array;
},
/**
@@ -69,7 +70,8 @@ cr.define('print_preview.ticket_items', function() {
* ranges.
*/
getPageRanges: function() {
- return pageRangeTextToPageRanges(this.getValue()) || [];
+ var pageRanges = pageRangeTextToPageRanges(this.getValue());
+ return pageRanges instanceof Array ? pageRanges : [];
},
/**
@@ -81,7 +83,24 @@ cr.define('print_preview.ticket_items', function() {
getDocumentPageRanges: function() {
var pageRanges = pageRangeTextToPageRanges(
this.getValue(), this.getDocumentInfoInternal().pageCount);
- return pageRanges || [];
+ return pageRanges instanceof Array ? pageRanges : [];
+ },
+
+ /**
+ * @return {!number} Number of pages reported by the document.
+ */
+ getDocumentNumPages: function() {
+ return this.getDocumentInfoInternal().pageCount;
+ },
+
+ /**
+ * @return {!PageRangeStatus}
+ */
+ checkValidity: function() {
+ var pageRanges = pageRangeTextToPageRanges(
+ this.getValue(), this.getDocumentInfoInternal().pageCount);
+ return pageRanges instanceof Array ?
+ PageRangeStatus.NO_ERROR : pageRanges;
},
};
diff --git a/chromium/chrome/browser/resources/print_preview/native_layer.js b/chromium/chrome/browser/resources/print_preview/native_layer.js
index 7bda60e6c3b..2cf0eaf6ea1 100644
--- a/chromium/chrome/browser/resources/print_preview/native_layer.js
+++ b/chromium/chrome/browser/resources/print_preview/native_layer.js
@@ -481,7 +481,6 @@ cr.define('print_preview', function() {
var nativeInitialSettings = new print_preview.NativeInitialSettings(
initialSettings['printAutomaticallyInKioskMode'] || false,
initialSettings['appKioskMode'] || false,
- initialSettings['hidePrintWithSystemDialogLink'] || false,
numberFormatSymbols[0] || ',',
numberFormatSymbols[1] || '.',
unitType,
@@ -938,7 +937,6 @@ cr.define('print_preview', function() {
function NativeInitialSettings(
isInKioskAutoPrintMode,
isInAppKioskMode,
- hidePrintWithSystemDialogLink,
thousandsDelimeter,
decimalDelimeter,
unitType,
@@ -965,13 +963,6 @@ cr.define('print_preview', function() {
this.isInAppKioskMode_ = isInAppKioskMode;
/**
- * Whether we should hide the link which shows the system print dialog.
- * @type {boolean}
- * @private
- */
- this.hidePrintWithSystemDialogLink_ = hidePrintWithSystemDialogLink;
-
- /**
* Character delimeter of thousands digits.
* @type {string}
* @private
@@ -1059,14 +1050,6 @@ cr.define('print_preview', function() {
return this.isInAppKioskMode_;
},
- /**
- * @return {boolean} Whether we should hide the link which shows the
- system print dialog.
- */
- get hidePrintWithSystemDialogLink() {
- return this.hidePrintWithSystemDialogLink_;
- },
-
/** @return {string} Character delimeter of thousands digits. */
get thousandsDelimeter() {
return this.thousandsDelimeter_;
diff --git a/chromium/chrome/browser/resources/print_preview/previewarea/margin_control.js b/chromium/chrome/browser/resources/print_preview/previewarea/margin_control.js
index 7ec2527e7a1..061a989d311 100644
--- a/chromium/chrome/browser/resources/print_preview/previewarea/margin_control.js
+++ b/chromium/chrome/browser/resources/print_preview/previewarea/margin_control.js
@@ -349,6 +349,17 @@ cr.define('print_preview', function() {
*/
setIsFocused_: function(isFocused) {
this.isFocused_ = isFocused;
+ // TODO(tkent): This is a workaround of a preview-area scrolling
+ // issue. Blink scrolls preview-area on focus, but we don't want it. We
+ // should adjust scroll position of PDF preview and positions of
+ // MarginContgrols here, or restructure the HTML so that the PDF review
+ // and MarginControls are on the single scrollable container.
+ // crbug.com/601341
+ if (isFocused) {
+ var previewArea = $('preview-area');
+ previewArea.scrollTop = 0;
+ previewArea.scrollLeft = 0;
+ }
},
/**
@@ -378,8 +389,9 @@ cr.define('print_preview', function() {
if (event.propertyName != 'opacity')
return;
var elStyle = window.getComputedStyle(this.getElement());
- var opacity = parseInt(elStyle.getPropertyValue('opacity'), 10);
- this.textbox_.setAttribute('aria-hidden', opacity == 0);
+ var disabled = parseInt(elStyle.getPropertyValue('opacity'), 10) == 0;
+ this.textbox_.setAttribute('aria-hidden', disabled);
+ this.textbox_.disabled = disabled;
},
/**
diff --git a/chromium/chrome/browser/resources/print_preview/print_preview.html b/chromium/chrome/browser/resources/print_preview/print_preview.html
index bbcb5a1544a..6294da754f0 100644
--- a/chromium/chrome/browser/resources/print_preview/print_preview.html
+++ b/chromium/chrome/browser/resources/print_preview/print_preview.html
@@ -39,6 +39,7 @@
<link rel="stylesheet" href="search/provisional_destination_resolver.css">
<script src="chrome://resources/js/action_link.js"></script>
+ <script src="chrome://resources/js/promise_resolver.js"></script>
<script src="chrome://resources/js/cr.js"></script>
<script src="chrome://resources/js/cr/event_target.js"></script>
<script src="chrome://resources/js/cr/ui.js"></script>
diff --git a/chromium/chrome/browser/resources/print_preview/print_preview.js b/chromium/chrome/browser/resources/print_preview/print_preview.js
index f4936f39202..56899206b39 100644
--- a/chromium/chrome/browser/resources/print_preview/print_preview.js
+++ b/chromium/chrome/browser/resources/print_preview/print_preview.js
@@ -651,8 +651,7 @@ cr.define('print_preview', function() {
this.appState_.setInitialized();
$('document-title').innerText = settings.documentTitle;
- this.hideSystemDialogLink_ = settings.hidePrintWithSystemDialogLink ||
- settings.isInAppKioskMode;
+ this.hideSystemDialogLink_ = settings.isInAppKioskMode;
if ($('system-dialog-link')) {
setIsVisible($('system-dialog-link'),
this.shouldShowSystemDialogLink_());
@@ -887,8 +886,8 @@ cr.define('print_preview', function() {
return;
}
- // On Mac, Cmd- should close the print dialog.
- if (cr.isMac && e.keyCode == 189 && e.metaKey) {
+ // On Mac, Cmd-. should close the print dialog.
+ if (cr.isMac && e.keyCode == 190 && e.metaKey) {
this.close_();
e.preventDefault();
return;
diff --git a/chromium/chrome/browser/resources/print_preview/print_preview_utils.js b/chromium/chrome/browser/resources/print_preview/print_preview_utils.js
index 49a367b51b5..2ab83dc1499 100644
--- a/chromium/chrome/browser/resources/print_preview/print_preview_utils.js
+++ b/chromium/chrome/browser/resources/print_preview/print_preview_utils.js
@@ -72,16 +72,25 @@ function removeDuplicates(inArray) {
return out;
}
+/** @enum {number} */
+var PageRangeStatus = {
+ NO_ERROR: 0,
+ SYNTAX_ERROR: -1,
+ LIMIT_ERROR: -2
+};
+
/**
* Returns a list of ranges in |pageRangeText|. The ranges are
* listed in the order they appear in |pageRangeText| and duplicates are not
- * eliminated. If |pageRangeText| is not valid null is returned.
+ * eliminated. If |pageRangeText| is not valid, PageRangeStatus.SYNTAX_ERROR
+ * is returned.
* A valid selection has a parsable format and every page identifier is
- * greater the 0 and less or equal to |totalPageCount| unless wildcards are
- * used(see examples).
+ * greater than 0 unless wildcards are used(see examples).
+ * If a page is greater than |totalPageCount|, PageRangeStatus.LIMIT_ERROR
+ * is returned.
* If |totalPageCount| is 0 or undefined function uses impossibly large number
* instead.
- * Wildcard the first number must be larger then 0 and less or equal then
+ * Wildcard the first number must be larger than 0 and less or equal then
* |totalPageCount|. If it's missed then 1 is used as the first number.
* Wildcard the second number must be larger then the first number. If it's
* missed then |totalPageCount| is used as the second number.
@@ -94,7 +103,7 @@ function removeDuplicates(inArray) {
* Example: "1-4dsf, 11" is invalid regardless of |totalPageCount|.
* @param {string} pageRangeText The text to be checked.
* @param {number=} opt_totalPageCount The total number of pages.
- * @return {Array<{from: number, to: number}>} An array of page range objects.
+ * @return {!PageRangeStatus|!Array<{from: number, to: number}>}
*/
function pageRangeTextToPageRanges(pageRangeText, opt_totalPageCount) {
if (pageRangeText == '') {
@@ -113,20 +122,22 @@ function pageRangeTextToPageRanges(pageRangeText, opt_totalPageCount) {
var match = parts[i].match(regex);
if (match) {
if (!isPositiveInteger(match[1]) && match[1] !== '')
- return null;
+ return PageRangeStatus.SYNTAX_ERROR;
if (!isPositiveInteger(match[2]) && match[2] !== '')
- return null;
+ return PageRangeStatus.SYNTAX_ERROR;
var from = match[1] ? parseInt(match[1], 10) : 1;
var to = match[2] ? parseInt(match[2], 10) : totalPageCount;
- if (from > to || from > totalPageCount)
- return null;
+ if (from > to)
+ return PageRangeStatus.SYNTAX_ERROR;
+ if (to > totalPageCount)
+ return PageRangeStatus.LIMIT_ERROR;
pageRanges.push({'from': from, 'to': to});
} else {
if (!isPositiveInteger(parts[i]))
- return null;
+ return PageRangeStatus.SYNTAX_ERROR;
var singlePageNumber = parseInt(parts[i], 10);
if (singlePageNumber > totalPageCount)
- return null;
+ return PageRangeStatus.LIMIT_ERROR;
pageRanges.push({'from': singlePageNumber, 'to': singlePageNumber});
}
}
@@ -146,7 +157,7 @@ function pageRangeTextToPageRanges(pageRangeText, opt_totalPageCount) {
function pageRangeTextToPageList(pageRangeText, totalPageCount) {
var pageRanges = pageRangeTextToPageRanges(pageRangeText, totalPageCount);
var pageList = [];
- if (pageRanges) {
+ if (pageRanges instanceof Array) {
for (var i = 0; i < pageRanges.length; ++i) {
for (var j = pageRanges[i].from; j <= Math.min(pageRanges[i].to,
totalPageCount); ++j) {
diff --git a/chromium/chrome/browser/resources/print_preview/print_preview_utils_unittest.gtestjs b/chromium/chrome/browser/resources/print_preview/print_preview_utils_unittest.gtestjs
index de50bcbc6f2..ff15d6fa61e 100644
--- a/chromium/chrome/browser/resources/print_preview/print_preview_utils_unittest.gtestjs
+++ b/chromium/chrome/browser/resources/print_preview/print_preview_utils_unittest.gtestjs
@@ -77,7 +77,7 @@ TEST_F('PrintPreviewUtilsUnitTest', 'PageRanges', function() {
assertRangesEqual([[10, 100]],
pageRangeTextToPageRanges("10-", 100));
assertRangesEqual([[10, 100000]],
- pageRangeTextToPageRanges("10-100000", 100));
+ pageRangeTextToPageRanges("10-100000", 100000));
assertRangesEqual([[1, 100]],
pageRangeTextToPageRanges("-", 100));
assertRangesEqual([1, 2],
@@ -89,11 +89,18 @@ TEST_F('PrintPreviewUtilsUnitTest', 'PageRanges', function() {
});
TEST_F('PrintPreviewUtilsUnitTest', 'InvalidPageRanges', function() {
- assertTrue(pageRangeTextToPageRanges("1,100000", 100) == null);
- assertTrue(pageRangeTextToPageRanges("1,2,0,56", 100) == null);
- assertTrue(pageRangeTextToPageRanges("-1,1,2,,56", 100) == null);
- assertTrue(pageRangeTextToPageRanges("1,2,56-40", 100) == null);
- assertTrue(pageRangeTextToPageRanges("101-110", 100) == null);
+ assertEquals(PageRangeStatus.LIMIT_ERROR,
+ pageRangeTextToPageRanges("10-100000", 100));
+ assertEquals(PageRangeStatus.LIMIT_ERROR,
+ pageRangeTextToPageRanges("1,100000", 100));
+ assertEquals(PageRangeStatus.SYNTAX_ERROR,
+ pageRangeTextToPageRanges("1,2,0,56", 100));
+ assertEquals(PageRangeStatus.SYNTAX_ERROR,
+ pageRangeTextToPageRanges("-1,1,2,,56", 100));
+ assertEquals(PageRangeStatus.SYNTAX_ERROR,
+ pageRangeTextToPageRanges("1,2,56-40", 100));
+ assertEquals(PageRangeStatus.LIMIT_ERROR,
+ pageRangeTextToPageRanges("101-110", 100));
});
TEST_F('PrintPreviewUtilsUnitTest', 'PageRangeTextToPageList', function() {
diff --git a/chromium/chrome/browser/resources/print_preview/search/provisional_destination_resolver.js b/chromium/chrome/browser/resources/print_preview/search/provisional_destination_resolver.js
index a78732f0ee8..b16e474efd9 100644
--- a/chromium/chrome/browser/resources/print_preview/search/provisional_destination_resolver.js
+++ b/chromium/chrome/browser/resources/print_preview/search/provisional_destination_resolver.js
@@ -15,41 +15,6 @@ cr.define('print_preview', function() {
};
/**
- * Utility class for bundling a promise object with it's resolver methods.
- * @param {!Promise<!print_preview.Destination>} promise A promise returning
- * a destination.
- * @param {function(!print_preview.Destination)} resolve Function resolving
- * the promise.
- * @param {function()} reject Function for rejecting the promise.
- * @constructor @struct
- */
- function PromiseResolver(promise, resolve, reject) {
- /** @type {!Promise<!print_preview.Destination>} */
- this.promise = promise;
- /** @type {function(!print_preview.Destination)} */
- this.resolve = resolve;
- /** @type {function()} */
- this.reject = reject;
- }
-
- /**
- * Create a Promise and an associated PromiseResolver.
- * @return {!PromiseResolver}
- */
- PromiseResolver.create = function() {
- var reject = null;
- var resolve = null;
- /** @type {!Promise<!print_preview.Destination>} */
- var promise = new Promise(function(resolvePromise, rejectPromise) {
- resolve = /** @type {function(!print_preview.Destination)}*/(
- resolvePromise);
- reject = /** @type {function()} */(rejectPromise);
- });
-
- return new PromiseResolver(promise, resolve, reject);
- };
-
- /**
* Overlay used to resolve a provisional extension destination. The user is
* prompted to allow print preview to grant a USB device access to an
* extension associated with the destination. If user agrees destination
@@ -78,7 +43,7 @@ cr.define('print_preview', function() {
/**
* Promise resolver for promise returned by {@code this.run}.
- * @private {?PromiseResolver}
+ * @private {?PromiseResolver<!print_preview.Destination>}
*/
this.promiseResolver_ = null;
}
@@ -126,7 +91,7 @@ cr.define('print_preview', function() {
'Showing overlay while not in initial state.');
assert(!this.promiseResolver_, 'Promise resolver already set.');
this.setState_(ResolverState.ACTIVE);
- this.promiseResolver_ = PromiseResolver.create();
+ this.promiseResolver_ = new PromiseResolver();
this.getChildElement('.default').focus();
} else if (this.state_ != ResolverState.DONE) {
assert(this.state_ != ResolverState.INITIAL, 'Hiding in initial state');
diff --git a/chromium/chrome/browser/resources/print_preview/settings/page_settings.js b/chromium/chrome/browser/resources/print_preview/settings/page_settings.js
index f86c02dd5a1..ef1cf1794a0 100644
--- a/chromium/chrome/browser/resources/print_preview/settings/page_settings.js
+++ b/chromium/chrome/browser/resources/print_preview/settings/page_settings.js
@@ -112,7 +112,7 @@ cr.define('print_preview', function() {
this.tracker.add(
this.customInput_, 'keydown', this.onCustomInputKeyDown_.bind(this));
this.tracker.add(
- this.customInput_, 'keyup', this.onCustomInputKeyUp_.bind(this));
+ this.customInput_, 'input', this.onCustomInputChange_.bind(this));
this.tracker.add(
this.pageRangeTicketItem_,
print_preview.ticket_items.TicketItem.EventType.CHANGE,
@@ -138,17 +138,30 @@ cr.define('print_preview', function() {
PageSettings.Classes_.CUSTOM_RADIO)[0];
this.customHintEl_ = this.getElement().getElementsByClassName(
PageSettings.Classes_.CUSTOM_HINT)[0];
- this.customHintEl_.textContent = loadTimeData.getStringF(
- 'pageRangeInstruction',
- loadTimeData.getString('examplePageRangeText'));
},
/**
- * @param {boolean} isVisible Whether the custom hint is visible.
+ * @param {!PageRangeStatus} validity (of page range)
* @private
*/
- setInvalidStateVisible_: function(isVisible) {
- if (isVisible) {
+ setInvalidStateVisible_: function(validity) {
+ if (validity !== PageRangeStatus.NO_ERROR) {
+ var message;
+ if (validity === PageRangeStatus.LIMIT_ERROR) {
+ if (this.pageRangeTicketItem_.getDocumentNumPages()) {
+ message = loadTimeData.getStringF(
+ 'pageRangeLimitInstructionWithValue',
+ this.pageRangeTicketItem_.getDocumentNumPages());
+ } else {
+ message = loadTimeData.getString(
+ 'pageRangeLimitInstruction');
+ }
+ } else {
+ message = loadTimeData.getStringF(
+ 'pageRangeSyntaxInstruction',
+ loadTimeData.getString('examplePageRangeText'));
+ }
+ this.customHintEl_.textContent = message;
this.customInput_.classList.add('invalid');
fadeInElement(this.customHintEl_);
} else {
@@ -210,24 +223,6 @@ cr.define('print_preview', function() {
},
/**
- * Called when a key is pressed on the custom input.
- * @param {Event} event Contains the key that was pressed.
- * @private
- */
- onCustomInputKeyUp_: function(event) {
- if (this.customInputTimeout_) {
- clearTimeout(this.customInputTimeout_);
- this.customInputTimeout_ = null;
- }
- if (event.keyCode != 13 /*enter*/) {
- this.customRadio_.checked = true;
- this.customInputTimeout_ = setTimeout(
- this.onCustomInputTimeout_.bind(this),
- PageSettings.CUSTOM_INPUT_DELAY_);
- }
- },
-
- /**
* Called after a delay following a key press in the custom input.
* @private
*/
@@ -239,6 +234,20 @@ cr.define('print_preview', function() {
},
/**
+ * Called for events that change the text - undo, redo, paste and
+ * keystrokes outside of enter, copy, etc. (Re)starts the
+ * re-evaluation timer.
+ * @private
+ */
+ onCustomInputChange_: function() {
+ if (this.customInputTimeout_)
+ clearTimeout(this.customInputTimeout_);
+ this.customInputTimeout_ = setTimeout(
+ this.onCustomInputTimeout_.bind(this),
+ PageSettings.CUSTOM_INPUT_DELAY_);
+ },
+
+ /**
* Called when the print ticket changes. Updates the state of the component.
* @private
*/
@@ -251,10 +260,11 @@ cr.define('print_preview', function() {
this.customInput_.value = pageRangeStr;
}
this.customRadio_.checked = true;
- this.setInvalidStateVisible_(!this.pageRangeTicketItem_.isValid());
+ this.setInvalidStateVisible_(
+ this.pageRangeTicketItem_.checkValidity());
} else {
this.allRadio_.checked = true;
- this.setInvalidStateVisible_(false);
+ this.setInvalidStateVisible_(PageRangeStatus.NO_ERROR);
}
}
this.updateUiStateInternal();
diff --git a/chromium/chrome/browser/resources/settings/OWNERS b/chromium/chrome/browser/resources/settings/OWNERS
index 4391dc29a94..300b7b91997 100644
--- a/chromium/chrome/browser/resources/settings/OWNERS
+++ b/chromium/chrome/browser/resources/settings/OWNERS
@@ -1,3 +1,5 @@
+dbeam@chromium.org
+dpapad@chromium.org
dschuyler@chromium.org
michaelpg@chromium.org
stevenjb@chromium.org
diff --git a/chromium/chrome/browser/resources/settings/a11y_page/a11y_page.css b/chromium/chrome/browser/resources/settings/a11y_page/a11y_page.css
deleted file mode 100644
index 65537ee02ff..00000000000
--- a/chromium/chrome/browser/resources/settings/a11y_page/a11y_page.css
+++ /dev/null
@@ -1,20 +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. */
-
-.autoclick-delay-label {
- -webkit-margin-end: 0;
- -webkit-margin-start: 40px;
- align-items: center;
- display: flex;
- margin-bottom: 10px;
- margin-top: 0;
-}
-
-#autoclickDropdown {
- -webkit-margin-start: 10px;
-}
-
-.more-a11y-link {
- margin-bottom: 10px;
-}
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 a92d55309dd..25ae86f239f 100644
--- a/chromium/chrome/browser/resources/settings/a11y_page/a11y_page.html
+++ b/chromium/chrome/browser/resources/settings/a11y_page/a11y_page.html
@@ -1,18 +1,21 @@
-<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
+<link rel="import" href="chrome://resources/html/polymer.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html">
+<if expr="chromeos">
<link rel="import" href="chrome://md-settings/controls/settings_checkbox.html">
+</if>
+<link rel="import" href="chrome://md-settings/settings_shared_css.html">
<dom-module id="settings-a11y-page">
- <link rel="import" type="css" href="chrome://md-settings/settings_shared.css">
- <link rel="import" type="css" href="a11y_page.css">
<template>
- <div class="settings-box">
+ <style include="settings-shared"></style>
+<if expr="chromeos">
+ <div class="settings-box row first">
<span i18n-content="a11yExplanation"></span>
<a i18n-values="href:a11yLearnMoreUrl" i18n-content="learnMore"
target="_blank"></a>
</div>
- <div class="settings-box">
+ <div class="settings-box block">
<settings-checkbox i18n-values="label:optionsInMenuLabel"
pref="{{prefs.settings.a11y.enable_menu}}">
</settings-checkbox>
@@ -39,11 +42,9 @@
pref="{{prefs.settings.a11y.autoclick}}">
</settings-checkbox>
- <div class="autoclick-delay-label"
- hidden$="[[!prefs.settings.a11y.autoclick]]">
- <span i18n-content="delayBeforeClickLabel"></span>
- <select id="autoclickDropdown"
- value="{{prefs.settings.a11y.autoclick_delay_ms::change}}">
+ <div class="list-item settings-checkbox-spacer">
+ <div i18n-content="delayBeforeClickLabel"></div>
+ <select value="{{prefs.settings.a11y.autoclick_delay_ms::change}}">
<option value="200" i18n-content="delayBeforeClickExtremelyShort">
</option>
<option value="400" i18n-content="delayBeforeClickVeryShort">
@@ -60,11 +61,34 @@
<settings-checkbox pref="{{prefs.settings.a11y.virtual_keyboard}}"
i18n-values="label:onScreenKeyboardLabel">
</settings-checkbox>
+ <template is="dom-if" if="[[showExperimentalFeatures_]]">
+ <settings-checkbox pref="{{prefs.settings.a11y.caret_highlight}}"
+ i18n-values="label:caretHighlightLabel">
+ </settings-checkbox>
+ <settings-checkbox pref="{{prefs.settings.a11y.cursor_highlight}}"
+ i18n-values="label:cursorHighlightLabel">
+ </settings-checkbox>
+ <settings-checkbox pref="{{prefs.settings.a11y.focus_highlight}}"
+ i18n-values="label:focusHighlightLabel">
+ </settings-checkbox>
+ <settings-checkbox pref="{{prefs.settings.a11y.select_to_speak}}"
+ i18n-values="label:selectToSpeakLabel">
+ </settings-checkbox>
+ <settings-checkbox pref="{{prefs.settings.a11y.switch_access}}"
+ i18n-values="label:switchAccessLabel">
+ </settings-checkbox>
+ </template>
</div>
+</if>
+<if expr="chromeos">
<div class="settings-box">
+</if>
+<if expr="not chromeos">
+ <div class="settings-box first">
+</if>
<div class="button-strip">
- <paper-button i18n-content="moreFeaturesLink"
+ <paper-button i18n-content="moreFeaturesLink" class="primary-button"
on-tap="onMoreFeaturesTap_"></paper-button>
</div>
</div>
diff --git a/chromium/chrome/browser/resources/settings/a11y_page/a11y_page.js b/chromium/chrome/browser/resources/settings/a11y_page/a11y_page.js
index 8fb7448b949..0c56580f9e4 100644
--- a/chromium/chrome/browser/resources/settings/a11y_page/a11y_page.js
+++ b/chromium/chrome/browser/resources/settings/a11y_page/a11y_page.js
@@ -13,9 +13,6 @@
* <settings-a11y-page prefs="{{prefs}}"></settings-a11y-page>
* ... other pages ...
* </iron-animated-pages>
- *
- * @group Chrome Settings Elements
- * @element settings-a11y-page
*/
Polymer({
is: 'settings-a11y-page',
@@ -28,6 +25,19 @@ Polymer({
type: Object,
notify: true,
},
+
+<if expr="chromeos">
+ /**
+ * Whether to show experimental accessibility features.
+ * @private {boolean}
+ */
+ showExperimentalFeatures_: {
+ type: Boolean,
+ value: function() {
+ return loadTimeData.getBoolean('showExperimentalA11yFeatures');
+ },
+ }
+</if>
},
/** @private */
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 c52e016f1f2..91b063fa31b 100644
--- a/chromium/chrome/browser/resources/settings/advanced_page/advanced_page.html
+++ b/chromium/chrome/browser/resources/settings/advanced_page/advanced_page.html
@@ -1,26 +1,33 @@
-<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.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://md-settings/a11y_page/a11y_page.html">
<link rel="import" href="chrome://md-settings/downloads_page/downloads_page.html">
<link rel="import" href="chrome://md-settings/languages_page/languages_page.html">
<link rel="import" href="chrome://md-settings/passwords_and_forms_page/passwords_and_forms_page.html">
<link rel="import" href="chrome://md-settings/privacy_page/privacy_page.html">
<link rel="import" href="chrome://md-settings/reset_page/reset_page.html">
+<link rel="import" href="chrome://md-settings/settings_page/main_page_behavior.html">
<link rel="import" href="chrome://md-settings/settings_page/settings_page_visibility.html">
<link rel="import" href="chrome://md-settings/settings_page/settings_section.html">
<link rel="import" href="chrome://md-settings/site_settings/constants.html">
<link rel="import" href="chrome://md-settings/site_settings/site_settings_category.html">
<if expr="chromeos">
-<link rel="import" href="chrome://md-settings/a11y_page/a11y_page.html">
<link rel="import" href="chrome://md-settings/bluetooth_page/bluetooth_page.html">
<link rel="import" href="chrome://md-settings/date_time_page/date_time_page.html">
</if>
+<if expr="not chromeos">
+<link rel="import" href="chrome://md-settings/system_page/system_page.html">
+</if>
+
<dom-module id="settings-advanced-page">
- <link rel="import" type="css" href="advanced_page.css">
+ <link rel="import" type="css" href="chrome://md-settings/settings_page.css">
<template>
+ <style include="main-page-styles"></style>
<if expr="chromeos">
<template is="dom-if" if="[[showPage(pageVisibility.dateTime)]]" restamp>
- <settings-section i18n-values="page-title:dateTimePageTitle"
+ <settings-section page-title="[[i18n('dateTimePageTitle')]]"
current-route="[[currentRoute]]" section="dateTime">
<settings-date-time-page prefs="{{prefs}}">
</settings-date-time-page>
@@ -28,7 +35,7 @@
</template>
</if>
<template is="dom-if" if="[[showPage(pageVisibility.privacy)]]" restamp>
- <settings-section i18n-values="page-title:privacyPageTitle"
+ <settings-section page-title="[[i18n('privacyPageTitle')]]"
current-route="[[currentRoute]]" section="privacy">
<settings-privacy-page prefs="{{prefs}}"
current-route="{{currentRoute}}">
@@ -37,18 +44,17 @@
</template>
<if expr="chromeos">
<template is="dom-if" if="[[showPage(pageVisibility.bluetooth)]]" restamp>
- <settings-section i18n-values="page-title:bluetoothPageTitle"
+ <settings-section page-title="[[i18n('bluetoothPageTitle')]]"
current-route="[[currentRoute]]" section="bluetooth">
<settings-bluetooth-page current-route="{{currentRoute}}">
</settings-bluetooth-page>
</settings-section>
</template>
</if>
-
<template is="dom-if" if="[[showPage(pageVisibility.passwordsAndForms)]]"
restamp>
<settings-section
- i18n-values="page-title:passwordsAndAutofillPageTitle"
+ page-title="[[i18n('passwordsAndAutofillPageTitle')]]"
current-route="[[currentRoute]]" section="passwordsAndForms">
<settings-passwords-and-forms-page prefs="{{prefs}}"
current-route="{{currentRoute}}">
@@ -56,7 +62,7 @@
</settings-section>
</template>
<template is="dom-if" if="[[showPage(pageVisibility.languages)]]" restamp>
- <settings-section i18n-values="page-title:languagesPageTitle"
+ <settings-section page-title="[[i18n('languagesPageTitle')]]"
current-route="[[currentRoute]]" section="languages">
<settings-languages-page prefs="{{prefs}}"
current-route="{{currentRoute}}">
@@ -64,28 +70,35 @@
</settings-section>
</template>
<template is="dom-if" if="[[showPage(pageVisibility.downloads)]]" restamp>
- <settings-section i18n-values="page-title:downloadsPageTitle"
+ <settings-section page-title="[[i18n('downloadsPageTitle')]]"
current-route="[[currentRoute]]" section="downloads">
<settings-downloads-page prefs="{{prefs}}">
</settings-downloads-page>
</settings-section>
</template>
- <template is="dom-if" if="[[showPage(pageVisibility.reset)]]" restamp>
- <settings-section i18n-values="page-title:resetPageTitle"
- current-route="[[currentRoute]]" section="reset">
- <settings-reset-page></settings-reset-page>
- </settings-section>
- </template>
-<if expr="chromeos">
- <!-- TODO(dbeam): find somewhere to stuff "Add more accessibility features"
- on desktop. -->
+
+ <!-- TODO(dschuyler): Add Google Cloud Print section here. -->
+
<template is="dom-if" if="[[showPage(pageVisibility.a11y)]]" restamp>
- <settings-section i18n-values="page-title:a11yPageTitle"
+ <settings-section page-title="[[i18n('a11yPageTitle')]]"
current-route="[[currentRoute]]" section="a11y">
<settings-a11y-page prefs="{{prefs}}"></settings-a11y-page>
</settings-section>
</template>
+<if expr="not chromeos">
+ <template is="dom-if" if="[[showPage(pageVisibility.system)]]" restamp>
+ <settings-section page-title="[[i18n('systemPageTitle')]]"
+ current-route="[[currentRoute]]" section="system">
+ <settings-system-page prefs="{{prefs}}"></settings-system-page>
+ </settings-section>
+ </template>
</if>
+ <template is="dom-if" if="[[showPage(pageVisibility.reset)]]" restamp>
+ <settings-section page-title="[[i18n('resetPageTitle')]]"
+ current-route="[[currentRoute]]" section="reset">
+ <settings-reset-page></settings-reset-page>
+ </settings-section>
+ </template>
</template>
<script src="chrome://md-settings/advanced_page/advanced_page.js"></script>
</dom-module>
diff --git a/chromium/chrome/browser/resources/settings/advanced_page/advanced_page.js b/chromium/chrome/browser/resources/settings/advanced_page/advanced_page.js
index 90508838ac2..8df437730c7 100644
--- a/chromium/chrome/browser/resources/settings/advanced_page/advanced_page.js
+++ b/chromium/chrome/browser/resources/settings/advanced_page/advanced_page.js
@@ -14,13 +14,12 @@
* </settings-advanced-page>
* ... other pages ...
* </iron-animated-pages>
- *
- * @group Chrome Settings Elements
- * @element settings-advanced-page
*/
Polymer({
is: 'settings-advanced-page',
+ behaviors: [I18nBehavior, SettingsPageVisibility, RoutableBehavior],
+
properties: {
/**
* Preferences state.
@@ -39,5 +38,16 @@ Polymer({
},
},
- behaviors: [SettingsPageVisibility],
+ /**
+ * @type {string} Selector to get the sections.
+ * TODO(michaelpg): replace duplicate docs with @override once b/24294625
+ * is fixed.
+ */
+ sectionSelector: 'settings-section',
+
+ /** @override */
+ attached: function() {
+ /** @override */
+ this.scroller = this.parentElement;
+ },
});
diff --git a/chromium/chrome/browser/resources/settings/advanced_page/compiled_resources.gyp b/chromium/chrome/browser/resources/settings/advanced_page/compiled_resources.gyp
deleted file mode 100644
index abb1b725f4e..00000000000
--- a/chromium/chrome/browser/resources/settings/advanced_page/compiled_resources.gyp
+++ /dev/null
@@ -1,18 +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.
-{
- 'targets': [
- {
- 'target_name': 'advanced_page',
- 'variables': {
- 'depends': [
- '../../../../../ui/webui/resources/js/compiled_resources.gyp:cr',
- '../settings_page/compiled_resources.gyp:settings_page_visibility',
- '../site_settings/constants.js',
- ],
- },
- 'includes': ['../../../../../third_party/closure_compiler/compile_js.gypi'],
- },
- ],
-}
diff --git a/chromium/chrome/browser/resources/settings/advanced_page/compiled_resources2.gyp b/chromium/chrome/browser/resources/settings/advanced_page/compiled_resources2.gyp
new file mode 100644
index 00000000000..5a4abab9848
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/advanced_page/compiled_resources2.gyp
@@ -0,0 +1,18 @@
+# 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': 'advanced_page',
+ 'dependencies': [
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:i18n_behavior',
+ '../settings_page/compiled_resources2.gyp:main_page_behavior',
+ '../settings_page/compiled_resources2.gyp:settings_page_visibility',
+ '../settings_page/compiled_resources2.gyp:transition_behavior',
+ '../system_page/compiled_resources2.gyp:system_page',
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ ],
+}
diff --git a/chromium/chrome/browser/resources/settings/appearance_page/appearance_fonts_page.html b/chromium/chrome/browser/resources/settings/appearance_page/appearance_fonts_page.html
index 4d8d60457e3..37c4a1cfae2 100644
--- a/chromium/chrome/browser/resources/settings/appearance_page/appearance_fonts_page.html
+++ b/chromium/chrome/browser/resources/settings/appearance_page/appearance_fonts_page.html
@@ -1,95 +1,108 @@
-<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.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/paper-slider/paper-slider.html">
+<link rel="import" href="chrome://md-settings/appearance_page/fonts_browser_proxy.html">
<link rel="import" href="chrome://md-settings/controls/settings_dropdown_menu.html">
+<link rel="import" href="chrome://md-settings/settings_shared_css.html">
<dom-module id="settings-appearance-fonts-page">
<link rel="import" type="css"
- href="chrome://md-settings/settings_shared.css">
- <link rel="import" type="css"
href="chrome://md-settings/appearance_page/appearance_shared.css">
<template>
- <div>[[selectedStandardFont_]]</div>
- <div class="settings-box">
- <div i18n-content="fontSize"></div>
- <paper-slider id="sizeSlider" value="{{fontSizeIndex_}}"
- max="[[fontSizeRangeLimit_]]"
- immediate-value="{{immediateSizeIndex_}}"
- on-immediate-value-change="immediateSizeIndexChanged_">
+ <style include="settings-shared"></style>
+ <div class="settings-box first">
+ <div class="start">$i18n{fontSize}</div>
+ <paper-slider class="slider-labels" id="sizeSlider"
+ value="{{fontSizeIndex_}}"
+ max="[[fontSizeRangeLimit_]]" max-markers="5"
+ immediate-value="{{immediateSizeIndex_}}" snaps>
</paper-slider>
</div>
<div class="settings-box">
- <settings-dropdown-menu id="standardFont"
- i18n-values="label:standardFont"
- pref="{{prefs.webkit.webprefs.fonts.standard.Zyyy}}"
- menu-options="[[fontOptions_]]">
- </settings-dropdown-menu>
- <div class="settings-column"
- style$="[[computeStyle_(defaultFontSize_,
- prefs.webkit.webprefs.fonts.standard.Zyyy.value)]]">
- <span>[[defaultFontSize_]]</span>:
- <span i18n-content="loremIpsum"></span>
- </div>
- </div>
- <div class="settings-box">
- <settings-dropdown-menu id="serifFont"
- i18n-values="label:serifFont"
- pref="{{prefs.webkit.webprefs.fonts.serif.Zyyy}}"
- menu-options="[[fontOptions_]]">
- </settings-dropdown-menu>
- <div class="settings-column"
- style$="[[computeStyle_(defaultFontSize_,
- prefs.webkit.webprefs.fonts.serif.Zyyy.value)]]">
- <span>[[defaultFontSize_]]</span>:
- <span i18n-content="loremIpsum"></span>
- </div>
- </div>
- <div class="settings-box">
- <settings-dropdown-menu id="sansSerifFont"
- i18n-values="label:sansSerifFont"
- pref="{{prefs.webkit.webprefs.fonts.sansserif.Zyyy}}"
- menu-options="[[fontOptions_]]">
- </settings-dropdown-menu>
- <div class="settings-column"
- style$="{{computeStyle_(defaultFontSize_,
- prefs.webkit.webprefs.fonts.sansserif.Zyyy.value)}}">
- <span>[[defaultFontSize_]]</span>:
- <span i18n-content="loremIpsum"></span>
+ <div class="start">$i18n{minimumFont}</div>
+ <div class="list-item" style$="[[computeStyle_(minimumFontSize_, prefs.webkit.webprefs.fonts.standard.Zyyy.value)]]">
+ <span>[[minimumFontSize_]]</span>:&nbsp;
+ <span i18n-content="quickBrownFox"></span>
</div>
+ <paper-slider class="slider-labels" id="minimumSizeSlider"
+ value="{{minimumSizeIndex_}}"
+ max="[[minimumFontSizeRangeLimit_]]" max-markers="5"
+ immediate-value="{{immediateMinimumSizeIndex_}}" snaps>
+ </paper-slider>
</div>
<div class="settings-box">
- <settings-dropdown-menu id="fixedFont"
- i18n-values="label:fixedWidthFont"
- pref="{{prefs.webkit.webprefs.fonts.fixed.Zyyy}}"
- menu-options="[[fontOptions_]]">
- </settings-dropdown-menu>
- <div class="settings-column"
- style$="[[computeStyle_(defaultFontSize_,
- prefs.webkit.webprefs.fonts.fixed.Zyyy.value)]]">
- <span i18n-content="loremIpsum"></span>
- </div>
- </div>
- <div class="settings-box">
- <div>
- <div i18n-content="minimumFont"></div>
- <paper-slider id="minimumSizeSlider" value="{{minimumSizeIndex_}}"
- max="[[minimumFontSizeRangeLimit_]]"
- immediate-value="{{immediateMinimumSizeIndex_}}"
- on-immediate-value-change="immediateMinimumSizeIndexChanged_">
- </paper-slider>
- </div>
- <div style$="[[computeStyle_(minimumFontSize_,
- prefs.webkit.webprefs.fonts.standard.Zyyy.value)]]">
- <span>[[minimumFontSize_]]</span>:
- <span i18n-content="loremIpsum"></span>
+ <div class="start">
+ <h2 i18n-content="standardFont"></h2>
+ <div class="list-frame">
+ <div class="list-item">
+ <settings-dropdown-menu class="start" id="standardFont"
+ pref="{{prefs.webkit.webprefs.fonts.standard.Zyyy}}"
+ menu-options="[[fontOptions_]]" no-label-float>
+ </settings-dropdown-menu>
+ </div>
+ <div class="list-item underbar"
+ style$="[[computeStyle_(defaultFontSize_, prefs.webkit.webprefs.fonts.standard.Zyyy.value)]]">
+ <span>[[defaultFontSize_]]</span>:&nbsp;
+ <span i18n-content="quickBrownFox"></span>
+ </div>
+ </div>
+ <h2 i18n-content="serifFont"></h2>
+ <div class="list-frame">
+ <div class="list-item">
+ <settings-dropdown-menu class="start" id="serifFont"
+ pref="{{prefs.webkit.webprefs.fonts.serif.Zyyy}}"
+ menu-options="[[fontOptions_]]" no-label-float>
+ </settings-dropdown-menu>
+ </div>
+ <div class="list-item underbar"
+ style$="[[computeStyle_(defaultFontSize_, prefs.webkit.webprefs.fonts.serif.Zyyy.value)]]">
+ <span>[[defaultFontSize_]]</span>:&nbsp;
+ <span i18n-content="quickBrownFox"></span>
+ </div>
+ </div>
+ <h2 i18n-content="sansSerifFont"></h2>
+ <div class="list-frame">
+ <div class="list-item">
+ <settings-dropdown-menu class="start" id="sansSerifFont"
+ pref="{{prefs.webkit.webprefs.fonts.sansserif.Zyyy}}"
+ menu-options="[[fontOptions_]]" no-label-float>
+ </settings-dropdown-menu>
+ </div>
+ <div class="list-item underbar"
+ style$="{{computeStyle_(defaultFontSize_, prefs.webkit.webprefs.fonts.sansserif.Zyyy.value)}}">
+ <span>[[defaultFontSize_]]</span>:&nbsp;
+ <span i18n-content="quickBrownFox"></span>
+ </div>
+ </div>
+ <h2 i18n-content="fixedWidthFont"></h2>
+ <div class="list-frame">
+ <div class="list-item">
+ <settings-dropdown-menu class="start" id="fixedFont"
+ pref="{{prefs.webkit.webprefs.fonts.fixed.Zyyy}}"
+ menu-options="[[fontOptions_]]" no-label-float>
+ </settings-dropdown-menu>
+ </div>
+ <div class="list-item"
+ style$="[[computeStyle_(defaultFontSize_, prefs.webkit.webprefs.fonts.fixed.Zyyy.value)]]">
+ <span>[[defaultFontSize_]]</span>:&nbsp;
+ <span i18n-content="quickBrownFox"></span>
+ </div>
+ </div>
</div>
</div>
<div class="settings-box">
+ <div class="start" i18n-content="encoding"></div>
<settings-dropdown-menu id="encoding"
- i18n-values="label:encoding"
pref="{{prefs.intl.charset_default}}"
- menu-options="[[encodingOptions_]]">
+ menu-options="[[encodingOptions_]]" no-label-float>
</settings-dropdown-menu>
</div>
+ <div class="settings-box two-line">
+ <div class="start">
+ <div i18n-content="advancedFontSettings"></div>
+ <div class="secondary" i18n-content="requiresWebStoreExtension"></div>
+ </div>
+ </div>
</template>
<script src="appearance_fonts_page.js"></script>
</dom-module>
diff --git a/chromium/chrome/browser/resources/settings/appearance_page/appearance_fonts_page.js b/chromium/chrome/browser/resources/settings/appearance_page/appearance_fonts_page.js
index 6c8edeb4a53..e698ece59ae 100644
--- a/chromium/chrome/browser/resources/settings/appearance_page/appearance_fonts_page.js
+++ b/chromium/chrome/browser/resources/settings/appearance_page/appearance_fonts_page.js
@@ -2,235 +2,238 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-/**
- * This is the absolute difference maintained between standard and
- * fixed-width font sizes. http://crbug.com/91922.
- * @const
- */
-var SIZE_DIFFERENCE_FIXED_STANDARD = 3;
-
-var FONT_SIZE_RANGE = [
- 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36,
- 40, 44, 48, 56, 64, 72,
-];
-
-var FONT_SIZE_RANGE_LIMIT = FONT_SIZE_RANGE.length - 1;
-
-var MINIMUM_FONT_SIZE_RANGE = [
- 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 20, 22, 24
-];
-
-var MINIMUM_FONT_SIZE_RANGE_LIMIT = MINIMUM_FONT_SIZE_RANGE.length - 1;
-
-/**
- * 'settings-appearance-page' is the settings page containing appearance
- * settings.
- *
- * Example:
- *
- * <settings-appearance-fonts-page prefs="{{prefs}}">
- * </settings-appearance-fonts-page>
- *
- * @group Chrome Settings Elements
- * @element settings-appearance-page
- */
-Polymer({
- is: 'settings-appearance-fonts-page',
-
- properties: {
- /**
- * The font size used by default.
- * @private
- */
- defaultFontSize_: {
- type: Number,
- },
+(function() {
+ 'use strict';
- /**
- * The value of the font size slider.
- * @private
- */
- fontSizeIndex_: {
- type: Number,
- },
+ /**
+ * This is the absolute difference maintained between standard and
+ * fixed-width font sizes. http://crbug.com/91922.
+ * @const @private {number}
+ */
+ var SIZE_DIFFERENCE_FIXED_STANDARD_ = 3;
- /**
- * Common font sizes.
- * @private {!Array<number>}
- */
- fontSizeRange_: {
- readOnly: true,
- type: Array,
- value: FONT_SIZE_RANGE,
+ /** @const @private {!Array<number>} */
+ var FONT_SIZE_RANGE_ = [
+ 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36,
+ 40, 44, 48, 56, 64, 72,
+ ];
+
+ /** @const @private {!Array<number>} */
+ var MINIMUM_FONT_SIZE_RANGE_ = [
+ 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 20, 22, 24
+ ];
+
+ /**
+ * 'settings-appearance-fonts-page' is the settings page containing appearance
+ * settings.
+ *
+ * Example:
+ *
+ * <settings-appearance-fonts-page prefs="{{prefs}}">
+ * </settings-appearance-fonts-page>
+ */
+ Polymer({
+ is: 'settings-appearance-fonts-page',
+
+ behaviors: [I18nBehavior],
+
+ properties: {
+ /** @private {!settings.FontsBrowserProxy} */
+ browserProxy_: Object,
+
+ /**
+ * The font size used by default.
+ * @private
+ */
+ defaultFontSize_: {
+ type: Number,
+ },
+
+ /**
+ * The value of the font size slider.
+ * @private
+ */
+ fontSizeIndex_: {
+ type: Number,
+ },
+
+ /**
+ * Common font sizes.
+ * @private {!Array<number>}
+ */
+ fontSizeRange_: {
+ readOnly: true,
+ type: Array,
+ value: FONT_SIZE_RANGE_,
+ },
+
+ /**
+ * Upper bound of the font size slider.
+ * @private
+ */
+ fontSizeRangeLimit_: {
+ readOnly: true,
+ type: Number,
+ value: FONT_SIZE_RANGE_.length - 1,
+ },
+
+ /**
+ * The interactive value of the minimum font size slider.
+ * @private
+ */
+ immediateMinimumSizeIndex_: {
+ observer: 'immediateMinimumSizeIndexChanged_',
+ type: Number,
+ },
+
+ /**
+ * The interactive value of the font size slider.
+ * @private
+ */
+ immediateSizeIndex_: {
+ observer: 'immediateSizeIndexChanged_',
+ type: Number,
+ },
+
+ /**
+ * Reasonable, minimum font sizes.
+ * @private {!Array<number>}
+ */
+ minimumFontSizeRange_: {
+ readOnly: true,
+ type: Array,
+ value: MINIMUM_FONT_SIZE_RANGE_,
+ },
+
+ /**
+ * Upper bound of the minimum font size slider.
+ * @private
+ */
+ minimumFontSizeRangeLimit_: {
+ readOnly: true,
+ type: Number,
+ value: MINIMUM_FONT_SIZE_RANGE_.length - 1,
+ },
+
+ /**
+ * The font size used at minimum.
+ * @private
+ */
+ minimumFontSize_: {
+ type: Number,
+ },
+
+ /**
+ * The value of the minimum font size slider.
+ * @private
+ */
+ minimumSizeIndex_: {
+ type: Number,
+ },
+
+ /**
+ * Preferences state.
+ */
+ prefs: {
+ type: Object,
+ notify: true,
+ },
},
- /**
- * Upper bound of the font size slider.
- * @private
- */
- fontSizeRangeLimit_: {
- readOnly: true,
- type: Number,
- value: MINIMUM_FONT_SIZE_RANGE_LIMIT,
+ observers: [
+ 'fontSizeChanged_(prefs.webkit.webprefs.default_font_size.value)',
+ 'minimumFontSizeChanged_(prefs.webkit.webprefs.minimum_font_size.value)',
+ ],
+
+ /** @override */
+ created: function() {
+ this.browserProxy_ = settings.FontsBrowserProxyImpl.getInstance();
},
- /**
- * The interactive value of the minimum font size slider.
- * @private
- */
- immediateMinimumSizeIndex_: {
- type: Number,
+ /** @override */
+ ready: function() {
+ this.browserProxy_.fetchFontsData().then(
+ this.setFontsData_.bind(this));
},
/**
- * The interactive value of the font size slider.
+ * @param {number} value The intermediate slider value.
* @private
*/
- immediateSizeIndex_: {
- type: Number,
+ immediateSizeIndexChanged_: function(value) {
+ this.set('prefs.webkit.webprefs.default_font_size.value',
+ this.fontSizeRange_[this.immediateSizeIndex_]);
},
/**
- * Reasonable, minimum font sizes.
- * @private {!Array<number>}
+ * @param {number} value The intermediate slider value.
+ * @private
*/
- minimumFontSizeRange_: {
- readOnly: true,
- type: Array,
- value: MINIMUM_FONT_SIZE_RANGE,
+ immediateMinimumSizeIndexChanged_: function(value) {
+ this.set('prefs.webkit.webprefs.minimum_font_size.value',
+ this.minimumFontSizeRange_[this.immediateMinimumSizeIndex_]);
},
/**
- * Upper bound of the minimum font size slider.
+ * @param {!FontsData} response A list of fonts and encodings.
* @private
*/
- minimumFontSizeRangeLimit_: {
- readOnly: true,
- type: Number,
- value: MINIMUM_FONT_SIZE_RANGE_LIMIT,
+ setFontsData_: function(response) {
+ var fontMenuOptions = [];
+ for (var i = 0; i < response.fontList.length; ++i) {
+ fontMenuOptions.push({
+ value: response.fontList[i][0],
+ name: response.fontList[i][1]
+ });
+ }
+ this.$.standardFont.menuOptions = fontMenuOptions;
+ this.$.serifFont.menuOptions = fontMenuOptions;
+ this.$.sansSerifFont.menuOptions = fontMenuOptions;
+ this.$.fixedFont.menuOptions = fontMenuOptions;
+
+ var encodingMenuOptions = [];
+ for (i = 0; i < response.encodingList.length; ++i) {
+ encodingMenuOptions.push({
+ value: response.encodingList[i][0],
+ name: response.encodingList[i][1]
+ });
+ }
+ this.$.encoding.menuOptions = encodingMenuOptions;
},
/**
- * The font size used at minimum.
+ * @param {number} value The changed font size slider value.
* @private
*/
- minimumFontSize_: {
- type: Number,
+ fontSizeChanged_: function(value) {
+ this.defaultFontSize_ = value;
+ if (!this.$.sizeSlider.dragging) {
+ this.fontSizeIndex_ = this.fontSizeRange_.indexOf(value);
+ this.set('prefs.webkit.webprefs.default_fixed_font_size.value',
+ value - SIZE_DIFFERENCE_FIXED_STANDARD_);
+ }
},
/**
- * The value of the minimum font size slider.
+ * @param {number} value The changed font size slider value.
* @private
*/
- minimumSizeIndex_: {
- type: Number,
+ minimumFontSizeChanged_: function(value) {
+ this.minimumFontSize_ = value;
+ if (!this.$.minimumSizeSlider.dragging)
+ this.minimumSizeIndex_ = this.minimumFontSizeRange_.indexOf(value);
},
/**
- * Preferences state.
+ * Creates an html style value.
+ * @param {number} fontSize The font size to use.
+ * @param {string} fontFamily The name of the font family use.
+ * @return {string}
+ * @private
*/
- prefs: {
- type: Object,
- notify: true,
+ computeStyle_: function(fontSize, fontFamily) {
+ return 'font-size: ' + fontSize + "px; font-family: '" + fontFamily +
+ "';";
},
- },
-
- /**
- * This is the absolute difference maintained between standard and
- * fixed-width font sizes. http://crbug.com/91922.
- * @const
- */
- SIZE_DIFFERENCE_FIXED_STANDARD: 3,
-
- observers: [
- 'fontSizeChanged_(prefs.webkit.webprefs.default_font_size.value)',
- 'minimumFontSizeChanged_(prefs.webkit.webprefs.minimum_font_size.value)',
- ],
-
- ready: function() {
- var self = this;
- cr.define('Settings', function() {
- return {
- setFontsData: function() {
- return self.setFontsData_.apply(self, arguments);
- },
- };
- });
- chrome.send('fetchFontsData');
- },
-
- /**
- * @param {number} value The intermediate slider value.
- * @private
- */
- immediateSizeIndexChanged_: function(value) {
- this.set('prefs.webkit.webprefs.default_font_size.value',
- this.fontSizeRange_[this.immediateSizeIndex_]);
- },
-
- /**
- * @param {number} value The intermediate slider value.
- * @private
- */
- immediateMinimumSizeIndexChanged_: function(value) {
- this.set('prefs.webkit.webprefs.minimum_font_size.value',
- this.minimumFontSizeRange_[this.immediateMinimumSizeIndex_]);
- },
-
- /**
- * @param {!Array<{0: string, 1: (string|undefined), 2: (string|undefined)}>}
- * fontList The font menu options.
- * @param {!Array<{0: string, 1: string}>} encodingList The encoding menu
- * options.
- * @private
- */
- setFontsData_: function(fontList, encodingList) {
- var fontMenuOptions = [];
- for (var i = 0; i < fontList.length; ++i)
- fontMenuOptions.push({value: fontList[i][0], name: fontList[i][1]});
- this.$.standardFont.menuOptions = fontMenuOptions;
- this.$.serifFont.menuOptions = fontMenuOptions;
- this.$.sansSerifFont.menuOptions = fontMenuOptions;
- this.$.fixedFont.menuOptions = fontMenuOptions;
-
- var encodingMenuOptions = [];
- for (var i = 0; i < encodingList.length; ++i) {
- encodingMenuOptions.push({
- value: encodingList[i][0], name: encodingList[i][1]});
- }
- this.$.encoding.menuOptions = encodingMenuOptions;
- },
-
- /**
- * @param {number} value The changed font size slider value.
- * @private
- */
- fontSizeChanged_: function(value) {
- this.defaultFontSize_ = value;
- if (!this.$.sizeSlider.dragging) {
- this.fontSizeIndex_ = this.fontSizeRange_.indexOf(value);
- this.set('prefs.webkit.webprefs.default_fixed_font_size.value',
- value - SIZE_DIFFERENCE_FIXED_STANDARD);
- }
- },
-
- /**
- * @param {number} value The changed font size slider value.
- * @private
- */
- minimumFontSizeChanged_: function(value) {
- this.minimumFontSize_ = value;
- if (!this.$.minimumSizeSlider.dragging)
- this.minimumSizeIndex_ = this.minimumFontSizeRange_.indexOf(value);
- },
-
- /**
- * Creates an html style value.
- * @param {number} fontSize The font size to use.
- * @param {string} fontFamily The name of the font family use.
- * @private
- */
- computeStyle_: function(fontSize, fontFamily) {
- return 'font-size: ' + fontSize + "px; font-family: '" + fontFamily + "';";
- },
-});
+ });
+})();
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 026ddad6001..9bc323e4397 100644
--- a/chromium/chrome/browser/resources/settings/appearance_page/appearance_page.html
+++ b/chromium/chrome/browser/resources/settings/appearance_page/appearance_page.html
@@ -1,6 +1,9 @@
-<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.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-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/iron-icons/device-icons.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/iron-icons/image-icons.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-radio-button/paper-radio-button.html">
@@ -9,95 +12,99 @@
<link rel="import" href="chrome://md-settings/controls/settings_input.html">
<link rel="import" href="chrome://md-settings/controls/settings_radio_group.html">
<link rel="import" href="chrome://md-settings/settings_page/settings_animated_pages.html">
-<link rel="import" href="chrome://md-settings/settings_page/settings_subheader.html">
-<link rel="import" href="chrome://resources/html/i18n_behavior.html">
+<link rel="import" href="chrome://md-settings/settings_page/settings_subpage.html">
+<link rel="import" href="chrome://md-settings/settings_shared_css.html">
<link rel="import" href="appearance_fonts_page.html">
<dom-module id="settings-appearance-page">
<link rel="import" type="css"
- href="chrome://md-settings/settings_shared.css">
- <link rel="import" type="css"
href="chrome://md-settings/appearance_page/appearance_shared.css">
<link rel="import" type="css" href="chrome://resources/css/widgets.css">
<link rel="import" href="chrome://resources/html/action_link.html">
<template>
+ <style include="settings-shared">
+ .settings-box iron-icon {
+ -webkit-margin-end: var(--checkbox-spacing);
+ }
+ </style>
<settings-animated-pages id="pages" current-route="{{currentRoute}}"
section="appearance">
<neon-animatable id="main">
- <div class="settings-box split">
+<if expr="chromeos">
+ <div class="settings-box first two-line">
+ <iron-icon icon="device:wallpaper"></iron-icon>
<div class="start">
- <iron-icon icon="image:brightness-1"></iron-icon>
- <paper-button i18n-content="setWallpaper"></paper-button>
+ <div>[[i18n('setWallpaper')]]</div>
+ <div class="secondary">[[i18n('openWallpaperApp')]]</div>
</div>
- <iron-icon icon="exit-to-app" disabled></iron-icon>
</div>
- <div class="settings-box split">
+ <div class="settings-box two-line" on-tap="openThemesGallery_">
+</if>
+<if expr="not chromeos">
+ <div class="settings-box two-line first" on-tap="openThemesGallery_">
+</if>
+ <iron-icon icon="image:palette"></iron-icon>
<div class="start">
- <iron-icon icon="image:brightness-1"></iron-icon>
- <paper-button id="get-themes"
- on-tap="openThemesGallery_"
- >[[i18n('getThemes')]]</paper-button>
+ <div>[[i18n('getThemes')]]</div>
+ <div class="secondary">[[themeSublabel_]]</div>
</div>
- <template is="dom-if" if="[[!allowResetTheme_]]">
- <iron-icon icon="exit-to-app"></iron-icon>
- </template>
<template is="dom-if" if="[[allowResetTheme_]]">
- <paper-button on-tap="resetTheme_"
+ <paper-button on-tap="resetTheme_" class="secondary-action"
>[[i18n('resetToDefaultTheme')]]</paper-button>
</template>
</div>
- <div class="settings-box split two-line">
+ <div class="settings-box two-line">
<settings-checkbox class="start" i18n-values="label:showHomeButton"
+ sub-label="[[getShowHomeSubLabel_(prefs.homepage_is_newtabpage.value, prefs.homepage.value)]]"
pref="{{prefs.browser.show_home_button}}">
</settings-checkbox>
</div>
<template is="dom-if" if="[[prefs.browser.show_home_button.value]]">
- <settings-radio-group pref="{{prefs.homepage_is_newtabpage}}">
- <paper-radio-button name="true"
- >[[i18n('homePageNtp')]]</paper-radio-button>
- <paper-radio-button name="false"
- >[[i18n('other')]]</paper-radio-button>
- </settings-radio-group>
- <div class="radio-extended">
- <settings-input no-label-float pref="{{prefs.homepage}}"
- label="[[i18n('exampleDotCom')]]">
- </settings-input>
+ <div class="list-frame">
+ <settings-radio-group pref="{{prefs.homepage_is_newtabpage}}">
+ <paper-radio-button class="list-item" name="true">
+ [[i18n('homePageNtp')]]
+ </paper-radio-button>
+ <paper-radio-button class="list-item" name="false">
+ [[i18n('other')]]
+ <settings-input no-label-float pref="{{prefs.homepage}}"
+ label="[[i18n('exampleDotCom')]]">
+ </settings-input>
+ </paper-radio-button>
+ </settings-radio-group>
</div>
</template>
- <div class="settings-box split">
+ <div class="settings-box">
<settings-checkbox class="start" i18n-values="label:showBookmarksBar"
pref="{{prefs.bookmark_bar.show_on_all_tabs}}">
</settings-checkbox>
</div>
- <div class="settings-box split">
+ <div class="settings-box">
<div class="start" i18n-content="fontSize"></div>
<settings-dropdown-menu id="defaultFontSize"
pref="{{prefs.webkit.webprefs.default_font_size}}"
- menu-options="[[fontSizeOptions_]]">
+ menu-options="[[fontSizeOptions_]]" no-label-float>
</settings-dropdown-menu>
</div>
- <div class="settings-box split">
- <div class="start" i18n-content="customizeFonts"></div>
- <paper-button on-tap="onCustomizeFontsTap_"
- i18n-content="customizeFonts"></paper-button>
+ <div class="settings-box two-line" on-tap="onCustomizeFontsTap_">
+ <div class="start">
+ <div i18n-content="customizeFonts"></div>
+ <div class="secondary" i18n-content="chooseFontsAndEncoding"></div>
+ </div>
</div>
- <div class="settings-box split">
+ <div class="settings-box">
<div class="start" i18n-content="pageZoom"></div>
- <settings-dropdown-menu id="pageZoom"
- pref="{{defaultZoomLevel_}}"
- menu-options="[[pageZoomOptions_]]">
+ <settings-dropdown-menu id="pageZoom" pref="{{defaultZoomLevel_}}"
+ menu-options="[[pageZoomOptions_]]" no-label-float>
</settings-dropdown-menu>
</div>
</neon-animatable>
- <neon-animatable id="appearance-fonts">
- <settings-subheader i18n-values="page-title:customizeFonts">
- </settings-subheader>
- <template is="dom-if" if="[[showFontsPage_(currentRoute.subpage.*)]]"
- restamp>
+ <template is="dom-if" name="appearance-fonts">
+ <settings-subpage page-title="[[i18n('customizeFonts')]]">
<settings-appearance-fonts-page prefs="{{prefs}}">
</settings-appearance-fonts-page>
- </template>
- </neon-animatable>
+ </settings-subpage>
+ </template>
</settings-animated-pages>
</template>
<script src="appearance_page.js"></script>
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 52691cb918f..c8320e907b5 100644
--- a/chromium/chrome/browser/resources/settings/appearance_page/appearance_page.js
+++ b/chromium/chrome/browser/resources/settings/appearance_page/appearance_page.js
@@ -13,13 +13,12 @@
* </settings-appearance-page>
* ... other pages ...
* </iron-animated-pages>
- *
- * @group Chrome Settings Elements
- * @element settings-appearance-page
*/
Polymer({
is: 'settings-appearance-page',
+ behaviors: [I18nBehavior],
+
properties: {
/**
* The current active route.
@@ -102,13 +101,13 @@ Polymer({
{value: 500, name: '500%'},
],
},
- },
- behaviors: [
- I18nBehavior,
- ],
+ /** @private */
+ themeSublabel_: String,
+ },
observers: [
+ 'themeChanged_(prefs.extensions.theme.id.value)',
'zoomLevelChanged_(defaultZoomLevel_.value)',
],
@@ -124,8 +123,8 @@ Polymer({
/** @override */
attached: function() {
// Query the initial state.
- cr.sendWithCallback('getResetThemeEnabled', undefined,
- this.setResetThemeEnabled.bind(this));
+ cr.sendWithPromise('getResetThemeEnabled').then(
+ this.setResetThemeEnabled.bind(this));
// Set up the change event listener.
cr.addWebUIListener('reset-theme-enabled-changed',
@@ -133,6 +132,18 @@ Polymer({
},
/**
+ * @param {boolean} isNtp Whether to use the NTP as the home page.
+ * @param {string} homepage If not using NTP, use this URL.
+ * @return {string} The sub-label.
+ * @private
+ */
+ getShowHomeSubLabel_: function(isNtp, homepage) {
+ if (isNtp)
+ return this.i18n('homePageNtp');
+ return homepage || this.i18n('exampleDotCom');
+ },
+
+ /**
* @param {boolean} enabled Whether the theme reset is available.
*/
setResetThemeEnabled: function(enabled) {
@@ -160,6 +171,21 @@ Polymer({
},
/**
+ * @param {string} themeId The theme ID.
+ * @private
+ */
+ themeChanged_: function(themeId) {
+ if (themeId) {
+ chrome.management.get(themeId,
+ function(info) {
+ this.themeSublabel_ = info.name;
+ }.bind(this));
+ } else {
+ this.themeSublabel_ = this.i18n('chooseFromWebStore');
+ }
+ },
+
+ /**
* @param {number} percent The integer percentage of the page zoom.
* @private
*/
diff --git a/chromium/chrome/browser/resources/settings/appearance_page/compiled_resources.gyp b/chromium/chrome/browser/resources/settings/appearance_page/compiled_resources.gyp
deleted file mode 100644
index 01f0b60b922..00000000000
--- a/chromium/chrome/browser/resources/settings/appearance_page/compiled_resources.gyp
+++ /dev/null
@@ -1,53 +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.
-{
- 'targets': [
- {
- 'target_name': 'appearance_fonts_page',
- 'variables': {
- 'depends': [
- '../../../../../ui/webui/resources/js/compiled_resources.gyp:assert',
- '../../../../../ui/webui/resources/js/compiled_resources.gyp:load_time_data',
- '../../../../../ui/webui/resources/js/compiled_resources.gyp:cr',
- '../../../../../ui/webui/resources/js/cr.js',
- '../../../../../ui/webui/resources/js/i18n_behavior.js',
- '../../../../../third_party/polymer/v1_0/components-chromium/iron-a11y-keys-behavior/iron-a11y-keys-behavior-extracted.js',
- '../../../../../third_party/polymer/v1_0/components-chromium/iron-behaviors/iron-button-state-extracted.js',
- '../../../../../third_party/polymer/v1_0/components-chromium/iron-behaviors/iron-control-state-extracted.js',
- '../../../../../third_party/polymer/v1_0/components-chromium/iron-form-element-behavior/iron-form-element-behavior-extracted.js',
- '../../../../../third_party/polymer/v1_0/components-chromium/iron-range-behavior/iron-range-behavior-extracted.js',
- '../../../../../third_party/polymer/v1_0/components-chromium/paper-behaviors/paper-inky-focus-behavior-extracted.js',
- '../../../../../third_party/polymer/v1_0/components-chromium/paper-behaviors/paper-ripple-behavior-extracted.js',
- '../../../../../third_party/polymer/v1_0/components-chromium/paper-ripple/paper-ripple-extracted.js',
- '../../../../../third_party/polymer/v1_0/components-chromium/paper-slider/paper-slider-extracted.js',
- '../controls/settings_dropdown_menu.js',
- '../prefs/pref_util.js'
- ],
- 'externs': [
- '../../../../../third_party/closure_compiler/externs/settings_private.js'
- ],
- },
- 'includes': ['../../../../../third_party/closure_compiler/compile_js.gypi'],
- },
- {
- 'target_name': 'appearance_page',
- 'variables': {
- 'depends': [
- '../../../../../ui/webui/resources/js/compiled_resources.gyp:assert',
- '../../../../../ui/webui/resources/js/compiled_resources.gyp:load_time_data',
- '../../../../../ui/webui/resources/js/cr.js',
- '../../../../../ui/webui/resources/js/i18n_behavior.js',
- '../controls/settings_dropdown_menu.js',
- '../prefs/pref_util.js',
- '../settings_page/settings_animated_pages.js'
- ],
- 'externs': [
- '../../../../../third_party/closure_compiler/externs/settings_private.js',
- '../../../../../third_party/closure_compiler/externs/chrome_send.js',
- ],
- },
- 'includes': ['../../../../../third_party/closure_compiler/compile_js.gypi'],
- },
- ],
-}
diff --git a/chromium/chrome/browser/resources/settings/appearance_page/compiled_resources2.gyp b/chromium/chrome/browser/resources/settings/appearance_page/compiled_resources2.gyp
new file mode 100644
index 00000000000..346e8f9504f
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/appearance_page/compiled_resources2.gyp
@@ -0,0 +1,41 @@
+# 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': 'appearance_fonts_page',
+ 'dependencies': [
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:i18n_behavior',
+ '<(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',
+ '<(EXTERNS_GYP):chrome_send',
+ 'fonts_browser_proxy',
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'appearance_page',
+ 'dependencies': [
+ '<(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',
+ '../controls/compiled_resources2.gyp:settings_dropdown_menu',
+ '../settings_page/compiled_resources2.gyp:settings_animated_pages'
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'fonts_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'],
+ },
+ ],
+}
diff --git a/chromium/chrome/browser/resources/settings/appearance_page/fonts_browser_proxy.html b/chromium/chrome/browser/resources/settings/appearance_page/fonts_browser_proxy.html
new file mode 100644
index 00000000000..b58f95e59e0
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/appearance_page/fonts_browser_proxy.html
@@ -0,0 +1,2 @@
+<link rel="href" src="chrome://resources/html/cr.html">
+<script src="chrome://md-settings/appearance_page/fonts_browser_proxy.js"></script>
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
new file mode 100644
index 00000000000..61f2edb3615
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/appearance_page/fonts_browser_proxy.js
@@ -0,0 +1,43 @@
+// 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 {{
+ * fontList: Array<{0: string, 1: (string|undefined), 2: (string|undefined)}>,
+ * encodingList: Array<{0: string, 1: string}>,
+ * }}
+ */
+var FontsData;
+
+cr.define('settings', function() {
+ /** @interface */
+ function FontsBrowserProxy() {}
+
+ FontsBrowserProxy.prototype = {
+ /**
+ * @return {!Promise<!FontsData>} Fonts and encodings.
+ */
+ fetchFontsData: assertNotReached,
+ };
+
+ /**
+ * @implements {settings.FontsBrowserProxy}
+ * @constructor
+ */
+ function FontsBrowserProxyImpl() {}
+
+ cr.addSingletonGetter(FontsBrowserProxyImpl);
+
+ FontsBrowserProxyImpl.prototype = {
+ /** @override */
+ fetchFontsData: function() {
+ return cr.sendWithPromise('fetchFontsData');
+ },
+ };
+
+ return {
+ FontsBrowserProxy: FontsBrowserProxy,
+ FontsBrowserProxyImpl: FontsBrowserProxyImpl,
+ };
+});
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 bad3074b10a..cb30d7016f6 100644
--- a/chromium/chrome/browser/resources/settings/basic_page/basic_page.html
+++ b/chromium/chrome/browser/resources/settings/basic_page/basic_page.html
@@ -1,6 +1,8 @@
-<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.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://md-settings/appearance_page/appearance_page.html">
<link rel="import" href="chrome://md-settings/search_page/search_page.html">
+<link rel="import" href="chrome://md-settings/settings_page/main_page_behavior.html">
<link rel="import" href="chrome://md-settings/settings_page/settings_page_visibility.html">
<link rel="import" href="chrome://md-settings/settings_page/settings_section.html">
<link rel="import" href="chrome://md-settings/on_startup_page/on_startup_page.html">
@@ -8,6 +10,7 @@
<link rel="import" href="chrome://md-settings/reset_page/reset_profile_banner.html">
<if expr="chromeos">
+<link rel="import" href="chrome://md-settings/device_page/device_page.html">
<link rel="import" href="chrome://md-settings/internet_page/internet_page.html">
</if>
@@ -16,46 +19,50 @@
</if>
<dom-module id="settings-basic-page">
- <link rel="import" type="css" href="basic_page.css">
+ <link rel="import" type="css" href="chrome://md-settings/settings_page.css">
<template>
+ <style include="main-page-styles"></style>
<template is="dom-if" if="[[showResetProfileBanner_]]">
<settings-reset-profile-banner on-reset-done="onResetDone_">
</settings-reset-profile-banner>
</template>
- <template is="dom-if" if="[[showPage(pageVisibility.people)]]" restamp>
- <settings-section i18n-values="page-title:peoplePageTitle"
- current-route="[[currentRoute]]" section="people">
- <settings-people-page prefs="{{prefs}}" current-route="{{currentRoute}}">
- </settings-people-page>
- </settings-section>
- </template>
<if expr="chromeos">
<template is="dom-if" if="[[showPage(pageVisibility.internet)]]" restamp>
- <settings-section i18n-values="page-title:internetPageTitle"
+ <settings-section page-title="[[i18n('internetPageTitle')]]"
current-route="[[currentRoute]]" section="internet">
<settings-internet-page current-route="{{currentRoute}}">
</settings-internet-page>
</settings-section>
</template>
</if>
+ <template is="dom-if" if="[[showPage(pageVisibility.people)]]" restamp>
+ <settings-section page-title="[[i18n('peoplePageTitle')]]"
+ current-route="[[currentRoute]]" section="people">
+ <settings-people-page prefs="{{prefs}}"
+ current-route="{{currentRoute}}">
+ </settings-people-page>
+ </settings-section>
+ </template>
<template is="dom-if" if="[[showPage(pageVisibility.appearance)]]" restamp>
- <settings-section i18n-values="page-title:appearancePageTitle"
+ <settings-section page-title="[[i18n('appearancePageTitle')]]"
current-route="[[currentRoute]]" section="appearance">
<settings-appearance-page prefs="{{prefs}}"
- current-route="[[currentRoute]]">
+ current-route="{{currentRoute}}">
</settings-appearance-page>
</settings-section>
</template>
- <template is="dom-if" if="[[showPage(pageVisibility.onStartup)]]" restamp>
- <settings-section i18n-values="page-title:onStartup"
- current-route="[[currentRoute]]" section="onStartup">
- <settings-on-startup-page prefs="{{prefs}}"
+<if expr="chromeos">
+ <template is="dom-if" if="[[showPage(pageVisibility.device)]]" restamp>
+ <settings-section page-title="[[i18n('devicePageTitle')]]"
+ current-route="[[currentRoute]]" section="device">
+ <settings-device-page prefs="{{prefs}}"
current-route="{{currentRoute}}">
- </settings-on-startup-page>
+ </settings-device-page>
</settings-section>
</template>
+</if>
<template is="dom-if" if="[[showPage(pageVisibility.search)]]" restamp>
- <settings-section i18n-values="page-title:searchPageTitle"
+ <settings-section page-title="[[i18n('searchPageTitle')]]"
current-route="[[currentRoute]]" section="search">
<settings-search-page current-route="{{currentRoute}}">
</settings-search-page>
@@ -64,7 +71,7 @@
<if expr="not chromeos">
<template is="dom-if" if="[[showPage(pageVisibility.defaultBrowser)]]"
restamp>
- <settings-section i18n-values="page-title:defaultBrowser"
+ <settings-section page-title="[[i18n('defaultBrowser')]]"
expand-container="{{expandContainer}}"
current-route="[[currentRoute]]" section="defaultBrowser">
<settings-default-browser-page>
@@ -72,6 +79,14 @@
</settings-section>
</template>
</if>
+ <template is="dom-if" if="[[showPage(pageVisibility.onStartup)]]" restamp>
+ <settings-section page-title="[[i18n('onStartup')]]"
+ current-route="[[currentRoute]]" section="onStartup">
+ <settings-on-startup-page prefs="{{prefs}}"
+ current-route="{{currentRoute}}">
+ </settings-on-startup-page>
+ </settings-section>
+ </template>
</template>
<script src="basic_page.js"></script>
</dom-module>
diff --git a/chromium/chrome/browser/resources/settings/basic_page/basic_page.js b/chromium/chrome/browser/resources/settings/basic_page/basic_page.js
index 4439fb1179f..80787fc349b 100644
--- a/chromium/chrome/browser/resources/settings/basic_page/basic_page.js
+++ b/chromium/chrome/browser/resources/settings/basic_page/basic_page.js
@@ -12,9 +12,6 @@
* <settings-basic-page prefs="{{prefs}}"></settings-basic-page>
* ... other pages ...
* </iron-animated-pages>
- *
- * @group Chrome Settings Elements
- * @element settings-basic-page
*/
Polymer({
is: 'settings-basic-page',
@@ -49,9 +46,22 @@ Polymer({
},
+ /**
+ * @type {string} Selector to get the sections.
+ * TODO(michaelpg): replace duplicate docs with @override once b/24294625
+ * is fixed.
+ */
+ sectionSelector: 'settings-section',
+
+ /** @override */
+ attached: function() {
+ /** @override */
+ this.scroller = this.parentElement;
+ },
+
+ behaviors: [I18nBehavior, SettingsPageVisibility, RoutableBehavior],
+
onResetDone_: function() {
this.showResetProfileBanner_ = false;
},
-
- behaviors: [SettingsPageVisibility],
});
diff --git a/chromium/chrome/browser/resources/settings/basic_page/compiled_resources.gyp b/chromium/chrome/browser/resources/settings/basic_page/compiled_resources.gyp
deleted file mode 100644
index 840e2ee3308..00000000000
--- a/chromium/chrome/browser/resources/settings/basic_page/compiled_resources.gyp
+++ /dev/null
@@ -1,17 +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.
-{
- 'targets': [
- {
- 'target_name': 'basic_page',
- 'variables': {
- 'depends': [
- '../../../../../ui/webui/resources/js/compiled_resources.gyp:load_time_data',
- '../settings_page/compiled_resources.gyp:settings_page_visibility',
- ],
- },
- 'includes': ['../../../../../third_party/closure_compiler/compile_js.gypi'],
- },
- ],
-}
diff --git a/chromium/chrome/browser/resources/settings/basic_page/compiled_resources2.gyp b/chromium/chrome/browser/resources/settings/basic_page/compiled_resources2.gyp
new file mode 100644
index 00000000000..b3013ed57a1
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/basic_page/compiled_resources2.gyp
@@ -0,0 +1,18 @@
+# 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': 'basic_page',
+ 'dependencies': [
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:load_time_data',
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:i18n_behavior',
+ '../settings_page/compiled_resources2.gyp:main_page_behavior',
+ '../settings_page/compiled_resources2.gyp:settings_page_visibility',
+ '../settings_page/compiled_resources2.gyp:transition_behavior',
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ ],
+}
diff --git a/chromium/chrome/browser/resources/settings/bluetooth_page/bluetooth_add_device_dialog.html b/chromium/chrome/browser/resources/settings/bluetooth_page/bluetooth_add_device_dialog.html
index c6f747c04f2..e936a7240c0 100644
--- a/chromium/chrome/browser/resources/settings/bluetooth_page/bluetooth_add_device_dialog.html
+++ b/chromium/chrome/browser/resources/settings/bluetooth_page/bluetooth_add_device_dialog.html
@@ -1,14 +1,15 @@
-<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.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-selector/iron-selector.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="chrome://md-settings/settings_shared_css.html">
<dom-module id="settings-bluetooth-add-device-dialog">
- <link rel="import" type="css" href="chrome://md-settings/settings_shared.css">
<link rel="import" type="css" href="bluetooth_page.css">
<link rel="import" type="css" href="bluetooth_dialog.css">
<template>
+ <style include="settings-shared"></style>
<div id="dialogOuterDiv" class="layout vertical flex">
<div id="dialogHeaderDiv" class="settings-box layout horizontal">
<span id="dialogTitle" class="flex"
@@ -40,7 +41,7 @@
<span i18n-content="bluetoothScanning"></span>
</div>
<paper-button id="cancel" class="end-justified"
- i18n-content="bluetoothCancel" on-tap="onCancelTap_">
+ i18n-content="cancel" on-tap="onCancelTap_">
</paper-button>
</div>
</div>
diff --git a/chromium/chrome/browser/resources/settings/bluetooth_page/bluetooth_add_device_dialog.js b/chromium/chrome/browser/resources/settings/bluetooth_page/bluetooth_add_device_dialog.js
index 189711f310f..eaff3ae4b33 100644
--- a/chromium/chrome/browser/resources/settings/bluetooth_page/bluetooth_add_device_dialog.js
+++ b/chromium/chrome/browser/resources/settings/bluetooth_page/bluetooth_add_device_dialog.js
@@ -6,9 +6,6 @@
* @fileoverview
* 'settings-bluetooth-add-device-dialog' is the settings subpage for adding
* bluetooth devices.
- *
- * @group Chrome Settings Elements
- * @element settings-bluetooth-add-device-dialog
*/
Polymer({
is: 'settings-bluetooth-add-device-dialog',
diff --git a/chromium/chrome/browser/resources/settings/bluetooth_page/bluetooth_device_list_item.css b/chromium/chrome/browser/resources/settings/bluetooth_page/bluetooth_device_list_item.css
index de43201be75..bd41095ea12 100644
--- a/chromium/chrome/browser/resources/settings/bluetooth_page/bluetooth_device_list_item.css
+++ b/chromium/chrome/browser/resources/settings/bluetooth_page/bluetooth_device_list_item.css
@@ -3,7 +3,10 @@
* found in the LICENSE file. */
#outer {
- padding: 5px 5px 5px 15px;
+ -webkit-padding-end: 5px;
+ -webkit-padding-start: 15px;
+ padding-bottom: 5px;
+ padding-top: 5px;
}
#outer:hover:not([dropdown]) {
@@ -12,7 +15,6 @@
iron-icon {
-webkit-padding-start: 10px;
- color: green;
}
paper-item:hover {
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 a868a559356..55a16906fb9 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,4 +1,4 @@
-<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.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">
diff --git a/chromium/chrome/browser/resources/settings/bluetooth_page/bluetooth_dialog.css b/chromium/chrome/browser/resources/settings/bluetooth_page/bluetooth_dialog.css
index 67646335f0b..827fd37a114 100644
--- a/chromium/chrome/browser/resources/settings/bluetooth_page/bluetooth_dialog.css
+++ b/chromium/chrome/browser/resources/settings/bluetooth_page/bluetooth_dialog.css
@@ -26,9 +26,9 @@
}
#dialogDeviceList {
+ -webkit-margin-start: 4px;
height: 210px;
margin-bottom: 20px;
- margin-left: 4px;
overflow-y: auto;
}
diff --git a/chromium/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.html b/chromium/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.html
index d6e576e17b1..7c720a64697 100644
--- a/chromium/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.html
+++ b/chromium/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.html
@@ -1,26 +1,26 @@
-<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.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-collapse/iron-collapse.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-icons/device-icons.html">
<link rel="import" href="chrome://resources/polymer/v1_0/iron-list/iron-list.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.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-toggle-button/paper-toggle-button.html">
-<link rel="import" href="chrome://resources/html/i18n_behavior.html">
<link rel="import" href="chrome://md-settings/settings_page/settings_animated_pages.html">
+<link rel="import" href="chrome://md-settings/settings_shared_css.html">
<link rel="import" href="bluetooth_device_list_item.html">
<link rel="import" href="bluetooth_add_device_dialog.html">
<link rel="import" href="bluetooth_pair_device_dialog.html">
<dom-module id="settings-bluetooth-page">
- <link rel="import" type="css" href="chrome://md-settings/settings_shared.css">
<link rel="import" type="css" href="bluetooth_page.css">
<template>
+ <style include="settings-shared"></style>
<settings-animated-pages id="pages" current-route="{{currentRoute}}"
section="bluetooth">
<neon-animatable id="main">
- <div class="settings-box">
+ <div class="settings-box first">
<div class="layout horizontal center">
<iron-icon icon="device:bluetooth"></iron-icon>
<span class="flex" i18n-content="bluetoothEnable"></span>
diff --git a/chromium/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.js b/chromium/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.js
index c8babf426cc..41ba307bde9 100644
--- a/chromium/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.js
+++ b/chromium/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.js
@@ -13,9 +13,6 @@
* </settings-bluetooth-page>
* ... other pages ...
* </core-animated-pages>
- *
- * @group Chrome Settings Elements
- * @element settings-bluetooth-page
*/
var bluetoothPage = bluetoothPage || {
@@ -416,7 +413,7 @@ Polymer({
* @private
*/
haveDevices_: function(deviceListChanges) {
- return this.deviceList.findIndex(function(d) { return d.paired; }) != -1;
+ return this.deviceList.findIndex(function(d) { return !!d.paired; }) != -1;
},
/**
diff --git a/chromium/chrome/browser/resources/settings/bluetooth_page/bluetooth_pair_device_dialog.html b/chromium/chrome/browser/resources/settings/bluetooth_page/bluetooth_pair_device_dialog.html
index 05ed236ecd1..2705f4e119a 100644
--- a/chromium/chrome/browser/resources/settings/bluetooth_page/bluetooth_pair_device_dialog.html
+++ b/chromium/chrome/browser/resources/settings/bluetooth_page/bluetooth_pair_device_dialog.html
@@ -1,14 +1,15 @@
-<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.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-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://md-settings/settings_shared_css.html">
<dom-module id="settings-bluetooth-pair-device-dialog">
- <link rel="import" type="css" href="chrome://md-settings/settings_shared.css">
<link rel="import" type="css" href="bluetooth_page.css">
<link rel="import" type="css" href="bluetooth_dialog.css">
<template>
+ <style include="settings-shared"></style>
<div id="dialogOuterDiv" class="layout vertical flex">
<div id="dialogHeaderDiv" class="settings-box layout horizontal center">
<span id="dialogTitle" class="flex"
@@ -58,8 +59,8 @@
hidden$="[[!showDismiss_(pairingDevice, pairingEvent)]]"
on-tap="onDismissTap_">
</paper-button>
- <paper-button i18n-content="bluetoothCancel" on-tap="onCancelTap_"
- hidden$="[[showDismiss_(pairingDevice, pairingEvent)]]"
+ <paper-button i18n-content="cancel" on-tap="onCancelTap_"
+ hidden$="[[showDismiss_(pairingDevice, pairingEvent)]]">
</paper-button>
</div>
</div>
diff --git a/chromium/chrome/browser/resources/settings/bluetooth_page/bluetooth_pair_device_dialog.js b/chromium/chrome/browser/resources/settings/bluetooth_page/bluetooth_pair_device_dialog.js
index fe286744b2b..83178309a7e 100644
--- a/chromium/chrome/browser/resources/settings/bluetooth_page/bluetooth_pair_device_dialog.js
+++ b/chromium/chrome/browser/resources/settings/bluetooth_page/bluetooth_pair_device_dialog.js
@@ -6,9 +6,6 @@
* @fileoverview
* 'settings-bluetooth-pair-device-dialog' is the settings dialog for pairing
* a bluetooth device.
- *
- * @group Chrome Settings Elements
- * @element settings-bluetooth-pair-device-dialog
*/
(function() {
diff --git a/chromium/chrome/browser/resources/settings/bluetooth_page/compiled_resources.gyp b/chromium/chrome/browser/resources/settings/bluetooth_page/compiled_resources.gyp
deleted file mode 100644
index 17032053dd6..00000000000
--- a/chromium/chrome/browser/resources/settings/bluetooth_page/compiled_resources.gyp
+++ /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.
-{
- 'targets': [
- {
- 'target_name': 'bluetooth_page',
- 'variables': {
- 'depends': [
- '../../../../../third_party/closure_compiler/externs/bluetooth_interface.js',
- '../../../../../third_party/closure_compiler/externs/bluetooth_private_interface.js',
- '../../../../../ui/webui/resources/js/compiled_resources.gyp:assert',
- '../../../../../ui/webui/resources/js/compiled_resources.gyp:load_time_data',
- '../../../../../ui/webui/resources/js/i18n_behavior.js',
- '../settings_page/settings_animated_pages.js'
- ],
- 'externs': [
- '../../../../../third_party/closure_compiler/externs/bluetooth.js',
- '../../../../../third_party/closure_compiler/externs/bluetooth_private.js'
- ],
- },
- 'includes': ['../../../../../third_party/closure_compiler/compile_js.gypi'],
- },
- {
- 'target_name': 'bluetooth_device_list_item',
- 'variables': {
- 'depends': [
- '../../../../../ui/webui/resources/js/compiled_resources.gyp:assert',
- ],
- 'externs': [
- '../../../../../third_party/closure_compiler/externs/bluetooth.js',
- '../../../../../third_party/closure_compiler/externs/bluetooth_private.js'
- ],
- },
- 'includes': ['../../../../../third_party/closure_compiler/compile_js.gypi'],
- },
- {
- 'target_name': 'bluetooth_add_device_dialog',
- 'variables': {
- 'depends': [
- '../../../../../third_party/closure_compiler/externs/bluetooth_interface.js',
- '../../../../../third_party/closure_compiler/externs/bluetooth_private_interface.js',
- '../../../../../ui/webui/resources/js/compiled_resources.gyp:assert',
- '../../../../../ui/webui/resources/js/compiled_resources.gyp:load_time_data',
- '../../../../../ui/webui/resources/js/i18n_behavior.js',
- ],
- 'externs': [
- '../../../../../third_party/closure_compiler/externs/bluetooth.js',
- '../../../../../third_party/closure_compiler/externs/bluetooth_private.js'
- ],
- },
- 'includes': ['../../../../../third_party/closure_compiler/compile_js.gypi'],
- },
- {
- 'target_name': 'bluetooth_pair_device_dialog',
- 'variables': {
- 'depends': [
- '../../../../../third_party/closure_compiler/externs/bluetooth_interface.js',
- '../../../../../third_party/closure_compiler/externs/bluetooth_private_interface.js',
- '../../../../../ui/webui/resources/js/compiled_resources.gyp:assert',
- '../../../../../ui/webui/resources/js/compiled_resources.gyp:load_time_data',
- '../../../../../ui/webui/resources/js/i18n_behavior.js',
- ],
- 'externs': [
- '../../../../../third_party/closure_compiler/externs/bluetooth.js',
- '../../../../../third_party/closure_compiler/externs/bluetooth_private.js'
- ],
- },
- 'includes': ['../../../../../third_party/closure_compiler/compile_js.gypi'],
- },
- ],
-}
diff --git a/chromium/chrome/browser/resources/settings/bluetooth_page/compiled_resources2.gyp b/chromium/chrome/browser/resources/settings/bluetooth_page/compiled_resources2.gyp
new file mode 100644
index 00000000000..3cbd221727d
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/bluetooth_page/compiled_resources2.gyp
@@ -0,0 +1,43 @@
+# 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': 'bluetooth_page',
+ 'dependencies': [
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:assert',
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:i18n_behavior',
+ '<(EXTERNS_GYP):bluetooth',
+ '<(EXTERNS_GYP):bluetooth_private',
+ '<(INTERFACES_GYP):bluetooth_interface',
+ '<(INTERFACES_GYP):bluetooth_private_interface',
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'bluetooth_device_list_item',
+ 'dependencies': [
+ '<(EXTERNS_GYP):bluetooth',
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'bluetooth_add_device_dialog',
+ 'dependencies': [
+ '<(EXTERNS_GYP):bluetooth',
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'bluetooth_pair_device_dialog',
+ 'dependencies': [
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:assert',
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:i18n_behavior',
+ '<(EXTERNS_GYP):bluetooth',
+ '<(EXTERNS_GYP):bluetooth_private',
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ ],
+}
diff --git a/chromium/chrome/browser/resources/settings/certificate_manager_page/ca_trust_edit_dialog.html b/chromium/chrome/browser/resources/settings/certificate_manager_page/ca_trust_edit_dialog.html
new file mode 100644
index 00000000000..7069b21e87a
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/certificate_manager_page/ca_trust_edit_dialog.html
@@ -0,0 +1,46 @@
+<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-spinner/paper-spinner.html">
+<link rel="import" href="chrome://md-settings/i18n_setup.html">
+<link rel="import" href="chrome://md-settings/settings_dialog.html">
+<link rel="import" href="chrome://md-settings/settings_shared_css.html">
+<link rel="import" href="chrome://md-settings/certificate_manager_page/certificates_browser_proxy.html">
+
+<dom-module id="settings-ca-trust-edit-dialog">
+ <template>
+ <style include="settings-shared">
+ paper-checkbox {
+ display: block;
+ margin: 15px 0;
+ }
+ </style>
+
+ <settings-dialog id="dialog">
+ <div class="title">$i18n{certificateManagerCaTrustEditDialogTitle}</div>
+ <div class="body">
+ <div>[[explanationText_]]</div>
+ <div>$i18n{certificateManagerCaTrustEditDialogDescription}</div>
+ <paper-checkbox id="ssl" checked="[[trustInfo_.ssl]]">
+ $i18n{certificateManagerCaTrustEditDialogSsl}
+ </paper-checkbox>
+ <paper-checkbox id="email" checked="[[trustInfo_.email]]">
+ $i18n{certificateManagerCaTrustEditDialogEmail}
+ </paper-checkbox>
+ <paper-checkbox id="objSign" checked="[[trustInfo_.objSign]]">
+ $i18n{certificateManagerCaTrustEditDialogObjSign}
+ </paper-checkbox>
+ </div>
+ <div class="button-container">
+ <paper-spinner id="spinner"></paper-spinner>
+ <paper-button class="cancel-button" on-tap="onCancelTap_">
+ $i18n{cancel}
+ </paper-button>
+ <paper-button id="ok" class="action-button" on-tap="onOkTap_">
+ $i18n{ok}
+ </paper-button>
+ </div>
+ </settings-dialog>
+ </template>
+ <script src="ca_trust_edit_dialog.js"></script>
+</dom-module>
diff --git a/chromium/chrome/browser/resources/settings/certificate_manager_page/ca_trust_edit_dialog.js b/chromium/chrome/browser/resources/settings/certificate_manager_page/ca_trust_edit_dialog.js
new file mode 100644
index 00000000000..a7071316ccc
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/certificate_manager_page/ca_trust_edit_dialog.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.
+
+/**
+ * @fileoverview 'settings-ca-trust-edit-dialog' allows the user to
+ * - specify the trust level of a certificate authority that is being
+ * imported.
+ * - edit the trust level of an already existing certificate authority.
+ */
+Polymer({
+ is: 'settings-ca-trust-edit-dialog',
+
+ properties: {
+ /** @private {!settings.CertificatesBrowserProxy} */
+ browserProxy_: Object,
+
+ /** @type {!CertificateSubnode|!NewCertificateSubNode} */
+ model: Object,
+
+ /** @private {?CaTrustInfo} */
+ trustInfo_: Object,
+
+ /** @private {string} */
+ explanationText_: String,
+ },
+
+ /** @override */
+ ready: function() {
+ this.browserProxy_ = settings.CertificatesBrowserProxyImpl.getInstance();
+ },
+
+ /** @override */
+ attached: function() {
+ this.explanationText_ = loadTimeData.getStringF(
+ 'certificateManagerCaTrustEditDialogExplanation',
+ this.model.name);
+
+ // A non existing |model.id| indicates that a new certificate is being
+ // imported, otherwise an existing certificate is being edited.
+ if (this.model.id) {
+ this.browserProxy_.getCaCertificateTrust(this.model.id).then(
+ /** @param {!CaTrustInfo} trustInfo */
+ function(trustInfo) {
+ this.trustInfo_ = trustInfo;
+ this.$.dialog.open();
+ }.bind(this));
+ } else {
+ this.$.dialog.open();
+ }
+ },
+
+ /** @private */
+ onCancelTap_: function() {
+ this.$.dialog.close();
+ },
+
+ /** @private */
+ onOkTap_: function() {
+ this.$.spinner.active = true;
+
+ var whenDone = this.model.id ?
+ this.browserProxy_.editCaCertificateTrust(
+ this.model.id, this.$.ssl.checked,
+ this.$.email.checked, this.$.objSign.checked) :
+ this.browserProxy_.importCaCertificateTrustSelected(
+ this.$.ssl.checked, this.$.email.checked, this.$.objSign.checked);
+
+ whenDone.then(function() {
+ this.$.spinner.active = false;
+ this.$.dialog.close();
+ }.bind(this),
+ /** @param {!CertificatesError} error */
+ function(error) {
+ this.$.dialog.close();
+ this.fire('certificates-error', error);
+ }.bind(this));
+ },
+});
diff --git a/chromium/chrome/browser/resources/settings/certificate_manager_page/certificate_delete_confirmation_dialog.html b/chromium/chrome/browser/resources/settings/certificate_manager_page/certificate_delete_confirmation_dialog.html
new file mode 100644
index 00000000000..4aed89811c4
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/certificate_manager_page/certificate_delete_confirmation_dialog.html
@@ -0,0 +1,27 @@
+<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://md-settings/i18n_setup.html">
+<link rel="import" href="chrome://md-settings/settings_dialog.html">
+<link rel="import" href="chrome://md-settings/settings_shared_css.html">
+<link rel="import" href="chrome://md-settings/certificate_manager_page/certificates_browser_proxy.html">
+
+<dom-module id="settings-certificate-delete-confirmation-dialog">
+ <template>
+ <style include="settings-shared"></style>
+ <settings-dialog id="dialog">
+ <div class="title">[[getTitleText_(model, certificateType)]]</div>
+ <div class="body">
+ <div>[[getDescriptionText_(model, certificateType)]]</div>
+ </div>
+ <div class="button-container">
+ <paper-button class="cancel-button" on-tap="onCancelTap_">
+ $i18n{cancel}
+ </paper-button>
+ <paper-button id="ok" class="action-button" on-tap="onOkTap_">
+ $i18n{ok}
+ </paper-button>
+ </div>
+ </settings-dialog>
+ </template>
+ <script src="certificate_delete_confirmation_dialog.js"></script>
+</dom-module>
diff --git a/chromium/chrome/browser/resources/settings/certificate_manager_page/certificate_delete_confirmation_dialog.js b/chromium/chrome/browser/resources/settings/certificate_manager_page/certificate_delete_confirmation_dialog.js
new file mode 100644
index 00000000000..595dfd22f98
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/certificate_manager_page/certificate_delete_confirmation_dialog.js
@@ -0,0 +1,95 @@
+// 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 confirmation dialog allowing the user to delete various types
+ * of certificates.
+ */
+Polymer({
+ is: 'settings-certificate-delete-confirmation-dialog',
+
+ properties: {
+ /** @private {!settings.CertificatesBrowserProxy} */
+ browserProxy_: Object,
+
+ /** @type {!CertificateSubnode} */
+ model: Object,
+
+ /** @type {!settings.CertificateType} */
+ certificateType: String,
+ },
+
+ /** @override */
+ ready: function() {
+ this.browserProxy_ = settings.CertificatesBrowserProxyImpl.getInstance();
+ },
+
+ /** @override */
+ attached: function() {
+ this.$.dialog.open();
+ },
+
+ /**
+ * @private
+ * @return {string}
+ */
+ getTitleText_: function() {
+ /**
+ * @param {string} localizedMessageId
+ * @return {string}
+ */
+ var getString = function(localizedMessageId) {
+ return loadTimeData.getStringF(localizedMessageId, this.model.name);
+ }.bind(this);
+
+ switch (this.certificateType) {
+ case settings.CertificateType.PERSONAL:
+ return getString('certificateManagerDeleteUserTitle');
+ case settings.CertificateType.SERVER:
+ return getString('certificateManagerDeleteServerTitle');
+ case settings.CertificateType.CA:
+ return getString('certificateManagerDeleteCaTitle');
+ case settings.CertificateType.OTHER:
+ return getString('certificateManagerDeleteOtherTitle');
+ }
+ assertNotReached();
+ },
+
+ /**
+ * @private
+ * @return {string}
+ */
+ getDescriptionText_: function() {
+ var getString = loadTimeData.getString.bind(loadTimeData);
+ switch (this.certificateType) {
+ case settings.CertificateType.PERSONAL:
+ return getString('certificateManagerDeleteUserDescription');
+ case settings.CertificateType.SERVER:
+ return getString('certificateManagerDeleteServerDescription');
+ case settings.CertificateType.CA:
+ return getString('certificateManagerDeleteCaDescription');
+ case settings.CertificateType.OTHER:
+ return '';
+ }
+ assertNotReached();
+ },
+
+ /** @private */
+ onCancelTap_: function() {
+ this.$.dialog.close();
+ },
+
+ /** @private */
+ onOkTap_: function() {
+ this.browserProxy_.deleteCertificate(this.model.id).then(
+ function() {
+ this.$.dialog.close();
+ }.bind(this),
+ /** @param {!CertificatesError} error */
+ function(error) {
+ this.$.dialog.close();
+ this.fire('certificates-error', error);
+ }.bind(this));
+ },
+});
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
new file mode 100644
index 00000000000..ed4eef12782
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/certificate_manager_page/certificate_entry.html
@@ -0,0 +1,33 @@
+<link rel="import" href="chrome://resources/html/polymer.html">
+<link rel="import" href="chrome://md-settings/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="chrome://resources/polymer/v1_0/iron-icons/iron-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://md-settings/settings_shared_css.html">
+<link rel="import" href="chrome://md-settings/certificate_manager_page/certificate_subentry.html">
+
+<dom-module id="settings-certificate-entry">
+ <template>
+ <style include="settings-shared"></style>
+ <div class="settings-box">
+ <div class="start">[[model.id]]</div>
+ <cr-expand-button expanded="{{expanded_}}"></cr-expand-button>
+ </div>
+ <iron-collapse opened="[[expanded_]]" no-animation>
+ <template is="dom-if" if="[[expanded_]]">
+ <div class="list-frame">
+ <template is="dom-repeat" items="[[model.subnodes]]">
+ <settings-certificate-subentry model="[[item]]"
+ certificate-type="[[certificateType]]"
+ is-last$="[[isLast_(index, model)]]">
+ </settings-certificate-subentry>
+ </template>
+ </div>
+ </template>
+ <iron-collapse>
+ </template>
+ <script src="certificate_entry.js"></script>
+</dom-module>
diff --git a/chromium/chrome/browser/resources/settings/certificate_manager_page/certificate_entry.js b/chromium/chrome/browser/resources/settings/certificate_manager_page/certificate_entry.js
new file mode 100644
index 00000000000..7dddd50943c
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/certificate_manager_page/certificate_entry.js
@@ -0,0 +1,27 @@
+// 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 An element that represents an SSL certificate entry.
+ */
+Polymer({
+ is: 'settings-certificate-entry',
+
+ properties: {
+ /** @type {!Certificate} */
+ model: Object,
+
+ /** @type {!settings.CertificateType} */
+ certificateType: String,
+ },
+
+ /**
+ * @param {number} index
+ * @return {boolean} Whether the given index corresponds to the last sub-node.
+ * @private
+ */
+ isLast_: function(index) {
+ return index == this.model.subnodes.length - 1;
+ },
+});
diff --git a/chromium/chrome/browser/resources/settings/certificate_manager_page/certificate_list.html b/chromium/chrome/browser/resources/settings/certificate_manager_page/certificate_list.html
new file mode 100644
index 00000000000..4ebf1e3a75c
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/certificate_manager_page/certificate_list.html
@@ -0,0 +1,30 @@
+<link rel="import" href="chrome://resources/html/polymer.html">
+<link rel="import" href="chrome://resources/html/assert.html">
+<link rel="import" href="chrome://resources/html/i18n_behavior.html">
+<link rel="import" href="chrome://md-settings/certificate_manager_page/certificate_entry.html">
+<link rel="import" href="chrome://md-settings/certificate_manager_page/certificates_browser_proxy.html">
+<link rel="import" href="chrome://md-settings/i18n_setup.html">
+<link rel="import" href="chrome://md-settings/settings_shared_css.html">
+
+<dom-module id="settings-certificate-list">
+ <template>
+ <style include="settings-shared">
+ .settings-box {
+ margin-bottom: 24px;
+ }
+ </style>
+ <div class="settings-box first">
+ <span class="start">
+ [[getDescription_(certificateType, certificates)]]</span>
+ <paper-button on-tap="onImportTap_"
+ hidden="[[!canImport_(certificateType)]]">
+ $i18n{certificateManagerImport}</paper-button>
+ </div>
+ <template is="dom-repeat" items="[[certificates]]">
+ <settings-certificate-entry model="[[item]]"
+ certificate-type="[[certificateType]]">
+ </settings-certificate-entry>
+ </template>
+ </template>
+ <script src="certificate_list.js"></script>
+</dom-module>
diff --git a/chromium/chrome/browser/resources/settings/certificate_manager_page/certificate_list.js b/chromium/chrome/browser/resources/settings/certificate_manager_page/certificate_list.js
new file mode 100644
index 00000000000..0388ee82b75
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/certificate_manager_page/certificate_list.js
@@ -0,0 +1,110 @@
+// 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-certificate-list' is an element that displays a list
+ * of certificates.
+ */
+Polymer({
+ is: 'settings-certificate-list',
+
+ properties: {
+ /** @type {!Array<!Certificate>} */
+ certificates: {
+ type: Array,
+ value: function() { return []; },
+ },
+
+ /** @type {!settings.CertificateType} */
+ certificateType: String,
+ },
+
+ behaviors: [I18nBehavior],
+
+ /**
+ * @return {string}
+ * @private
+ */
+ getDescription_: function() {
+ if (this.certificates.length == 0)
+ return this.i18n('certificateManagerNoCertificates');
+
+ switch (this.certificateType) {
+ case settings.CertificateType.PERSONAL:
+ return this.i18n('certificateManagerYourCertificatesDescription');
+ case settings.CertificateType.SERVER:
+ return this.i18n('certificateManagerServersDescription');
+ case settings.CertificateType.CA:
+ return this.i18n('certificateManagerAuthoritiesDescription');
+ case settings.CertificateType.OTHER:
+ return this.i18n('certificateManagerOthersDescription');
+ }
+
+ assertNotReached();
+ },
+
+ /**
+ * @return {boolean}
+ * @private
+ */
+ canImport_: function() {
+ return this.certificateType != settings.CertificateType.OTHER;
+ },
+
+ /**
+ * Handles a rejected Promise returned from |browserProxy_|.
+ * @param {null|!CertificatesError|!CertificatesImportError} error
+ * @private
+ */
+ onRejected_: function(error) {
+ if (error === null) {
+ // Nothing to do here. Null indicates that the user clicked "cancel" on
+ // a native file chooser dialog.
+ return;
+ }
+
+ // Otherwise propagate the error to the parents, such that a dialog
+ // displaying the error will be shown.
+ this.fire('certificates-error', error);
+ },
+
+
+ /**
+ * @param {?NewCertificateSubNode} subnode
+ * @private
+ */
+ dispatchImportActionEvent_: function(subnode) {
+ this.fire(
+ settings.CertificateActionEvent,
+ /** @type {!CertificateActionEventDetail} */ ({
+ action: settings.CertificateAction.IMPORT,
+ subnode: subnode,
+ certificateType: this.certificateType,
+ }));
+ },
+
+ /** @private */
+ onImportTap_: function() {
+ var browserProxy = settings.CertificatesBrowserProxyImpl.getInstance();
+ if (this.certificateType == settings.CertificateType.PERSONAL) {
+ browserProxy.importPersonalCertificate(false).then(
+ function(showPasswordPrompt) {
+ if (showPasswordPrompt)
+ this.dispatchImportActionEvent_(null);
+ }.bind(this),
+ this.onRejected_.bind(this));
+ } else if (this.certificateType == settings.CertificateType.CA) {
+ browserProxy.importCaCertificate().then(
+ function(certificateName) {
+ this.dispatchImportActionEvent_({name: certificateName});
+ }.bind(this),
+ this.onRejected_.bind(this));
+ } else if (this.certificateType == settings.CertificateType.SERVER) {
+ browserProxy.importServerCertificate().catch(
+ this.onRejected_.bind(this));
+ } else {
+ assertNotReached();
+ }
+ },
+});
diff --git a/chromium/chrome/browser/resources/settings/certificate_manager_page/certificate_manager_page.css b/chromium/chrome/browser/resources/settings/certificate_manager_page/certificate_manager_page.css
deleted file mode 100644
index 24b0ceb103d..00000000000
--- a/chromium/chrome/browser/resources/settings/certificate_manager_page/certificate_manager_page.css
+++ /dev/null
@@ -1,7 +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. */
-
-.privacy-buttons {
- margin-top: 25px;
-}
diff --git a/chromium/chrome/browser/resources/settings/certificate_manager_page/certificate_manager_page.html b/chromium/chrome/browser/resources/settings/certificate_manager_page/certificate_manager_page.html
index 70a5b6eae46..5e3d0eea365 100644
--- a/chromium/chrome/browser/resources/settings/certificate_manager_page/certificate_manager_page.html
+++ b/chromium/chrome/browser/resources/settings/certificate_manager_page/certificate_manager_page.html
@@ -1,73 +1,92 @@
-<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-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/paper-tabs/paper-tabs.html">
<link rel="import" href="chrome://resources/polymer/v1_0/iron-pages/iron-pages.html">
+<link rel="import" href="chrome://md-settings/certificate_manager_page/ca_trust_edit_dialog.html">
+<link rel="import" href="chrome://md-settings/certificate_manager_page/certificate_delete_confirmation_dialog.html">
+<link rel="import" href="chrome://md-settings/certificate_manager_page/certificate_list.html">
+<link rel="import" href="chrome://md-settings/certificate_manager_page/certificate_password_decryption_dialog.html">
+<link rel="import" href="chrome://md-settings/certificate_manager_page/certificate_password_encryption_dialog.html">
+<link rel="import" href="chrome://md-settings/certificate_manager_page/certificates_browser_proxy.html">
+<link rel="import" href="chrome://md-settings/certificate_manager_page/certificates_error_dialog.html">
<dom-module id="settings-certificate-manager-page">
- <link rel="import" type="css" href="certificate_manager_page.css">
<template>
- <paper-tabs selected="{{selected}}">
- <paper-tab i18n-content="certificateManagerYourCertificates"></paper-tab>
- <paper-tab i18n-content="certificateManagerServers"></paper-tab>
- <paper-tab i18n-content="certificateManagerAuthorities"></paper-tab>
- <paper-tab i18n-content="certificateManagerOthers"></paper-tab>
- </paper-tabs>
+ <style>
+ :host {
+ --paper-tabs-selection-bar-color: var(--paper-blue-500);
+ }
+
+ paper-tabs {
+ height: 40px;
+ margin-bottom: 24px;
+ }
+
+ paper-tab {
+ text-transform: uppercase;
+ }
+ </style>
- <iron-pages selected="{{selected}}">
+ <template is="dom-if" if="[[showCaTrustEditDialog_]]" restamp>
+ <settings-ca-trust-edit-dialog model="[[dialogModel_]]">
+ </settings-ca-trust-edit-dialog>
+ </template>
+ <template is="dom-if" if="[[showDeleteConfirmationDialog_]]" restamp>
+ <settings-certificate-delete-confirmation-dialog
+ model="[[dialogModel_]]"
+ certificate-type="[[dialogModelCertificateType_]]">
+ </settings-certificate-delete-confirmation-dialog>
+ </template>
+ <template is="dom-if" if="[[showPasswordEncryptionDialog_]]" restamp>
+ <settings-certificate-password-encryption-dialog
+ model="[[dialogModel_]]">
+ </settings-certificate-password-encryption-dialog>
+ </template>
+ <template is="dom-if" if="[[showPasswordDecryptionDialog_]]" restamp>
+ <settings-certificate-password-decryption-dialog>
+ </settings-certificate-password-decryption-dialog>
+ </template>
+ <template is="dom-if" if="[[showErrorDialog_]]" restamp>
+ <settings-certificates-error-dialog model="[[errorDialogModel_]]">
+ </settings-certificates-error-dialog>
+ </template>
+
+ <paper-tabs noink selected="{{selected}}">
+ <paper-tab>$i18n{certificateManagerYourCertificates}</paper-tab>
+ <paper-tab>$i18n{certificateManagerServers}</paper-tab>
+ <paper-tab>$i18n{certificateManagerAuthorities}</paper-tab>
+ <paper-tab>$i18n{certificateManagerOthers}</paper-tab>
+ </paper-tabs>
+ <iron-pages selected="[[selected]]">
<div>
- <div i18n-content="certificateManagerYourCertificatesSubtitle"></div>
- <div class="privacy-buttons layout horizontal end-justified">
- <paper-button i18n-content="certificateManagerView"></paper-button>
- <paper-button i18n-content="certificateManagerImport"></paper-button>
- <paper-button i18n-content="certificateManagerImportAndBind">
- </paper-button>
- <paper-button i18n-content="certificateManagerExport"></paper-button>
- <paper-button i18n-content="certificateManagerDelete"></paper-button>
- <span class="flex"></span>
- <paper-button raised i18n-content="certificateManagerDone">
- </paper-button>
- </div>
+ <settings-certificate-list id="personalCerts"
+ certificates="[[personalCerts]]"
+ certificate-type="[[certificateTypeEnum_.PERSONAL]]">
+ </settings-certificate-list>
</div>
<div>
- <div i18n-content="certificateManagerServersSubtitle"></div>
- <div class="privacy-buttons layout horizontal end-justified">
- <paper-button disabled i18n-content="certificateManagerView">
- </paper-button>
- <paper-button i18n-content="certificateManagerImport"></paper-button>
- <paper-button disabled i18n-content="certificateManagerExport">
- </paper-button>
- <paper-button disabled i18n-content="certificateManagerDelete">
- </paper-button>
- <span class="flex"></span>
- <paper-button raised i18n-content="certificateManagerDone">
- </paper-button>
- </div>
+ <template is="dom-if" if="[[isTabSelected_(selected, 1)]]">
+ <settings-certificate-list id="serverCerts"
+ certificates="[[serverCerts]]"
+ certificate-type="[[certificateTypeEnum_.SERVER]]">
+ </settings-certificate-list>
+ </template>
</div>
<div>
- <div i18n-content="certificateManagerAuthoritiesSubtitle"></div>
- <div class="privacy-buttons layout horizontal end-justified">
- <paper-button i18n-content="certificateManagerView"></paper-button>
- <paper-button i18n-content="certificateManagerImport"></paper-button>
- <paper-button i18n-content="certificateManagerExport"></paper-button>
- <paper-button i18n-content="certificateManagerDelete"></paper-button>
- <span class="flex"></span>
- <paper-button raised i18n-content="certificateManagerDone">
- </paper-button>
- </div>
+ <template is="dom-if" if="[[isTabSelected_(selected, 2)]]">
+ <settings-certificate-list id="caCerts"
+ certificates="[[caCerts]]"
+ certificate-type="[[certificateTypeEnum_.CA]]">
+ </settings-certificate-list>
+ </template>
</div>
<div>
- <div i18n-content="certificateManagerOthersSubtitle"></div>
- <div class="privacy-buttons layout horizontal end-justified">
- <paper-button disabled i18n-content="certificateManagerView">
- </paper-button>
- <paper-button disabled i18n-content="certificateManagerExport">
- </paper-button>
- <paper-button disabled i18n-content="certificateManagerDelete">
- </paper-button>
- <span class="flex"></span>
- <paper-button raised i18n-content="certificateManagerDone">
- </paper-button>
- </div>
+ <template is="dom-if" if="[[isTabSelected_(selected, 3)]]">
+ <settings-certificate-list id="otherCerts"
+ certificates="[[otherCerts]]"
+ certificate-type="[[certificateTypeEnum_.OTHER]]">
+ </settings-certificate-list>
+ </template>
</div>
</iron-pages>
</template>
diff --git a/chromium/chrome/browser/resources/settings/certificate_manager_page/certificate_manager_page.js b/chromium/chrome/browser/resources/settings/certificate_manager_page/certificate_manager_page.js
index 8c9f3134794..cc468ef480e 100644
--- a/chromium/chrome/browser/resources/settings/certificate_manager_page/certificate_manager_page.js
+++ b/chromium/chrome/browser/resources/settings/certificate_manager_page/certificate_manager_page.js
@@ -3,32 +3,164 @@
// found in the LICENSE file.
/**
- * @fileoverview
- * 'settings-certificate-manager-page' is the settings page containing SSL
- * certificate settings.
- *
- * Example:
- *
- * <iron-animated-pages>
- * <settings-certificate-manager-page prefs="{{prefs}}">
- * </settings-certificate-manager-page>
- * ... other pages ...
- * </iron-animated-pages>
- *
- * @group Chrome Settings Elements
- * @element settings-certificate-manager-page
+ * @fileoverview 'settings-certificate-manager-page' is the settings page
+ * containing SSL certificate settings.
*/
Polymer({
is: 'settings-certificate-manager-page',
+ behaviors: [WebUIListenerBehavior],
+
properties: {
- /**
- * Preferences state.
- * TODO(dschuyler) check whether this is necessary.
- */
- prefs: {
+ /** @type {number} */
+ selected: {
+ type: Number,
+ value: 0,
+ },
+
+ /** @type {!Array<!Certificate>} */
+ personalCerts: {
+ type: Array,
+ value: function() { return []; },
+ },
+
+ /** @type {!Array<!Certificate>} */
+ serverCerts: {
+ type: Array,
+ value: function() { return []; },
+ },
+
+ /** @type {!Array<!Certificate>} */
+ caCerts: {
+ type: Array,
+ value: function() { return []; },
+ },
+
+ /** @type {!Array<!Certificate>} */
+ otherCerts: {
+ type: Array,
+ value: function() { return []; },
+ },
+
+ /** @private */
+ certificateTypeEnum_: {
type: Object,
- notify: true,
+ value: settings.CertificateType,
+ readonly: true,
},
+
+ /** @private */
+ showCaTrustEditDialog_: Boolean,
+
+ /** @private */
+ showDeleteConfirmationDialog_: Boolean,
+
+ /** @private */
+ showPasswordEncryptionDialog_: Boolean,
+
+ /** @private */
+ showPasswordDecryptionDialog_: Boolean,
+
+ /** @private */
+ showErrorDialog_: Boolean,
+
+ /**
+ * The model to be passed to dialogs that refer to a given certificate.
+ * @private {?CertificateSubnode}
+ */
+ dialogModel_: Object,
+
+ /**
+ * The certificate type to be passed to dialogs that refer to a given
+ * certificate.
+ * @private {?settings.CertificateType}
+ */
+ dialogModelCertificateType_: String,
+
+ /**
+ * The model to be passed to the error dialog.
+ * @private {null|!CertificatesError|!CertificatesImportError}
+ */
+ errorDialogModel_: Object,
+ },
+
+ /** @override */
+ attached: function() {
+ this.addWebUIListener('certificates-changed', this.set.bind(this));
+ settings.CertificatesBrowserProxyImpl.getInstance().refreshCertificates();
+ },
+
+ /**
+ * @param {number} selectedIndex
+ * @param {number} tabIndex
+ * @return {boolean} Whether to show tab at |tabIndex|.
+ * @private
+ */
+ isTabSelected_: function(selectedIndex, tabIndex) {
+ return selectedIndex == tabIndex;
+ },
+
+ /** @override */
+ ready: function() {
+ this.addEventListener(settings.CertificateActionEvent, function(event) {
+ this.dialogModel_ = event.detail.subnode;
+ this.dialogModelCertificateType_ = event.detail.certificateType;
+
+ if (event.detail.action == settings.CertificateAction.IMPORT) {
+ if (event.detail.certificateType == settings.CertificateType.PERSONAL) {
+ this.openDialog_(
+ 'settings-certificate-password-decryption-dialog',
+ 'showPasswordDecryptionDialog_');
+ } else if (event.detail.certificateType ==
+ settings.CertificateType.CA) {
+ this.openDialog_(
+ 'settings-ca-trust-edit-dialog', 'showCaTrustEditDialog_');
+ }
+ } else {
+ if (event.detail.action == settings.CertificateAction.EDIT) {
+ this.openDialog_(
+ 'settings-ca-trust-edit-dialog', 'showCaTrustEditDialog_');
+ } else if (event.detail.action == settings.CertificateAction.DELETE) {
+ this.openDialog_(
+ 'settings-certificate-delete-confirmation-dialog',
+ 'showDeleteConfirmationDialog_');
+ } else if (event.detail.action ==
+ settings.CertificateAction.EXPORT_PERSONAL) {
+ this.openDialog_(
+ 'settings-certificate-password-encryption-dialog',
+ 'showPasswordEncryptionDialog_');
+ }
+ }
+
+ event.stopPropagation();
+ }.bind(this));
+
+ this.addEventListener('certificates-error', function(event) {
+ this.errorDialogModel_ = event.detail;
+ this.openDialog_(
+ 'settings-certificates-error-dialog',
+ 'showErrorDialog_');
+ event.stopPropagation();
+ }.bind(this));
+ },
+
+ /**
+ * Opens a 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').
+ *
+ * @param {string} dialogTagName The tag name of the dialog to be shown.
+ * @param {string} domIfBooleanName The name of the boolean variable
+ * corresponding to the dialog.
+ * @private
+ */
+ openDialog_: function(dialogTagName, domIfBooleanName) {
+ this.set(domIfBooleanName, true);
+ this.async(function() {
+ var dialog = this.$$(dialogTagName);
+ dialog.addEventListener('iron-overlay-closed', function() {
+ this.set(domIfBooleanName, false);
+ }.bind(this));
+ }.bind(this));
},
});
diff --git a/chromium/chrome/browser/resources/settings/certificate_manager_page/certificate_password_decryption_dialog.html b/chromium/chrome/browser/resources/settings/certificate_manager_page/certificate_password_decryption_dialog.html
new file mode 100644
index 00000000000..2957d2c8413
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/certificate_manager_page/certificate_password_decryption_dialog.html
@@ -0,0 +1,31 @@
+<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-input/paper-input.html">
+<link rel="import" href="chrome://md-settings/i18n_setup.html">
+<link rel="import" href="chrome://md-settings/settings_dialog.html">
+<link rel="import" href="chrome://md-settings/settings_shared_css.html">
+<link rel="import" href="chrome://md-settings/certificate_manager_page/certificates_browser_proxy.html">
+
+<dom-module id="settings-certificate-password-decryption-dialog">
+ <template>
+ <style include="settings-shared"></style>
+ <settings-dialog id="dialog">
+ <div class="title">$i18n{certificateManagerDecryptPasswordTitle}</div>
+ <div class="body">
+ <paper-input type="password" id="password"
+ label="$i18n{certificateManagerPassword}"
+ value="{{password_}}"></paper-input>
+ </div>
+ <div class="button-container">
+ <paper-button class="cancel-button" on-tap="onCancelTap_">
+ $i18n{cancel}
+ </paper-button>
+ <paper-button id="ok" class="action-button" on-tap="onOkTap_"
+ disabled="[[!password_.length]]">
+ $i18n{ok}
+ </paper-button>
+ </div>
+ </settings-dialog>
+ </template>
+ <script src="certificate_password_decryption_dialog.js"></script>
+</dom-module>
diff --git a/chromium/chrome/browser/resources/settings/certificate_manager_page/certificate_password_decryption_dialog.js b/chromium/chrome/browser/resources/settings/certificate_manager_page/certificate_password_decryption_dialog.js
new file mode 100644
index 00000000000..7eff4c4bd29
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/certificate_manager_page/certificate_password_decryption_dialog.js
@@ -0,0 +1,51 @@
+// 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 dialog prompting the user for a decryption password such that
+ * a previously exported personal certificate can be imported.
+ */
+Polymer({
+ is: 'settings-certificate-password-decryption-dialog',
+
+ properties: {
+ /** @private {!settings.CertificatesBrowserProxy} */
+ browserProxy_: Object,
+
+ /** @private */
+ password_: {
+ type: String,
+ value: '',
+ },
+ },
+
+ /** @override */
+ ready: function() {
+ this.browserProxy_ = settings.CertificatesBrowserProxyImpl.getInstance();
+ },
+
+ /** @override */
+ attached: function() {
+ this.$.dialog.open();
+ },
+
+ /** @private */
+ onCancelTap_: function() {
+ this.$.dialog.close();
+ },
+
+ /** @private */
+ onOkTap_: function() {
+ this.browserProxy_.importPersonalCertificatePasswordSelected(
+ this.password_).then(
+ function() {
+ this.$.dialog.close();
+ }.bind(this),
+ /** @param {!CertificatesError} error */
+ function(error) {
+ this.$.dialog.close();
+ this.fire('certificates-error', error);
+ }.bind(this));
+ },
+});
diff --git a/chromium/chrome/browser/resources/settings/certificate_manager_page/certificate_password_encryption_dialog.html b/chromium/chrome/browser/resources/settings/certificate_manager_page/certificate_password_encryption_dialog.html
new file mode 100644
index 00000000000..7b996f26044
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/certificate_manager_page/certificate_password_encryption_dialog.html
@@ -0,0 +1,41 @@
+<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-input/paper-input.html">
+<link rel="import" href="chrome://md-settings/i18n_setup.html">
+<link rel="import" href="chrome://md-settings/settings_dialog.html">
+<link rel="import" href="chrome://md-settings/settings_shared_css.html">
+<link rel="import" href="chrome://md-settings/certificate_manager_page/certificates_browser_proxy.html">
+
+<dom-module id="settings-certificate-password-encryption-dialog">
+ <template>
+ <style include="settings-shared">
+ .password-buttons {
+ margin-bottom: 20px;
+ }
+ </style>
+ <settings-dialog id="dialog">
+ <div class="title">$i18n{certificateManagerEncryptPasswordTitle}</div>
+ <div class="body">
+ <div>$i18n{certificateManagerEncryptPasswordDescription}</div>
+ <div class="password-buttons">
+ <paper-input type="password" value="{{password_}}" id="password"
+ label="$i18n{certificateManagerPassword}"
+ on-input="validate_"></paper-input>
+ <paper-input type="password"
+ value="{{confirmPassword_}}" id="confirmPassword"
+ label="$i18n{certificateManagerConfirmPassword}"
+ on-input="validate_"></paper-input>
+ </div>
+ </div>
+ <div class="button-container">
+ <paper-button class="cancel-button" on-tap="onCancelTap_">
+ $i18n{cancel}
+ </paper-button>
+ <paper-button id="ok" class="action-button" on-tap="onOkTap_" disabled>
+ $i18n{ok}
+ </paper-button>
+ </div>
+ </settings-dialog>
+ </template>
+ <script src="certificate_password_encryption_dialog.js"></script>
+</dom-module>
diff --git a/chromium/chrome/browser/resources/settings/certificate_manager_page/certificate_password_encryption_dialog.js b/chromium/chrome/browser/resources/settings/certificate_manager_page/certificate_password_encryption_dialog.js
new file mode 100644
index 00000000000..4d6803db55c
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/certificate_manager_page/certificate_password_encryption_dialog.js
@@ -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.
+
+/**
+ * @fileoverview A dialog prompting the user to encrypt a personal certificate
+ * before it is exported to disk.
+ */
+Polymer({
+ is: 'settings-certificate-password-encryption-dialog',
+
+ properties: {
+ /** @private {!settings.CertificatesBrowserProxy} */
+ browserProxy_: Object,
+
+ /** @type {!CertificateSubnode} */
+ model: Object,
+
+ /** @private */
+ password_: {
+ type: String,
+ value: '',
+ },
+
+ /** @private */
+ confirmPassword_: {
+ type: String,
+ value: '',
+ },
+ },
+
+ /** @override */
+ ready: function() {
+ this.browserProxy_ = settings.CertificatesBrowserProxyImpl.getInstance();
+ },
+
+ /** @override */
+ attached: function() {
+ this.$.dialog.open();
+ },
+
+ /** @private */
+ onCancelTap_: function() {
+ this.$.dialog.close();
+ },
+
+ /** @private */
+ onOkTap_: function() {
+ this.browserProxy_.exportPersonalCertificatePasswordSelected(
+ this.password_).then(
+ function() {
+ this.$.dialog.close();
+ }.bind(this),
+ /** @param {!CertificatesError} error */
+ function(error) {
+ this.$.dialog.close();
+ this.fire('certificates-error', error);
+ }.bind(this));
+ },
+
+ /** @private */
+ validate_: function() {
+ var isValid = this.password_ != '' &&
+ this.password_ == this.confirmPassword_;
+ this.$.ok.disabled = !isValid;
+ },
+});
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
new file mode 100644
index 00000000000..7f7d3732435
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/certificate_manager_page/certificate_subentry.html
@@ -0,0 +1,73 @@
+<link rel="import" href="chrome://resources/html/polymer.html">
+<link rel="import" href="chrome://md-settings/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-dropdown/iron-dropdown.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/iron-icons/iron-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://md-settings/settings_shared_css.html">
+
+<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;
+ }
+
+ .untrusted {
+ color: var(--settings-error-color);
+ font-weight: 500;
+ text-transform: uppercase;
+ -webkit-margin-end: 16px;
+ }
+
+ paper-item:hover {
+ background-color: var(--settings-hover-color);
+ }
+
+ :host([is-last]) .list-item {
+ border-bottom: none;
+ }
+ </style>
+ <div class="list-item underbar">
+ <div class="untrusted" hidden$="[[!model.untrusted]]">
+ $i18n{certificateManagerUntrusted}
+ </div>
+ <div class="name">[[model.name]]</div>
+ <paper-icon-button id="dots" icon="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="top" horizontal-align="right"
+ opened="{{menuOpened}}">
+ <div class="dropdown-content">
+ <paper-item id="view" on-tap="onViewTap_">
+ $i18n{certificateManagerView}
+ </paper-item>
+ <paper-item id="edit" hidden$="[[!canEdit_(certificateType, model)]]"
+ on-tap="onEditTap_">
+ $i18n{certificateManagerEdit}
+ </paper-item>
+ <paper-item id="export"
+ hidden$="[[!canExport_(certificateType, model)]]"
+ on-tap="onExportTap_">
+ $i18n{certificateManagerExport}
+ </paper-item>
+ <paper-item id="delete" hidden$="[[!canDelete_(model)]]"
+ on-tap="onDeleteTap_">
+ $i18n{certificateManagerDelete}
+ </paper-item>
+ </div>
+ </iron-dropdown>
+ </template>
+ <div>
+ </template>
+ <script src="certificate_subentry.js"></script>
+</dom-module>
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
new file mode 100644
index 00000000000..9405f103a94
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/certificate_manager_page/certificate_subentry.js
@@ -0,0 +1,179 @@
+// 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-certificate-subentry represents an SSL certificate
+ * sub-entry.
+ */
+
+/**
+ * The payload of the certificate-action event that is emitted from this
+ * component.
+ * @typedef {{
+ * action: !settings.CertificateAction,
+ * subnode: null|CertificateSubnode|NewCertificateSubNode,
+ * certificateType: !settings.CertificateType
+ * }}
+ */
+var CertificateActionEventDetail;
+
+cr.define('settings', function() {
+ /**
+ * Enumeration of actions that require a popup menu to be shown to the user.
+ * @enum {number}
+ */
+ var CertificateAction = {
+ DELETE: 0,
+ EDIT: 1,
+ EXPORT_PERSONAL: 2,
+ IMPORT: 3,
+ };
+
+ /**
+ * The name of the event that is fired when a menu item is tapped.
+ * @type {string}
+ */
+ var CertificateActionEvent = 'certificate-action';
+
+ return {
+ CertificateAction: CertificateAction,
+ CertificateActionEvent: CertificateActionEvent,
+ };
+});
+
+Polymer({
+ is: 'settings-certificate-subentry',
+
+ properties: {
+ /** @type {!CertificateSubnode>} */
+ model: Object,
+
+ /** @type {!settings.CertificateType} */
+ certificateType: String,
+ },
+
+ /** @private {!settings.CertificatesManagerBrowserProxy} */
+ browserProxy_: null,
+
+ /** @override */
+ created: function() {
+ this.browserProxy_ = settings.CertificatesBrowserProxyImpl.getInstance();
+ },
+
+ /**
+ * Dispatches an event indicating which certificate action was tapped. It is
+ * used by the parent of this element to display a modal dialog accordingly.
+ * @param {!settings.CertificateAction} action
+ * @private
+ */
+ dispatchCertificateActionEvent_: function(action) {
+ this.fire(
+ settings.CertificateActionEvent,
+ /** @type {!CertificateActionEventDetail} */ ({
+ action: action,
+ subnode: this.model,
+ certificateType: this.certificateType,
+ }));
+ },
+
+ /**
+ * Handles the case where a call to the browser resulted in a rejected
+ * promise.
+ * @param {?CertificatesError} error
+ * @private
+ */
+ onRejected_: function(error) {
+ if (error === null) {
+ // Nothing to do here. Null indicates that the user clicked "cancel" on
+ // the native file chooser dialog.
+ return;
+ }
+
+ // Otherwise propagate the error to the parents, such that a dialog
+ // displaying the error will be shown.
+ this.fire('certificates-error', error);
+ },
+
+ /**
+ * @param {!Event} event
+ * @private
+ */
+ onViewTap_: function(event) {
+ this.closePopupMenu_();
+ this.browserProxy_.viewCertificate(this.model.id);
+ },
+
+ /**
+ * @param {!Event} event
+ * @private
+ */
+ onEditTap_: function(event) {
+ this.closePopupMenu_();
+ this.dispatchCertificateActionEvent_(settings.CertificateAction.EDIT);
+ },
+
+ /**
+ * @param {!Event} event
+ * @private
+ */
+ onDeleteTap_: function(event) {
+ this.closePopupMenu_();
+ this.dispatchCertificateActionEvent_(settings.CertificateAction.DELETE);
+ },
+
+ /**
+ * @param {!Event} event
+ * @private
+ */
+ onExportTap_: function(event) {
+ this.closePopupMenu_();
+ if (this.certificateType == settings.CertificateType.PERSONAL) {
+ this.browserProxy_.exportPersonalCertificate(this.model.id).then(
+ function() {
+ this.dispatchCertificateActionEvent_(
+ settings.CertificateAction.EXPORT_PERSONAL);
+ }.bind(this),
+ this.onRejected_.bind(this));
+ } else {
+ this.browserProxy_.exportCertificate(this.model.id);
+ }
+ },
+
+ /**
+ * @param {!settings.CertificateType} certificateType
+ * @param {!CertificateSubnode} model
+ * @return {boolean} Whether the certificate can be edited.
+ * @private
+ */
+ canEdit_: function(certificateType, model) {
+ return certificateType == settings.CertificateType.CA && !model.policy;
+ },
+
+ /**
+ * @param {!settings.CertificateType} certificateType
+ * @param {!CertificateSubnode} model
+ * @return {boolean} Whether the certificate can be exported.
+ * @private
+ */
+ canExport_: function(certificateType, model) {
+ if (certificateType == settings.CertificateType.PERSONAL) {
+ return model.extractable;
+ }
+ return true;
+ },
+
+ /**
+ * @param {!CertificateSubnode} model
+ * @return {boolean} Whether the certificate can be deleted.
+ * @private
+ */
+ canDelete_: function(model) {
+ return !model.readonly && !model.policy;
+ },
+
+ /** @private */
+ closePopupMenu_: function() {
+ this.$$('iron-dropdown').close();
+ },
+});
diff --git a/chromium/chrome/browser/resources/settings/certificate_manager_page/certificates_browser_proxy.html b/chromium/chrome/browser/resources/settings/certificate_manager_page/certificates_browser_proxy.html
new file mode 100644
index 00000000000..b3bccdfce86
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/certificate_manager_page/certificates_browser_proxy.html
@@ -0,0 +1 @@
+<script src="chrome://md-settings/certificate_manager_page/certificates_browser_proxy.js"></script>
diff --git a/chromium/chrome/browser/resources/settings/certificate_manager_page/certificates_browser_proxy.js b/chromium/chrome/browser/resources/settings/certificate_manager_page/certificates_browser_proxy.js
new file mode 100644
index 00000000000..20474685379
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/certificate_manager_page/certificates_browser_proxy.js
@@ -0,0 +1,275 @@
+// 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 "Manage certificates" section
+ * to interact with the browser.
+ */
+
+/**
+ * @typedef {{
+ * extractable: boolean,
+ * id: string,
+ * name: string,
+ * policy: boolean,
+ * readonly: boolean,
+ * untrusted: boolean,
+ * }}
+ * @see chrome/browser/ui/webui/settings/certificates_handler.cc
+ */
+var CertificateSubnode;
+
+/**
+ * A data structure describing a certificate that is currently being imported,
+ * therefore it has no ID yet, but it has a name. Used within JS only.
+ * @typedef {{
+ * name: string,
+ * }}
+ */
+var NewCertificateSubNode;
+
+/**
+ * @typedef {{
+ * id: string,
+ * name: string,
+ * subnodes: !Array<!CertificateSubnode>
+ * }}
+ * @see chrome/browser/ui/webui/settings/certificates_handler.cc
+ */
+var Certificate;
+
+/**
+ * @typedef {{
+ * ssl: boolean,
+ * email: boolean,
+ * objSign: boolean
+ * }}
+ */
+var CaTrustInfo;
+
+/**
+ * Generic error returned from C++ via a Promise reject callback.
+ * @typedef {{
+ * title: string,
+ * description: string
+ * }}
+ * @see chrome/browser/ui/webui/settings/certificates_handler.cc
+ */
+var CertificatesError;
+
+
+/**
+ * Error returned from C++ via a Promise reject callback, when some certificates
+ * fail to be imported.
+ * @typedef {{
+ * title: string,
+ * description: string
+ * certificateErrors: !Array<{name: string, error: string}>
+ * }}
+ * @see chrome/browser/ui/webui/settings/certificates_handler.cc
+ */
+var CertificatesImportError;
+
+cr.define('settings', function() {
+ /**
+ * Enumeration of all possible certificate types.
+ * @enum {string}
+ */
+ var CertificateType = {
+ CA: 'ca',
+ OTHER: 'other',
+ PERSONAL: 'personal',
+ SERVER: 'server',
+ };
+
+ /** @interface */
+ function CertificatesBrowserProxy() {}
+
+ CertificatesBrowserProxy.prototype = {
+ /**
+ * Triggers 5 events in the following order
+ * 1x 'certificates-model-ready' event.
+ * 4x 'certificates-changed' event, one for each certificate category.
+ */
+ refreshCertificates: function() {},
+
+ /** @param {string} id */
+ viewCertificate: function(id) {},
+
+ /** @param {string} id */
+ exportCertificate: function(id) {},
+
+ /**
+ * @param {string} id
+ * @return {!Promise} A promise resolved when the certificate has been
+ * deleted successfully or rejected with a CertificatesError.
+ */
+ deleteCertificate: function(id) {},
+
+ /**
+ * @param {string} id
+ * @return {!Promise<!CaTrustInfo>}
+ */
+ getCaCertificateTrust: function(id) {},
+
+ /**
+ * @param {string} id
+ * @param {boolean} ssl
+ * @param {boolean} email
+ * @param {boolean} objSign
+ * @return {!Promise}
+ */
+ editCaCertificateTrust: function(id, ssl, email, objSign) {},
+
+ cancelImportExportCertificate: function() {},
+
+ /**
+ * @param {string} id
+ * @return {!Promise} A promise firing once the user has selected
+ * the export location. A prompt should be shown to asking for a
+ * password to use for encrypting the file. The password should be
+ * passed back via a call to
+ * exportPersonalCertificatePasswordSelected().
+ */
+ exportPersonalCertificate: function(id) {},
+
+ /**
+ * @param {string} password
+ * @return {!Promise}
+ */
+ exportPersonalCertificatePasswordSelected: function(password) {},
+
+ /**
+ * @param {boolean} useHardwareBacked
+ * @return {!Promise<boolean>} A promise firing once the user has selected
+ * the file to be imported. If true a password prompt should be shown to
+ * the user, and the password should be passed back via a call to
+ * importPersonalCertificatePasswordSelected().
+ */
+ importPersonalCertificate: function(useHardwareBacked) {},
+
+ /**
+ * @param {string} password
+ * @return {!Promise}
+ */
+ importPersonalCertificatePasswordSelected: function(password) {},
+
+ /**
+ * @return {!Promise} A promise firing once the user has selected
+ * the file to be imported, or failing with CertificatesError.
+ * Upon success, a prompt should be shown to the user to specify the
+ * trust levels, and that information should be passed back via a call
+ * to importCaCertificateTrustSelected().
+ */
+ importCaCertificate: function() {},
+
+ /**
+ * @param {boolean} ssl
+ * @param {boolean} email
+ * @param {boolean} objSign
+ * @return {!Promise} A promise firing once the trust level for the imported
+ * certificate has been successfully set. The promise is rejected if an
+ * error occurred with either a CertificatesError or
+ * CertificatesImportError.
+ */
+ importCaCertificateTrustSelected: function(ssl, email, objSign) {},
+
+ /**
+ * @return {!Promise} A promise firing once the certificate has been
+ * imported. The promise is rejected if an error occurred, with either
+ * a CertificatesError or CertificatesImportError.
+ */
+ importServerCertificate: function() {},
+ };
+
+ /**
+ * @constructor
+ * @implements {settings.CertificatesBrowserProxy}
+ */
+ function CertificatesBrowserProxyImpl() {}
+ // The singleton instance_ is replaced with a test version of this wrapper
+ // during testing.
+ cr.addSingletonGetter(CertificatesBrowserProxyImpl);
+
+ CertificatesBrowserProxyImpl.prototype = {
+ /** @override */
+ refreshCertificates: function() {
+ chrome.send('refreshCertificates');
+ },
+
+ /** @override */
+ viewCertificate: function(id) {
+ chrome.send('viewCertificate', [id]);
+ },
+
+ /** @override */
+ exportCertificate: function(id) {
+ chrome.send('exportCertificate', [id]);
+ },
+
+ /** @override */
+ deleteCertificate: function(id) {
+ return cr.sendWithPromise('deleteCertificate', id);
+ },
+
+ /** @override */
+ exportPersonalCertificate: function(id) {
+ return cr.sendWithPromise('exportPersonalCertificate', id);
+ },
+
+ /** @override */
+ exportPersonalCertificatePasswordSelected: function(password) {
+ return cr.sendWithPromise(
+ 'exportPersonalCertificatePasswordSelected', password);
+ },
+
+ /** @override */
+ importPersonalCertificate: function(useHardwareBacked) {
+ return cr.sendWithPromise('importPersonalCertificate', useHardwareBacked);
+ },
+
+ /** @override */
+ importPersonalCertificatePasswordSelected: function(password) {
+ return cr.sendWithPromise(
+ 'importPersonalCertificatePasswordSelected', password);
+ },
+
+ /** @override */
+ getCaCertificateTrust: function(id) {
+ return cr.sendWithPromise('getCaCertificateTrust', id);
+ },
+
+ /** @override */
+ editCaCertificateTrust: function(id, ssl, email, objSign) {
+ return cr.sendWithPromise(
+ 'editCaCertificateTrust', id, ssl, email, objSign);
+ },
+
+ /** @override */
+ importCaCertificateTrustSelected: function(ssl, email, objSign) {
+ return cr.sendWithPromise(
+ 'importCaCertificateTrustSelected', ssl, email, objSign);
+ },
+
+ /** @override */
+ cancelImportExportCertificate: function() {
+ chrome.send('cancelImportExportCertificate');
+ },
+
+ /** @override */
+ importCaCertificate: function() {
+ return cr.sendWithPromise('importCaCertificate');
+ },
+
+ /** @override */
+ importServerCertificate: function() {
+ return cr.sendWithPromise('importServerCertificate');
+ },
+ };
+
+ return {
+ CertificatesBrowserProxyImpl: CertificatesBrowserProxyImpl,
+ CertificateType: CertificateType,
+ };
+});
diff --git a/chromium/chrome/browser/resources/settings/certificate_manager_page/certificates_error_dialog.html b/chromium/chrome/browser/resources/settings/certificate_manager_page/certificates_error_dialog.html
new file mode 100644
index 00000000000..e0f532ad886
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/certificate_manager_page/certificates_error_dialog.html
@@ -0,0 +1,28 @@
+<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://md-settings/i18n_setup.html">
+<link rel="import" href="chrome://md-settings/settings_dialog.html">
+<link rel="import" href="chrome://md-settings/settings_shared_css.html">
+
+<dom-module id="settings-certificates-error-dialog">
+ <template>
+ <style include="settings-shared"></style>
+ <settings-dialog id="dialog">
+ <div class="title">[[model.title]]</div>
+ <div class="body">
+ <div>[[model.description]]</div>
+ <template is="dom-if" if="[[model.certificateErrors]]">
+ <template is="dom-repeat" items="[[model.certificateErrors]]">
+ <div>[[getCertificateErrorText_(item)]]</div>
+ </template>
+ </template>
+ </div>
+ <div class="button-container">
+ <paper-button id="ok" class="action-button" on-tap="onOkTap_">
+ $i18n{ok}
+ </paper-button>
+ </div>
+ </settings-dialog>
+ </template>
+ <script src="certificates_error_dialog.js"></script>
+</dom-module>
diff --git a/chromium/chrome/browser/resources/settings/certificate_manager_page/certificates_error_dialog.js b/chromium/chrome/browser/resources/settings/certificate_manager_page/certificates_error_dialog.js
new file mode 100644
index 00000000000..10069a2be58
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/certificate_manager_page/certificates_error_dialog.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.
+
+/**
+ * @fileoverview A dialog for showing SSL certificate related error messages.
+ * The user can only close the dialog, there is no other possible interaction.
+ */
+Polymer({
+ is: 'settings-certificates-error-dialog',
+
+ properties: {
+ /** @type {!CertificatesError|!CertificatesImportError} */
+ model: Object,
+ },
+
+ /** @override */
+ attached: function() {
+ this.$.dialog.open();
+ },
+
+ /** @private */
+ onOkTap_: function() {
+ this.$.dialog.close();
+ },
+
+ /**
+ * @param {{certificateName: string, error: string}} importError
+ * @return {string}
+ * @private
+ */
+ getCertificateErrorText_: function(importError) {
+ return loadTimeData.getStringF(
+ 'certificateImportErrorFormat', importError.name, importError.error);
+ },
+});
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
new file mode 100644
index 00000000000..360c5edebcf
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/clear_browsing_data_dialog/clear_browsing_data_dialog.html
@@ -0,0 +1,69 @@
+<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://md-settings/i18n_setup.html">
+<link rel="import" href="chrome://md-settings/controls/settings_checkbox.html">
+<link rel="import" href="chrome://md-settings/controls/settings_dropdown_menu.html">
+<link rel="import" href="chrome://md-settings/settings_dialog.html">
+<link rel="import" href="chrome://md-settings/settings_shared_css.html">
+
+<dom-module id="settings-clear-browsing-data-dialog">
+ <template>
+ <style include="settings-shared"></style>
+ <settings-dialog id="dialog" on-iron-overlay-closed="onDialogClosed_">
+ <div class="title" i18n-content="clearBrowsingData"></div>
+ <div class="body">
+ <div class="row">
+ <span class="start" i18n-content="clearFollowingItemsFrom"></span>
+ <settings-dropdown-menu id="clearFrom"
+ pref="{{prefs.browser.clear_data.time_period}}"
+ menu-options="[[clearFromOptions_]]" no-label-float>
+ </settings-dropdown-menu>
+ </div>
+ <settings-checkbox id="browsingCheckbox"
+ pref="{{prefs.browser.clear_data.browsing_history}}"
+ i18n-values="label:clearBrowsingHistory">
+ </settings-checkbox>
+ <settings-checkbox id="downloadCheckbox"
+ pref="{{prefs.browser.clear_data.download_history}}"
+ i18n-values="label:clearDownloadHistory">
+ </settings-checkbox>
+ <settings-checkbox
+ pref="{{prefs.browser.clear_data.cache}}"
+ i18n-values="label:clearCache">
+ </settings-checkbox>
+ <settings-checkbox
+ pref="{{prefs.browser.clear_data.cookies}}"
+ i18n-values="label:clearCookies">
+ </settings-checkbox>
+ <settings-checkbox
+ pref="{{prefs.browser.clear_data.passwords}}"
+ i18n-values="label:clearPasswords">
+ </settings-checkbox>
+ <settings-checkbox
+ pref="{{prefs.browser.clear_data.form_data}}"
+ i18n-values="label:clearFormData">
+ </settings-checkbox>
+ <settings-checkbox
+ pref="{{prefs.browser.clear_data.hosted_apps_data}}"
+ i18n-values="label:clearHostedAppData">
+ </settings-checkbox>
+ <settings-checkbox
+ pref="{{prefs.browser.clear_data.content_licenses}}"
+ i18n-values="label:clearDeauthorizeContentLicenses">
+ </settings-checkbox>
+ </div>
+ <div class="button-container">
+ <paper-button class="cancel-button" i18n-content="cancel"
+ dialog-dismiss></paper-button>
+ <paper-button class="action-button" id="clearDataButton"
+ i18n-content="clearBrowsingData" dialog-confirm>
+ </paper-button>
+ </div>
+ <div class="footer">
+ <span i18n-content="warnAboutNonClearedData"></span>
+ <span i18n-content="clearsSyncedData"></span>
+ </div>
+ </settings-dialog>
+ </template>
+ <script src="clear_browsing_data_dialog.js"></script>
+</dom-module>
diff --git a/chromium/chrome/browser/resources/settings/clear_browsing_data_page/clear_browsing_data_page.js b/chromium/chrome/browser/resources/settings/clear_browsing_data_dialog/clear_browsing_data_dialog.js
index 5a9b14c2c61..0d9f4de1dd6 100644
--- a/chromium/chrome/browser/resources/settings/clear_browsing_data_page/clear_browsing_data_page.js
+++ b/chromium/chrome/browser/resources/settings/clear_browsing_data_dialog/clear_browsing_data_dialog.js
@@ -14,12 +14,9 @@
* </settings-clear-browsing-data-page>
* ... other pages ...
* </iron-animated-pages>
- *
- * @group Chrome Settings Elements
- * @element settings-privacy-page
*/
Polymer({
- is: 'settings-clear-browsing-data-page',
+ is: 'settings-clear-browsing-data-dialog',
properties: {
/**
@@ -75,8 +72,7 @@ Polymer({
/** @private */
doneClearing_: function() {
- if (this.$)
- this.$.clearDataButton.disabled = false;
+ // TODO(dschuyler): inform the user on whether clearing data was successful.
},
/**
@@ -95,9 +91,16 @@ Polymer({
}
},
- /** @private */
- onPerformClearBrowsingDataTap_: function() {
- this.$.clearDataButton.disabled = true;
- chrome.send('performClearBrowserData');
+ open: function() {
+ this.$.dialog.open();
+ },
+
+ /**
+ * @param {!Event} event Tells us whether to perform an action or cancel.
+ * @private
+ */
+ onDialogClosed_: function(event) {
+ if (event.detail.confirmed)
+ chrome.send('performClearBrowserData');
},
});
diff --git a/chromium/chrome/browser/resources/settings/clear_browsing_data_page/clear_browsing_data_page.css b/chromium/chrome/browser/resources/settings/clear_browsing_data_page/clear_browsing_data_page.css
deleted file mode 100644
index cfa7986801d..00000000000
--- a/chromium/chrome/browser/resources/settings/clear_browsing_data_page/clear_browsing_data_page.css
+++ /dev/null
@@ -1,4 +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. */
-
diff --git a/chromium/chrome/browser/resources/settings/clear_browsing_data_page/clear_browsing_data_page.html b/chromium/chrome/browser/resources/settings/clear_browsing_data_page/clear_browsing_data_page.html
deleted file mode 100644
index 3edd6ddd88d..00000000000
--- a/chromium/chrome/browser/resources/settings/clear_browsing_data_page/clear_browsing_data_page.html
+++ /dev/null
@@ -1,64 +0,0 @@
-<link rel="import" href="chrome://resources/polymer/v1_0/polymer/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-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-dropdown-menu/paper-dropdown-menu.html">
-<link rel="import" href="chrome://md-settings/controls/settings_checkbox.html">
-<link rel="import" href="chrome://md-settings/controls/settings_dropdown_menu.html">
-
-<dom-module id="settings-clear-browsing-data-page">
- <link rel="import" type="css"
- href="chrome://md-settings/settings_shared.css">
- <link rel="import" type="css" href="clear_browsing_data_page.css">
- <template>
- <div class="settings-box">
- <span i18n-content="clearFollowingItemsFrom"></span>
- <settings-dropdown-menu id="clearFrom"
- pref="{{prefs.browser.clear_data.time_period}}"
- menu-options="[[clearFromOptions_]]">
- </settings-dropdown-menu>
- <settings-checkbox id="browsingCheckbox"
- pref="{{prefs.browser.clear_data.browsing_history}}"
- i18n-values="label:clearBrowsingHistory">
- </settings-checkbox>
- <settings-checkbox id="downloadCheckbox"
- pref="{{prefs.browser.clear_data.download_history}}"
- i18n-values="label:clearDownloadHistory">
- </settings-checkbox>
- <settings-checkbox
- pref="{{prefs.browser.clear_data.cache}}"
- i18n-values="label:clearCache">
- </settings-checkbox>
- <settings-checkbox
- pref="{{prefs.browser.clear_data.cookies}}"
- i18n-values="label:clearCookies">
- </settings-checkbox>
- <settings-checkbox
- pref="{{prefs.browser.clear_data.passwords}}"
- i18n-values="label:clearPasswords">
- </settings-checkbox>
- <settings-checkbox
- pref="{{prefs.browser.clear_data.form_data}}"
- i18n-values="label:clearFormData">
- </settings-checkbox>
- <settings-checkbox
- pref="{{prefs.browser.clear_data.hosted_apps_data}}"
- i18n-values="label:clearHostedAppData">
- </settings-checkbox>
- <settings-checkbox
- pref="{{prefs.browser.clear_data.content_licenses}}"
- i18n-values="label:clearDeauthorizeContentLicenses">
- </settings-checkbox>
- </settings-box>
- <span i18n-content="warnAboutNonClearedData"></span>
- <span i18n-content="clearsSyncedData"></span>
- </settings-box>
- <settings-box>
- <paper-button id="clearDataButton"
- on-tap="onPerformClearBrowsingDataTap_"
- raised i18n-content="clearBrowsingData">
- </paper-button>
- </div>
- </template>
- <script src="clear_browsing_data_page.js"></script>
-</dom-module>
diff --git a/chromium/chrome/browser/resources/settings/compiled_resources.gyp b/chromium/chrome/browser/resources/settings/compiled_resources.gyp
deleted file mode 100644
index a76bc54ce18..00000000000
--- a/chromium/chrome/browser/resources/settings/compiled_resources.gyp
+++ /dev/null
@@ -1,26 +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.
-{
- 'targets': [
- {
- 'target_name': 'settings_resources',
- 'type': 'none',
- 'dependencies': [
- 'appearance_page/compiled_resources.gyp:*',
- 'advanced_page/compiled_resources.gyp:*',
- 'basic_page/compiled_resources.gyp:*',
- 'bluetooth_page/compiled_resources.gyp:*',
- 'internet_page/compiled_resources.gyp:*',
- 'languages_page/compiled_resources.gyp:*',
- 'on_startup_page/compiled_resources.gyp:*',
- 'people_page/compiled_resources.gyp:*',
- 'prefs/compiled_resources.gyp:*',
- 'settings_page/compiled_resources.gyp:*',
- 'site_settings/compiled_resources.gyp:*',
- 'site_settings_page/compiled_resources.gyp:*',
- 'controls/compiled_resources.gyp:*',
- ],
- },
- ]
-}
diff --git a/chromium/chrome/browser/resources/settings/compiled_resources2.gyp b/chromium/chrome/browser/resources/settings/compiled_resources2.gyp
new file mode 100644
index 00000000000..f6f6c522984
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/compiled_resources2.gyp
@@ -0,0 +1,39 @@
+# 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': 'settings_resources',
+ 'type': 'none',
+ 'dependencies': [
+ 'advanced_page/compiled_resources2.gyp:*',
+ 'appearance_page/compiled_resources2.gyp:*',
+ 'basic_page/compiled_resources2.gyp:*',
+ 'bluetooth_page/compiled_resources2.gyp:*',
+ 'controls/compiled_resources2.gyp:*',
+ 'device_page/compiled_resources2.gyp:*',
+ 'internet_page/compiled_resources2.gyp:*',
+ 'languages_page/compiled_resources2.gyp:*',
+ 'on_startup_page/compiled_resources2.gyp:*',
+ 'passwords_and_forms_page/compiled_resources2.gyp:*',
+ 'people_page/compiled_resources2.gyp:*',
+ 'prefs/compiled_resources2.gyp:*',
+ 'reset_page/compiled_resources2.gyp:*',
+ 'settings_page/compiled_resources2.gyp:*',
+ 'site_settings/compiled_resources2.gyp:*',
+ 'site_settings_page/compiled_resources2.gyp:*',
+ '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'],
+ },
+ ],
+}
diff --git a/chromium/chrome/browser/resources/settings/controls/compiled_resources.gyp b/chromium/chrome/browser/resources/settings/controls/compiled_resources.gyp
deleted file mode 100644
index 7a9a788ca59..00000000000
--- a/chromium/chrome/browser/resources/settings/controls/compiled_resources.gyp
+++ /dev/null
@@ -1,67 +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.
-{
- 'targets': [
- {
- 'target_name': 'settings_checkbox',
- 'variables': {
- 'depends': [
- '../../../../../ui/webui/resources/cr_elements/policy/cr_policy_indicator_behavior.js',
- '../../../../../ui/webui/resources/cr_elements/policy/cr_policy_pref_behavior.js',
- '../../../../../ui/webui/resources/js/compiled_resources.gyp:assert',
- '../../../../../ui/webui/resources/js/compiled_resources.gyp:load_time_data',
- ],
- 'externs': [
- '../../../../../third_party/closure_compiler/externs/settings_private.js'
- ],
- },
- 'includes': ['../../../../../third_party/closure_compiler/compile_js.gypi'],
- },
- {
- 'target_name': 'settings_dropdown_menu',
- 'variables': {
- 'depends': [
- '../../../../../ui/webui/resources/js/compiled_resources.gyp:assert',
- '../../../../../ui/webui/resources/js/compiled_resources.gyp:cr',
- '../../../../../ui/webui/resources/js/compiled_resources.gyp:load_time_data',
- '../../../../../ui/webui/resources/js/i18n_behavior.js',
- '../prefs/pref_util.js',
- ],
- 'externs': [
- '../../../../../third_party/closure_compiler/externs/settings_private.js'
- ],
- },
- 'includes': ['../../../../../third_party/closure_compiler/compile_js.gypi'],
- },
- {
- 'target_name': 'settings_input',
- 'variables': {
- 'depends': [
- '../../../../../ui/webui/resources/cr_elements/policy/cr_policy_indicator_behavior.js',
- '../../../../../ui/webui/resources/cr_elements/policy/cr_policy_pref_behavior.js',
- '../../../../../ui/webui/resources/js/compiled_resources.gyp:assert',
- '../../../../../ui/webui/resources/js/compiled_resources.gyp:load_time_data',
- ],
- 'externs': [
- '../../../../../third_party/closure_compiler/externs/settings_private.js'
- ],
- },
- 'includes': ['../../../../../third_party/closure_compiler/compile_js.gypi'],
- },
- {
- 'target_name': 'settings_radio_group',
- 'variables': {
- 'depends': [
- '../../../../../ui/webui/resources/js/compiled_resources.gyp:assert',
- '../../../../../ui/webui/resources/js/compiled_resources.gyp:cr',
- '../prefs/pref_util.js',
- ],
- 'externs': [
- '../../../../../third_party/closure_compiler/externs/settings_private.js'
- ],
- },
- 'includes': ['../../../../../third_party/closure_compiler/compile_js.gypi'],
- },
- ],
-}
diff --git a/chromium/chrome/browser/resources/settings/controls/compiled_resources2.gyp b/chromium/chrome/browser/resources/settings/controls/compiled_resources2.gyp
new file mode 100644
index 00000000000..962857a6bb7
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/controls/compiled_resources2.gyp
@@ -0,0 +1,62 @@
+# 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': 'pref_control_behavior',
+ 'dependencies': [
+ '../prefs/compiled_resources2.gyp:prefs_types',
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'settings_checkbox',
+ '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',
+ 'pref_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',
+ '<(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:i18n_behavior',
+ '<(EXTERNS_GYP):settings_private',
+ '../prefs/compiled_resources2.gyp:pref_util',
+ 'pref_control_behavior',
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'settings_input',
+ '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',
+ 'pref_control_behavior',
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'settings_radio_group',
+ 'dependencies': [
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:assert',
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
+ '<(EXTERNS_GYP):settings_private',
+ '../prefs/compiled_resources2.gyp:pref_util',
+ 'pref_control_behavior',
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ ],
+}
diff --git a/chromium/chrome/browser/resources/settings/controls/pref_control_behavior.html b/chromium/chrome/browser/resources/settings/controls/pref_control_behavior.html
new file mode 100644
index 00000000000..4ddb3c88ecf
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/controls/pref_control_behavior.html
@@ -0,0 +1,3 @@
+<link rel="import" href="chrome://resources/html/polymer.html">
+<link rel="import" href="chrome://md-settings/prefs/prefs_types.html">
+<script src="pref_control_behavior.js"></script>
diff --git a/chromium/chrome/browser/resources/settings/controls/pref_control_behavior.js b/chromium/chrome/browser/resources/settings/controls/pref_control_behavior.js
new file mode 100644
index 00000000000..29da24c6647
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/controls/pref_control_behavior.js
@@ -0,0 +1,43 @@
+// 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.
+
+/**
+ * @polymerBehavior Tracks the initialization of a specified preference and
+ * logs an error if the pref is not defined after prefs have been fetched.
+ */
+var PrefControlBehavior = {
+ properties: {
+ /**
+ * The Preference object being tracked.
+ * @type {!chrome.settingsPrivate.PrefObject|undefined}
+ */
+ pref: {
+ type: Object,
+ notify: true,
+ observer: 'validatePref_',
+ },
+ },
+
+ /** @override */
+ ready: function() {
+ this.validatePref_();
+ },
+
+ /**
+ * Logs an error once prefs are initialized if the tracked pref is not found.
+ * @private
+ */
+ validatePref_: function() {
+ CrSettingsPrefs.initialized.then(function() {
+ if (!this.pref) {
+ var error = 'Pref not found for element ' + this.tagName;
+ if (this.id)
+ error += '#' + this.id;
+ error += ' in ' + this.domHost.tagName;
+ console.error(error);
+ }
+ }.bind(this));
+ },
+};
+
diff --git a/chromium/chrome/browser/resources/settings/controls/settings_checkbox.css b/chromium/chrome/browser/resources/settings/controls/settings_checkbox.css
deleted file mode 100644
index 9d1735b8048..00000000000
--- a/chromium/chrome/browser/resources/settings/controls/settings_checkbox.css
+++ /dev/null
@@ -1,21 +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. */
-
-:host {
- display: block;
- margin-bottom: 10px;
- margin-top: 10px;
-}
-
-#outerDiv {
- -webkit-margin-end: 10px;
-}
-
-#mainLabel {
- -webkit-margin-end: 10px;
-}
-
-#subLabel {
- color: rgba(0, 0, 0, .5);
-}
diff --git a/chromium/chrome/browser/resources/settings/controls/settings_checkbox.html b/chromium/chrome/browser/resources/settings/controls/settings_checkbox.html
index 5c30da8fc8b..15b0fb57890 100644
--- a/chromium/chrome/browser/resources/settings/controls/settings_checkbox.html
+++ b/chromium/chrome/browser/resources/settings/controls/settings_checkbox.html
@@ -1,22 +1,44 @@
-<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
+<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/cr_events/cr_events.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="chrome://md-settings/pref_tracker/pref_tracker.html">
+<link rel="import" href="chrome://md-settings/controls/pref_control_behavior.html">
+<link rel="import" href="chrome://md-settings/settings_shared_css.html">
<dom-module id="settings-checkbox">
<link rel="import" type="css" href="chrome://resources/cr_elements/shared.css">
- <link rel="import" type="css" href="settings_checkbox.css">
<template>
+ <style is="custom-style" include="settings-shared">
+ :host {
+ align-items: center;
+ display: flex;
+ min-height: 40px;
+ }
+
+ paper-checkbox {
+ --paper-checkbox-label-spacing: var(--checkbox-spacing);
+ --paper-checkbox-size: var(--checkbox-size);
+ --paper-checkbox-checked-color: var(--google-blue-500);
+ --paper-checkbox-unchecked-color: var(--paper-grey-600);
+ -webkit-margin-start: var(--checkbox-margin-start);
+ }
+
+ .secondary {
+ @apply(--settings-secondary);
+ }
+
+ cr-policy-pref-indicator {
+ -webkit-margin-start: var(--checkbox-spacing);
+ }
+ </style>
<cr-events id="events"></cr-events>
- <settings-pref-tracker pref="[[pref]]"></settings-pref-tracker>
- <div id="outerDiv" class="layout horizontal center">
+ <div class="layout horizontal center">
<paper-checkbox id="checkbox" checked="{{checked}}"
disabled="[[checkboxDisabled_(disabled, pref)]]">
- <div id="mainLabel">{{label}}</div>
- <div id="subLabel">{{subLabel}}</div>
+ <div>[[label]]</div>
+ <div class="secondary">[[subLabel]]</div>
</paper-checkbox>
<template is="dom-if" if="[[pref.policySource]]">
<cr-policy-pref-indicator pref="[[pref]]"></cr-policy-pref-indicator>
diff --git a/chromium/chrome/browser/resources/settings/controls/settings_checkbox.js b/chromium/chrome/browser/resources/settings/controls/settings_checkbox.js
index d0bbebc2507..34e89beb9a0 100644
--- a/chromium/chrome/browser/resources/settings/controls/settings_checkbox.js
+++ b/chromium/chrome/browser/resources/settings/controls/settings_checkbox.js
@@ -10,24 +10,13 @@
* <settings-checkbox pref="{{prefs.settings.enableFoo}}"
* label="Enable foo setting." subLabel="(bar also)">
* </settings-checkbox>
- *
- * @element settings-checkbox
*/
Polymer({
is: 'settings-checkbox',
- behaviors: [CrPolicyPrefBehavior],
+ behaviors: [CrPolicyPrefBehavior, PrefControlBehavior],
properties: {
- /**
- * The boolean preference object to control.
- * @type {!chrome.settingsPrivate.PrefObject|undefined}
- */
- pref: {
- type: Object,
- notify: true,
- },
-
/** Whether the checkbox should represent the inverted value. */
inverted: {
type: Boolean,
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 a7b2caa2176..65e00bfe1aa 100644
--- a/chromium/chrome/browser/resources/settings/controls/settings_dropdown_menu.html
+++ b/chromium/chrome/browser/resources/settings/controls/settings_dropdown_menu.html
@@ -1,16 +1,33 @@
-<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.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/paper-dropdown-menu/paper-dropdown-menu.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/html/i18n_behavior.html">
+<link rel="import" href="chrome://md-settings/controls/pref_control_behavior.html">
<link rel="import" href="chrome://md-settings/prefs/pref_util.html">
+<link rel="import" href="chrome://md-settings/settings_shared_css.html">
<dom-module id="settings-dropdown-menu">
- <link rel="import" type="css"
- href="chrome://md-settings/settings_shared.css">
<template>
+ <style include="settings-shared">
+ paper-item {
+ color: var(--paper-grey-800);
+ font-size: inherit;
+ }
+
+ paper-dropdown-menu {
+ --iron-icon-fill-color: var(--paper-grey-600);
+ --paper-font-subhead: {
+ font-size: inherit;
+ };
+ --paper-input-container-underline: {
+ background: var(--paper-grey-300);
+ };
+ width: 160px;
+ }
+ </style>
<paper-dropdown-menu id="dropdownMenu" label="[[menuLabel_]]"
- on-iron-select="onSelect_"
+ on-iron-select="onSelect_" no-label-float$="[[noLabelFloat]]"
disabled="[[shouldDisableMenu_(disabled, menuOptions.*)]]">
<paper-menu class="dropdown-content" selected="{{selected_}}"
attr-for-selected="data-value">
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 9bfa1d75a91..c26c9268712 100644
--- a/chromium/chrome/browser/resources/settings/controls/settings_dropdown_menu.js
+++ b/chromium/chrome/browser/resources/settings/controls/settings_dropdown_menu.js
@@ -25,9 +25,6 @@ var DropdownMenuOptionList;
*
* <settings-dropdown-menu pref="{{prefs.foo}}">
* </settings-dropdown-menu>
- *
- * @group Chrome Settings Elements
- * @element settings-dropdown-menu
*/
Polymer({
is: 'settings-dropdown-menu',
@@ -45,15 +42,6 @@ Polymer({
value: function() { return []; },
},
- /**
- * A single Preference object being tracked.
- * @type {!chrome.settingsPrivate.PrefObject|undefined}
- */
- pref: {
- type: Object,
- notify: true,
- },
-
/** Whether the dropdown menu should be disabled. */
disabled: {
type: Boolean,
@@ -88,6 +76,7 @@ Polymer({
behaviors: [
I18nBehavior,
+ PrefControlBehavior,
],
observers: [
diff --git a/chromium/chrome/browser/resources/settings/controls/settings_input.html b/chromium/chrome/browser/resources/settings/controls/settings_input.html
index 4154796dc36..94dc0c7dbca 100644
--- a/chromium/chrome/browser/resources/settings/controls/settings_input.html
+++ b/chromium/chrome/browser/resources/settings/controls/settings_input.html
@@ -1,16 +1,15 @@
-<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.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/cr_elements/cr_events/cr_events.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="chrome://md-settings/pref_tracker/pref_tracker.html">
+<link rel="import" href="chrome://md-settings/controls/pref_control_behavior.html">
<dom-module id="settings-input">
<link rel="import" type="css" href="chrome://resources/cr_elements/shared.css">
<link rel="import" type="css" href="settings_input.css">
<template>
<cr-events id="events"></cr-events>
- <settings-pref-tracker pref="[[pref]]"></settings-pref-tracker>
<div id="outerDiv" class="layout horizontal center">
<paper-input id="input" auto-validate value="{{value}}"
diff --git a/chromium/chrome/browser/resources/settings/controls/settings_input.js b/chromium/chrome/browser/resources/settings/controls/settings_input.js
index ab0cfe50c6b..37801d89220 100644
--- a/chromium/chrome/browser/resources/settings/controls/settings_input.js
+++ b/chromium/chrome/browser/resources/settings/controls/settings_input.js
@@ -6,22 +6,19 @@
* @fileoverview
* `settings-input` is a single-line text field for user input associated
* with a pref value.
- *
- * @element settings-input
*/
Polymer({
is: 'settings-input',
- behaviors: [CrPolicyPrefBehavior],
+ behaviors: [CrPolicyPrefBehavior, PrefControlBehavior],
properties: {
/**
* The preference object to control.
* @type {!chrome.settingsPrivate.PrefObject|undefined}
+ * @override
*/
pref: {
- type: Object,
- notify: true,
observer: 'prefChanged_'
},
diff --git a/chromium/chrome/browser/resources/settings/controls/settings_radio_group.html b/chromium/chrome/browser/resources/settings/controls/settings_radio_group.html
index d1697a9400e..a5a5143da02 100644
--- a/chromium/chrome/browser/resources/settings/controls/settings_radio_group.html
+++ b/chromium/chrome/browser/resources/settings/controls/settings_radio_group.html
@@ -1,11 +1,20 @@
-<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
+<link rel="import" href="chrome://resources/html/polymer.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-radio-group/paper-radio-group.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-radio-button/paper-radio-button.html">
+<link rel="import" href="chrome://md-settings/controls/pref_control_behavior.html">
<link rel="import" href="chrome://md-settings/prefs/pref_util.html">
<dom-module id="settings-radio-group">
<link rel="import" type="css" href="settings_radio_group.css">
<template>
+ <style is="custom-style">
+ :host ::content paper-radio-button {
+ @apply(--layout-center);
+ display: flex;
+ min-height: 40px;
+ padding: 0;
+ }
+ </style>
<div>[[label]]</div>
<paper-radio-group selected="{{selected}}">
<content></content>
diff --git a/chromium/chrome/browser/resources/settings/controls/settings_radio_group.js b/chromium/chrome/browser/resources/settings/controls/settings_radio_group.js
index 4f361182291..a9bc71dc07e 100644
--- a/chromium/chrome/browser/resources/settings/controls/settings_radio_group.js
+++ b/chromium/chrome/browser/resources/settings/controls/settings_radio_group.js
@@ -11,22 +11,13 @@
* <settings-radio-group pref="{{prefs.settings.foo}}"
* label="Foo Options." buttons="{{fooOptionsList}}">
* </settings-radio-group>
- *
- * @element settings-radio-group
*/
Polymer({
is: 'settings-radio-group',
- properties: {
- /**
- * The preference object to control.
- * @type {!chrome.settingsPrivate.PrefObject|undefined}
- */
- pref: {
- type: Object,
- notify: true,
- },
+ behaviors: [PrefControlBehavior],
+ properties: {
/**
* IronSelectableBehavior selected attribute.
*/
diff --git a/chromium/chrome/browser/resources/settings/date_time_page/date_time_page.css b/chromium/chrome/browser/resources/settings/date_time_page/date_time_page.css
deleted file mode 100644
index 64b2a421354..00000000000
--- a/chromium/chrome/browser/resources/settings/date_time_page/date_time_page.css
+++ /dev/null
@@ -1,14 +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. */
-
-.time-zone-label {
- -webkit-margin-end: 20px;
- -webkit-margin-start: 10px;
- margin-bottom: 10px;
- margin-top: 10px;
-}
-
-#setAutomatically {
- margin: 10px;
-}
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 0a298433f08..a935f11dd5b 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,20 +1,19 @@
-<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.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://md-settings/controls/settings_checkbox.html">
+<link rel="import" href="chrome://md-settings/settings_shared_css.html">
<dom-module id="settings-date-time-page">
- <link rel="import" type="css"
- href="chrome://md-settings/settings_shared.css">
- <link rel="import" type="css" href="date_time_page.css">
<template>
- <div class="horizontal layout center">
- <span class="time-zone-label" i18n-content="timeZone"></span>
+ <style include="settings-shared"></style>
+ <div class="settings-box first block">
+ <div i18n-content="timeZone"></div>
+ <settings-checkbox pref="{{prefs.settings.clock.use_24hour_clock}}"
+ i18n-values="label:use24HourClock">
+ </settings-checkbox>
+ <div id="setAutomatically" i18n-content="dateTimeSetAutomatically">
+ </div>
</div>
- <settings-checkbox pref="{{prefs.settings.clock.use_24hour_clock}}"
- i18n-values="label:use24HourClock">
- </settings-checkbox>
- <span id="setAutomatically" i18n-content="dateTimeSetAutomatically">
- </span>
</template>
<script src="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 cd0b5b7d1fd..0d8a7b4cbca 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
@@ -14,9 +14,6 @@
* </settings-date-time-page>
* ... other pages ...
* </core-animated-pages>
- *
- * @group Chrome Settings Elements
- * @element settings-date-time-page
*/
Polymer({
is: 'settings-date-time-page',
diff --git a/chromium/chrome/browser/resources/settings/default_browser_page/default_browser_page.css b/chromium/chrome/browser/resources/settings/default_browser_page/default_browser_page.css
index 3cd20531cab..f706f049345 100644
--- a/chromium/chrome/browser/resources/settings/default_browser_page/default_browser_page.css
+++ b/chromium/chrome/browser/resources/settings/default_browser_page/default_browser_page.css
@@ -3,5 +3,5 @@
* found in the LICENSE file. */
.error-icon {
- color: red;
+ color: var(--settings-error-color);
}
diff --git a/chromium/chrome/browser/resources/settings/default_browser_page/default_browser_page.html b/chromium/chrome/browser/resources/settings/default_browser_page/default_browser_page.html
index fc6351627e0..53000ef6cff 100644
--- a/chromium/chrome/browser/resources/settings/default_browser_page/default_browser_page.html
+++ b/chromium/chrome/browser/resources/settings/default_browser_page/default_browser_page.html
@@ -1,23 +1,27 @@
-<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.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-icon/iron-icon.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html">
-<link rel="import" href="chrome://resources/html/i18n_behavior.html">
+<link rel="import" href="chrome://md-settings/settings_shared_css.html">
<dom-module id="settings-default-browser-page">
- <link rel="import" type="css"
- href="chrome://md-settings/settings_shared.css">
<link rel="import" type="css" href="default_browser_page.css">
<template>
- <div class="settings-box">[[message_]]</div>
- <div class="settings-box">
+ <style include="settings-shared"></style>
+ <div class="settings-box first two-line">
<template is="dom-if" if="[[showButton_]]">
- <paper-button on-tap="onSetDefaultBrowserTap_"
- >[[i18n('defaultBrowserMakeDefault')]]</paper-button>
+ <div class="start" on-tap="onSetDefaultBrowserTap_">
+ <div>[[i18n('defaultBrowser')]]</div>
+ <div class="secondary">[[i18n('defaultBrowserMakeDefault')]]</div>
+ </div>
<template is="dom-if" if="[[showError_]]">
<iron-icon icon="error" class="error-icon"
title="[[i18n('unableToSetDefaultBrowser')]]"></iron-icon>
</template>
</template>
+ <template is="dom-if" if="[[!showButton_]]">
+ <div class="secondary">[[message_]]</div>
+ </template>
</div>
</template>
<script src="default_browser_page.js"></script>
diff --git a/chromium/chrome/browser/resources/settings/default_browser_page/default_browser_page.js b/chromium/chrome/browser/resources/settings/default_browser_page/default_browser_page.js
index 29b18b25314..694ece0ca9c 100644
--- a/chromium/chrome/browser/resources/settings/default_browser_page/default_browser_page.js
+++ b/chromium/chrome/browser/resources/settings/default_browser_page/default_browser_page.js
@@ -14,9 +14,6 @@
* </settings-default-browser-page>
* ... other pages ...
* </iron-animated-pages>
- *
- * @group Chrome Settings Elements
- * @element settings-default-browser-page
*/
Polymer({
is: 'settings-default-browser-page',
@@ -38,6 +35,15 @@ Polymer({
},
/**
+ * Indicates if the next updateDefaultBrowserState_ invocation is following
+ * a call to SettingsDefaultBrowser.setAsDefaultBrowser().
+ */
+ startedSetAsDefault_: {
+ type: Boolean,
+ value: false,
+ },
+
+ /**
* Show or hide an error indicator showing whether SetAsDefault succeeded.
*/
showError_: {
@@ -73,14 +79,6 @@ Polymer({
},
/**
- * @param {boolean} succeeded
- * @private
- */
- setAsDefaultConcluded_: function(succeeded) {
- this.showError_ = !succeeded;
- },
-
- /**
* @param {boolean} isDefault Whether Chrome is currently the user's default
* browser.
* @param {boolean} canBeDefault Whether Chrome can be the default browser on
@@ -88,18 +86,23 @@ Polymer({
* @private
*/
updateDefaultBrowserState_: function(isDefault, canBeDefault) {
- this.showButton_ = !isDefault && canBeDefault;
- if (canBeDefault) {
- this.message_ = loadTimeData.getString(isDefault ?
- 'defaultBrowserDefault' :
- 'defaultBrowserNotDefault');
+ if (this.startedSetAsDefault_ && !isDefault) {
+ this.startedSetAsDefault_ = false;
+ this.showError_ = true;
} else {
- this.message_ = loadTimeData.getString('defaultBrowserUnknown');
+ this.showError_ = false;
+ }
+
+ this.showButton_ = !isDefault && canBeDefault;
+ if (!this.showButton) {
+ this.message_ = loadTimeData.getString(
+ canBeDefault ? 'defaultBrowserDefault' : 'defaultBrowserUnknown');
}
},
/** @private */
onSetDefaultBrowserTap_: function() {
+ this.startedSetAsDefault_ = true;
chrome.send('SettingsDefaultBrowser.setAsDefaultBrowser');
},
});
diff --git a/chromium/chrome/browser/resources/settings/device_page/compiled_resources2.gyp b/chromium/chrome/browser/resources/settings/device_page/compiled_resources2.gyp
new file mode 100644
index 00000000000..67a7d9c82af
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/device_page/compiled_resources2.gyp
@@ -0,0 +1,37 @@
+# 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': 'device_page',
+ 'dependencies': [
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:i18n_behavior',
+ '../settings_page/compiled_resources2.gyp:settings_animated_pages',
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'touchpad',
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'keyboard',
+ 'dependencies': [
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:i18n_behavior',
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'display',
+ 'dependencies': [
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:i18n_behavior',
+ '<(EXTERNS_GYP):system_display',
+ '<(INTERFACES_GYP):system_display_interface',
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ ],
+}
diff --git a/chromium/chrome/browser/resources/settings/device_page/device_page.html b/chromium/chrome/browser/resources/settings/device_page/device_page.html
new file mode 100644
index 00000000000..d541f8d2613
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/device_page/device_page.html
@@ -0,0 +1,54 @@
+<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/iron-icons/hardware-icons.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/iron-icons/image-icons.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/neon-animation/neon-animatable.html">
+<link rel="import" href="chrome://md-settings/controls/settings_dropdown_menu.html">
+<link rel="import" href="chrome://md-settings/device_page/display.html">
+<link rel="import" href="chrome://md-settings/device_page/keyboard.html">
+<link rel="import" href="chrome://md-settings/device_page/touchpad.html">
+<link rel="import" href="chrome://md-settings/i18n_setup.html">
+<link rel="import" href="chrome://md-settings/prefs/prefs.html">
+<link rel="import" href="chrome://md-settings/settings_page/settings_animated_pages.html">
+<link rel="import" href="chrome://md-settings/settings_page/settings_subpage.html">
+<link rel="import" href="chrome://md-settings/settings_shared_css.html">
+
+<dom-module id="settings-device-page">
+ <template>
+ <style include="settings-shared"></style>
+ <settings-animated-pages id="pages" section="device"
+ current-route="{{currentRoute}}">
+ <neon-animatable id="main">
+ <div class="settings-box first" on-tap="onTouchpadTap_">
+ <!-- TODO(michaelpg): Get a touchpad icon. -->
+ <iron-icon icon="image:brightness-1"></iron-icon>
+ <div class="middle">$i18n{touchpadTitle}</div>
+ </div>
+ <div id="keyboardRow" class="settings-box" on-tap="onKeyboardTap_">
+ <iron-icon icon="hardware:keyboard"></iron-icon>
+ <div class="middle">$i18n{keyboardTitle}</div>
+ </div>
+ <div id="displayRow" class="settings-box" on-tap="onDisplayTap_">
+ <iron-icon icon="hardware:desktop-windows"></iron-icon>
+ <div class="middle">$i18n{displayTitle}</div>
+ </div>
+ </neon-animatable>
+ <template is="dom-if" name="touchpad">
+ <settings-subpage page-title="$i18n{touchpadTitle}">
+ <settings-touchpad prefs="{{prefs}}"></settings-touchpad>
+ </settings-subpage>
+ </template>
+ <template is="dom-if" name="keyboard">
+ <settings-subpage page-title="$i18n{keyboardTitle}">
+ <settings-keyboard prefs="{{prefs}}"></settings-keyboard>
+ </settings-subpage>
+ </template>
+ <template is="dom-if" name="display">
+ <settings-subpage page-title="$i18n{displayTitle}">
+ <settings-display></settings-display>
+ </settings-subpage>
+ </template>
+ </settings-animated-pages>
+ </template>
+ <script src="device_page.js"></script>
+</dom-module>
diff --git a/chromium/chrome/browser/resources/settings/device_page/device_page.js b/chromium/chrome/browser/resources/settings/device_page/device_page.js
new file mode 100644
index 00000000000..f11e2a7db9c
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/device_page/device_page.js
@@ -0,0 +1,49 @@
+// 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-device-page' is the settings page for device and
+ * peripheral settings.
+ */
+Polymer({
+ is: 'settings-device-page',
+
+ properties: {
+ /** The current active route. */
+ currentRoute: {
+ type: Object,
+ notify: true,
+ },
+
+ /** Preferences state. */
+ prefs: {
+ type: Object,
+ notify: true,
+ },
+ },
+
+ /**
+ * Handler for tapping the Touchpad settings menu item.
+ * @private
+ */
+ onTouchpadTap_: function() {
+ this.$.pages.setSubpageChain(['touchpad']);
+ },
+
+ /**
+ * Handler for tapping the Keyboard settings menu item.
+ * @private
+ */
+ onKeyboardTap_: function() {
+ this.$.pages.setSubpageChain(['keyboard']);
+ },
+
+ /**
+ * Handler for tapping the Display settings menu item.
+ * @private
+ */
+ onDisplayTap_: function() {
+ this.$.pages.setSubpageChain(['display']);
+ },
+});
diff --git a/chromium/chrome/browser/resources/settings/device_page/display.html b/chromium/chrome/browser/resources/settings/device_page/display.html
new file mode 100644
index 00000000000..14597761355
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/device_page/display.html
@@ -0,0 +1,72 @@
+<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-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.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-listbox/paper-listbox.html">
+<link rel="import" href="chrome://md-settings/settings_shared_css.html">
+
+<dom-module id="settings-display">
+ <template>
+ <style include="settings-shared">
+ .display-section {
+ @apply(--layout-self-start);
+ font-size: 100%;
+ font-weight: 500;
+ margin: 10px 0;
+ }
+
+ .settings-box.embedded {
+ margin-left: 20px;
+ padding: 0;
+ }
+
+ /* TODO(stevenjb): Placeholder */
+ .display-area {
+ border: lightgrey solid 1px;
+ height: 300px;
+ margin: 10px;
+ width: 600px;
+ }
+ </style>
+ <div class="settings-box first layout vertical">
+ <div class="display-section">$i18n{displayArrangement}</div>
+ <!-- TODO(stevenjb): Placeholder -->
+ <div class="display-area"></div>
+ </div>
+ <div class="settings-box layout vertical">
+ <div class="display-section">[[selectedDisplay.name]]</div>
+ <div class="settings-box embedded first self-stretch"
+ hidden$="[[!hasMultipleDisplays_(displays)]]">
+ <paper-checkbox class="flex" checked="[[isMirrored_(selectedDisplay)]]">
+ $i18n{displayMirror}
+ </paper-checkbox>
+ <paper-button hidden$="[[selectedDisplay.isPrimary]]">
+ $i18n{displayMakePrimary}
+ </paper-button>
+ </div>
+ <div class="settings-box embedded self-stretch">
+ <div class="start">$i18n{displayResolution}</div>
+ <!-- TODO(stevenjb): Implement -->
+ <paper-slider disabled></paper-slider>
+ </div>
+ <div class="settings-box embedded self-stretch">
+ <div class="start">$i18n{displayOrientation}</div>
+ <paper-dropdown-menu>
+ <paper-listbox class="dropdown-content"
+ selected="[[selectedDisplay.rotation]]"
+ attr-for-selected="value"
+ on-iron-activate="onSetOrientation_">
+ <paper-item value="0">$i18n{displayOrientationStandard}
+ </paper-item>
+ <paper-item value="90">90</paper-item>
+ <paper-item value="180">180</paper-item>
+ <paper-item value="270">270</paper-item>
+ </paper-listbox>
+ </paper-dropdown-menu>
+ </div>
+ </div>
+ </template>
+ <script src="display.js"></script>
+</dom-module>
diff --git a/chromium/chrome/browser/resources/settings/device_page/display.js b/chromium/chrome/browser/resources/settings/device_page/display.js
new file mode 100644
index 00000000000..3c2edb20b47
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/device_page/display.js
@@ -0,0 +1,100 @@
+// 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-display' is the settings subpage for display settings.
+ *
+ * @group Chrome Settings Elements
+ */
+
+cr.define('settings.display', function() {
+ var systemDisplayApi = /** @type {!SystemDisplay} */ (chrome.system.display);
+
+ return {
+ systemDisplayApi: systemDisplayApi,
+ };
+});
+
+Polymer({
+ is: 'settings-display',
+
+ behaviors: [
+ I18nBehavior,
+ ],
+
+ properties: {
+ /**
+ * Map of displays by id.
+ * @type {!Object<!chrome.system.display.DisplayUnitInfo>}
+ */
+ displays: Object,
+
+ /** Primary display id */
+ primaryDisplayId: String,
+
+ /**
+ * Selected display
+ * @type {!chrome.system.display.DisplayUnitInfo|undefined}
+ */
+ selectedDisplay: Object,
+ },
+
+ /**
+ * Listener for chrome.system.display.onDisplayChanged events.
+ * @type {function(void)|undefined}
+ * @private
+ */
+ displayChangedListener_: undefined,
+
+ /** @override */
+ attached: function() {
+ this.displayChangedListener_ = this.getDisplayInfo_.bind(this);
+ settings.display.systemDisplayApi.onDisplayChanged.addListener(
+ this.displayChangedListener_);
+ this.getDisplayInfo_();
+ },
+
+ /** @override */
+ detached: function() {
+ if (this.displayChangedListener_) {
+ settings.display.systemDisplayApi.onDisplayChanged.removeListener(
+ this.displayChangedListener_);
+ }
+ },
+
+ /** @private */
+ getDisplayInfo_: function() {
+ settings.display.systemDisplayApi.getInfo(
+ this.updateDisplayInfo_.bind(this));
+ },
+
+ /** @private */
+ hasMultipleDisplays_: function(displays) {
+ return Object.keys(displays).length > 1;
+ },
+
+ /** @private */
+ isMirrored_: function(selectedDisplay) {
+ return !!this.selectedDisplay.mirroringSourceId;
+ },
+
+ /**
+ * @param {!Array<!chrome.system.display.DisplayUnitInfo>} displaysArray
+ * @private
+ */
+ updateDisplayInfo_(displaysArray) {
+ var displays = {};
+ this.primaryDisplayId = '';
+ for (var i = 0; i < displaysArray.length; ++i) {
+ var display = displaysArray[i];
+ displays[display.id] = display;
+ if (display.isPrimary && !this.primaryDisplayId)
+ this.primaryDisplayId = display.id;
+ }
+ this.displays = displays;
+ // Always update selectedDisplay.
+ this.selectedDisplay = this.displays[this.primaryDisplayId];
+ },
+});
diff --git a/chromium/chrome/browser/resources/settings/device_page/keyboard.html b/chromium/chrome/browser/resources/settings/device_page/keyboard.html
new file mode 100644
index 00000000000..75187a21cbc
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/device_page/keyboard.html
@@ -0,0 +1,61 @@
+<link rel="import" href="chrome://resources/html/polymer.html">
+<link rel="import" href="chrome://resources/html/i18n_behavior.html">
+<link rel="import" href="chrome://md-settings/controls/settings_checkbox.html">
+<link rel="import" href="chrome://md-settings/controls/settings_dropdown_menu.html">
+<link rel="import" href="chrome://md-settings/settings_shared_css.html">
+
+<dom-module id="settings-keyboard">
+ <template>
+ <style include="settings-shared"></style>
+ <div class="settings-box first">
+ <div class="start">[[i18n('keyboardKeySearch')]]</div>
+ <settings-dropdown-menu
+ pref="{{prefs.settings.language.xkb_remap_search_key_to}}"
+ menu-options="[[keyMapTargetsWithCapsLock_]]">
+ </settings-dropdown-menu>
+ </div>
+ <div class="settings-box">
+ <div class="start">[[i18n('keyboardKeyCtrl')]]</div>
+ <settings-dropdown-menu
+ pref="{{prefs.settings.language.xkb_remap_control_key_to}}"
+ menu-options="[[keyMapTargets_]]">
+ </settings-dropdown-menu>
+ </div>
+ <div class="settings-box">
+ <div class="start">[[i18n('keyboardKeyAlt')]]</div>
+ <settings-dropdown-menu
+ pref="{{prefs.settings.language.xkb_remap_alt_key_to}}"
+ menu-options="[[keyMapTargets_]]">
+ </settings-dropdown-menu>
+ </div>
+ <template is="dom-if" if="[[showCapsLock_]]">
+ <div class="settings-box" id="capsLockKey">
+ <div class="start">[[i18n('keyboardKeyCapsLock')]]</div>
+ <settings-dropdown-menu
+ pref="{{prefs.settings.language.remap_caps_lock_key_to}}"
+ menu-options="[[keyMapTargetsWithCapsLock_]]">
+ </settings-dropdown-menu>
+ </div>
+ </template>
+ <template is="dom-if" if="[[showDiamondKey_]]">
+ <div class="settings-box" id="diamondKey">
+ <div class="start">[[i18n('keyboardKeyDiamond')]]</div>
+ <settings-dropdown-menu
+ pref="{{prefs.settings.language.remap_diamond_key_to}}"
+ menu-options="[[keyMapTargets_]]">
+ </settings-dropdown-menu>
+ </div>
+ </template>
+ <div class="settings-box two-line">
+ <settings-checkbox
+ pref="{{prefs.settings.language.send_function_keys}}"
+ label="[[i18n('keyboardSendFunctionKeys')]]"
+ sub-label="[[i18n('keyboardSendFunctionKeysDescription')]]">
+ </settings-checkbox>
+ </div>
+ <!-- TODO(michaelpg): Auto-repeat options. -->
+ <!-- TODO(michaelpg): Keyboard shortcuts button. -->
+ <!-- TODO(michaelpg): Language & input button. -->
+ </template>
+ <script src="keyboard.js"></script>
+</dom-module>
diff --git a/chromium/chrome/browser/resources/settings/device_page/keyboard.js b/chromium/chrome/browser/resources/settings/device_page/keyboard.js
new file mode 100644
index 00000000000..0c538902414
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/device_page/keyboard.js
@@ -0,0 +1,87 @@
+// 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-keyboard' is the settings subpage with keyboard 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;
+
+Polymer({
+ is: 'settings-keyboard',
+
+ behaviors: [
+ I18nBehavior,
+ ],
+
+ properties: {
+ /** Preferences state. */
+ prefs: {
+ type: Object,
+ notify: true,
+ },
+
+ /** @private Whether to show Caps Lock options. */
+ showCapsLock_: Boolean,
+
+ /** @private Whether to show diamond key options. */
+ showDiamondKey_: Boolean,
+
+ /** @private {!DropdownMenuOptionList} Menu items for key mapping. */
+ keyMapTargets_: Object,
+
+ /**
+ * @private {!DropdownMenuOptionList} Menu items for key mapping, including
+ * Caps Lock.
+ */
+ keyMapTargetsWithCapsLock_: Object,
+ },
+
+ /** @override */
+ ready: function() {
+ cr.addWebUIListener('show-keys-changed', this.onShowKeysChange_.bind(this));
+ chrome.send('initializeKeyboardSettings');
+ this.setUpKeyMapTargets_();
+ },
+
+ /**
+ * Initializes the dropdown menu options for remapping keys.
+ * @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;
+ },
+
+ /**
+ * Handler for updating which keys to show.
+ * @param {boolean} showCapsLock
+ * @param {boolean} showDiamondKey
+ * @private
+ */
+ onShowKeysChange_: function(showCapsLock, showDiamondKey) {
+ this.showCapsLock_ = showCapsLock;
+ this.showDiamondKey_ = showDiamondKey;
+ },
+});
diff --git a/chromium/chrome/browser/resources/settings/device_page/touchpad.html b/chromium/chrome/browser/resources/settings/device_page/touchpad.html
new file mode 100644
index 00000000000..af7a0fa6a31
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/device_page/touchpad.html
@@ -0,0 +1,33 @@
+<link rel="import" href="chrome://resources/polymer/v1_0/iron-selector/iron-selector.html">
+<link rel="import" href="chrome://resources/html/polymer.html">
+<link rel="import" href="chrome://md-settings/controls/settings_checkbox.html">
+<link rel="import" href="chrome://md-settings/controls/settings_radio_group.html">
+<link rel="import" href="chrome://md-settings/settings_shared_css.html">
+
+<dom-module id="settings-touchpad">
+ <template>
+ <style include="settings-shared"></style>
+ <!-- TODO(michaelpg): Add touchpad speed slider. -->
+ <div class="settings-box block first">
+ <settings-checkbox pref="{{prefs.settings.touchpad.enable_tap_to_click}}"
+ i18n-values="label:touchpadTapToClickEnabledLabel">
+ </settings-checkbox>
+ <settings-checkbox pref="{{prefs.settings.touchpad.enable_tap_dragging}}"
+ i18n-values="label:tapDraggingLabel">
+ </settings-checkbox>
+ </div>
+ <div class="settings-box" i18n-content="scrollLabel"></div>
+ <div class="list-frame">
+ <settings-radio-group pref="{{prefs.settings.touchpad.natural_scroll}}">
+ <paper-radio-button name="false" i18n-content="traditionalScrollLabel">
+ </paper-radio-button>
+ <!-- TODO(michaelpg): Make link inside label clickable.
+ https://github.com/PolymerElements/paper-radio-button/issues/86
+ -->
+ <paper-radio-button name="true"
+ i18n-values=".innerHTML:naturalScrollLabel"></paper-radio-button>
+ </settings-radio-group>
+ </div>
+ </template>
+ <script src="touchpad.js"></script>
+</dom-module>
diff --git a/chromium/chrome/browser/resources/settings/device_page/touchpad.js b/chromium/chrome/browser/resources/settings/device_page/touchpad.js
new file mode 100644
index 00000000000..b0b3183f194
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/device_page/touchpad.js
@@ -0,0 +1,19 @@
+// 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-touchpad' is the settings subpage with touchpad settings.
+ */
+Polymer({
+ is: 'settings-touchpad',
+
+ properties: {
+ /** Preferences state. */
+ prefs: {
+ type: Object,
+ notify: true,
+ },
+ },
+});
diff --git a/chromium/chrome/browser/resources/settings/direction_delegate.html b/chromium/chrome/browser/resources/settings/direction_delegate.html
new file mode 100644
index 00000000000..31d9f3301de
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/direction_delegate.html
@@ -0,0 +1,4 @@
+<link rel="import" href="chrome://md-settings/i18n_setup.html">
+<link rel="import" href="chrome://resources/html/assert.html">
+<link rel="import" href="chrome://resources/html/cr.html">
+<script src="chrome://md-settings/direction_delegate.js"></script>
diff --git a/chromium/chrome/browser/resources/settings/direction_delegate.js b/chromium/chrome/browser/resources/settings/direction_delegate.js
new file mode 100644
index 00000000000..3b8020a3562
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/direction_delegate.js
@@ -0,0 +1,29 @@
+// 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.exportPath('settings');
+
+/** @interface */
+settings.DirectionDelegate = function() {};
+
+settings.DirectionDelegate.prototype = {
+ /**
+ * @return {boolean} Whether the direction of the settings UI is
+ * right-to-left.
+ */
+ isRtl: assertNotReached,
+};
+
+/**
+ * @implements {settings.DirectionDelegate}
+ * @constructor
+ */
+settings.DirectionDelegateImpl = function() {};
+
+settings.DirectionDelegateImpl.prototype = {
+ /** @override */
+ isRtl: function() {
+ return loadTimeData.getString('textdirection') == 'rtl';
+ },
+};
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 0f81e6762c8..c09ef403936 100644
--- a/chromium/chrome/browser/resources/settings/downloads_page/downloads_page.html
+++ b/chromium/chrome/browser/resources/settings/downloads_page/downloads_page.html
@@ -1,30 +1,33 @@
-<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.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://md-settings/controls/settings_checkbox.html">
<link rel="import" href="chrome://md-settings/controls/settings_input.html">
+<link rel="import" href="chrome://md-settings/settings_shared_css.html">
<dom-module id="settings-downloads-page">
- <link rel="import" type="css"
- href="chrome://md-settings/settings_shared.css">
<link rel="import" type="css" href="downloads_page.css">
<template>
- <div class="settings-box split">
- <div class="start layout horizontal center">
- <div id="locationLabel" i18n-content="downloadLocation"></div>
- <settings-input id="downloadsPath" no-label-float readonly
- pref="{{prefs.download.default_directory}}"
- aria-labelledby="locationLabel">
- </settings-input>
+ <style include="settings-shared"></style>
+ <div class="settings-box first two-line">
+ <div class="start">
+ <div>$i18n{downloadLocation}</div>
+ <div class="secondary">[[prefs.download.default_directory.value]]</div>
</div>
- <paper-button id="changeDownloadsPath" on-tap="selectDownloadLocation_"
- i18n-content="changeDownloadLocation">
+ <paper-button class="secondary-action" id="changeDownloadsPath"
+ on-tap="selectDownloadLocation_">
+ $i18n{changeDownloadLocation}
</paper-button>
</div>
- <div class="settings-box">
+ <div class="settings-box block">
<settings-checkbox pref="{{prefs.download.prompt_for_download}}"
- i18n-values="label:promptForDownload">
+ label="$i18n{promptForDownload}">
</settings-checkbox>
+<if expr="chromeos">
+ <settings-checkbox pref="{{prefs.gdata.disabled}}"
+ label="$i18n{disconnectGoogleDriveAccount}">
+ </settings-checkbox>
+</if>
</div>
</template>
<script src="downloads_page.js"></script>
diff --git a/chromium/chrome/browser/resources/settings/downloads_page/downloads_page.js b/chromium/chrome/browser/resources/settings/downloads_page/downloads_page.js
index a12d76d34b3..2442cfc7a14 100644
--- a/chromium/chrome/browser/resources/settings/downloads_page/downloads_page.js
+++ b/chromium/chrome/browser/resources/settings/downloads_page/downloads_page.js
@@ -14,9 +14,6 @@
* </settings-downloads-page>
* ... other pages ...
* </iron-animated-pages>
- *
- * @group Chrome Settings Elements
- * @element settings-downloads-page
*/
Polymer({
is: 'settings-downloads-page',
diff --git a/chromium/chrome/browser/resources/settings/icons.html b/chromium/chrome/browser/resources/settings/icons.html
index a2414c1353d..d4b7ee25f1b 100644
--- a/chromium/chrome/browser/resources/settings/icons.html
+++ b/chromium/chrome/browser/resources/settings/icons.html
@@ -1,4 +1,4 @@
-<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
+<link rel="import" href="chrome://resources/html/polymer.html">
<link rel="import" href="chrome://resources/polymer/v1_0/iron-iconset-svg/iron-iconset-svg.html">
<iron-iconset-svg name="md-settings-icons" size="48">
@@ -12,6 +12,11 @@
</g>
</g>
</g>
+
+ <g id="search" stroke="none" stroke-width="1" fill="#ffffff">
+ <path d="M31 28h-1.59l-.55-.55C30.82 25.18 32 22.23 32 19c0-7.18-5.82-13-13-13S6 11.82 6 19s5.82 13 13 13c3.23 0 6.18-1.18 8.45-3.13l.55.55V31l10 9.98L40.98 38 31 28zm-12 0c-4.97 0-9-4.03-9-9s4.03-9 9-9 9 4.03 9 9-4.03 9-9 9z"></path>
+ <path d="M0 0h48v48H0z" fill="none"></path>
+ </g>
</defs>
</svg>
</iron-icon-set>
diff --git a/chromium/chrome/browser/resources/settings/internet_page/compiled_resources.gyp b/chromium/chrome/browser/resources/settings/internet_page/compiled_resources.gyp
deleted file mode 100644
index 0b3580a40e1..00000000000
--- a/chromium/chrome/browser/resources/settings/internet_page/compiled_resources.gyp
+++ /dev/null
@@ -1,190 +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.
-{
- 'targets': [
- {
- 'target_name': 'internet_page',
- 'variables': {
- 'depends': [
- '../../../../../third_party/closure_compiler/externs/networking_private_interface.js',
- '../../../../../ui/webui/resources/cr_elements/network/cr_onc_types.js',
- '../../../../../ui/webui/resources/js/compiled_resources.gyp:assert',
- '../../../../../ui/webui/resources/js/compiled_resources.gyp:load_time_data',
- '../settings_page/settings_animated_pages.js'
- ],
- 'externs': [
- '../../../../../third_party/closure_compiler/externs/networking_private.js'
- ],
- },
- 'includes': ['../../../../../third_party/closure_compiler/compile_js.gypi'],
- },
- {
- 'target_name': 'internet_detail_page',
- 'variables': {
- 'depends': [
- '../../../../../third_party/closure_compiler/externs/networking_private_interface.js',
- '../../../../../ui/webui/resources/cr_elements/network/cr_onc_types.js',
- '../../../../../ui/webui/resources/cr_elements/policy/cr_policy_network_behavior.js',
- '../../../../../ui/webui/resources/js/compiled_resources.gyp:assert',
- '../../../../../ui/webui/resources/js/compiled_resources.gyp:load_time_data',
- ],
- 'externs': [
- '../../../../../third_party/closure_compiler/externs/networking_private.js'
- ],
- },
- 'includes': ['../../../../../third_party/closure_compiler/compile_js.gypi'],
- },
- {
- 'target_name': 'internet_known_networks_page',
- 'variables': {
- 'depends': [
- '../../../../../third_party/closure_compiler/externs/networking_private_interface.js',
- '../../../../../ui/webui/resources/cr_elements/network/cr_onc_types.js',
- '../../../../../ui/webui/resources/js/compiled_resources.gyp:assert',
- '../../../../../ui/webui/resources/js/compiled_resources.gyp:load_time_data',
- ],
- 'externs': [
- '../../../../../third_party/closure_compiler/externs/networking_private.js'
- ],
- },
- 'includes': ['../../../../../third_party/closure_compiler/compile_js.gypi'],
- },
- {
- 'target_name': 'network_apnlist',
- 'variables': {
- 'depends': [
- '../../../../../ui/webui/resources/cr_elements/network/cr_onc_types.js',
- '../../../../../ui/webui/resources/js/compiled_resources.gyp:load_time_data',
- ],
- 'externs': [
- '../../../../../third_party/closure_compiler/externs/networking_private.js'
- ],
- },
- 'includes': ['../../../../../third_party/closure_compiler/compile_js.gypi'],
- },
- {
- 'target_name': 'network_ip_config',
- 'variables': {
- 'depends': [
- '../../../../../ui/webui/resources/cr_elements/network/cr_onc_types.js',
- '../../../../../ui/webui/resources/js/compiled_resources.gyp:load_time_data',
- ],
- 'externs': [
- '../../../../../third_party/closure_compiler/externs/networking_private.js'
- ],
- },
- 'includes': ['../../../../../third_party/closure_compiler/compile_js.gypi'],
- },
- {
- 'target_name': 'network_nameservers',
- 'variables': {
- 'depends': [
- '../../../../../ui/webui/resources/cr_elements/network/cr_onc_types.js',
- '../../../../../ui/webui/resources/js/compiled_resources.gyp:load_time_data',
- ],
- 'externs': [
- '../../../../../third_party/closure_compiler/externs/networking_private.js'
- ],
- },
- 'includes': ['../../../../../third_party/closure_compiler/compile_js.gypi'],
- },
- {
- 'target_name': 'network_property_list',
- 'variables': {
- 'depends': [
- '../../../../../ui/webui/resources/cr_elements/network/cr_onc_types.js',
- '../../../../../ui/webui/resources/cr_elements/policy/cr_policy_network_behavior.js',
- '../../../../../ui/webui/resources/js/compiled_resources.gyp:load_time_data',
- ],
- 'externs': [
- '../../../../../third_party/closure_compiler/externs/networking_private.js'
- ],
- },
- 'includes': ['../../../../../third_party/closure_compiler/compile_js.gypi'],
- },
- {
- 'target_name': 'network_proxy',
- 'variables': {
- 'depends': [
- '../../../../../ui/webui/resources/cr_elements/network/cr_onc_types.js',
- '../../../../../ui/webui/resources/cr_elements/policy/cr_policy_network_behavior.js',
- '../../../../../ui/webui/resources/js/compiled_resources.gyp:load_time_data',
- ],
- 'externs': [
- '../../../../../third_party/closure_compiler/externs/networking_private.js'
- ],
- },
- 'includes': ['../../../../../third_party/closure_compiler/compile_js.gypi'],
- },
- {
- 'target_name': 'network_proxy_input',
- 'variables': {
- 'depends': [
- '../../../../../ui/webui/resources/cr_elements/network/cr_onc_types.js',
- '../../../../../ui/webui/resources/js/compiled_resources.gyp:load_time_data',
- ],
- 'externs': [
- '../../../../../third_party/closure_compiler/externs/networking_private.js'
- ],
- },
- 'includes': ['../../../../../third_party/closure_compiler/compile_js.gypi'],
- },
- {
- 'target_name': 'network_proxy_exclusions',
- 'variables': {
- 'depends': [
- '../../../../../ui/webui/resources/cr_elements/network/cr_onc_types.js',
- '../../../../../ui/webui/resources/js/compiled_resources.gyp:load_time_data',
- ],
- 'externs': [
- '../../../../../third_party/closure_compiler/externs/networking_private.js'
- ],
- },
- 'includes': ['../../../../../third_party/closure_compiler/compile_js.gypi'],
- },
- {
- 'target_name': 'network_siminfo',
- 'variables': {
- 'depends': [
- '../../../../../third_party/closure_compiler/externs/networking_private_interface.js',
- '../../../../../ui/webui/resources/cr_elements/network/cr_onc_types.js',
- '../../../../../ui/webui/resources/js/compiled_resources.gyp:assert',
- '../../../../../ui/webui/resources/js/compiled_resources.gyp:load_time_data',
- ],
- 'externs': [
- '../../../../../third_party/closure_compiler/externs/networking_private.js'
- ],
- },
- 'includes': ['../../../../../third_party/closure_compiler/compile_js.gypi'],
- },
- {
- 'target_name': 'network_summary',
- 'variables': {
- 'depends': [
- '../../../../../third_party/closure_compiler/externs/networking_private_interface.js',
- '../../../../../ui/webui/resources/cr_elements/network/cr_onc_types.js',
- '../../../../../ui/webui/resources/js/compiled_resources.gyp:assert',
- '../../../../../ui/webui/resources/js/compiled_resources.gyp:load_time_data',
- ],
- 'externs': [
- '../../../../../third_party/closure_compiler/externs/networking_private.js'
- ],
- },
- 'includes': ['../../../../../third_party/closure_compiler/compile_js.gypi'],
- },
- {
- 'target_name': 'network_summary_item',
- 'variables': {
- 'depends': [
- '../../../../../ui/webui/resources/cr_elements/network/cr_onc_types.js',
- '../../../../../ui/webui/resources/js/compiled_resources.gyp:load_time_data',
- ],
- 'externs': [
- '../../../../../third_party/closure_compiler/externs/networking_private.js'
- ],
- },
- 'includes': ['../../../../../third_party/closure_compiler/compile_js.gypi'],
- },
- ],
-}
diff --git a/chromium/chrome/browser/resources/settings/internet_page/compiled_resources2.gyp b/chromium/chrome/browser/resources/settings/internet_page/compiled_resources2.gyp
new file mode 100644
index 00000000000..e016009873e
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/internet_page/compiled_resources2.gyp
@@ -0,0 +1,112 @@
+# 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': 'internet_page',
+ 'dependencies': [
+ '<(DEPTH)/ui/webui/resources/cr_elements/network/compiled_resources2.gyp:cr_onc_types',
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:assert',
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:i18n_behavior',
+ '<(INTERFACES_GYP):networking_private_interface',
+ '../settings_page/compiled_resources2.gyp:settings_animated_pages',
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'internet_detail_page',
+ 'dependencies': [
+ '<(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',
+ '<(EXTERNS_GYP):networking_private',
+ '<(INTERFACES_GYP):networking_private_interface',
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'internet_known_networks_page',
+ 'dependencies': [
+ '<(DEPTH)/ui/webui/resources/cr_elements/network/compiled_resources2.gyp:cr_onc_types',
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:assert',
+ '<(EXTERNS_GYP):networking_private',
+ '<(INTERFACES_GYP):networking_private_interface',
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'network_apnlist',
+ 'dependencies': [
+ '<(DEPTH)/ui/webui/resources/cr_elements/network/compiled_resources2.gyp:cr_onc_types',
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'network_ip_config',
+ 'dependencies': [
+ '<(DEPTH)/ui/webui/resources/cr_elements/network/compiled_resources2.gyp:cr_onc_types',
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'network_nameservers',
+ 'dependencies': [
+ '<(DEPTH)/ui/webui/resources/cr_elements/network/compiled_resources2.gyp:cr_onc_types',
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'network_property_list',
+ 'dependencies': [
+ '<(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',
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'network_proxy',
+ 'dependencies': [
+ '<(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',
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'network_proxy_input',
+ 'dependencies': [
+ '<(DEPTH)/ui/webui/resources/cr_elements/network/compiled_resources2.gyp:cr_onc_types',
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'network_proxy_exclusions',
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'network_siminfo',
+ 'dependencies': [
+ '<(DEPTH)/ui/webui/resources/cr_elements/network/compiled_resources2.gyp:cr_onc_types',
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:assert',
+ '<(INTERFACES_GYP):networking_private_interface',
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'network_summary',
+ 'dependencies': [
+ '<(DEPTH)/ui/webui/resources/cr_elements/network/compiled_resources2.gyp:cr_onc_types',
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:assert',
+ '<(INTERFACES_GYP):networking_private_interface',
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'network_summary_item',
+ 'dependencies': [
+ '<(DEPTH)/ui/webui/resources/cr_elements/network/compiled_resources2.gyp:cr_onc_types',
+ ],
+ '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 0cf3f8fc4ef..179f44ec37f 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,4 +1,4 @@
-<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.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-flex-layout/classes/iron-flex-layout.html">
<link rel="import" href="chrome://resources/polymer/v1_0/iron-icons/iron-icons.html">
@@ -10,6 +10,7 @@
<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://md-settings/settings_shared_css.html">
<link rel="import" href="network_apnlist.html">
<link rel="import" href="network_ip_config.html">
<link rel="import" href="network_nameservers.html">
@@ -18,9 +19,9 @@
<link rel="import" href="network_siminfo.html">
<dom-module id="settings-internet-detail-page">
- <link rel="import" type="css" href="chrome://md-settings/settings_shared.css">
<link rel="import" type="css" href="internet_detail_page.css">
<template>
+ <style include="settings-shared"></style>
<div class="layout vertical">
<!-- Title section: Icon + name + connection state. -->
<div id="titleDiv" class="layout horizontal center">
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 e44c0b329c6..f15a9f13c0a 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
@@ -6,9 +6,6 @@
* @fileoverview
* 'settings-internet-detail' is the settings subpage containing details
* for a network.
- *
- * @group Chrome Settings Elements
- * @element settings-internet-detail
*/
(function() {
'use strict';
@@ -27,7 +24,6 @@ Polymer({
guid: {
type: String,
value: '',
- observer: 'guidChanged_',
},
/**
@@ -99,6 +95,10 @@ Polymer({
},
},
+ observers: [
+ 'guidChanged_(guid, networkingPrivate)',
+ ],
+
/**
* Listener function for chrome.networkingPrivate.onNetworksChanged event.
* @type {function(!Array<string>)}
diff --git a/chromium/chrome/browser/resources/settings/internet_page/internet_known_networks_page.html b/chromium/chrome/browser/resources/settings/internet_page/internet_known_networks_page.html
index 6dd5f1e65dd..807d6735c93 100644
--- a/chromium/chrome/browser/resources/settings/internet_page/internet_known_networks_page.html
+++ b/chromium/chrome/browser/resources/settings/internet_page/internet_known_networks_page.html
@@ -1,13 +1,14 @@
-<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.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-icons/iron-icons.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/network/cr_network_list.html">
+<link rel="import" href="chrome://md-settings/settings_shared_css.html">
<dom-module id="settings-internet-known-networks-page">
- <link rel="import" type="css" href="chrome://md-settings/settings_shared.css">
<link rel="import" type="css" href="internet_known_networks_page.css">
<template>
+ <style include="settings-shared"></style>
<div class="layout vertical">
<div id="outerDiv" class="layout vertical">
<div id="headerDiv" class="layout horizontal">
diff --git a/chromium/chrome/browser/resources/settings/internet_page/internet_known_networks_page.js b/chromium/chrome/browser/resources/settings/internet_page/internet_known_networks_page.js
index 45133344e59..d43f1fcc054 100644
--- a/chromium/chrome/browser/resources/settings/internet_page/internet_known_networks_page.js
+++ b/chromium/chrome/browser/resources/settings/internet_page/internet_known_networks_page.js
@@ -6,9 +6,6 @@
* @fileoverview
* 'settings-internet-known-networks' is the settings subpage listing the
* known networks for a type (currently always WiFi).
- *
- * @group Chrome Settings Elements
- * @element settings-internet-known-networks
*/
Polymer({
is: 'settings-internet-known-networks-page',
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 ccaa873e0de..7c9a84b5336 100644
--- a/chromium/chrome/browser/resources/settings/internet_page/internet_page.html
+++ b/chromium/chrome/browser/resources/settings/internet_page/internet_page.html
@@ -1,16 +1,17 @@
-<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.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/neon-animation/neon-animatable.html">
<link rel="import" href="chrome://resources/cr_elements/network/cr_onc_types.html">
<link rel="import" href="chrome://md-settings/settings_page/settings_animated_pages.html">
-<link rel="import" href="chrome://md-settings/settings_page/settings_subheader.html">
+<link rel="import" href="chrome://md-settings/settings_page/settings_subpage.html">
+<link rel="import" href="chrome://md-settings/settings_shared_css.html">
<link rel="import" href="internet_detail_page.html">
<link rel="import" href="internet_known_networks_page.html">
<link rel="import" href="network_summary.html">
<dom-module id="settings-internet-page">
- <link rel="import" type="css"
- href="chrome://md-settings/settings_shared.css">
<template>
+ <style include="settings-shared"></style>
<settings-animated-pages id="pages" current-route="{{currentRoute}}"
section="internet">
<neon-animatable id="main">
@@ -20,26 +21,26 @@
networking-private="[[networkingPrivate]]">
</network-summary>
</neon-animatable>
- <neon-animatable id="network-detail">
- <settings-subheader i18n-values="page-title:internetDetailPageTitle">
- </settings-subheader>
- <settings-internet-detail-page
- guid="[[detailGuid]]"
- default-network="[[defaultNetwork]]"
- on-close="onBackTap_"
- networking-private="[[networkingPrivate]]">
- </settings-internet-detail-page>
- </neon-animatable>
- <neon-animatable id="known-networks">
- <settings-subheader
- i18n-values="page-title:internetKnownNetworksPageTitle">
- </settings-subheader>
- <settings-internet-known-networks-page
- network-type="[[knownNetworksType]]"
- on-show-detail="onShowDetail_"
- networking-private="[[networkingPrivate]]">
- </settings-internet-known-networks-page>
- </neon-animatable>
+ <template is="dom-if" name="network-detail">
+ <settings-subpage page-title="[[i18n('internetDetailPageTitle')]]">
+ <settings-internet-detail-page
+ guid="[[detailGuid]]"
+ default-network="[[defaultNetwork]]"
+ on-close="onBackTap_"
+ networking-private="[[networkingPrivate]]">
+ </settings-internet-detail-page>
+ </settings-subpage>
+ </template>
+ <template is="dom-if" name="known-networks">
+ <settings-subpage
+ page-title="[[i18n('internetKnownNetworksPageTitle')]]">
+ <settings-internet-known-networks-page
+ network-type="[[knownNetworksType]]"
+ on-show-detail="onShowDetail_"
+ networking-private="[[networkingPrivate]]">
+ </settings-internet-known-networks-page>
+ </settings-subpage>
+ </template>
</settings-animated-pages>
</template>
<script src="internet_page.js"></script>
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 49e8c1219fb..4ca97f10d6f 100644
--- a/chromium/chrome/browser/resources/settings/internet_page/internet_page.js
+++ b/chromium/chrome/browser/resources/settings/internet_page/internet_page.js
@@ -14,13 +14,14 @@
* </settings-internet-page>
* ... other pages ...
* </core-animated-pages>
- *
- * @group Chrome Settings Elements
- * @element settings-internet-page
*/
Polymer({
is: 'settings-internet-page',
+ behaviors: [
+ I18nBehavior,
+ ],
+
properties: {
/**
* The current active route.
diff --git a/chromium/chrome/browser/resources/settings/internet_page/network_apnlist.css b/chromium/chrome/browser/resources/settings/internet_page/network_apnlist.css
index 3f7caed2235..19a5acfa7bb 100644
--- a/chromium/chrome/browser/resources/settings/internet_page/network_apnlist.css
+++ b/chromium/chrome/browser/resources/settings/internet_page/network_apnlist.css
@@ -11,10 +11,10 @@
}
#selectDiv select {
- margin-left: 10px;
+ -webkit-margin-start: 10px;
padding: 5px;
}
#otherDiv network-property-list {
- margin-left: 15px;
+ -webkit-margin-start: 15px;
}
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 9a7abd48fcc..a8b338e6359 100644
--- a/chromium/chrome/browser/resources/settings/internet_page/network_apnlist.html
+++ b/chromium/chrome/browser/resources/settings/internet_page/network_apnlist.html
@@ -1,4 +1,4 @@
-<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.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/cr_elements/network/cr_onc_types.html">
<link rel="import" href="network_property_list.html">
diff --git a/chromium/chrome/browser/resources/settings/internet_page/network_ip_config.css b/chromium/chrome/browser/resources/settings/internet_page/network_ip_config.css
index 98afcb9f581..13e9069562e 100644
--- a/chromium/chrome/browser/resources/settings/internet_page/network_ip_config.css
+++ b/chromium/chrome/browser/resources/settings/internet_page/network_ip_config.css
@@ -7,5 +7,5 @@ paper-checkbox {
}
network-property-list {
- margin-left: 28px;
+ -webkit-margin-start: 28px;
}
diff --git a/chromium/chrome/browser/resources/settings/internet_page/network_ip_config.html b/chromium/chrome/browser/resources/settings/internet_page/network_ip_config.html
index 6db5873adf1..f84807a540f 100644
--- a/chromium/chrome/browser/resources/settings/internet_page/network_ip_config.html
+++ b/chromium/chrome/browser/resources/settings/internet_page/network_ip_config.html
@@ -1,4 +1,4 @@
-<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
+<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/network/cr_onc_types.html">
<link rel="import" href="network_property_list.html">
diff --git a/chromium/chrome/browser/resources/settings/internet_page/network_nameservers.css b/chromium/chrome/browser/resources/settings/internet_page/network_nameservers.css
index d94c3c98b51..384697de512 100644
--- a/chromium/chrome/browser/resources/settings/internet_page/network_nameservers.css
+++ b/chromium/chrome/browser/resources/settings/internet_page/network_nameservers.css
@@ -11,5 +11,5 @@ select {
}
paper-input-container {
- margin: -9px 5px 0 5px;
+ margin: -9px 5px 0;
}
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 3932b64d91d..2b4bbe2bc57 100644
--- a/chromium/chrome/browser/resources/settings/internet_page/network_nameservers.html
+++ b/chromium/chrome/browser/resources/settings/internet_page/network_nameservers.html
@@ -1,4 +1,4 @@
-<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.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/cr_elements/network/cr_onc_types.html">
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 426b2f8d1e4..17364175e0b 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
@@ -1,4 +1,4 @@
-<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.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/cr_elements/network/cr_onc_types.html">
<link rel="import" href="chrome://resources/cr_elements/policy/cr_policy_network_behavior.html">
diff --git a/chromium/chrome/browser/resources/settings/internet_page/network_proxy.css b/chromium/chrome/browser/resources/settings/internet_page/network_proxy.css
index a4ff258515c..82bf90990ed 100644
--- a/chromium/chrome/browser/resources/settings/internet_page/network_proxy.css
+++ b/chromium/chrome/browser/resources/settings/internet_page/network_proxy.css
@@ -28,5 +28,5 @@ paper-checkbox {
}
paper-input {
- margin: -9px 5px 0 5px;
+ margin: -9px 5px 0;
}
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 9e5f5a0c8cb..b6c6501d8f0 100644
--- a/chromium/chrome/browser/resources/settings/internet_page/network_proxy.html
+++ b/chromium/chrome/browser/resources/settings/internet_page/network_proxy.html
@@ -1,4 +1,4 @@
-<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.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-input/paper-input.html">
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 35dad0e2fa7..241e3f1edd0 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
@@ -1,4 +1,4 @@
-<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
+<link rel="import" href="chrome://resources/html/polymer.html">
<link rel="import" href="chrome://resources/polymer/v1_0/iron-icons/iron-icons.html">
<dom-module id="network-proxy-exclusions">
diff --git a/chromium/chrome/browser/resources/settings/internet_page/network_proxy_input.css b/chromium/chrome/browser/resources/settings/internet_page/network_proxy_input.css
index 518cedf12b9..514c7af4694 100644
--- a/chromium/chrome/browser/resources/settings/internet_page/network_proxy_input.css
+++ b/chromium/chrome/browser/resources/settings/internet_page/network_proxy_input.css
@@ -7,9 +7,9 @@
}
span {
- margin-right: 5px;
+ -webkit-margin-end: 5px;
}
paper-input {
- margin: -9px 5px 0 5px;
+ margin: -9px 5px 0;
}
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 21f196cd237..42c3852180c 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,4 @@
-<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
+<link rel="import" href="chrome://resources/html/polymer.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-input/paper-input.html">
<dom-module id="network-proxy-input">
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 cb13629bbfb..1bb1397367a 100644
--- a/chromium/chrome/browser/resources/settings/internet_page/network_siminfo.html
+++ b/chromium/chrome/browser/resources/settings/internet_page/network_siminfo.html
@@ -1,4 +1,4 @@
-<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.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/iron-icons/notification-icons.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html">
diff --git a/chromium/chrome/browser/resources/settings/internet_page/network_summary.html b/chromium/chrome/browser/resources/settings/internet_page/network_summary.html
index 505d61e361c..6ff7fd0d8ed 100644
--- a/chromium/chrome/browser/resources/settings/internet_page/network_summary.html
+++ b/chromium/chrome/browser/resources/settings/internet_page/network_summary.html
@@ -1,4 +1,4 @@
-<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
+<link rel="import" href="chrome://resources/html/polymer.html">
<link rel="import" href="chrome://resources/cr_elements/network/cr_onc_types.html">
<link rel="import" href="network_summary_item.html">
diff --git a/chromium/chrome/browser/resources/settings/internet_page/network_summary_item.css b/chromium/chrome/browser/resources/settings/internet_page/network_summary_item.css
index 83f4d253230..678b3d849c9 100644
--- a/chromium/chrome/browser/resources/settings/internet_page/network_summary_item.css
+++ b/chromium/chrome/browser/resources/settings/internet_page/network_summary_item.css
@@ -15,11 +15,11 @@
}
paper-spinner {
- margin-left: 20px;
+ -webkit-margin-start: 20px;
}
#deviceEnabledButton {
- margin-left: 10px;
+ -webkit-margin-start: 10px;
}
#listDiv {
@@ -28,6 +28,6 @@ paper-spinner {
}
#networkList {
- margin: 5px 0 10px 0;
+ margin: 5px 0 10px;
max-height: 400px;
}
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 897787cb6ad..73e3c8660d5 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
@@ -1,4 +1,4 @@
-<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.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-spinner/paper-spinner.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-toggle-button/paper-toggle-button.html">
diff --git a/chromium/chrome/browser/resources/settings/languages_page/compiled_resources.gyp b/chromium/chrome/browser/resources/settings/languages_page/compiled_resources.gyp
deleted file mode 100644
index 67b25d332c9..00000000000
--- a/chromium/chrome/browser/resources/settings/languages_page/compiled_resources.gyp
+++ /dev/null
@@ -1,75 +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.
-{
- 'targets': [
- {
- 'target_name': 'languages',
- 'variables': {
- 'depends': [
- '../prefs/prefs_types.js',
- '../prefs/compiled_resources.gyp:prefs',
- '../../../../../ui/webui/resources/js/compiled_resources.gyp:assert',
- '../../../../../ui/webui/resources/js/compiled_resources.gyp:cr',
- 'languages_types.js',
- ],
- 'externs': [
- '<(EXTERNS_DIR)/chrome_send.js',
- '<(EXTERNS_DIR)/language_settings_private.js',
- ],
- },
- 'includes': ['../../../../../third_party/closure_compiler/compile_js.gypi'],
- },
- {
- 'target_name': 'language_detail_page',
- 'variables': {
- 'depends': [
- '../../../../../ui/webui/resources/cr_elements/policy/compiled_resources.gyp:cr_policy_indicator_behavior',
- '../../../../../ui/webui/resources/js/chromeos/compiled_resources.gyp:ui_account_tweaks',
- '../../../../../ui/webui/resources/js/compiled_resources.gyp:load_time_data',
- '../prefs/compiled_resources.gyp:prefs',
- 'languages_types.js',
- 'languages.js',
- ],
- 'externs': [
- '<(EXTERNS_DIR)/language_settings_private.js',
- ],
- },
- 'includes': ['../../../../../third_party/closure_compiler/compile_js.gypi'],
- },
- {
- 'target_name': 'languages_page',
- 'variables': {
- 'depends': [
- '../../../../../ui/webui/resources/js/compiled_resources.gyp:assert',
- '../../../../../ui/webui/resources/js/compiled_resources.gyp:cr',
- '../../../../../ui/webui/resources/js/compiled_resources.gyp:load_time_data',
- '../settings_page/settings_animated_pages.js',
- '../prefs/prefs_types.js',
- '../prefs/compiled_resources.gyp:prefs',
- 'languages_types.js',
- 'languages.js',
- ],
- 'externs': [
- '<(EXTERNS_DIR)/language_settings_private.js',
- ],
- },
- 'includes': ['../../../../../third_party/closure_compiler/compile_js.gypi'],
- },
- {
- 'target_name': 'manage_languages_page',
- 'variables': {
- 'depends': [
- '../../../../../ui/webui/resources/js/compiled_resources.gyp:assert',
- '../prefs/compiled_resources.gyp:prefs',
- 'languages_types.js',
- 'languages.js',
- ],
- 'externs': [
- '<(EXTERNS_DIR)/language_settings_private.js',
- ],
- },
- 'includes': ['../../../../../third_party/closure_compiler/compile_js.gypi'],
- },
- ],
-}
diff --git a/chromium/chrome/browser/resources/settings/languages_page/compiled_resources2.gyp b/chromium/chrome/browser/resources/settings/languages_page/compiled_resources2.gyp
new file mode 100644
index 00000000000..bdbbec63a99
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/languages_page/compiled_resources2.gyp
@@ -0,0 +1,62 @@
+# 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': 'languages',
+ 'dependencies': [
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:assert',
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
+ '<(EXTERNS_GYP):chrome_send',
+ '<(EXTERNS_GYP):language_settings_private',
+ '<(INTERFACES_GYP):language_settings_private_interface',
+ '../prefs/compiled_resources2.gyp:prefs_types',
+ '../prefs/compiled_resources2.gyp:prefs',
+ 'languages_types',
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'language_detail_page',
+ 'dependencies': [
+ '<(DEPTH)/ui/webui/resources/cr_elements/policy/compiled_resources2.gyp:cr_policy_indicator_behavior',
+ '<(DEPTH)/ui/webui/resources/js/chromeos/compiled_resources2.gyp:ui_account_tweaks',
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:load_time_data',
+ '<(EXTERNS_GYP):chrome_send',
+ 'languages_types',
+ 'languages',
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'languages_page',
+ '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:i18n_behavior',
+ '../settings_page/compiled_resources2.gyp:settings_animated_pages',
+ 'languages_types',
+ 'languages',
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'languages_types',
+ 'dependencies': [
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:assert',
+ '<(EXTERNS_GYP):language_settings_private',
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'manage_languages_page',
+ 'dependencies': [
+ '<(DEPTH)/third_party/polymer/v1_0/components-chromium/paper-checkbox/compiled_resources2.gyp:paper-checkbox-extracted',
+ 'languages_types',
+ 'languages',
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ ],
+}
diff --git a/chromium/chrome/browser/resources/settings/languages_page/edit_dictionary_page.css b/chromium/chrome/browser/resources/settings/languages_page/edit_dictionary_page.css
deleted file mode 100644
index 306a9d25cc1..00000000000
--- a/chromium/chrome/browser/resources/settings/languages_page/edit_dictionary_page.css
+++ /dev/null
@@ -1,25 +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. */
-
-:host {
- display: flex;
- flex-direction: column;
-}
-
-#addWordRow {
- display: flex;
-}
-
-#newWord {
- flex: 1;
-}
-
-iron-list {
- /* TODO(michaelpg): Size to fit the viewport. */
- height: 300px;
-}
-
-iron-list .word {
- flex: 1;
-}
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 6788df9d11f..447a083ee62 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,17 +1,38 @@
-<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.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-icons/iron-icons.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-item/paper-item.html">
+<link rel="import" href="chrome://md-settings/settings_shared_css.html">
<dom-module id="settings-edit-dictionary-page">
- <link rel="import" type="css" href="chrome://md-settings/settings_shared.css">
- <link rel="import" type="css" href="edit_dictionary_page.css">
<template>
- <div class="settings-box">
+ <style include="settings-shared">
+ :host {
+ display: flex;
+ flex-direction: column;
+ }
+
+ #addWordRow {
+ display: flex;
+ }
+
+ #newWord {
+ flex: .5;
+ }
+
+ iron-list {
+ /* TODO(michaelpg): Size to fit the viewport. */
+ height: 300px;
+ }
+
+ iron-list .word {
+ flex: 1;
+ }
+ </style>
+ <div class="settings-box block">
<div id="addWordRow">
<iron-a11y-keys id="keys" keys="enter esc"
on-keys-pressed="onKeysPress_"></iron-a11y-keys>
@@ -20,16 +41,20 @@
<paper-button on-tap="onAddWordTap_"
i18n-content="addDictionaryWordButton"></paper-button>
</div>
+ </div>
+ <div class="settings-box block">
<h2 i18n-content="customDictionaryWords"></h2>
- <iron-list id="list" items="{{words_}}">
- <template>
- <paper-item>
- <div class="word">[[item]]</div>
- <paper-icon-button icon="clear" on-tap="onRemoveWordTap_">
- </paper-icon-button>
- </paper-item>
- </template>
- </iron-list>
+ <div class="list-frame">
+ <iron-list id="list" items="{{words_}}">
+ <template>
+ <div class="list-item">
+ <div class="word">[[item]]</div>
+ <paper-icon-button icon="clear" on-tap="onRemoveWordTap_">
+ </paper-icon-button>
+ </div>
+ </template>
+ </iron-list>
+ </div>
</div>
</template>
<script src="edit_dictionary_page.js"></script>
diff --git a/chromium/chrome/browser/resources/settings/languages_page/edit_dictionary_page.js b/chromium/chrome/browser/resources/settings/languages_page/edit_dictionary_page.js
index 4db5a30856b..7dc1b199e61 100644
--- a/chromium/chrome/browser/resources/settings/languages_page/edit_dictionary_page.js
+++ b/chromium/chrome/browser/resources/settings/languages_page/edit_dictionary_page.js
@@ -5,9 +5,6 @@
/**
* @fileoverview 'settings-edit-dictionary-page' is a sub-page for editing
* the "dictionary" of custom words used for spell check.
- *
- * @group Chrome Settings Elements
- * @element settings-edit-dictionary-page
*/
Polymer({
is: 'settings-edit-dictionary-page',
diff --git a/chromium/chrome/browser/resources/settings/languages_page/language_detail_page.css b/chromium/chrome/browser/resources/settings/languages_page/language_detail_page.css
deleted file mode 100644
index 1da7422e1cc..00000000000
--- a/chromium/chrome/browser/resources/settings/languages_page/language_detail_page.css
+++ /dev/null
@@ -1,20 +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. */
-
-label {
- align-items: center;
- display: flex;
-}
-
-label > *:not(:first-child) {
- margin-left: 5px;
-}
-
-label > span {
- line-height: 42px;
-}
-
-label paper-button {
- line-height: initial;
-}
diff --git a/chromium/chrome/browser/resources/settings/languages_page/language_detail_page.html b/chromium/chrome/browser/resources/settings/languages_page/language_detail_page.html
index 28bc6d63d93..0c9203f7a4e 100644
--- a/chromium/chrome/browser/resources/settings/languages_page/language_detail_page.html
+++ b/chromium/chrome/browser/resources/settings/languages_page/language_detail_page.html
@@ -1,9 +1,10 @@
-<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.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-toggle-button/paper-toggle-button.html">
<link rel="import" href="chrome://resources/cr_elements/policy/cr_policy_pref_indicator.html">
<link rel="import" href="chrome://resources/html/assert.html">
<link rel="import" href="chrome://resources/html/cr.html">
+<link rel="import" href="chrome://md-settings/settings_shared_css.html">
<link rel="import" href="languages.html">
<if expr="chromeos">
@@ -11,43 +12,69 @@
</if>
<dom-module id="settings-language-detail-page">
- <link rel="import" type="css" href="chrome://md-settings/settings_shared.css">
- <link rel="import" type="css" href="language_detail_page.css">
<template>
+ <style include="settings-shared">
+ label {
+ align-items: center;
+ display: flex;
+ }
+
+ label > *:not(:first-child) {
+ -webkit-margin-start: 5px;
+ }
+
+ label > span {
+ line-height: 42px;
+ }
+
+ label paper-button {
+ line-height: initial;
+ }
+ </style>
<settings-languages languages="{{languages}}"></settings-languages>
+ <div class="settings-box block first">
<if expr="chromeos or is_win">
- <div id="languageSettings">
- <label hidden$="[[!detail.language.supportsUI]]">
- <paper-toggle-button
- checked="[[isProspectiveUILanguage_(detail.language.code, prefs.intl.app_locale.value)]]"
- on-change="onUILanguageChange_"
- disabled$="[[isUILanguageChangeDisabled_(detail.language.code, prefs.intl.app_locale.value)]]">
- </paper-toggle-button>
- <span i18n-content="isDisplayedInThisLanguage"
- hidden$="[[!isCurrentUILanguage_(detail.language.code, prefs.intl.app_locale.value)]]">
- </span>
- <span hidden$="[[isCurrentUILanguage_(detail.language.code, prefs.intl.app_locale.value)]]">
- <span i18n-content="displayInThisLanguage"></span>
- <paper-button i18n-content="restart" on-tap="onRestartTap_"
- hidden$="[[!isRestartRequired_(detail.language.code, prefs.intl.app_locale.value)]]">
- </paper-button>
- </span>
- <cr-policy-pref-indicator id="policyIndicator">
- </cr-policy-pref-indicator>
- </label>
- <span i18n-content="cannotBeDisplayedInThisLanguage"
- hidden$="[[detail.language.supportsUI]]"></span>
- </div>
+ <div id="languageSettings" class="list-item">
+ <label hidden$="[[!detail.language.supportsUI]]">
+ <paper-toggle-button
+ checked="[[isProspectiveUILanguage_(
+ detail.language.code, prefs.intl.app_locale.value)]]"
+ on-change="onUILanguageChange_"
+ disabled$="[[isUILanguageChangeDisabled_(
+ detail.language.code, prefs.intl.app_locale.value)]]">
+ </paper-toggle-button>
+ <span i18n-content="isDisplayedInThisLanguage"
+ hidden$="[[!isCurrentUILanguage_(
+ detail.language.code, prefs.intl.app_locale.value)]]">
+ </span>
+ <span hidden$="[[isCurrentUILanguage_(
+ detail.language.code, prefs.intl.app_locale.value)]]">
+ <span i18n-content="displayInThisLanguage"></span>
+ <paper-button i18n-content="restart" on-tap="onRestartTap_"
+ hidden$="[[!isRestartRequired_(
+ detail.language.code, prefs.intl.app_locale.value)]]">
+ </paper-button>
+ </span>
+ <cr-policy-pref-indicator id="policyIndicator">
+ </cr-policy-pref-indicator>
+ </label>
+ <span i18n-content="cannotBeDisplayedInThisLanguage"
+ hidden$="[[detail.language.supportsUI]]"></span>
+ </div>
</if>
- <div hidden$="[[shouldHideTranslate_(detail.language.code, prefs.translate.enabled.value)]]">
- <paper-checkbox checked="[[detail.state.translateEnabled]]"
- on-change="onTranslateEnabledChange_"
- i18n-content="offerToTranslateInThisLanguage"
- hidden$="[[!detail.language.supportsTranslate]]"
- disabled="[[isTranslateDisabled_(detail.language.code, languages.translateTarget)]]">
- </paper-checkbox>
- <div i18n-content="cannotTranslateInThisLanguage"
- hidden$="[[detail.language.supportsTranslate]]"></div>
+ <div class="list-item"
+ hidden$="[[shouldHideTranslate_(
+ detail.language.code, prefs.translate.enabled.value)]]">
+ <paper-checkbox checked="[[detail.state.translateEnabled]]"
+ on-change="onTranslateEnabledChange_"
+ i18n-content="offerToTranslateInThisLanguage"
+ hidden$="[[!detail.language.supportsTranslate]]"
+ disabled="[[isTranslateDisabled_(
+ detail.language.code, languages.translateTarget)]]">
+ </paper-checkbox>
+ <div i18n-content="cannotTranslateInThisLanguage"
+ hidden$="[[detail.language.supportsTranslate]]"></div>
+ </div>
</div>
</template>
<script src="language_detail_page.js"></script>
diff --git a/chromium/chrome/browser/resources/settings/languages_page/language_detail_page.js b/chromium/chrome/browser/resources/settings/languages_page/language_detail_page.js
index 8f89226f835..f500dbead3b 100644
--- a/chromium/chrome/browser/resources/settings/languages_page/language_detail_page.js
+++ b/chromium/chrome/browser/resources/settings/languages_page/language_detail_page.js
@@ -5,9 +5,6 @@
/**
* @fileoverview 'settings-language-detail-page' is a sub-page for editing
* an individual language's settings.
- *
- * @group Chrome Settings Elements
- * @element settings-language-detail-page
*/
Polymer({
is: 'settings-language-detail-page',
diff --git a/chromium/chrome/browser/resources/settings/languages_page/languages.html b/chromium/chrome/browser/resources/settings/languages_page/languages.html
index d6003b3b3b3..c729b94578f 100644
--- a/chromium/chrome/browser/resources/settings/languages_page/languages.html
+++ b/chromium/chrome/browser/resources/settings/languages_page/languages.html
@@ -1,6 +1,6 @@
<link rel="import" href="chrome://resources/html/assert.html">
<link rel="import" href="chrome://resources/html/cr.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
+<link rel="import" href="chrome://resources/html/polymer.html">
<link rel="import" href="chrome://md-settings/prefs/prefs.html">
<link rel="import" href="chrome://md-settings/prefs/prefs_behavior.html">
diff --git a/chromium/chrome/browser/resources/settings/languages_page/languages.js b/chromium/chrome/browser/resources/settings/languages_page/languages.js
index a8925429cd2..cf7a7542d23 100644
--- a/chromium/chrome/browser/resources/settings/languages_page/languages.js
+++ b/chromium/chrome/browser/resources/settings/languages_page/languages.js
@@ -19,13 +19,12 @@
* </settings-languages>
* <div>[[languages.someProperty]]</div>
* </template>
- *
- * @group Chrome Settings Elements
- * @element settings-languages
*/
var SettingsLanguagesSingletonElement;
+cr.exportPath('languageSettings');
+
(function() {
'use strict';
@@ -80,6 +79,10 @@ SettingsLanguagesSingletonElement = Polymer({
},
},
+ /** @type {!LanguageSettingsPrivate} */
+ languageSettingsPrivate: languageSettings.languageSettingsPrivateApiForTest ||
+ /** @type {!LanguageSettingsPrivate} */(chrome.languageSettingsPrivate),
+
/**
* Hash map of languages.supportedLanguages using language codes as keys for
* fast lookup.
@@ -106,28 +109,31 @@ SettingsLanguagesSingletonElement = Polymer({
var languageList;
var translateTarget;
- // Request language information to populate the model.
- Promise.all([
+ /**
+ * Promise to be resolved when the languages singleton has been initialized.
+ * @type {!Promise}
+ */
+ this.initialized = Promise.all([
// Wait until prefs are initialized before creating the model, so we can
// include information about enabled languages.
CrSettingsPrefs.initialized,
// Get the language list.
new Promise(function(resolve) {
- chrome.languageSettingsPrivate.getLanguageList(function(list) {
+ this.languageSettingsPrivate.getLanguageList(function(list) {
languageList = list;
resolve();
});
- }),
+ }.bind(this)),
// Get the translate target language.
new Promise(function(resolve) {
- chrome.languageSettingsPrivate.getTranslateTargetLanguage(
+ this.languageSettingsPrivate.getTranslateTargetLanguage(
function(targetLanguageCode) {
translateTarget = targetLanguageCode;
resolve();
});
- }),
+ }.bind(this)),
]).then(function() {
this.createModel_(languageList, translateTarget);
this.initialized_ = true;
@@ -298,6 +304,7 @@ SettingsLanguagesSingletonElement = Polymer({
resetUILanguage: function() {
chrome.send('setUILanguage', [navigator.language]);
},
+</if>
/**
* Returns the "prospective" UI language, i.e. the one to be used on next
@@ -309,7 +316,6 @@ SettingsLanguagesSingletonElement = Polymer({
return /** @type {string} */(this.getPref('intl.app_locale').value) ||
navigator.language;
},
-</if>
/**
* @param {string} languageCode
@@ -332,7 +338,7 @@ SettingsLanguagesSingletonElement = Polymer({
if (languageCodes.indexOf(languageCode) > -1)
return;
languageCodes.push(languageCode);
- chrome.languageSettingsPrivate.setLanguageList(languageCodes);
+ this.languageSettingsPrivate.setLanguageList(languageCodes);
this.disableTranslateLanguage(languageCode);
},
@@ -356,7 +362,7 @@ SettingsLanguagesSingletonElement = Polymer({
if (languageIndex == -1)
return;
languageCodes.splice(languageIndex, 1);
- chrome.languageSettingsPrivate.setLanguageList(languageCodes);
+ this.languageSettingsPrivate.setLanguageList(languageCodes);
this.enableTranslateLanguage(languageCode);
},
@@ -466,11 +472,12 @@ Polymer({
properties: {
/**
* Singleton element created at startup which provides the languages model.
- * @type {!SettingsLanguagesSingletonElement}
+ * @type {SettingsLanguagesSingletonElement}
*/
singleton_: {
type: Object,
- value: LanguageHelperImpl.getInstance(),
+ value: languageSettings.languageSettingsPrivateApiForTest ?
+ undefined : LanguageHelperImpl.getInstance(),
},
/**
@@ -486,12 +493,14 @@ Polymer({
},
ready: function() {
- // Set the 'languages' property to reference the singleton's model.
- this._setLanguages(this.singleton_.languages);
- // Listen for changes to the singleton's languages property, so we know
- // when to notify hosts of changes to (our reference to) the property.
- this.listen(
- this.singleton_, 'languages-changed', 'singletonLanguagesChanged_');
+ this.singleton_.initialized.then(function() {
+ // Set the 'languages' property to reference the singleton's model.
+ this._setLanguages(this.singleton_.languages);
+ // Listen for changes to the singleton's languages property, so we know
+ // when to notify hosts of changes to (our reference to) the property.
+ this.listen(
+ this.singleton_, 'languages-changed', 'singletonLanguagesChanged_');
+ }.bind(this));
},
/**
diff --git a/chromium/chrome/browser/resources/settings/languages_page/languages_page.css b/chromium/chrome/browser/resources/settings/languages_page/languages_page.css
deleted file mode 100644
index 78a79f3b439..00000000000
--- a/chromium/chrome/browser/resources/settings/languages_page/languages_page.css
+++ /dev/null
@@ -1,9 +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. */
-
-.manage {
- @apply(--layout);
- @apply(--layout-horizontal-reverse);
- margin-top: 20px;
-}
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 882342c7d61..2af51df3dc8 100644
--- a/chromium/chrome/browser/resources/settings/languages_page/languages_page.html
+++ b/chromium/chrome/browser/resources/settings/languages_page/languages_page.html
@@ -1,15 +1,16 @@
-<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/iron-flex-layout.html">
+<link rel="import" href="chrome://resources/html/assert.html">
+<link rel="import" href="chrome://resources/html/cr.html">
+<link rel="import" href="chrome://resources/html/i18n_behavior.html">
+<link rel="import" href="chrome://resources/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/iron-icons/iron-icons.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.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/paper-item/paper-item.html">
-<link rel="import" href="chrome://resources/html/assert.html">
-<link rel="import" href="chrome://resources/html/cr.html">
+<link rel="import" href="chrome://resources/cr_elements/cr_expand_button/cr_expand_button.html">
<link rel="import" href="chrome://md-settings/settings_page/settings_animated_pages.html">
-<link rel="import" href="chrome://md-settings/settings_page/settings_subheader.html">
+<link rel="import" href="chrome://md-settings/settings_page/settings_subpage.html">
+<link rel="import" href="chrome://md-settings/settings_shared_css.html">
<link rel="import" href="language_detail_page.html">
<link rel="import" href="languages.html">
<link rel="import" href="manage_languages_page.html">
@@ -19,92 +20,136 @@
</if>
<dom-module id="settings-languages-page">
- <link rel="import" type="css"
- href="chrome://md-settings/settings_shared.css">
- <link rel="import" type="css" href="languages_page.css">
<template>
+ <style include="settings-shared"></style>
<settings-languages languages="{{languages}}"></settings-languages>
<settings-animated-pages id="pages" current-route="{{currentRoute}}"
section="languages">
<neon-animatable id="main">
- <div class="settings-box">
- <h2 i18n-content="languagesListTitle"></h2>
- <div>
- <array-selector id="languageSelector" selected="{{detailLanguage}}"
- items="{{languages.enabledLanguages}}"></array-selector>
+ <div class="settings-box first two-line">
+ <div class="start">
+ <div i18n-content="languagesListTitle"></div>
+ <div class="secondary">
+ [[getProspectiveUILanguageName_(prefs.intl.app_locale.value)]]
+ </div>
+ </div>
+ <cr-expand-button expanded="{{languagesOpened_}}">
+ </cr-expand-button>
+ </div>
+ <iron-collapse id="languagesCollapse" opened="[[languagesOpened_]]">
+ <div class="list-frame vertical-list">
<template is="dom-repeat" items="{{languages.enabledLanguages}}">
- <paper-item class="split" on-tap="onLanguageTap_">
- <div class="flex" title="[[item.language.nativeDisplayName]]"
- >[[item.language.displayName]]</div>
+ <div class$="list-item [[getLanguageItemClass_(
+ item.language.code, prefs.intl.app_locale.value)]]"
+ on-tap="onLanguageTap_">
+<if expr="not chromeos and not is_win">
+ <div class="start" title="[[item.language.nativeDisplayName]]">
+ [[item.language.displayName]]
+ </div>
+</if>
<if expr="chromeos or is_win">
- <iron-icon icon="done"
- hidden$="[[!isProspectiveUILanguage_(item.language.code, prefs.intl.app_locale.value)]]">
- </iron-icon>
+ <div title="[[item.language.nativeDisplayName]]">
+ [[item.language.displayName]]
+ </div>
+ <div class="middle">
+ <iron-icon icon="done"
+ hidden$="[[!isProspectiveUILanguage_(
+ item.language.code, prefs.intl.app_locale.value)]]">
+ </iron-icon>
+ </div>
</if>
<paper-icon-button icon="settings"
on-tap="onShowLanguageDetailTap_"></paper-icon-button>
- </paper-item>
+ </div>
</template>
+ <div class="list-item list-button" i18n-content="manageLanguages"
+ on-tap="onManageLanguagesTap_">
+ </div>
</div>
- <div class="manage">
- <paper-button i18n-content="manageLanguages"
- on-tap="onManageLanguagesTap_"></paper-button>
- </div>
+ </iron-collapse>
<if expr="chromeos">
- <h2 i18n-content="inputMethodsListTitle"></h2>
- <div>
+ <div class="settings-box two-line">
+ <div class="start">
+ <div i18n-content="inputMethodsListTitle"></div>
+ <div class="secondary">[[inputMethodsSecondary_]]</div>
+ </div>
+ <cr-expand-button expanded="{{inputMethodsOpened_}}">
+ </cr-expand-button>
+ </div>
+ <iron-collapse id="inputMethodsCollapse"
+ opened="[[inputMethodsOpened_]]">
+ <div class="list-frame vertical-list">
<template is="dom-repeat" items="{{languages.inputMethods}}">
- <paper-item class="split">
- <div class="flex">[[item.name]]</div>
- <iron-icon icon="done"
- hidden$="[[!isCurrentInputMethod_(item.id, languages.currentInputMethod)]]">
- </iron-icon>
+ <div class$=
+ "list-item [[getInputMethodItemClass_(id, currentId)]]">
+ <div class="start">
+ <div>[[item.name]]</div>
+ <iron-icon icon="done"
+ hidden$="[[!isCurrentInputMethod_(
+ item.id, languages.currentInputMethod)]]">
+ </iron-icon>
+ </div>
<paper-icon-button icon="settings"></paper-icon-button>
- </paper-item>
+ </div>
</template>
+ <div class="list-item list-button"
+ i18n-content="manageInputMethods">
+ </div>
</div>
- <div class="manage">
- <paper-button i18n-content="manageInputMethods"></paper-button>
- </div>
+ </iron-collapse>
</if>
<if expr="not is_macosx">
- <h2 i18n-content="spellCheckListTitle"></h2>
- <div class="layout vertical">
- <template is="dom-repeat" items="{{languages.enabledLanguages}}">
- <paper-checkbox hidden="[[!item.language.supportsSpellcheck]]"
- checked="[[item.state.spellCheckEnabled]]"
- on-change="onSpellCheckChange_"
- >[[item.language.displayName]]</paper-checkbox>
- </template>
+ <div class="settings-box two-line">
+ <div class="start">
+ <div i18n-content="spellCheckListTitle"></div>
+ <div class="secondary">[[spellCheckSecondary_]]</div>
</div>
- <div class="manage">
- <paper-button i18n-content="manageSpellCheck"
- on-tap="onEditDictionaryTap_"></paper-button>
+ <cr-expand-button expanded="{{spellCheckOpened_}}">
+ </cr-expand-button>
+ </div>
+ <iron-collapse id="spellCheckCollapse" opened="[[spellCheckOpened_]]">
+ <div class="list-frame vertical-list">
+ <template is="dom-repeat"
+ items="[[spellCheckLanguages_(languages.enabledLanguages.*)]]">
+ <div class="list-item">
+ <div class="start">
+ <paper-checkbox
+ checked="[[item.state.spellCheckEnabled]]"
+ on-change="onSpellCheckChange_">
+ [[item.language.displayName]]
+ </paper-checkbox>
+ </div>
+ <paper-icon-button icon="settings"
+ on-tap="onShowLanguageDetailTap_"></paper-icon-button>
+ </div>
+ </template>
+ <div class="list-item list-button" i18n-content="manageSpellCheck"
+ on-tap="onEditDictionaryTap_">
+ </div>
</div>
+ </iron-collapse>
</if>
- </div>
- </neon-animatable>
- <neon-animatable id="manage-languages">
- <settings-subheader i18n-values="page-title:manageLanguagesPageTitle">
- </settings-subheader>
- <settings-manage-languages-page
- prefs="{{prefs}}"></settings-manage-languages-page>
- </neon-animatable>
- <neon-animatable id="language-detail">
- <settings-subheader id="language-detail-subheader"
- page-title="[[detailLanguage.language.displayName]]">
- </settings-subheader>
- <settings-language-detail-page id="languageDetailPage"
- prefs="{{prefs}}" detail="[[detailLanguage]]">
- </settings-language-detail-page>
</neon-animatable>
+ <template is="dom-if" name="manage-languages">
+ <settings-subpage page-title="[[i18n('manageLanguagesPageTitle')]]">
+ <settings-manage-languages-page
+ prefs="{{prefs}}"></settings-manage-languages-page>
+ </settings-subpage>
+ </template>
+ <template is="dom-if" name="language-detail">
+ <settings-subpage
+ page-title="[[detailLanguage_.language.displayName]]">
+ <settings-language-detail-page id="languageDetailPage"
+ prefs="{{prefs}}" detail="[[detailLanguage_]]">
+ </settings-language-detail-page>
+ </settings-subpage>
+ </template>
<if expr="not is_macosx">
- <neon-animatable id="edit-dictionary">
- <settings-subheader id="edit-dictionary-subheader"
- i18n-values="page-title:editDictionaryPageTitle">
- </settings-subheader>
- <settings-edit-dictionary-page></settings-edit-dictionary-page>
- </neon-animatable>
+ <template is="dom-if" name="edit-dictionary">
+ <settings-subpage page-title="[[i18n('editDictionaryPageTitle')]]">
+ <settings-edit-dictionary-page></settings-edit-dictionary-page>
+ </settings-subpage>
+ </template>
</if>
</settings-animated-pages>
</template>
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 12c83e3a7e3..fe4f6a00e48 100644
--- a/chromium/chrome/browser/resources/settings/languages_page/languages_page.js
+++ b/chromium/chrome/browser/resources/settings/languages_page/languages_page.js
@@ -5,9 +5,6 @@
/**
* @fileoverview 'settings-languages-page' is the settings page
* for language and input method settings.
- *
- * @group Chrome Settings Elements
- * @element settings-languages-page
*/
(function() {
'use strict';
@@ -15,6 +12,10 @@
Polymer({
is: 'settings-languages-page',
+ behaviors: [
+ I18nBehavior,
+ ],
+
properties: {
/**
* The current active route.
@@ -41,6 +42,25 @@ Polymer({
type: Object,
notify: true,
},
+
+ /** @private */
+ inputMethodsSecondary_: {
+ type: String,
+ value: 'Placeholder, e.g. US keyboard',
+ },
+
+ /** @private */
+ spellCheckSecondary_: {
+ type: String,
+ value: 'Placeholder, e.g. English (United States)',
+ },
+
+ /**
+ * The language to display the details for.
+ * @type {!LanguageInfo|undefined}
+ * @private
+ */
+ detailLanguage_: Object,
},
/** @private {!LanguageHelper} */
@@ -90,16 +110,26 @@ Polymer({
/**
* Opens the Language Detail page for the language.
- * @param {!{model: !{item}}} e
+ * @param {!{model: !{item: !LanguageInfo}}} e
* @private
*/
onShowLanguageDetailTap_: function(e) {
- this.$.languageSelector.select(e.model.item);
+ this.detailLanguage_ = e.model.item;
this.$.pages.setSubpageChain(['language-detail']);
},
<if expr="not is_macosx">
/**
+ * Returns the enabled languages which support spell check.
+ * @private
+ */
+ spellCheckLanguages_: function() {
+ return this.languages.enabledLanguages.filter(function(languageInfo) {
+ return languageInfo.language.supportsSpellcheck;
+ });
+ },
+
+ /**
* Opens the Custom Dictionary page.
* @private
*/
@@ -125,6 +155,33 @@ Polymer({
},
</if>
+ /**
+ * @return {string}
+ * @private
+ */
+ getProspectiveUILanguageName_: function() {
+ return this.languageHelper_.getLanguage(
+ this.languageHelper_.getProspectiveUILanguage()).displayName;
+ },
+
+ /**
+ * Returns either the "selected" class, if the language matches the
+ * prospective UI language, or an empty string. Languages can only be
+ * selected on Chrome OS and Windows.
+ * @param {string} languageCode The language code identifying a language.
+ * @param {string} prospectiveUILanguage The prospective UI language.
+ * @return {string} The class name for the language item.
+ * @private
+ */
+ getLanguageItemClass_: function(languageCode, prospectiveUILanguage) {
+<if expr="chromeos or is_win">
+ if (this.isProspectiveUILanguage_(languageCode, prospectiveUILanguage))
+ return 'selected';
+</if>
+ return '';
+ },
+
+<if expr="chromeos">
/**
* @param {string} id The input method ID.
* @param {string} currentId The ID of the currently enabled input method.
@@ -137,6 +194,17 @@ Polymer({
},
/**
+ * @param {string} id The input method ID.
+ * @param {string} currentId The ID of the currently enabled input method.
+ * @return {string} The class for the input method item.
+ * @private
+ */
+ getInputMethodItemClass_: function(id, currentId) {
+ return this.isCurrentInputMethod_(id, currentId) ? 'selected' : '';
+ },
+</if>
+
+ /**
* HACK(michaelpg): This is necessary to show the list when navigating to
* the sub-page. Remove this function when PolymerElements/neon-animation#60
* is fixed.
diff --git a/chromium/chrome/browser/resources/settings/languages_page/languages_types.js b/chromium/chrome/browser/resources/settings/languages_page/languages_types.js
index 895d3469bfe..0fe9220e23d 100644
--- a/chromium/chrome/browser/resources/settings/languages_page/languages_types.js
+++ b/chromium/chrome/browser/resources/settings/languages_page/languages_types.js
@@ -55,6 +55,7 @@ LanguageHelper.prototype = {
/** Resets the prospective UI language back to the actual UI language. */
resetUILanguage: assertNotReached,
+</if>
/**
* Returns the "prospective" UI language, i.e. the one to be used on next
@@ -63,7 +64,6 @@ LanguageHelper.prototype = {
* @return {string} Language code of the prospective UI language.
*/
getProspectiveUILanguage: assertNotReached,
-</if>
/**
* @param {string} languageCode
diff --git a/chromium/chrome/browser/resources/settings/languages_page/manage_languages_page.css b/chromium/chrome/browser/resources/settings/languages_page/manage_languages_page.css
deleted file mode 100644
index ba789dc2de6..00000000000
--- a/chromium/chrome/browser/resources/settings/languages_page/manage_languages_page.css
+++ /dev/null
@@ -1,15 +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. */
-
-iron-list {
- height: 300px;
-}
-
-paper-item {
- display: flex;
-}
-
-paper-item .language-name {
- flex: 1;
-}
diff --git a/chromium/chrome/browser/resources/settings/languages_page/manage_languages_page.html b/chromium/chrome/browser/resources/settings/languages_page/manage_languages_page.html
index 393585f5d5f..d193e594431 100644
--- a/chromium/chrome/browser/resources/settings/languages_page/manage_languages_page.html
+++ b/chromium/chrome/browser/resources/settings/languages_page/manage_languages_page.html
@@ -1,49 +1,61 @@
-<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html">
+<link rel="import" href="chrome://resources/html/assert.html">
+<link rel="import" href="chrome://resources/html/cr.html">
+<link rel="import" href="chrome://resources/html/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/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-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/polymer/v1_0/paper-item/paper-item.html">
-<link rel="import" href="chrome://resources/html/assert.html">
-<link rel="import" href="chrome://resources/html/cr.html">
+<link rel="import" href="chrome://md-settings/settings_shared_css.html">
<link rel="import" href="languages.html">
<dom-module id="settings-manage-languages-page">
- <link rel="import" type="css"
- href="chrome://md-settings/settings_shared.css">
- <link rel="import" type="css" href="manage_languages_page.css">
<template>
+ <style include="settings-shared">
+ .list-frame {
+ display: flex;
+ flex-direction: column;
+ align-items: initial;
+ }
+
+ iron-list {
+ height: 300px;
+ }
+ </style>
<settings-languages languages="{{languages}}"></settings-languages>
- <div class="settings-box content">
- <h2 i18n-content="enabledLanguages"></h2>
- <div>
- <template is="dom-repeat" items="{{languages.enabledLanguages}}">
- <paper-item class="split">
- <div class="language-name"
- title="[[item.language.nativeDisplayName]]"
- >[[item.language.displayName]]</div>
- <paper-icon-button icon="clear" on-tap="onRemoveLanguageTap_"
- hidden$="[[!canRemoveLanguage_(item.language.code, prefs.intl.app_locale.value)]]">
- </paper-icon-button>
- </paper-item>
- </template>
- </div>
- <h2 i18n-content="allLanguages"></h2>
- <iron-list items="{{availableLanguages_}}" as="item">
- <template>
- <paper-item on-tap="onAddLanguageTap_">
- <div class="language-name">
- <span>[[item.displayName]]</span> -
- <span>[[item.nativeDisplayName]]</span>
+ <div class="settings-box first content">
+ <div class="start">
+ <h2 i18n-content="enabledLanguages"></h2>
+ <div class="list-frame vertical-list">
+ <template is="dom-repeat" items="{{languages.enabledLanguages}}">
+ <div class="list-item">
+ <div class="start" title="[[item.language.nativeDisplayName]]">
+ [[item.language.displayName]]
+ </div>
+ <paper-icon-button icon="clear" on-tap="onRemoveLanguageTap_"
+ hidden$="[[!canRemoveLanguage_(
+ item.language.code, prefs.intl.app_locale.value)]]">
+ </paper-icon-button>
</div>
- <iron-icon icon="done" hidden$="[[!item.enabled]]">
- </iron-icon>
- </paper-item>
- </template>
- </iron-list>
+ </template>
+ </div>
+ <h2 i18n-content="allLanguages"></h2>
+ <div class="list-frame vertical-list">
+ <iron-list items="{{availableLanguages_}}" as="item">
+ <template>
+ <div class="list-item">
+ <paper-checkbox checked="[[item.enabled]]"
+ title$="[[item.nativeDisplayName]]"
+ disabled="[[!canRemoveLanguage_(
+ item.code, prefs.intl.app_locale.value)]]"
+ on-change="onLanguageCheckboxChange_">
+ [[item.displayName]]
+ </paper-checkbox>
+ </div>
+ </template>
+ </iron-list>
+ </div>
+ </div>
</div>
</template>
<script src="manage_languages_page.js"></script>
</dom-module>
-
diff --git a/chromium/chrome/browser/resources/settings/languages_page/manage_languages_page.js b/chromium/chrome/browser/resources/settings/languages_page/manage_languages_page.js
index 36a8cc4a6fc..c7e44bfad36 100644
--- a/chromium/chrome/browser/resources/settings/languages_page/manage_languages_page.js
+++ b/chromium/chrome/browser/resources/settings/languages_page/manage_languages_page.js
@@ -5,9 +5,6 @@
/**
* @fileoverview 'settings-manage-languages-page' is a sub-page for enabling
* and disabling languages.
- *
- * @group Chrome Settings Elements
- * @element settings-manage-languages-page
*/
Polymer({
is: 'settings-manage-languages-page',
@@ -54,16 +51,22 @@ Polymer({
},
/**
- * Handler for adding a language.
- * @param {!{model: {item: !chrome.languageSettingsPrivate.Language}}} e
+ * Handler for checking or unchecking a language item.
+ * @param {!{model: !{item: !chrome.languageSettingsPrivate.Language},
+ * target: !PaperCheckboxElement}} e
* @private
*/
- onAddLanguageTap_: function(e) {
- this.languageHelper_.enableLanguage(e.model.item.code);
+ onLanguageCheckboxChange_: function(e) {
+ var code = e.model.item.code;
+ if (e.target.checked)
+ this.languageHelper_.enableLanguage(code);
+ else
+ this.languageHelper_.disableLanguage(code);
},
/**
- * True if a language is not the current or prospective UI language.
+ * True if a language is not the current or prospective UI language, ie,
+ * it could be disabled.
* @param {string} languageCode
* @param {string} prospectiveUILanguageCode
* @return {boolean}
@@ -74,7 +77,6 @@ Polymer({
languageCode == prospectiveUILanguageCode) {
return false;
}
- assert(this.languages.enabledLanguages.length > 1);
return true;
},
diff --git a/chromium/chrome/browser/resources/settings/on_startup_page/compiled_resources.gyp b/chromium/chrome/browser/resources/settings/on_startup_page/compiled_resources.gyp
deleted file mode 100644
index 90cb870e86f..00000000000
--- a/chromium/chrome/browser/resources/settings/on_startup_page/compiled_resources.gyp
+++ /dev/null
@@ -1,34 +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.
-{
- 'targets': [
- {
- 'target_name': 'on_startup_page',
- 'variables': {
- 'depends': [
- '../../../../../ui/webui/resources/js/compiled_resources.gyp:assert',
- '../../../../../ui/webui/resources/js/compiled_resources.gyp:load_time_data',
- '../settings_page/settings_animated_pages.js'
- ],
- 'externs': [
- '../../../../../third_party/closure_compiler/externs/settings_private.js'
- ],
- },
- 'includes': ['../../../../../third_party/closure_compiler/compile_js.gypi'],
- },
- {
- 'target_name': 'startup_urls_page',
- 'variables': {
- 'depends': [
- '../../../../../ui/webui/resources/js/compiled_resources.gyp:load_time_data',
- '../../../../../ui/webui/resources/js/compiled_resources.gyp:cr',
- ],
- 'externs': [
- '../../../../../third_party/closure_compiler/externs/settings_private.js'
- ],
- },
- 'includes': ['../../../../../third_party/closure_compiler/compile_js.gypi'],
- },
- ],
-}
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
new file mode 100644
index 00000000000..d7d853145da
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/on_startup_page/compiled_resources2.gyp
@@ -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.
+{
+ 'targets': [
+ {
+ 'target_name': 'on_startup_page',
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'startup_urls_page',
+ '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:promise_resolver',
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:util',
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:web_ui_listener_behavior',
+ 'startup_urls_page_browser_proxy',
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'startup_urls_page_browser_proxy',
+ '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:promise_resolver',
+ '<(EXTERNS_GYP):chrome_send',
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ ],
+}
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 35413cbaa0d..e51905bca65 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,38 +1,33 @@
-<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.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/neon-animation/neon-animatable.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-radio-button/paper-radio-button.html">
<link rel="import" href="chrome://md-settings/controls/settings_radio_group.html">
<link rel="import" href="chrome://md-settings/on_startup_page/startup_urls_page.html">
-<link rel="import" href="chrome://md-settings/settings_page/settings_animated_pages.html">
-<link rel="import" href="chrome://md-settings/settings_page/settings_subheader.html">
+<link rel="import" href="chrome://md-settings/settings_shared_css.html">
<dom-module id="settings-on-startup-page">
- <link rel="import" type="css"
- href="chrome://md-settings/settings_shared.css">
<link rel="import" type="css" href="on_startup_shared.css">
<template>
- <div class="settings-box">
- <settings-radio-group id="onStartupRadioGroup"
- pref="{{prefs.session.restore_on_startup}}">
- <paper-radio-button name="[[prefValues_.OPEN_NEW_TAB]]"
- i18n-content="onStartupOpenNewTab">
- </paper-radio-button>
- <paper-radio-button name="[[prefValues_.CONTINUE]]"
- i18n-content="onStartupContinue">
- </paper-radio-button>
- <paper-radio-button name="[[prefValues_.OPEN_SPECIFIC]]">
- <span i18n-content="onStartupOpenSpecific"></span>
- </paper-radio-button>
- </settings-radio-group>
- <template is="dom-if"
- if="[[showStartupUrls_(prefs.session.restore_on_startup.value)]]">
- <div class="list-frame">
- <settings-startup-urls-page prefs="{{prefs}}">
- </settings-startup-urls-page>
- </div>
- </template>
- </div>
+ <style include="settings-shared"></style>
+ <div class="settings-box block first">
+ <settings-radio-group id="onStartupRadioGroup"
+ pref="{{prefs.session.restore_on_startup}}">
+ <paper-radio-button name="[[prefValues_.OPEN_NEW_TAB]]">
+ $i18n{onStartupOpenNewTab}
+ </paper-radio-button>
+ <paper-radio-button name="[[prefValues_.CONTINUE]]">
+ $i18n{onStartupContinue}
+ </paper-radio-button>
+ <paper-radio-button name="[[prefValues_.OPEN_SPECIFIC]]">
+ $i18n{onStartupOpenSpecific}
+ </paper-radio-button>
+ </settings-radio-group>
+ </div>
+ <template is="dom-if"
+ if="[[showStartupUrls_(prefs.session.restore_on_startup.value)]]">
+ <settings-startup-urls-page prefs="{{prefs}}">
+ </settings-startup-urls-page>
</template>
+ </template>
<script src="on_startup_page.js"></script>
</dom-module>
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 765cd8a24ae..d32d6a01be5 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
@@ -13,9 +13,6 @@
* </settings-on-startup-page>
* ... other pages ...
* </neon-animated-pages>
- *
- * @group Chrome Settings Elements
- * @element settings-on-startup-page
*/
Polymer({
is: 'settings-on-startup-page',
diff --git a/chromium/chrome/browser/resources/settings/on_startup_page/on_startup_shared.css b/chromium/chrome/browser/resources/settings/on_startup_page/on_startup_shared.css
index a01757d06b3..28a452c83b8 100644
--- a/chromium/chrome/browser/resources/settings/on_startup_page/on_startup_shared.css
+++ b/chromium/chrome/browser/resources/settings/on_startup_page/on_startup_shared.css
@@ -2,10 +2,6 @@
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file. */
-paper-dialog .body {
- min-width: 500px;
-}
-
paper-radio-button {
display: block;
}
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 ef9944ebcc1..725325a374f 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,61 +1,59 @@
-<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/paper-dialog/paper-dialog.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/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-item/paper-icon-item.html">
+<link rel="import" href="chrome://md-settings/settings_dialog.html">
+<link rel="import" href="chrome://md-settings/settings_shared_css.html">
+<link rel="import" href="chrome://md-settings/on_startup_page/startup_urls_page_browser_proxy.html">
<dom-module id="settings-startup-urls-page">
- <link rel="import" type="css" href="chrome://md-settings/settings_dialog.css">
- <link rel="import" type="css" href="chrome://md-settings/settings_shared.css">
<link rel="import" type="css" href="on_startup_shared.css">
<template>
- <template is="dom-repeat" items="[[startupPages_]]">
- <div class="list-item">
- <iron-icon class="secondary" icon="image:brightness-1"
- item-icon></iron-icon>
- <div class="middle">
- <div class="text-elide">[[item.title]]</div>
- <div class="text-elide secondary">[[item.url]]</div>
+ <style include="settings-shared">
+ .favicon-image {
+ background-size: contain;
+ background-repeat: no-repeat;
+ height: 16px;
+ width: 16px;
+ }
+ </style>
+ <div class="list-frame vertical-list">
+ <template is="dom-repeat" items="[[startupPages_]]">
+ <div class="list-item">
+ <div class="favicon-image"
+ style="background-image: [[getIconSet_(item.url)]]">
+ </div>
+ <div class="middle">
+ <div class="text-elide">[[item.title]]</div>
+ <div class="text-elide secondary">[[item.url]]</div>
+ </div>
+ <iron-icon on-tap="onRemoveUrlTap_" icon="clear"></iron-icon>
</div>
- <iron-icon on-tap="onRemoveUrlTap_" icon="clear"></iron-icon>
+ </template>
+ <div class="list-item list-button" id="addPage" on-tap="onAddPageTap_">
+ $i18n{onStartupAddNewPage}
+ </div>
+ <div class="list-item list-button" on-tap="onUseCurrentPagesTap_">
+ $i18n{onStartupUseCurrent}
</div>
- </template>
- <div class="list-item">
- <paper-button class="link-button" on-tap="onAddPageTap_"
- i18n-content="onStartupAddNewPage">
- </paper-button>
- </div>
- <div class="list-item">
- <paper-button class="link-button" on-tap="onUseCurrentPagesTap_"
- i18n-content="onStartupUseCurrent">
- </paper-button>
</div>
- <paper-dialog modal id="addUrlDialog" class="layout vertical">
- <div id="dialog-content">
- <div class="top-row">
- <div class="title" i18n-content="onStartupAddNewPage"></div>
- <paper-icon-button icon="clear" on-tap="onCancelTap_" id="close">
- </paper-icon-button>
- </div>
- <div class="body">
- <div class="explanation">
- <paper-input class="flex" always-float-label
- i18n-values="label:onStartupSiteUrl" value="{{newUrl}}">
- </paper-input>
- </div>
- <div class="button-container">
- <div class="action-buttons">
- <paper-button class="cancel-button" on-tap="onCancelTap_"
- id="cancel" i18n-content="cancel"></paper-button>
- <paper-button class="action-button" id="addUrlButton"
- on-tap="onOkTap_" i18n-content="addLabel">
- </paper-button>
- </div>
- </div>
+ <settings-dialog id="addUrlDialog">
+ <div class="title">$i18n{onStartupAddNewPage}</div>
+ <div class="body">
+ <paper-input class="flex" always-float-label id="newUrl"
+ label="$i18n{onStartupSiteUrl}" value="{{newUrl_}}">
+ </paper-input>
+ </div>
+ <div class="button-container">
+ <div class="action-buttons">
+ <paper-button class="cancel-button" on-tap="onCancelTap_"
+ id="cancel">$i18n{cancel}</paper-button>
+ <paper-button id="add" class="action-button" on-tap="onAddTap_"
+ disabled="[[!isNewUrlValid_]]">$i18n{add}</paper-button>
</div>
</div>
- </paper-dialog>
-
+ </settings-dialog>
</template>
<script src="startup_urls_page.js"></script>
</dom-module>
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 524a21dd58c..51669432735 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
@@ -22,13 +22,12 @@ var StartupPageInfo;
* </settings-startup-urls-page>
* ... other pages ...
* </neon-animated-pages>
- *
- * @group Chrome Settings Elements
- * @element settings-startup-urls-page
*/
Polymer({
is: 'settings-startup-urls-page',
+ behaviors: [WebUIListenerBehavior],
+
properties: {
/**
* Preferences state.
@@ -38,8 +37,19 @@ Polymer({
notify: true,
},
- newUrl: {
+ /** @type {settings.StartupUrlsPageBrowserProxy} */
+ browserProxy_: Object,
+
+ /** @private {string} */
+ newUrl_: {
+ observer: 'newUrlChanged_',
type: String,
+ value: '',
+ },
+
+ isNewUrlValid_: {
+ type: Boolean,
+ value: false,
},
/**
@@ -49,16 +59,23 @@ Polymer({
startupPages_: Array,
},
+ created: function() {
+ this.browserProxy_ = settings.StartupUrlsPageBrowserProxyImpl.getInstance();
+ },
+
attached: function() {
- var self = this;
- cr.define('Settings', function() {
- return {
- updateStartupPages: function() {
- return self.updateStartupPages_.apply(self, arguments);
- },
- };
- });
- chrome.send('onStartupPrefsPageLoad');
+ this.addWebUIListener('update-startup-pages',
+ this.updateStartupPages_.bind(this));
+ this.browserProxy_.loadStartupPages();
+ },
+
+ /**
+ * @param {string} url Location of an image to get a set of icons fors.
+ * @return {string} A set of icon URLs.
+ * @private
+ */
+ getIconSet_: function(url) {
+ return getFaviconImageSet(url);
},
/** @private */
@@ -68,12 +85,13 @@ Polymer({
/** @private */
onAddPageTap_: function() {
+ this.newUrl_ = '';
this.$.addUrlDialog.open();
},
/** @private */
onUseCurrentPagesTap_: function() {
- chrome.send('setStartupPagesToCurrentPages');
+ this.browserProxy_.useCurrentPages();
},
/** @private */
@@ -81,13 +99,29 @@ Polymer({
this.$.addUrlDialog.close();
},
+ /**
+ * @param {string} newUrl
+ * @private
+ */
+ newUrlChanged_: function(newUrl) {
+ if (this.validationResolver_)
+ this.validationResolver_.reject(false);
+
+ /** @type {?PromiseResolver<boolean>} */
+ this.validationResolver_ = this.browserProxy_.validateStartupPage(newUrl);
+
+ this.validationResolver_.promise.then(function(isValid) {
+ this.isNewUrlValid_ = isValid;
+ this.validationResolver_ = null;
+ }.bind(this), function() {
+ // Squelchs console errors.
+ });
+ },
+
/** @private */
- onOkTap_: function() {
- var value = this.newUrl && this.newUrl.trim();
- if (!value)
- return;
- chrome.send('addStartupPage', [value]);
- this.newUrl = '';
+ onAddTap_: function() {
+ assert(this.isNewUrlValid_);
+ this.browserProxy_.addStartupPage(this.newUrl_);
this.$.addUrlDialog.close();
},
@@ -96,6 +130,6 @@ Polymer({
* @private
*/
onRemoveUrlTap_: function(e) {
- chrome.send('removeStartupPage', [e.model.index]);
+ this.browserProxy_.removeStartupPage(e.model.index);
},
});
diff --git a/chromium/chrome/browser/resources/settings/on_startup_page/startup_urls_page_browser_proxy.html b/chromium/chrome/browser/resources/settings/on_startup_page/startup_urls_page_browser_proxy.html
new file mode 100644
index 00000000000..7346aa55fd3
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/on_startup_page/startup_urls_page_browser_proxy.html
@@ -0,0 +1,4 @@
+<link rel="href" src="chrome://resources/html/assert.html">
+<link rel="href" src="chrome://resources/html/cr.html">
+<link rel="href" src="chrome://resources/html/promise_resolver.html">
+<script src="chrome://md-settings/on_startup_page/startup_urls_page_browser_proxy.js"></script>
diff --git a/chromium/chrome/browser/resources/settings/on_startup_page/startup_urls_page_browser_proxy.js b/chromium/chrome/browser/resources/settings/on_startup_page/startup_urls_page_browser_proxy.js
new file mode 100644
index 00000000000..025748f5009
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/on_startup_page/startup_urls_page_browser_proxy.js
@@ -0,0 +1,69 @@
+// 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 StartupUrlsPageBrowserProxy() {}
+
+ StartupUrlsPageBrowserProxy.prototype = {
+ loadStartupPages: assertNotReached,
+
+ useCurrentPages: assertNotReached,
+
+ /**
+ * @param {string} url
+ * @return {!PromiseResolver<boolean>} Whether the URL is valid.
+ */
+ validateStartupPage: assertNotReached,
+
+ /** @param {string} url */
+ addStartupPage: assertNotReached,
+
+ /** @param {number} index */
+ removeStartupPage: assertNotReached,
+ };
+
+ /**
+ * @implements {settings.StartupUrlsPageBrowserProxy}
+ * @constructor
+ */
+ function StartupUrlsPageBrowserProxyImpl() {}
+
+ cr.addSingletonGetter(StartupUrlsPageBrowserProxyImpl);
+
+ StartupUrlsPageBrowserProxyImpl.prototype = {
+ /** @override */
+ loadStartupPages: function() {
+ chrome.send('onStartupPrefsPageLoad');
+ },
+
+ /** @override */
+ useCurrentPages: function() {
+ chrome.send('setStartupPagesToCurrentPages');
+ },
+
+ /** @override */
+ validateStartupPage: function(url) {
+ var resolver = new PromiseResolver();
+ resolver.promise = url.trim().length == 0 ? Promise.resolve(false) :
+ cr.sendWithPromise('validateStartupPage', url);
+ return resolver;
+ },
+
+ /** @override */
+ addStartupPage: function(url) {
+ chrome.send('addStartupPage', [url.trim()]);
+ },
+
+ /** @override */
+ removeStartupPage: function(index) {
+ chrome.send('removeStartupPage', [index]);
+ },
+ };
+
+ return {
+ StartupUrlsPageBrowserProxy: StartupUrlsPageBrowserProxy,
+ StartupUrlsPageBrowserProxyImpl: StartupUrlsPageBrowserProxyImpl,
+ };
+});
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
new file mode 100644
index 00000000000..cec537426c7
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/passwords_and_forms_page/compiled_resources2.gyp
@@ -0,0 +1,37 @@
+# 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': 'passwords_and_forms_page',
+ 'dependencies': [
+ '../prefs/compiled_resources2.gyp:prefs_behavior',
+ '../settings_page/compiled_resources2.gyp:settings_animated_pages',
+ '<(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:i18n_behavior',
+ '<(EXTERNS_GYP):passwords_private',
+ '<(EXTERNS_GYP):settings_private',
+ 'passwords_section',
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'passwords_section',
+ 'dependencies': [
+ '<(DEPTH)/ui/webui/resources/cr_elements/cr_shared_menu/compiled_resources2.gyp:cr_shared_menu',
+ '<(EXTERNS_GYP):passwords_private',
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'password_edit_dialog',
+ 'dependencies': [
+ '<(DEPTH)/ui/webui/resources/cr_elements/cr_shared_menu/compiled_resources2.gyp:cr_shared_menu',
+ '<(EXTERNS_GYP):passwords_private',
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ ],
+}
diff --git a/chromium/chrome/browser/resources/settings/passwords_and_forms_page/password_edit_dialog.html b/chromium/chrome/browser/resources/settings/passwords_and_forms_page/password_edit_dialog.html
new file mode 100644
index 00000000000..604142e565d
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/passwords_and_forms_page/password_edit_dialog.html
@@ -0,0 +1,55 @@
+<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-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://md-settings/settings_dialog.html">
+<link rel="import" href="chrome://md-settings/settings_shared_css.html">
+
+<dom-module id="password-edit-dialog">
+ <template>
+ <style include="settings-shared"></style>
+ <style>
+ #passwordGroup {
+ align-items: center;
+ display: flex;
+ }
+
+ paper-input {
+ width: var(--paper-input-max-width);
+ }
+
+ paper-icon-button {
+ --iron-icon-fill-color: var(--paper-grey-800);
+ }
+ </style>
+ <settings-dialog id="dialog">
+ <div class="title" i18n-content="editPasswordTitle"></div>
+ <div class="body">
+ <paper-input id="websiteInput"
+ i18n-values="label:editPasswordWebsiteLabel"
+ value="[[item.loginPair.originUrl]]">
+ </paper-input>
+ <paper-input id="usernameInput"
+ i18n-values="label:editPasswordUsernameLabel"
+ value="[[item.loginPair.username]]">
+ </paper-input>
+ <div id="passwordGroup">
+ <paper-input id="passwordInput"
+ i18n-values="label:editPasswordPasswordLabel"
+ type="[[getPasswordInputType_(password)]]"
+ value="[[getPassword_(item, password)]]">
+ </paper-input>
+ <paper-icon-button id="showPasswordButton" icon="icons:visibility"
+ on-tap="onShowPasswordButtonTap_"></paper-icon-button>
+ </div>
+ </div>
+ <div class="button-container">
+ <paper-button id="cancelButton" i18n-content="cancel"
+ on-tap="onCancelButtonTap_"></paper-button>
+ <paper-button id="saveButton" class="action-button" i18n-content="save"
+ on-tap="onSaveButtonTap_"></paper-button>
+ </div>
+ </settings-dialog>
+ </template>
+ <script src="chrome://md-settings/passwords_and_forms_page/password_edit_dialog.js"></script>
+</dom-module>
diff --git a/chromium/chrome/browser/resources/settings/passwords_and_forms_page/password_edit_dialog.js b/chromium/chrome/browser/resources/settings/passwords_and_forms_page/password_edit_dialog.js
new file mode 100644
index 00000000000..b841f52b241
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/passwords_and_forms_page/password_edit_dialog.js
@@ -0,0 +1,95 @@
+// 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 'password-edit-dialog' is the dialog that allows showing a
+ * saved password.
+ */
+
+(function() {
+'use strict';
+
+Polymer({
+ is: 'password-edit-dialog',
+
+ properties: {
+ /**
+ * The password that is being displayed.
+ * @type {!chrome.passwordsPrivate.PasswordUiEntry}
+ */
+ item: {
+ type: Object,
+ value: null,
+ },
+
+ password: {
+ type: String,
+ value: '',
+ },
+ },
+
+ /** Opens the dialog. */
+ open: function() {
+ this.password = '';
+ this.$.dialog.open();
+ },
+
+ /** Closes the dialog. */
+ close: function() {
+ this.$.dialog.close();
+ },
+
+ /**
+ * Gets the password input's type. Should be 'text' when password is visible
+ * and 'password' when it's not.
+ * @param {string} password
+ * @private
+ */
+ getPasswordInputType_: function(password) {
+ return password ? 'text' : 'password';
+ },
+
+ /**
+ * Gets the text of the password. Will use the value of |password| unless it
+ * cannot be shown, in which case it will be spaces.
+ * @param {!chrome.passwordsPrivate.PasswordUiEntry} item
+ * @param {string} password
+ * @private
+ */
+ getPassword_: function(item, password) {
+ if (password)
+ return password;
+ return item ? ' '.repeat(item.numCharactersInPassword) : '';
+ },
+
+ /**
+ * Handler for tapping the show/hide button. Will fire an event to request the
+ * password for this login pair.
+ * @private
+ */
+ onShowPasswordButtonTap_: function() {
+ if (this.password)
+ this.password = '';
+ else
+ this.fire('show-password', this.item.loginPair); // Request the password.
+ },
+
+ /**
+ * Handler for tapping the 'cancel' button. Should just dismiss the dialog.
+ * @private
+ */
+ onCancelButtonTap_: function() {
+ this.close();
+ },
+
+ /**
+ * Handler for tapping the save button.
+ * @private
+ */
+ onSaveButtonTap_: function() {
+ // TODO(hcarmona): what to save?
+ this.close();
+ },
+});
+})();
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 b4257a37782..a949532cf0e 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
@@ -1,45 +1,48 @@
-<link rel="import" href="chrome://resources/polymer/v1_0/polymer/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/polymer/v1_0/paper-item/paper-item-body.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/paper-item/paper-item.html">
+<link rel="import" href="chrome://resources/html/assert.html">
+<link rel="import" href="chrome://resources/html/cr.html">
+<link rel="import" href="chrome://resources/html/i18n_behavior.html">
+<link rel="import" href="chrome://resources/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-toggle-button/paper-toggle-button.html">
<link rel="import" href="chrome://md-settings/passwords_and_forms_page/passwords_section.html">
+<link rel="import" href="chrome://md-settings/prefs/prefs_behavior.html">
+<link rel="import" href="chrome://md-settings/settings_page/settings_animated_pages.html">
+<link rel="import" href="chrome://md-settings/settings_page/settings_subpage.html">
+<link rel="import" href="chrome://md-settings/settings_shared_css.html">
<dom-module id="settings-passwords-and-forms-page">
- <link rel="import" type="css" href="chrome://md-settings/settings_shared.css">
<template>
- <div class="settings-box">
- <paper-item>
- <paper-item-body two-line>
- <div i18n-content="autofill"></div>
- <div secondary i18n-content="autofillDetail"></div>
- </paper-item-body>
- <paper-toggle-button
- checked="{{prefs.autofill.enabled.value}}">
- </paper-toggle-button>
- <cr-expand-button disabled="{{!prefs.autofill.enabled.value}}">
- </cr-expand-button>
- </paper-item>
- </div>
- <div class="settings-box">
- <paper-item>
- <paper-item-body two-line>
- <div i18n-content="passwords"></div>
- <div secondary i18n-content="passwordsDetail"></div>
- </paper-item-body>
- <paper-toggle-button
- checked="{{prefs.profile.password_manager_enabled.value}}">
- </paper-toggle-button>
- <cr-expand-button expanded="{{passwordsOpened}}"
- disabled="{{!prefs.profile.password_manager_enabled.value}}">
- </cr-expand-button>
- </paper-item>
- <iron-collapse id="collapse" opened="{{passwordsOpened}}">
- <passwords-section saved-passwords="{{savedPasswords}}">
- </passwords-section>
- </iron-collapse>
- </div>
+ <style include="settings-shared"></style>
+ <settings-animated-pages id="pages" current-route="{{currentRoute}}"
+ section="passwordsAndForms">
+ <neon-animatable id="main">
+ <div class="settings-box first two-line">
+ <div class="start">
+ <div>[[i18n('autofill')]]</div>
+ <div class="secondary">[[i18n('autofillDetail')]]</div>
+ </div>
+ <paper-toggle-button
+ checked="{{prefs.autofill.enabled.value}}">
+ </paper-toggle-button>
+ </div>
+ <div class="settings-box two-line" on-tap="onPasswordsTap_">
+ <div class="start">
+ <div>[[i18n('passwords')]]</div>
+ <div class="secondary">[[i18n('passwordsDetail')]]</div>
+ </div>
+ <paper-toggle-button id="passwordToggle"
+ checked="{{prefs.profile.password_manager_enabled.value}}">
+ </paper-toggle-button>
+ </div>
+ </neon-animatable>
+ <template is="dom-if" name="manage-passwords">
+ <settings-subpage page-title="[[i18n('passwords')]]">
+ <passwords-section saved-passwords="[[savedPasswords]]"
+ id="passwordSection" password-exceptions="[[passwordExceptions]]">
+ </passwords-section>
+ </settings-subpage>
+ </template>
+ </settings-animated-pages>
</template>
<script src="passwords_and_forms_page.js"></script>
</dom-module>
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 b46e9fb3b23..17cb463942f 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
@@ -5,28 +5,136 @@
/**
* @fileoverview 'settings-passwords-and-forms-page' is the settings page
* for passwords and auto fill.
- *
- * @group Chrome Settings Elements
- * @element settings-passwords-and-forms-page
*/
+
+/**
+ * Interface for all callbacks to the password API.
+ * @interface
+ */
+function PasswordManager() {}
+
+/** @typedef {chrome.passwordsPrivate.PasswordUiEntry} */
+PasswordManager.PasswordUiEntry;
+
+/** @typedef {chrome.passwordsPrivate.LoginPair} */
+PasswordManager.LoginPair;
+
+/** @typedef {chrome.passwordsPrivate.PlaintextPasswordEventParameters} */
+PasswordManager.PlaintextPasswordEvent;
+
+PasswordManager.prototype = {
+ /**
+ * Register a callback for when the list of passwords is updated.
+ * Calling this function should trigger an update.
+ * @param {function(!Array<!PasswordManager.PasswordUiEntry>):void} callback
+ */
+ onSavedPasswordListChangedCallback: assertNotReached,
+
+ /**
+ * Should remove the saved password and notify that the list has changed.
+ * @param {!PasswordManager.LoginPair} loginPair The saved password that
+ * should be removed from the list. No-op if |loginPair| is not found.
+ */
+ removeSavedPassword: assertNotReached,
+
+ /**
+ * Register a callback for when the list of exceptions is updated.
+ * Calling this function should trigger an update.
+ * @param {function(!Array<!string>):void} callback
+ */
+ onExceptionListChangedCallback: assertNotReached,
+
+ /**
+ * Should remove the password exception and notify that the list has changed.
+ * @param {!string} exception The exception that should be removed from the
+ * list. No-op if |exception| is not in the list.
+ */
+ removePasswordException: assertNotReached,
+
+ /**
+ * Register a callback for when a password is requested.
+ * @param {function(!Array<!PasswordManager.LoginPair>):void} callback
+ */
+ onPlaintextPasswordRequestedCallback: assertNotReached,
+
+ /**
+ * Should request the saved password for a given login pair.
+ * @param {!PasswordManager.LoginPair} loginPair The saved password that
+ * should be retrieved.
+ */
+ requestPlaintextPassword: assertNotReached,
+};
+
+/**
+ * Implementation that accesses the private API.
+ * @implements {PasswordManager}
+ * @constructor
+ */
+function PasswordManagerImpl() {}
+cr.addSingletonGetter(PasswordManagerImpl);
+
+PasswordManagerImpl.prototype = {
+ __proto__: PasswordManager,
+
+ /** @override */
+ onSavedPasswordListChangedCallback: function(callback) {
+ chrome.passwordsPrivate.onSavedPasswordsListChanged.addListener(callback);
+ },
+
+ /** @override */
+ removeSavedPassword: function(loginPair) {
+ chrome.passwordsPrivate.removeSavedPassword(loginPair);
+ },
+
+ /** @override */
+ onExceptionListChangedCallback: function(callback) {
+ chrome.passwordsPrivate.onPasswordExceptionsListChanged.addListener(
+ callback);
+ },
+
+ /** @override */
+ removePasswordException: function(exception) {
+ chrome.passwordsPrivate.removePasswordException(exception);
+ },
+
+ /** @override */
+ onPlaintextPasswordRequestedCallback: function(callback) {
+ chrome.passwordsPrivate.onPlaintextPasswordRetrieved.addListener(callback);
+ },
+
+ /** @override */
+ requestPlaintextPassword: function(loginPair) {
+ chrome.passwordsPrivate.requestPlaintextPassword(loginPair);
+ },
+};
+
(function() {
'use strict';
Polymer({
is: 'settings-passwords-and-forms-page',
+ behaviors: [
+ I18nBehavior,
+ PrefsBehavior,
+ ],
+
properties: {
- /**
- * Preferences state.
- */
+ /** Preferences state. */
prefs: {
type: Object,
notify: true,
},
+ /** The current active route. */
+ currentRoute: {
+ type: Object,
+ notify: true,
+ },
+
/**
* An array of passwords to display.
- * Lazy loaded when the password section is expanded.
+ * @type {!Array<!PasswordManager.PasswordUiEntry>}
*/
savedPasswords: {
type: Array,
@@ -34,34 +142,75 @@ Polymer({
},
/**
- * Whether the password section section is opened or not.
+ * An array of sites to display.
+ * @type {!Array<!string>}
*/
- passwordsOpened: {
- type: Boolean,
- value: false,
- observer: 'loadPasswords_',
+ passwordExceptions: {
+ type: Array,
+ value: function() { return []; },
},
},
+ listeners: {
+ 'remove-password-exception': 'removePasswordException_',
+ 'remove-saved-password': 'removeSavedPassword_',
+ 'show-password': 'showPassword_',
+ },
+
+ /** @override */
+ ready: function() {
+ this.passwordManager_ = PasswordManagerImpl.getInstance();
+
+ this.passwordManager_.onSavedPasswordListChangedCallback(function(list) {
+ this.savedPasswords = list;
+ }.bind(this));
+ this.passwordManager_.onExceptionListChangedCallback(function(list) {
+ this.passwordExceptions = list;
+ }.bind(this));
+ this.passwordManager_.onPlaintextPasswordRequestedCallback(function(e) {
+ this.$$('#passwordSection').setPassword(e.loginPair, e.plaintextPassword);
+ }.bind(this));
+ },
+
+ /**
+ * Listens for the remove-password-exception event, and calls the private API.
+ * @param {!Event} event
+ * @private
+ */
+ removePasswordException_: function(event) {
+ this.passwordManager_.removePasswordException(event.detail);
+ },
+
/**
- * Called when the section is expanded. This will load the list of passwords
- * only when needed.
- * @param {boolean} passwordSectionOpened
+ * Listens for the remove-saved-password event, and calls the private API.
+ * @param {!Event} event
+ * @private
*/
- loadPasswords_: function(passwordSectionOpened) {
- if (passwordSectionOpened) {
- // TODO(hcarmona): Get real data.
- this.savedPasswords =
- [{origin: 'otherwebsite.com',
- username: 'bowser',
- password: '************'},
- {origin: 'otherlongwebsite.com',
- username: 'koopa',
- password: '*********'},
- {origin: 'otherverylongwebsite.com',
- username: 'goomba',
- password: '******'}];
+ removeSavedPassword_: function(event) {
+ this.passwordManager_.removeSavedPassword(event.detail);
+ },
+
+ /**
+ * Shows the manage passwords sub page.
+ * @param {!Event} event
+ * @private
+ */
+ onPasswordsTap_: function(event) {
+ // Ignore clicking on the toggle button and only expand if the manager is
+ // enabled.
+ if (Polymer.dom(event).localTarget != this.$.passwordToggle &&
+ this.getPref('profile.password_manager_enabled').value) {
+ this.$.pages.setSubpageChain(['manage-passwords']);
}
},
+
+ /**
+ * Listens for the show-password event, and calls the private API.
+ * @param {!Event} event
+ * @private
+ */
+ showPassword_: function(event) {
+ this.passwordManager_.requestPlaintextPassword(event.detail);
+ },
});
})();
diff --git a/chromium/chrome/browser/resources/settings/passwords_and_forms_page/passwords_section.css b/chromium/chrome/browser/resources/settings/passwords_and_forms_page/passwords_section.css
deleted file mode 100644
index a11186fba11..00000000000
--- a/chromium/chrome/browser/resources/settings/passwords_and_forms_page/passwords_section.css
+++ /dev/null
@@ -1,27 +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. */
-
-.heading {
- color: gray;
-}
-
-.section {
- -webkit-padding-start: 32px;
- padding-top: 16px;
-}
-
-.separator {
- border-top: 1px solid #e0e0e0;
-}
-
-.separator:first-of-type {
- border-top: none;
-}
-
-iron-list {
- /* TODO(hcarmona): Make this flex. */
- -webkit-padding-start: 8px;
- height: 300px;
- padding-top: 16px;
-}
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 47d9d61565d..2626e429c14 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,27 +1,139 @@
-<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.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-item/paper-item-body.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-icon-button/paper-icon-button.html">
+<link rel="import" href="chrome://resources/cr_elements/cr_shared_menu/cr_shared_menu.html">
+<link rel="import" href="chrome://md-settings/passwords_and_forms_page/password_edit_dialog.html">
+<link rel="import" href="chrome://md-settings/settings_shared_css.html">
<dom-module id="passwords-section">
- <link rel="import" type="css" href="chrome://md-settings/site_settings_page/site_settings_page.css">
- <link rel="import" type="css" href="chrome://md-settings/passwords_and_forms_page/passwords_section.css">
<template>
- <div class="section">
- <div class="heading" i18n-content="savedPasswordsHeading"></div>
- <iron-list id="passwordList" class="list-section"
- items="{{savedPasswords}}">
- <template>
- <paper-item class="separator">
- <paper-item-body two-line>
- <div id="origin">[[item.origin]]</div>
- <div id="username"secondary>[[item.username]]</div>
- </paper-item-body>
- <div id="password">[[item.password]]</div>
- </paper-item>
- </template>
- </iron-list>
+ <style include="settings-shared"></style>
+ <style>
+ :host {
+ display: flex;
+ flex-direction: column;
+ }
+
+ #manageLink {
+ -webkit-margin-start: 20px;
+ margin-bottom: 24px;
+ }
+
+ .heading {
+ -webkit-margin-start: 20px;
+ margin-bottom: 8px;
+ }
+
+ #password {
+ background-color: transparent;
+ border: none;
+ flex: 1;
+ height: 20px;
+ width: 0;
+ }
+
+ #saved-password-columns {
+ -webkit-margin-end: 20px;
+ -webkit-margin-start: 56px;
+ color: var(--google-grey-500);
+ font-weight: 500;
+ }
+
+ #passwordList > div:first-of-type {
+ border-top: 1px solid #e0e0e0;
+ }
+
+ .website-column {
+ flex: 3;
+ }
+
+ .username-column {
+ -webkit-margin-end: 16px;
+ -webkit-margin-start: 16px;
+ flex: 2;
+ }
+
+ .password-column {
+ align-items: center;
+ display: flex;
+ flex: 2;
+ }
+
+ /* TODO(hcarmona): Grow menu width by 64px if content is wider */
+ .menu-item {
+ -webkit-padding-start: 24px;
+ width: 104px;
+ }
+
+ paper-icon-button {
+ -webkit-margin-end: 0;
+ -webkit-margin-start: 20px;
+ -webkit-padding-end: 0;
+ -webkit-padding-start: 0;
+ color: var(--google-grey-600);
+ width: 20px;
+ }
+
+ iron-list {
+ -webkit-margin-end: 20px;
+ -webkit-margin-start: 56px;
+ margin-bottom: 16px;
+ }
+ </style>
+ <!-- TODO(hcarmona): i18n this string and link -->
+ <div id="manageLink">Access your passwords from any device at
+ <a target="_blank"
+ href="https://passwords.google.com">passwords.google.com</a></div>
+ <div class="heading" i18n-content="savedPasswordsHeading"></div>
+ <div id="saved-password-columns" class="list-item">
+ <div class="website-column" i18n-content="editPasswordWebsiteLabel"></div>
+ <div class="username-column"
+ i18n-content="editPasswordUsernameLabel"></div>
+ <div class="password-column"
+ i18n-content="editPasswordPasswordLabel"></div>
</div>
+ <iron-list id="passwordList" class="vertical-list list-section"
+ items="[[savedPasswords]]">
+ <template>
+ <div class="list-item">
+ <div id="originUrl"
+ class="website-column">[[item.loginPair.originUrl]]</div>
+ <div id="username"
+ class="username-column">[[item.loginPair.username]]</div>
+ <div class="password-column">
+ <!-- Password type and disabled in order to match mock. -->
+ <input id="password" type="password" disabled
+ value="[[getEmptyPassword_(item.numCharactersInPassword)]]">
+ </input>
+ <paper-icon-button id="passwordMenu" icon="more-vert"
+ on-tap="onPasswordMenuTap_" i18n-values="alt:passwordMenu"
+ tabindex$="[[tabIndex]]">
+ </paper-icon-button>
+ </div>
+ </div>
+ </template>
+ </iron-list>
+ <cr-shared-menu id="menu">
+ <div id="menuEditPassword" class="list-item menu-item"
+ i18n-content="editPassword" on-tap="onMenuEditPasswordTap_"
+ hidden="[[!showPasswords]]"></div>
+ <div id="menuRemovePassword" class="list-item menu-item"
+ i18n-content="removePassword" on-tap="onMenuRemovePasswordTap_">
+ </div>
+ </cr-shared-menu>
+ <password-edit-dialog id="passwordEditDialog"></password-edit-dialog>
+ <div class="heading" i18n-content="passwordExceptionsHeading"></div>
+ <iron-list id="passwordExceptionsList" class="vertical-list list-section"
+ items="[[passwordExceptions]]">
+ <template>
+ <div class="list-item two-line">
+ <div id="exception" class="start">[[item]]</div>
+ <paper-icon-button id="removeExceptionButton" icon="close"
+ on-tap="onRemoveExceptionButtonTap_" tabindex$="[[tabIndex]]"
+ i18n-values="alt:deletePasswordException"></paper-icon-button>
+ </div>
+ </template>
+ </iron-list>
</template>
<script src="chrome://md-settings/passwords_and_forms_page/passwords_section.js"></script>
</dom-module>
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 fc506e8b838..ea16cf493dc 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
@@ -6,10 +6,11 @@
* @fileoverview 'passwords-section' is the collapsible section containing
* the list of saved passwords as well as the list of sites that will never
* save any passwords.
- *
- * @group Chrome Settings Elements
- * @element passwords-section
*/
+
+/** @typedef {!{model: !{item: !chrome.passwordsPrivate.PasswordUiEntry}}} */
+var PasswordUiEntryEvent;
+
(function() {
'use strict';
@@ -19,11 +20,112 @@ Polymer({
properties: {
/**
* An array of passwords to display.
+ * @type {!Array<!chrome.passwordsPrivate.PasswordUiEntry>}
*/
savedPasswords: {
type: Array,
value: function() { return []; },
},
+
+ /**
+ * Whether passwords can be shown or not.
+ * @type {boolean}
+ */
+ showPasswords: {
+ type: Boolean,
+ },
+
+ /**
+ * An array of sites to display.
+ * @type {!Array<!string>}
+ */
+ passwordExceptions: {
+ type: Array,
+ value: function() { return []; },
+ },
+ },
+
+ listeners: {
+ 'passwordList.scroll': 'closeMenu_',
+ 'tap': 'closeMenu_',
+ },
+
+ /**
+ * Sets the password in the current password dialog if the loginPair matches.
+ * @param {!chrome.passwordsPrivate.LoginPair} loginPair
+ * @param {!string} password
+ */
+ setPassword: function(loginPair, password) {
+ var passwordDialog = this.$.passwordEditDialog;
+ if (passwordDialog.item && passwordDialog.item.loginPair &&
+ passwordDialog.item.loginPair.originUrl == loginPair.originUrl &&
+ passwordDialog.item.loginPair.username == loginPair.username) {
+ passwordDialog.password = password;
+ }
+ },
+
+ /**
+ * Shows the edit password dialog.
+ * @private
+ */
+ onMenuEditPasswordTap_: function() {
+ var menu = /** @type {CrSharedMenuElement} */(this.$.menu);
+ var data =
+ /** @type {chrome.passwordsPrivate.PasswordUiEntry} */(menu.itemData);
+ this.$.passwordEditDialog.item = data;
+ this.$.passwordEditDialog.open();
+ menu.closeMenu();
+ },
+
+ /**
+ * Fires an event that should delete the saved password.
+ * @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();
+ },
+
+ /**
+ * Fires an event that should delete the password exception.
+ * @param {!{model: !{item: !string}}} e The polymer event.
+ * @private
+ */
+ onRemoveExceptionButtonTap_: function(e) {
+ this.fire('remove-password-exception', e.model.item);
+ },
+
+ /**
+ * Creates an empty password of specified length.
+ * @param {number} length
+ * @return {string} password
+ * @private
+ */
+ getEmptyPassword_: function(length) { return ' '.repeat(length); },
+
+ /**
+ * Toggles the overflow menu.
+ * @param {!Event} e The polymer event.
+ * @private
+ */
+ onPasswordMenuTap_: function(e) {
+ var menu = /** @type {CrSharedMenuElement} */(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();
},
});
})();
diff --git a/chromium/chrome/browser/resources/settings/people_page/camera.css b/chromium/chrome/browser/resources/settings/people_page/camera.css
new file mode 100644
index 00000000000..f3ce2e64abd
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/people_page/camera.css
@@ -0,0 +1,60 @@
+/* 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. */
+
+#perspectiveBox {
+ -webkit-perspective: 600px;
+ height: 228px;
+ width: 228px;
+}
+
+#userImageStreamCrop {
+ height: 228px;
+ overflow: hidden;
+ position: relative;
+ width: 228px;
+}
+
+#userImageStreamCrop.flip-x {
+ -webkit-transform: rotateY(180deg);
+}
+
+paper-spinner {
+ bottom: 0;
+ left: 0;
+ margin: auto auto;
+ position: absolute;
+ right: 0;
+ top: 0;
+}
+
+#cameraVideo {
+ height: 228px;
+ /* Center image for 4:3 aspect ratio. */
+ left: -16.6%;
+ position: absolute;
+}
+
+#cameraControls {
+ background-color: var(--paper-grey-800);
+ border-bottom-left-radius: 2px;
+ border-bottom-right-radius: 2px;
+ padding: 8px;
+}
+
+#flipPhoto {
+ color: white;
+ float: right;
+}
+
+:host-context([dir=rtl]) #flipPhoto {
+ float: left;
+}
+
+#takePhoto {
+ background-color: var(--paper-green-500);
+ border-radius: 50%;
+ color: white;
+ display: block;
+ margin: 0 auto 0 auto;
+}
diff --git a/chromium/chrome/browser/resources/settings/people_page/camera.html b/chromium/chrome/browser/resources/settings/people_page/camera.html
new file mode 100644
index 00000000000..9d73b384cd6
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/people_page/camera.html
@@ -0,0 +1,33 @@
+<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/html/util.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/iron-icons/image-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-spinner/paper-spinner.html">
+<link rel="import" href="chrome://md-settings/settings_shared_css.html">
+
+<dom-module id="settings-camera">
+ <link rel="import" type="css" href="camera.css">
+ <template>
+ <style include="settings-shared"></style>
+ <div hidden="[[!cameraActive]]">
+ <div id="perspectiveBox">
+ <div id="userImageStreamCrop">
+ <video id="cameraVideo" autoplay hidden="[[!cameraOnline_]]"></video>
+ <paper-spinner active="[[!cameraOnline_]]"></paper-spinner>
+ </div>
+ </div>
+ <div id="cameraControls">
+ <paper-icon-button id="flipPhoto" tabindex="2" icon="image:flip"
+ i18n-values="title:flipPhoto" on-tap="onTapFlipPhoto_"
+ disabled="[[!cameraOnline_]]">
+ </paper-icon-button>
+ <paper-icon-button id="takePhoto" tabindex="1" icon="image:camera-alt"
+ i18n-values="title:takePhoto" on-tap="takePhoto"
+ disabled="[[!cameraOnline_]]">
+ </paper-icon-button>
+ </div>
+ </div>
+ </template>
+ <script src="camera.js"></script>
+</dom-module>
diff --git a/chromium/chrome/browser/resources/settings/people_page/camera.js b/chromium/chrome/browser/resources/settings/people_page/camera.js
new file mode 100644
index 00000000000..91a8f7d03ae
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/people_page/camera.js
@@ -0,0 +1,212 @@
+// 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
+ * 'settings-camera' is the Polymer control used to take a picture from the
+ * user webcam to use as a ChromeOS profile picture.
+ */
+(function() {
+
+/**
+ * Dimensions for camera capture.
+ * @const
+ */
+var CAPTURE_SIZE = {
+ height: 480,
+ width: 480
+};
+
+Polymer({
+ is: 'settings-camera',
+
+ behaviors: [
+ I18nBehavior,
+ ],
+
+ properties: {
+ /**
+ * True if the user has selected the camera as the user image source.
+ * @type {boolean}
+ */
+ cameraActive: {
+ type: Boolean,
+ observer: 'cameraActiveChanged_',
+ },
+
+ /**
+ * True when the camera is actually streaming video. May be false even when
+ * the camera is present and shown, but still initializing.
+ * @private {boolean}
+ */
+ cameraOnline_: {
+ type: Boolean,
+ value: false,
+ },
+
+ /**
+ * True if the photo is currently marked flipped.
+ * @private {boolean}
+ */
+ isFlipped_: {
+ type: Boolean,
+ value: false,
+ },
+ },
+
+ /** @override */
+ attached: function() {
+ this.$.cameraVideo.addEventListener('canplay', function() {
+ this.cameraOnline_ = true;
+ }.bind(this));
+ },
+
+ /**
+ * Performs photo capture from the live camera stream. 'phototaken' event
+ * will be fired as soon as captured photo is available, with 'dataURL'
+ * property containing the photo encoded as a data URL.
+ * @private
+ */
+ takePhoto: function() {
+ if (!this.cameraOnline_)
+ return;
+ var canvas =
+ /** @type {HTMLCanvasElement} */ (document.createElement('canvas'));
+ canvas.width = CAPTURE_SIZE.width;
+ canvas.height = CAPTURE_SIZE.height;
+ this.captureFrame_(
+ this.$.cameraVideo,
+ /** @type {!CanvasRenderingContext2D} */ (canvas.getContext('2d')));
+
+ var photoDataUrl = this.isFlipped_ ? this.flipFrame_(canvas) :
+ canvas.toDataURL('image/png');
+ this.fire('phototaken', {photoDataUrl: photoDataUrl});
+
+ announceAccessibleMessage(
+ loadTimeData.getString('photoCaptureAccessibleText'));
+ },
+
+ /**
+ * Observer for the cameraActive property.
+ * @private
+ */
+ cameraActiveChanged_: function() {
+ if (this.cameraActive)
+ this.startCamera_();
+ else
+ this.stopCamera_();
+ },
+
+ /**
+ * Tries to start the camera stream capture.
+ * @private
+ */
+ startCamera_: function() {
+ this.stopCamera_();
+ this.cameraStartInProgress_ = true;
+
+ var successCallback = function(stream) {
+ if (this.cameraStartInProgress_) {
+ this.$.cameraVideo.src = URL.createObjectURL(stream);
+ this.cameraStream_ = stream;
+ } else {
+ this.stopVideoTracks_(stream);
+ }
+ this.cameraStartInProgress_ = false;
+ }.bind(this);
+
+ var errorCallback = function() {
+ this.cameraOnline_ = false;
+ this.cameraStartInProgress_ = false;
+ }.bind(this);
+
+ navigator.webkitGetUserMedia({video: true}, successCallback, errorCallback);
+ },
+
+ /**
+ * Stops camera capture, if it's currently cameraActive.
+ * @private
+ */
+ stopCamera_: function() {
+ this.cameraOnline_ = false;
+ this.$.cameraVideo.src = '';
+ if (this.cameraStream_)
+ this.stopVideoTracks_(this.cameraStream_);
+ // Cancel any pending getUserMedia() checks.
+ this.cameraStartInProgress_ = false;
+ },
+
+ /**
+ * Stops all video tracks associated with a MediaStream object.
+ * @param {!MediaStream} stream
+ * @private
+ */
+ stopVideoTracks_: function(stream) {
+ var tracks = stream.getVideoTracks();
+ for (var t of tracks)
+ t.stop();
+ },
+
+ /**
+ * Flip the live camera stream.
+ * @private
+ */
+ onTapFlipPhoto_: function() {
+ this.isFlipped_ = !this.isFlipped_;
+ this.$.userImageStreamCrop.classList.toggle('flip-x', this.isFlipped_);
+
+ var flipMessageId = this.isFlipped_ ?
+ 'photoFlippedAccessibleText' : 'photoFlippedBackAccessibleText';
+ announceAccessibleMessage(loadTimeData.getString(flipMessageId));
+ },
+
+ /**
+ * Captures a single still frame from a <video> element, placing it at the
+ * current drawing origin of a canvas context.
+ * @param {!HTMLVideoElement} video Video element to capture from.
+ * @param {!CanvasRenderingContext2D} ctx Canvas context to draw onto.
+ * @private
+ */
+ captureFrame_: function(video, ctx) {
+ var width = video.videoWidth;
+ var height = video.videoHeight;
+ if (width < CAPTURE_SIZE.width || height < CAPTURE_SIZE.height) {
+ console.error('Video capture size too small: ' +
+ width + 'x' + height + '!');
+ }
+ var src = {};
+ if (width / CAPTURE_SIZE.width > height / CAPTURE_SIZE.height) {
+ // Full height, crop left/right.
+ src.height = height;
+ src.width = height * CAPTURE_SIZE.width / CAPTURE_SIZE.height;
+ } else {
+ // Full width, crop top/bottom.
+ src.width = width;
+ src.height = width * CAPTURE_SIZE.height / CAPTURE_SIZE.width;
+ }
+ src.x = (width - src.width) / 2;
+ src.y = (height - src.height) / 2;
+ ctx.drawImage(video, src.x, src.y, src.width, src.height,
+ 0, 0, CAPTURE_SIZE.width, CAPTURE_SIZE.height);
+ },
+
+ /**
+ * Flips frame horizontally.
+ * @param {!(HTMLImageElement|HTMLCanvasElement|HTMLVideoElement)} source
+ * Frame to flip.
+ * @return {string} Flipped frame as data URL.
+ */
+ flipFrame_: function(source) {
+ var canvas = document.createElement('canvas');
+ canvas.width = CAPTURE_SIZE.width;
+ canvas.height = CAPTURE_SIZE.height;
+ var ctx = canvas.getContext('2d');
+ ctx.translate(CAPTURE_SIZE.width, 0);
+ ctx.scale(-1.0, 1.0);
+ ctx.drawImage(source, 0, 0);
+ return canvas.toDataURL('image/png');
+ },
+});
+
+})();
diff --git a/chromium/chrome/browser/resources/settings/people_page/change_picture.css b/chromium/chrome/browser/resources/settings/people_page/change_picture.css
index 914164484c7..48ebc65d72e 100644
--- a/chromium/chrome/browser/resources/settings/people_page/change_picture.css
+++ b/chromium/chrome/browser/resources/settings/people_page/change_picture.css
@@ -2,12 +2,70 @@
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file. */
-#availableIcons {
+#container {
-webkit-margin-start: 16px;
- margin-top: 16px;
+ align-items: flex-start;
+ padding-top: 16px;
}
-.user-image {
+#availableIcons img,
+#availableIcons iron-icon {
+ border-radius: 4px;
+ margin: 8px;
+}
+
+#availableIcons img {
height: 64px;
+ padding: 2px;
+ vertical-align: top;
width: 64px;
}
+
+#availableIcons iron-icon {
+ border: 1px solid var(--google-grey-500);
+ padding: 17px;
+}
+
+#availableIcons .iron-selected {
+ border: 2px solid var(--google-blue-500);
+}
+
+#availableIcons img.iron-selected {
+ padding: 0;
+}
+
+#availableIcons iron-icon.iron-selected {
+ padding: 16px;
+}
+
+#authorCredit,
+#authorCredit a {
+ color: var(--paper-grey-500);
+}
+
+#previewPane {
+ -webkit-margin-end: 10px;
+ flex-shrink: 0;
+ width: 228px;
+}
+
+#previewPane img {
+ display: block;
+ height: 228px;
+ width: 228px;
+}
+
+#discardControlBar {
+ background-color: var(--paper-grey-800);
+ border-bottom-left-radius: 2px;
+ border-bottom-right-radius: 2px;
+ padding: 8px;
+}
+
+#discardOldImage {
+ background-color: var(--paper-red-500);
+ border-radius: 50%;
+ color: white;
+ display: block;
+ margin: 0 auto 0 auto;
+}
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 7fd64f7eb35..b16553d17f1 100644
--- a/chromium/chrome/browser/resources/settings/people_page/change_picture.html
+++ b/chromium/chrome/browser/resources/settings/people_page/change_picture.html
@@ -1,37 +1,64 @@
<link rel="import" href="chrome://resources/html/i18n_behavior.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html">
-<link rel="import" href="chrome://md-settings/people_page/change_picture_private_api.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/html/web_ui_listener_behavior.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-icons/image-icons.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/iron-icons/iron-icons.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/iron-selector/iron-selector.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button.html">
+<link rel="import" href="chrome://md-settings/people_page/camera.html">
+<link rel="import" href="chrome://md-settings/people_page/change_picture_browser_proxy.html">
+<link rel="import" href="chrome://md-settings/settings_shared_css.html">
<dom-module id="settings-change-picture">
- <link rel="import" type="css"
- href="chrome://md-settings/settings_shared.css">
<link rel="import" type="css" href="change_picture.css">
<template>
- <div class="settings-box">
- <div class="split">
- <div id="availableIcons">
- <paper-button toggles
- active="{{isActiveImage_(profileImageUrl_, selectedImageUrl_)}}"
- on-tap="onProfileImageTap_">
- <img class="user-image" src="[[profileImageUrl_]]"
- alt="[[i18n('profilePhotoLoading')]]">
- </paper-button>
- <template is="dom-if" if="[[oldImageUrl_]]">
- <paper-button toggles
- active="{{isActiveImage_(oldImageUrl_, selectedImageUrl_)}}"
- on-tap="onOldImageTap_">
- <img class="user-image" src="[[oldImageUrl_]]">
- </paper-button>
- </template>
+ <style include="settings-shared"></style>
+ <div id="container" class="settings-box" tabindex="0">
+ <iron-a11y-keys keys="up down left right space enter"
+ on-keys-pressed="onKeysPress_">
+ </iron-a11y-keys>
+ <div id="availableIcons" class="start">
+ <iron-selector id="selector" on-iron-activate="onImageActivate_"
+ selected-item="{{selectedItem_}}">
+ <iron-icon id="cameraImage" data-type="camera" icon="image:camera-alt"
+ i18n-values="alt:takePhoto" hidden="[[!cameraPresent_]]">
+ </iron-icon>
+ <iron-icon data-type="file" icon="folder"
+ i18n-values="alt:chooseFile">
+ </iron-icon>
+ <img id="profileImage" data-type="profile"
+ src="[[profileImageUrl_]]" i18n-values="alt:profilePhotoLoading">
+ <img id="oldImage" data-type="old"
+ src="[[oldImageUrl_]]" hidden="[[!oldImageUrl_]]">
<template is="dom-repeat" items="[[defaultImages_]]">
- <paper-button toggles
- active="{{isActiveImage_(item.url, selectedImageUrl_)}}"
- on-tap="onDefaultImageTap_" data-image-url$="[[item.url]]">
- <img class="user-image" src="[[item.url]]" alt="[[item.title]]">
- </paper-button>
+ <img data-type="default" data-default-image-index$="[[index]]"
+ src="[[item.url]]" alt="[[item.title]]">
</template>
+ </iron-selector>
+ <template is="dom-if" if="[[isAuthorCreditShown_(selectedItem_)]]">
+ <div id="authorCredit">
+ [[i18n('authorCredit')]]
+ [[getAuthorName_(selectedItem_, defaultImages_)]]
+ <a href="[[getAuthorWebsite_(selectedItem_, defaultImages_)]]"
+ target="_blank">
+ [[getAuthorWebsite_(selectedItem_, defaultImages_)]]
+ </a>
+ </div>
+ </template>
+ </div>
+ <div id="previewPane">
+ <img i18n-values="alt:previewAltText" src="[[selectedItem_.src]]"
+ hidden="[[isPreviewImageHidden_(selectedItem_)]]">
+ <div id="discardControlBar" hidden="[[isDiscardHidden_(selectedItem_)]]">
+ <paper-icon-button id="discardOldImage" tabindex="0" icon="delete"
+ i18n-values="title:discardPhoto" on-tap="onTapDiscardOldImage_">
+ </paper-icon-button>
</div>
+ <settings-camera id="camera"
+ camera-active="[[isCameraActive_(cameraPresent_, selectedItem_)]]"
+ on-phototaken="onPhotoTaken_">
</div>
</div>
</template>
diff --git a/chromium/chrome/browser/resources/settings/people_page/change_picture.js b/chromium/chrome/browser/resources/settings/people_page/change_picture.js
index 5fe931b3e17..57d0e24f8b5 100644
--- a/chromium/chrome/browser/resources/settings/people_page/change_picture.js
+++ b/chromium/chrome/browser/resources/settings/people_page/change_picture.js
@@ -2,34 +2,67 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+cr.exportPath('settings_test');
+
+/** @type {boolean} */
+settings_test.changePictureNotifyForTest;
+
+/**
+ * An image element.
+ * @typedef {{
+ * dataset: {
+ * type: string,
+ * defaultImageIndex: ?number,
+ * },
+ * src: string,
+ * }}
+ */
+settings.ChangePictureImageElement;
+
/**
* @fileoverview
* 'settings-change-picture' is the settings subpage containing controls to
* edit a ChromeOS user's picture.
- *
- * @group Chrome Settings Elements
- * @element settings-change-picture
*/
Polymer({
is: 'settings-change-picture',
behaviors: [
I18nBehavior,
+ WebUIListenerBehavior,
],
properties: {
/**
- * The currently selected profile image URL. May be a data URL.
- * @private {string}
+ * True if the user has a plugged-in webcam.
+ * @private {boolean}
+ */
+ cameraPresent_: {
+ type: Boolean,
+ value: false,
+ },
+
+ /**
+ * The currently selected item. This property is bound to the iron-selector
+ * and never directly assigned.
+ * @private {settings.ChangePictureImageElement}
*/
- selectedImageUrl_: String,
+ selectedItem_: {
+ type: settings.ChangePictureImageElement,
+ notify: !!settings_test.changePictureNotifyForTest,
+ },
/**
* The url of the 'old' image, which is the existing image sourced from
- * the camera, a file, or a deprecated default image.
+ * the camera, a file, or a deprecated default image. It defaults to an
+ * empty string instead of undefined, because Polymer bindings don't behave
+ * as expected with undefined properties.
* @private {string}
*/
- oldImageUrl_: String,
+ oldImageUrl_: {
+ type: String,
+ value: '',
+ },
/**
* The url of the profile image.
@@ -37,132 +70,340 @@ Polymer({
*/
profileImageUrl_: {
type: String,
- value: settings.ChangePicturePrivateApi.ButtonImages.PROFILE_PICTURE,
+ value: 'chrome://theme/IDR_PROFILE_PICTURE_LOADING',
},
/**
- * The default user images. Populated by ChangePicturePrivateApi.
+ * The default user images.
* @private {!Array<!settings.DefaultImage>}
*/
defaultImages_: {
type: Array,
value: function() { return []; },
},
+
+ /**
+ * The fallback image to be selected when the user discards the 'old' image.
+ * This may be null if the user started with the 'old' image.
+ * @private {?settings.ChangePictureImageElement}
+ */
+ fallbackImage_: {
+ type: settings.ChangePictureImageElement,
+ value: null,
+ },
+
+ /**
+ * Type of the last selected icon. This is used to jump back to the camera
+ * after the user discards a newly taken photo.
+ * @private {string}
+ */
+ lastSelectedImageType_: {
+ type: String,
+ value: '',
+ },
+
+ /** @private {!settings.ChangePictureBrowserProxyImpl} */
+ browserProxy_: {
+ type: Object,
+ value: function() {
+ return settings.ChangePictureBrowserProxyImpl.getInstance();
+ },
+ },
},
/** @override */
attached: function() {
- // This is the interface called by the C++ handler.
- var nativeInterface = {
- /**
- * Called from C++ to provide the default set of images.
- * @param {!Array<!settings.DefaultImage>} images
- */
- receiveDefaultImages: function(images) {
- this.defaultImages_ = images;
- }.bind(this),
-
- /**
- * Called from C++ to provide the URL of the selected image.
- * @param {string} imageUrl
- */
- receiveSelectedImage: function(imageUrl) {
- this.selectedImageUrl_ = imageUrl;
- }.bind(this),
-
- /**
- * Called from C++ to provide the URL of the 'old' image. The 'old'
- * image is any selected non-profile and non-default image. It can be
- * from the camera, a file, or a deprecated default image. When this
- * method is called, it's implied that the old image is selected.
- * @param {string} imageUrl
- */
- receiveOldImage: function(imageUrl) {
- this.oldImageUrl_ = imageUrl;
- this.selectedImageUrl_ = imageUrl;
- }.bind(this),
-
- /**
- * Called from C++ to provide the URL of the profile image.
- * @param {string} imageUrl
- * @param {boolean} selected
- */
- receiveProfileImage: function(imageUrl, selected) {
- this.profileImageUrl_ = imageUrl;
- if (selected)
- this.selectedImageUrl_ = imageUrl;
- }.bind(this),
-
- /**
- * Called from the C++ to notify page about camera presence.
- * @param {boolean} cameraPresent
- */
- receiveCameraPresence: function(cameraPresent) {
- // TODO(tommycli): Implement camera functionality.
- }.bind(this),
- };
-
- cr.define('settings', function() {
- var ChangePicturePage = nativeInterface;
- return {
- ChangePicturePage: ChangePicturePage,
- };
+ this.addWebUIListener('default-images-changed',
+ this.receiveDefaultImages_.bind(this));
+ this.addWebUIListener('selected-image-changed',
+ this.receiveSelectedImage_.bind(this));
+ this.addWebUIListener('old-image-changed',
+ this.receiveOldImage_.bind(this));
+ this.addWebUIListener('profile-image-changed',
+ this.receiveProfileImage_.bind(this));
+ this.addWebUIListener('camera-presence-changed',
+ this.receiveCameraPresence_.bind(this));
+
+ this.browserProxy_.initialize();
+ },
+
+ /**
+ * Handler for the 'default-images-changed' event.
+ * @param {!Array<!settings.DefaultImage>} images
+ * @private
+ */
+ receiveDefaultImages_: function(images) {
+ this.defaultImages_ = images;
+ },
+
+ /**
+ * Handler for the 'selected-image-changed' event. Is only called with
+ * default images.
+ * @param {string} imageUrl
+ * @private
+ */
+ receiveSelectedImage_: function(imageUrl) {
+ var index = this.$.selector.items.findIndex(function(image) {
+ return image.dataset.type == 'default' && image.src == imageUrl;
});
+ assert(index != -1, 'Default image not found: ' + imageUrl);
+
+ this.fallbackImage_ = this.$.selector.items[index];
+
+ // If user is currently taking a photo, do not steal the focus.
+ if (!this.selectedItem_ || this.selectedItem_.dataset.type != 'camera')
+ this.$.selector.select(index);
+ },
+
+ /**
+ * Handler for the 'old-image-changed' event. The 'old' image is any selected
+ * non-profile and non-default image. It can be from the camera, a file, or a
+ * deprecated default image. When this method is called, the old image
+ * becomes the selected image.
+ * @param {string} imageUrl
+ * @private
+ */
+ receiveOldImage_: function(imageUrl) {
+ this.oldImageUrl_ = imageUrl;
+ this.$.selector.select(this.$.selector.indexOf(this.$.oldImage));
+ },
+
+ /**
+ * Handler for the 'profile-image-changed' event.
+ * @param {string} imageUrl
+ * @param {boolean} selected
+ * @private
+ */
+ receiveProfileImage_: function(imageUrl, selected) {
+ this.profileImageUrl_ = imageUrl;
+ this.$.profileImage.alt = this.i18n('profilePhoto');
+
+ if (!selected)
+ return;
+
+ this.fallbackImage_ = this.$.profileImage;
+
+ // If user is currently taking a photo, do not steal the focus.
+ if (!this.selectedItem_ || this.selectedItem_.dataset.type != 'camera')
+ this.$.selector.select(this.$.selector.indexOf(this.$.profileImage));
+ },
- settings.ChangePicturePrivateApi.initialize();
+ /**
+ * Handler for the 'camera-presence-changed' event.
+ * @param {boolean} cameraPresent
+ * @private
+ */
+ receiveCameraPresence_: function(cameraPresent) {
+ this.cameraPresent_ = cameraPresent;
},
/**
- * Handler for when the user clicks a new profile image.
+ * Selects an image element.
+ * @param {!settings.ChangePictureImageElement} image
* @private
+ */
+ selectImage_: function(image) {
+ switch (image.dataset.type) {
+ case 'camera':
+ // Nothing needs to be done.
+ break;
+ case 'file':
+ this.browserProxy_.chooseFile();
+ break;
+ case 'profile':
+ this.browserProxy_.selectProfileImage();
+ break;
+ case 'old':
+ this.browserProxy_.selectOldImage();
+ break;
+ case 'default':
+ this.browserProxy_.selectDefaultImage(image.src);
+ break;
+ default:
+ assertNotReached('Selected unknown image type');
+ }
+ },
+
+ /**
+ * Handler for when accessibility-specific keys are pressed.
+ * @param {!{detail: !{key: string}}} e
+ */
+ onKeysPress_: function(e) {
+ if (!this.selectedItem_)
+ return;
+
+ // In the old Options user images grid, the 'up' and 'down' keys had
+ // different behavior depending on whether ChromeVox was on or off.
+ // If ChromeVox was on, 'up' or 'down' would select the next or previous
+ // image on the left or right. If ChromeVox was off, it would select the
+ // image spatially above or below using calculated columns.
+ //
+ // The code below implements the simple behavior of selecting the image
+ // to the left or right (as if ChromeVox was always on).
+ //
+ // TODO(tommycli): Investigate if it's necessary to calculate columns
+ // and select the image on the top or bottom for non-ChromeVox users.
+ var /** IronSelectorElement */ selector = this.$.selector;
+ switch (e.detail.key) {
+ case 'up':
+ case 'left':
+ // This loop always terminates because the file and profile icons are
+ // never hidden.
+ do {
+ selector.selectPrevious();
+ } while (this.selectedItem_.hidden);
+
+ this.lastSelectedImageType_ = this.selectedItem_.dataset.type;
+ break;
+
+ case 'down':
+ case 'right':
+ // This loop always terminates because the file and profile icons are
+ // never hidden.
+ do {
+ selector.selectNext();
+ } while (this.selectedItem_.hidden);
+
+ this.lastSelectedImageType_ = this.selectedItem_.dataset.type;
+ break;
+
+ case 'enter':
+ case 'space':
+ if (this.selectedItem_.dataset.type == 'camera') {
+ var /** SettingsCameraElement */ camera = this.$.camera;
+ camera.takePhoto();
+ } else if (this.selectedItem_.dataset.type == 'file') {
+ this.browserProxy_.chooseFile();
+ } else if (this.selectedItem_.dataset.type == 'old') {
+ this.onTapDiscardOldImage_();
+ }
+ break;
+ }
+ },
+
+ /**
+ * Handler for when the an image is activated.
* @param {!Event} event
+ * @private
+ */
+ onImageActivate_: function(event) {
+ var image = event.detail.item;
+ this.lastSelectedImageType_ = image.dataset.type;
+ this.selectImage_(image);
+ },
+
+ /**
+ * Handle photo captured event, which contains the data URL of the image.
+ * @param {!{detail: !{photoDataUrl: string}}} event
+ * containing a data URL.
+ */
+ onPhotoTaken_: function(event) {
+ this.browserProxy_.photoTaken(event.detail.photoDataUrl);
+ },
+
+ /**
+ * Discard currently selected old image. Selects the first default icon.
+ * Returns to the camera stream if the user had just taken a picture.
+ * @private
*/
- onDefaultImageTap_: function(event) {
- var element = Polymer.dom(event).rootTarget;
+ onTapDiscardOldImage_: function() {
+ this.oldImageUrl_ = '';
- var imageUrl = null;
- if (element.nodeName == 'IMG')
- imageUrl = element.src;
- else if (element.dataset && element.dataset.imageUrl)
- imageUrl = element.dataset.imageUrl;
+ if (this.lastSelectedImageType_ == 'camera')
+ this.$.selector.select(this.$.selector.indexOf(this.$.cameraImage));
- if (imageUrl != null) {
- settings.ChangePicturePrivateApi.selectDefaultImage(imageUrl);
- // Button toggle state is instead controlled by the selected image URL.
- event.preventDefault();
+ if (this.fallbackImage_ != null) {
+ this.selectImage_(this.fallbackImage_);
+ return;
}
+
+ // If the user has not chosen an image since opening the subpage and
+ // discards the current photo, select the first default image.
+ assert(this.defaultImages_.length > 0);
+ this.browserProxy_.selectDefaultImage(this.defaultImages_[0].url);
+
+ announceAccessibleMessage(
+ loadTimeData.getString('photoDiscardAccessibleText'));
},
/**
- * Handler for when the user clicks the 'old' image.
+ * @param {string} oldImageUrl
+ * @return {boolean} True if there is no old image and the old image icon
+ * should be hidden.
+ * @private
+ */
+ isOldImageHidden_: function(oldImageUrl) { return oldImageUrl.length == 0; },
+
+ /**
+ * @param {settings.ChangePictureImageElement} selectedItem
+ * @return {boolean} True if the preview image should be hidden.
* @private
- * @param {!Event} event
*/
- onOldImageTap_: function(event) {
- settings.ChangePicturePrivateApi.selectOldImage();
- // Button toggle state is instead controlled by the selected image URL.
- event.preventDefault();
+ isPreviewImageHidden_: function(selectedItem) {
+ if (!selectedItem)
+ return true;
+
+ var type = selectedItem.dataset.type;
+ return type != 'default' && type != 'profile' && type != 'old';
},
/**
- * Handler for when the user clicks the 'profile' image.
+ * @param {settings.ChangePictureImageElement} selectedItem
+ * @return {boolean} True if the camera is selected in the image grid.
* @private
- * @param {!Event} event
*/
- onProfileImageTap_: function(event) {
- settings.ChangePicturePrivateApi.selectProfileImage();
- // Button toggle state is instead controlled by the selected image URL.
- event.preventDefault();
+ isCameraActive_: function(cameraPresent, selectedItem) {
+ return cameraPresent && selectedItem &&
+ selectedItem.dataset.type == 'camera';
},
/**
- * Computed binding determining which profile image button is toggled on.
+ * @param {settings.ChangePictureImageElement} selectedItem
+ * @return {boolean} True if the discard controls should be hidden.
* @private
- * @param {string} imageUrl
- * @param {string} selectedImageUrl
- * @return {boolean}
*/
- isActiveImage_: function(imageUrl, selectedImageUrl) {
- return imageUrl == selectedImageUrl;
+ isDiscardHidden_: function(selectedItem) {
+ return !selectedItem || selectedItem.dataset.type != 'old';
+ },
+
+ /**
+ * @param {settings.ChangePictureImageElement} selectedItem
+ * @return {boolean} True if the author credit text is shown.
+ * @private
+ */
+ isAuthorCreditShown_: function(selectedItem) {
+ return selectedItem && selectedItem.dataset.type == 'default';
+ },
+
+ /**
+ * @param {!settings.ChangePictureImageElement} selectedItem
+ * @param {!Array<!settings.DefaultImage>} defaultImages
+ * @return {string} The author name for the selected default image. An empty
+ * string is returned if there is no valid author name.
+ * @private
+ */
+ getAuthorName_: function(selectedItem, defaultImages) {
+ if (!this.isAuthorCreditShown_(selectedItem))
+ return '';
+
+ assert(selectedItem.dataset.defaultImageIndex !== null &&
+ selectedItem.dataset.defaultImageIndex < defaultImages.length);
+ return defaultImages[selectedItem.dataset.defaultImageIndex].author;
+ },
+
+ /**
+ * @param {!settings.ChangePictureImageElement} selectedItem
+ * @param {!Array<!settings.DefaultImage>} defaultImages
+ * @return {string} The author website for the selected default image. An
+ * empty string is returned if there is no valid author name.
+ * @private
+ */
+ getAuthorWebsite_: function(selectedItem, defaultImages) {
+ if (!this.isAuthorCreditShown_(selectedItem))
+ return '';
+
+ assert(selectedItem.dataset.defaultImageIndex !== null &&
+ selectedItem.dataset.defaultImageIndex < defaultImages.length);
+ return defaultImages[selectedItem.dataset.defaultImageIndex].website;
},
});
diff --git a/chromium/chrome/browser/resources/settings/people_page/change_picture_browser_proxy.html b/chromium/chrome/browser/resources/settings/people_page/change_picture_browser_proxy.html
new file mode 100644
index 00000000000..2175c99a8c5
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/people_page/change_picture_browser_proxy.html
@@ -0,0 +1 @@
+<script src="chrome://md-settings/people_page/change_picture_browser_proxy.js"></script>
diff --git a/chromium/chrome/browser/resources/settings/people_page/change_picture_browser_proxy.js b/chromium/chrome/browser/resources/settings/people_page/change_picture_browser_proxy.js
new file mode 100644
index 00000000000..cfcd3cda2e0
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/people_page/change_picture_browser_proxy.js
@@ -0,0 +1,112 @@
+// 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 "Change Picture" subpage of
+ * the People section to interact with the browser. ChromeOS only.
+ */
+cr.exportPath('settings');
+
+/**
+ * An object describing a default image.
+ * @typedef {{
+ * author: string,
+ * title: string,
+ * url: string,
+ * website: string
+ * }}
+ */
+settings.DefaultImage;
+
+cr.define('settings', function() {
+ /** @interface */
+ function ChangePictureBrowserProxy() {}
+
+ ChangePictureBrowserProxy.prototype = {
+ /**
+ * Retrieves the initial set of default images, profile image, etc. As a
+ * response, the C++ sends these WebUIListener events:
+ * 'default-images-changed', 'profile-image-changed', 'old-image-changed',
+ * and 'selected-image-changed'
+ */
+ initialize: function() {},
+
+ /**
+ * Sets the user image to one of the default images. As a response, the C++
+ * sends the 'default-images-changed' WebUIListener event.
+ * @param {string} imageUrl
+ */
+ selectDefaultImage: function(imageUrl) {},
+
+ /**
+ * Sets the user image to the 'old' image. As a response, the C++ sends the
+ * 'old-image-changed' WebUIListener event.
+ */
+ selectOldImage: function() {},
+
+ /**
+ * Sets the user image to the profile image. As a response, the C++ sends
+ * the 'profile-image-changed' WebUIListener event.
+ */
+ selectProfileImage: function() {},
+
+ /**
+ * Provides the taken photo as a data URL to the C++. No response is
+ * expected.
+ * @param {string} photoDataUrl
+ */
+ photoTaken: function(photoDataUrl) {},
+
+ /**
+ * Requests a file chooser to select a new user image. No response is
+ * expected.
+ */
+ chooseFile: function() {},
+ };
+
+ /**
+ * @constructor
+ * @implements {ChangePictureBrowserProxy}
+ */
+ function ChangePictureBrowserProxyImpl() {}
+ // The singleton instance_ is replaced with a test version of this wrapper
+ // during testing.
+ cr.addSingletonGetter(ChangePictureBrowserProxyImpl);
+
+ ChangePictureBrowserProxyImpl.prototype = {
+ /** @override */
+ initialize: function() {
+ chrome.send('onChangePicturePageInitialized');
+ },
+
+ /** @override */
+ selectDefaultImage: function(imageUrl) {
+ chrome.send('selectImage', [imageUrl, 'default']);
+ },
+
+ /** @override */
+ selectOldImage: function() {
+ chrome.send('selectImage', ['', 'old']);
+ },
+
+ /** @override */
+ selectProfileImage: function() {
+ chrome.send('selectImage', ['', 'profile']);
+ },
+
+ /** @override */
+ photoTaken: function(photoDataUrl) {
+ chrome.send('photoTaken', [photoDataUrl]);
+ },
+
+ /** @override */
+ chooseFile: function() {
+ chrome.send('chooseFile');
+ },
+ };
+
+ return {
+ ChangePictureBrowserProxyImpl: ChangePictureBrowserProxyImpl,
+ };
+});
diff --git a/chromium/chrome/browser/resources/settings/people_page/change_picture_private_api.html b/chromium/chrome/browser/resources/settings/people_page/change_picture_private_api.html
deleted file mode 100644
index 1160701f2e9..00000000000
--- a/chromium/chrome/browser/resources/settings/people_page/change_picture_private_api.html
+++ /dev/null
@@ -1 +0,0 @@
-<script src="chrome://md-settings/people_page/change_picture_private_api.js"></script>
diff --git a/chromium/chrome/browser/resources/settings/people_page/change_picture_private_api.js b/chromium/chrome/browser/resources/settings/people_page/change_picture_private_api.js
deleted file mode 100644
index 208a3cdd5c3..00000000000
--- a/chromium/chrome/browser/resources/settings/people_page/change_picture_private_api.js
+++ /dev/null
@@ -1,74 +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.exportPath('settings');
-
-/**
- * An object describing a default image.
- * @typedef {{
- * author: string,
- * title: string,
- * url: string,
- * website: string
- * }}
- */
-settings.DefaultImage;
-
-cr.define('settings', function() {
- /**
- * API which encapsulates messaging between JS and C++ for the ChromeOS
- * Change Picture subpage.
- * @constructor
- */
- function ChangePicturePrivateApi() {}
-
- /**
- * URLs of special button images.
- * @enum {string}
- */
- ChangePicturePrivateApi.ButtonImages = {
- TAKE_PHOTO: 'chrome://theme/IDR_BUTTON_USER_IMAGE_TAKE_PHOTO',
- CHOOSE_FILE: 'chrome://theme/IDR_BUTTON_USER_IMAGE_CHOOSE_FILE',
- PROFILE_PICTURE: 'chrome://theme/IDR_PROFILE_PICTURE_LOADING'
- };
-
- /**
- * Called from JavaScript. Retrieves the initial set of default images,
- * profile image, etc. As a response, the C++ calls these ChangePicturePage
- * methods as callbacks: receiveDefaultImages, receiveOldImage,
- * receiveProfileImage, and receiveSelectedImage.
- */
- ChangePicturePrivateApi.initialize = function() {
- chrome.send('onChangePicturePageInitialized');
- };
-
- /**
- * Called from JavaScript. Sets the user image to one of the default images.
- * As a response, the C++ calls ChangePicturePage.receiveSelectedImage.
- * @param {string} imageUrl
- */
- ChangePicturePrivateApi.selectDefaultImage = function(imageUrl) {
- chrome.send('selectImage', [imageUrl, 'default']);
- };
-
- /**
- * Called from JavaScript. Sets the user image to the 'old' image.
- * As a response, the C++ calls ChangePicturePage.receiveSelectedImage.
- */
- ChangePicturePrivateApi.selectOldImage = function() {
- chrome.send('selectImage', ['', 'old']);
- };
-
- /**
- * Called from JavaScript. Sets the user image to the profile image.
- * As a response, the C++ calls ChangePicturePage.receiveSelectedImage.
- */
- ChangePicturePrivateApi.selectProfileImage = function() {
- chrome.send('selectImage', ['', 'profile']);
- };
-
- return {
- ChangePicturePrivateApi: ChangePicturePrivateApi,
- };
-});
diff --git a/chromium/chrome/browser/resources/settings/people_page/compiled_resources.gyp b/chromium/chrome/browser/resources/settings/people_page/compiled_resources.gyp
deleted file mode 100644
index 7e16fa5cf80..00000000000
--- a/chromium/chrome/browser/resources/settings/people_page/compiled_resources.gyp
+++ /dev/null
@@ -1,67 +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.
-{
- 'targets': [
- {
- 'target_name': 'change_picture',
- 'variables': {
- 'depends': [
- '../../../../../ui/webui/resources/js/compiled_resources.gyp:cr',
- '../../../../../ui/webui/resources/js/compiled_resources.gyp:load_time_data',
- '../../../../../ui/webui/resources/js/i18n_behavior.js',
- 'change_picture_private_api.js',
- ],
- },
- 'includes': ['../../../../../third_party/closure_compiler/compile_js.gypi'],
- },
- {
- 'target_name': 'change_picture_private_api',
- 'variables': {
- 'depends': [
- '../../../../../ui/webui/resources/js/compiled_resources.gyp:cr',
- ],
- },
- 'includes': ['../../../../../third_party/closure_compiler/compile_js.gypi'],
- },
- {
- 'target_name': 'people_page',
- 'variables': {
- 'depends': [
- '../../../../../ui/webui/resources/js/compiled_resources.gyp:assert',
- '../../../../../ui/webui/resources/js/compiled_resources.gyp:cr',
- '../../../../../ui/webui/resources/js/compiled_resources.gyp:load_time_data',
- '../../../../../ui/webui/resources/js/i18n_behavior.js',
- '../settings_page/settings_animated_pages.js',
- 'sync_private_api.js',
- ],
- },
- 'includes': ['../../../../../third_party/closure_compiler/compile_js.gypi'],
- },
- {
- 'target_name': 'sync_page',
- 'variables': {
- 'depends': [
- '../../../../../ui/webui/resources/js/compiled_resources.gyp:assert',
- '../../../../../ui/webui/resources/js/compiled_resources.gyp:cr',
- '../../../../../ui/webui/resources/js/compiled_resources.gyp:load_time_data',
- '../../../../../ui/webui/resources/js/i18n_behavior.js',
- '../settings_page/settings_animated_pages.js',
- 'sync_private_api.js',
- ],
- },
- 'includes': ['../../../../../third_party/closure_compiler/compile_js.gypi'],
- },
- {
- 'target_name': 'sync_private_api',
- 'variables': {
- 'depends': [
- '../../../../../ui/webui/resources/js/compiled_resources.gyp:assert',
- '../../../../../ui/webui/resources/js/compiled_resources.gyp:cr',
- '../../../../../ui/webui/resources/js/cr.js',
- ],
- },
- 'includes': ['../../../../../third_party/closure_compiler/compile_js.gypi'],
- },
- ],
-}
diff --git a/chromium/chrome/browser/resources/settings/people_page/compiled_resources2.gyp b/chromium/chrome/browser/resources/settings/people_page/compiled_resources2.gyp
new file mode 100644
index 00000000000..2d63ef94272
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/people_page/compiled_resources2.gyp
@@ -0,0 +1,102 @@
+# 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': 'camera',
+ 'dependencies': [
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:load_time_data',
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:util',
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:i18n_behavior',
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'change_picture',
+ 'dependencies': [
+ '<(DEPTH)/third_party/polymer/v1_0/components-chromium/iron-selector/compiled_resources2.gyp:iron-selector-extracted',
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:i18n_behavior',
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:load_time_data',
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:util',
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:web_ui_listener_behavior',
+ 'camera',
+ 'change_picture_browser_proxy',
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'change_picture_browser_proxy',
+ 'dependencies': [
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'easy_unlock_browser_proxy',
+ 'dependencies': [
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'easy_unlock_turn_off_dialog',
+ 'dependencies': [
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:i18n_behavior',
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:web_ui_listener_behavior',
+ 'easy_unlock_browser_proxy',
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'manage_profile',
+ 'dependencies': [
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:web_ui_listener_behavior',
+ 'manage_profile_browser_proxy',
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'manage_profile_browser_proxy',
+ 'dependencies': [
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'people_page',
+ 'dependencies': [
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:assert',
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:load_time_data',
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:i18n_behavior',
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:web_ui_listener_behavior',
+ '../settings_page/compiled_resources2.gyp:settings_animated_pages',
+ 'easy_unlock_browser_proxy',
+ 'easy_unlock_turn_off_dialog',
+ 'sync_private_api',
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'sync_page',
+ 'dependencies': [
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:assert',
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:load_time_data',
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:i18n_behavior',
+ '../settings_page/compiled_resources2.gyp:settings_animated_pages',
+ 'sync_private_api',
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'sync_private_api',
+ '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'],
+ },
+ ],
+}
diff --git a/chromium/chrome/browser/resources/settings/people_page/easy_unlock_browser_proxy.html b/chromium/chrome/browser/resources/settings/people_page/easy_unlock_browser_proxy.html
new file mode 100644
index 00000000000..a6bb9dd5ec0
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/people_page/easy_unlock_browser_proxy.html
@@ -0,0 +1 @@
+<script src="chrome://md-settings/people_page/easy_unlock_browser_proxy.js"></script>
diff --git a/chromium/chrome/browser/resources/settings/people_page/easy_unlock_browser_proxy.js b/chromium/chrome/browser/resources/settings/people_page/easy_unlock_browser_proxy.js
new file mode 100644
index 00000000000..72f0a9bcb8b
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/people_page/easy_unlock_browser_proxy.js
@@ -0,0 +1,83 @@
+// 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 People section to interact
+ * with the Easy Unlock functionality of the browser. ChromeOS only.
+ */
+cr.exportPath('settings');
+
+cr.define('settings', function() {
+ /** @interface */
+ function EasyUnlockBrowserProxy() {}
+
+ EasyUnlockBrowserProxy.prototype = {
+ /**
+ * Returns a true promise if Easy Unlock is already enabled on the device.
+ * @return {!Promise<boolean>}
+ */
+ getEnabledStatus: function() {},
+
+ /**
+ * Starts the Easy Unlock setup flow.
+ */
+ startTurnOnFlow: function() {},
+
+ /**
+ * Returns the Easy Unlock turn off flow status.
+ * @return {!Promise<string>}
+ */
+ getTurnOffFlowStatus: function() {},
+
+ /**
+ * Begins the Easy Unlock turn off flow.
+ */
+ startTurnOffFlow: function() {},
+
+ /**
+ * Cancels any in-progress Easy Unlock turn-off flows.
+ */
+ cancelTurnOffFlow: function() {},
+ };
+
+ /**
+ * @constructor
+ * @implements {EasyUnlockBrowserProxy}
+ */
+ function EasyUnlockBrowserProxyImpl() {}
+ // The singleton instance_ is replaced with a test version of this wrapper
+ // during testing.
+ cr.addSingletonGetter(EasyUnlockBrowserProxyImpl);
+
+ EasyUnlockBrowserProxyImpl.prototype = {
+ /** @override */
+ getEnabledStatus: function() {
+ return cr.sendWithPromise('easyUnlockGetEnabledStatus');
+ },
+
+ /** @override */
+ startTurnOnFlow: function() {
+ chrome.send('easyUnlockStartTurnOnFlow');
+ },
+
+ /** @override */
+ getTurnOffFlowStatus: function() {
+ return cr.sendWithPromise('easyUnlockGetTurnOffFlowStatus');
+ },
+
+ /** @override */
+ startTurnOffFlow: function() {
+ chrome.send('easyUnlockStartTurnOffFlow');
+ },
+
+ /** @override */
+ cancelTurnOffFlow: function() {
+ chrome.send('easyUnlockCancelTurnOffFlow');
+ },
+ };
+
+ return {
+ EasyUnlockBrowserProxyImpl: EasyUnlockBrowserProxyImpl,
+ };
+});
diff --git a/chromium/chrome/browser/resources/settings/people_page/easy_unlock_turn_off_dialog.html b/chromium/chrome/browser/resources/settings/people_page/easy_unlock_turn_off_dialog.html
new file mode 100644
index 00000000000..3c3df6e57fb
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/people_page/easy_unlock_turn_off_dialog.html
@@ -0,0 +1,33 @@
+<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-button/paper-button.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-spinner/paper-spinner.html">
+<link rel="import" href="chrome://md-settings/i18n_setup.html">
+<link rel="import" href="chrome://md-settings/people_page/easy_unlock_browser_proxy.html">
+<link rel="import" href="chrome://md-settings/settings_dialog.html">
+<link rel="import" href="chrome://md-settings/settings_shared_css.html">
+
+<dom-module id="easy-unlock-turn-off-dialog">
+ <template>
+ <style include="settings-shared"></style>
+ <settings-dialog id="dialog">
+ <div class="title">[[getTitleText_(state_)]]</div>
+ <div class="body">
+ [[getDescriptionText_(state_)]]
+ </div>
+ <div class="button-container" hidden="[[isButtonBarHidden_(state_)]]">
+ <paper-spinner active="[[isSpinnerActive_(state_)]]">
+ </paper-spinner>
+ <paper-button class="cancel-button" on-tap="onCancelTap_"
+ hidden="[[isCancelButtonHidden_(state_)]]">
+ $i18n{cancel}
+ </paper-button>
+ <paper-button id="turnOff" class="action-button" on-tap="onTurnOffTap_"
+ disabled="[[!isTurnOffButtonEnabled_(state_)]]">
+ [[getTurnOffButtonText_(state_)]]
+ </paper-button>
+ </div>
+ </settings-dialog>
+ </template>
+ <script src="easy_unlock_turn_off_dialog.js"></script>
+</dom-module>
diff --git a/chromium/chrome/browser/resources/settings/people_page/easy_unlock_turn_off_dialog.js b/chromium/chrome/browser/resources/settings/people_page/easy_unlock_turn_off_dialog.js
new file mode 100644
index 00000000000..e658dee3942
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/people_page/easy_unlock_turn_off_dialog.js
@@ -0,0 +1,206 @@
+// 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 dialog allowing the user to turn off the Easy Unlock feature.
+ */
+
+(function() {
+
+/**
+ * Possible UI statuses for the EasyUnlockTurnOffDialogElement.
+ * See easy_unlock_settings_handler.cc.
+ * @enum {string}
+ */
+var EasyUnlockTurnOffStatus = {
+ UNKNOWN: 'unknown',
+ OFFLINE: 'offline',
+ IDLE: 'idle',
+ PENDING: 'pending',
+ SERVER_ERROR: 'server-error',
+};
+
+Polymer({
+ is: 'easy-unlock-turn-off-dialog',
+
+ behaviors: [I18nBehavior, WebUIListenerBehavior],
+
+ properties: {
+ /** @private {!settings.EasyUnlockBrowserProxyImpl} */
+ browserProxy_: Object,
+
+ /** @private {!EasyUnlockTurnOffStatus} */
+ status_: {
+ type: String,
+ value: EasyUnlockTurnOffStatus.UNKNOWN,
+ },
+
+ /** @private {?WebUIListener} */
+ turnOffStatusWebUiListener_: {
+ type: Object,
+ value: null,
+ },
+ },
+
+ /** @override */
+ ready: function() {
+ this.browserProxy_ = settings.EasyUnlockBrowserProxyImpl.getInstance();
+
+ this.addWebUIListener(
+ 'easy-unlock-enabled-status',
+ this.handleEasyUnlockEnabledStatusChanged_.bind(this));
+ },
+
+ /**
+ * Opens the dialog.
+ */
+ open: function() {
+ this.getTurnOffStatus_().then(function(status) {
+ this.status_ = status;
+ this.$.dialog.open();
+ }.bind(this));
+
+ // The turn off flow status listener should only be active when the dialog
+ // is actually open.
+ assert(this.turnOffStatusWebUiListener_ == null);
+ this.turnOffStatusWebUiListener_ = cr.addWebUIListener(
+ 'easy-unlock-turn-off-flow-status',
+ function(status) { this.status_ = status; }.bind(this));
+ },
+
+ /**
+ * @return {!Promise<!EasyUnlockTurnOffStatus>}
+ * @private
+ */
+ getTurnOffStatus_: function() {
+ return navigator.onLine ?
+ this.browserProxy_.getTurnOffFlowStatus() :
+ Promise.resolve(EasyUnlockTurnOffStatus.OFFLINE);
+ },
+
+ /**
+ * This dialog listens for Easy Unlock to become disabled. This signals
+ * that the turnoff process has succeeded. Regardless of whether the turnoff
+ * was initiated from this tab or another, this closes the dialog.
+ * @param {boolean} easyUnlockEnabled
+ * @private
+ */
+ handleEasyUnlockEnabledStatusChanged_: function(easyUnlockEnabled) {
+ var dialog = /** @type {{opened: boolean}} */ this.$.dialog;
+ if (!easyUnlockEnabled && dialog.opened)
+ this.onCancelTap_();
+ },
+
+ /** @private */
+ onCancelTap_: function() {
+ if (this.turnOffStatusWebUiListener_) {
+ cr.removeWebUIListener(this.turnOffStatusWebUiListener_);
+ this.turnOffStatusWebUiListener_ = null;
+ }
+
+ this.browserProxy_.cancelTurnOffFlow();
+ this.$.dialog.close();
+ },
+
+ /** @private */
+ onTurnOffTap_: function() {
+ this.browserProxy_.startTurnOffFlow();
+ },
+
+ /**
+ * @param {!EasyUnlockTurnOffStatus} status
+ * @return {string}
+ * @private
+ */
+ getTitleText_: function(status) {
+ switch (status) {
+ case EasyUnlockTurnOffStatus.OFFLINE:
+ return this.i18n('easyUnlockTurnOffOfflineTitle');
+ case EasyUnlockTurnOffStatus.UNKNOWN:
+ case EasyUnlockTurnOffStatus.IDLE:
+ case EasyUnlockTurnOffStatus.PENDING:
+ return this.i18n('easyUnlockTurnOffTitle');
+ case EasyUnlockTurnOffStatus.SERVER_ERROR:
+ return this.i18n('easyUnlockTurnOffErrorTitle');
+ }
+ assertNotReached();
+ },
+
+ /**
+ * @param {!EasyUnlockTurnOffStatus} status
+ * @return {string}
+ * @private
+ */
+ getDescriptionText_: function(status) {
+ switch (status) {
+ case EasyUnlockTurnOffStatus.OFFLINE:
+ return this.i18n('easyUnlockTurnOffOfflineMessage');
+ case EasyUnlockTurnOffStatus.UNKNOWN:
+ case EasyUnlockTurnOffStatus.IDLE:
+ case EasyUnlockTurnOffStatus.PENDING:
+ return this.i18n('easyUnlockTurnOffDescription');
+ case EasyUnlockTurnOffStatus.SERVER_ERROR:
+ return this.i18n('easyUnlockTurnOffErrorMessage');
+ }
+ assertNotReached();
+ },
+
+ /**
+ * @param {!EasyUnlockTurnOffStatus} status
+ * @return {string}
+ * @private
+ */
+ getTurnOffButtonText_: function(status) {
+ switch (status) {
+ case EasyUnlockTurnOffStatus.OFFLINE:
+ return '';
+ case EasyUnlockTurnOffStatus.UNKNOWN:
+ case EasyUnlockTurnOffStatus.IDLE:
+ case EasyUnlockTurnOffStatus.PENDING:
+ return this.i18n('easyUnlockTurnOffButton');
+ case EasyUnlockTurnOffStatus.SERVER_ERROR:
+ return this.i18n('easyUnlockTurnOffRetryButton');
+ }
+ assertNotReached();
+ },
+
+ /**
+ * @param {!EasyUnlockTurnOffStatus} status
+ * @return {boolean}
+ * @private
+ */
+ isButtonBarHidden_: function(status) {
+ return status == EasyUnlockTurnOffStatus.OFFLINE;
+ },
+
+ /**
+ * @param {!EasyUnlockTurnOffStatus} status
+ * @return {boolean}
+ * @private
+ */
+ isSpinnerActive_: function(status) {
+ return status == EasyUnlockTurnOffStatus.PENDING;
+ },
+
+ /**
+ * @param {!EasyUnlockTurnOffStatus} status
+ * @return {boolean}
+ * @private
+ */
+ isCancelButtonHidden_: function(status) {
+ return status == EasyUnlockTurnOffStatus.SERVER_ERROR;
+ },
+
+ /**
+ * @param {!EasyUnlockTurnOffStatus} status
+ * @return {boolean}
+ * @private
+ */
+ isTurnOffButtonEnabled_: function(status) {
+ return status == EasyUnlockTurnOffStatus.IDLE ||
+ status == EasyUnlockTurnOffStatus.SERVER_ERROR;
+ },
+});
+
+})();
diff --git a/chromium/chrome/browser/resources/settings/people_page/manage_profile.css b/chromium/chrome/browser/resources/settings/people_page/manage_profile.css
deleted file mode 100644
index fe8c87b6d26..00000000000
--- a/chromium/chrome/browser/resources/settings/people_page/manage_profile.css
+++ /dev/null
@@ -1,12 +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. */
-
-paper-input {
- width: 300px;
-}
-
-#availableIcons {
- -webkit-margin-start: 16px;
- margin-top: 16px;
-}
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 822836826da..3697e5ca653 100644
--- a/chromium/chrome/browser/resources/settings/people_page/manage_profile.html
+++ b/chromium/chrome/browser/resources/settings/people_page/manage_profile.html
@@ -1,25 +1,62 @@
-<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.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-selector/iron-selector.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="chrome://md-settings/people_page/sync_private_api.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-styles/shadow.html">
+<link rel="import" href="chrome://md-settings/people_page/manage_profile_browser_proxy.html">
+<link rel="import" href="chrome://md-settings/settings_shared_css.html">
<dom-module id="settings-manage-profile">
- <link rel="import" type="css"
- href="chrome://md-settings/settings_shared.css">
- <link rel="import" type="css" href="manage_profile.css">
<template>
- <div class="settings-box">
- <paper-input value="{{profileName}}" pattern=".*\S.*" auto-validate
- on-blur="onProfileNameChanged_">
+ <style include="settings-shared">
+ #availableIcons {
+ -webkit-margin-start: 16px;
+ margin-top: 16px;
+ max-width: 600px;
+ }
+
+ #selector {
+ display: flex;
+ flex-wrap: wrap;
+ }
+
+ /* Special style for Manage Profile icon grid buttons only. */
+ paper-button {
+ align-items: center;
+ background-color: var(--paper-grey-300);
+ border: 1px solid var(--paper-grey-300);
+ border-radius: 4px;
+ display: flex;
+ height: 48px;
+ justify-content: center;
+ margin: 8px;
+ padding: 0;
+ width: 48px;
+ }
+
+ paper-button:hover {
+ @apply(--shadow-elevation-2dp);
+ }
+
+ paper-button.iron-selected {
+ border: 1px solid var(--google-blue-500);
+ }
+ </style>
+ <div class="settings-box first">
+ <paper-input id="name" value="{{profileName}}" pattern=".*\S.*"
+ auto-validate required on-change="onProfileNameChanged_">
</paper-input>
- <div id="availableIcons">
+ </div>
+ <div id="availableIcons">
+ <iron-selector id="selector" on-iron-activate="onIconActivate_"
+ selected="[[profileIconUrl]]" attr-for-selected="data-icon-url">
<template is="dom-repeat" items="[[availableIconUrls]]">
- <paper-button toggles active="{{isActiveIcon_(item, profileIconUrl)}}"
- on-tap="onIconTap_" data-icon-url$="[[item]]">
+ <paper-button data-icon-url$="[[item]]">
<img src="[[item]]">
</paper-button>
</template>
- </div>
+ </iron-selector>
</div>
</template>
<script src="manage_profile.js"></script>
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 2d4a7cdca3f..2851f688a4d 100644
--- a/chromium/chrome/browser/resources/settings/people_page/manage_profile.js
+++ b/chromium/chrome/browser/resources/settings/people_page/manage_profile.js
@@ -6,13 +6,12 @@
* @fileoverview
* 'settings-manage-profile' is the settings subpage containing controls to
* edit a profile's name, icon, and desktop shortcut.
- *
- * @group Chrome Settings Elements
- * @element settings-manage-profile
*/
Polymer({
is: 'settings-manage-profile',
+ behaviors: [WebUIListenerBehavior],
+
properties: {
/**
* The currently selected profile icon URL. May be a data URL.
@@ -25,28 +24,33 @@ Polymer({
profileName: String,
/**
- * The available icons for selection. Populated by SyncPrivateApi.
- * @type {!Array<!string>}
+ * The available icons for selection.
+ * @type {!Array<string>}
*/
availableIconUrls: {
type: Array,
value: function() { return []; },
},
+
+ /**
+ * @private {!settings.ManageProfileBrowserProxyImpl}
+ */
+ browserProxy_: {
+ type: Object,
+ value: function() {
+ return settings.ManageProfileBrowserProxyImpl.getInstance();
+ },
+ },
},
/** @override */
- created: function() {
- settings.SyncPrivateApi.getAvailableIcons(
- this.handleAvailableIcons_.bind(this));
- },
+ attached: function() {
+ var setIcons = function(iconUrls) {
+ this.availableIconUrls = iconUrls;
+ }.bind(this);
- /**
- * Handler for when the available icons are pushed from SyncPrivateApi.
- * @private
- * @param {!Array<!string>} iconUrls
- */
- handleAvailableIcons_: function(iconUrls) {
- this.availableIconUrls = iconUrls;
+ this.addWebUIListener('available-icons-changed', setIcons);
+ this.browserProxy_.getAvailableIcons().then(setIcons);
},
/**
@@ -55,42 +59,22 @@ Polymer({
* @param {!Event} event
*/
onProfileNameChanged_: function(event) {
- settings.SyncPrivateApi.setProfileIconAndName(this.profileIconUrl,
- event.target.value);
- },
-
- /**
- * Handler for when the user clicks a new profile icon.
- * @private
- * @param {!Event} event
- */
- onIconTap_: function(event) {
- var element = Polymer.dom(event).rootTarget;
-
- var iconUrl;
- if (element.nodeName == 'IMG')
- iconUrl = element.src;
- else if (element.dataset && element.dataset.iconUrl)
- iconUrl = element.dataset.iconUrl;
-
- if (!iconUrl)
+ if (event.target.invalid)
return;
- settings.SyncPrivateApi.setProfileIconAndName(iconUrl, this.profileName);
-
- // Button toggle state is controlled by the selected icon URL. Prevent
- // tap events from changing the toggle state.
- event.preventDefault();
+ this.browserProxy_.setProfileIconAndName(this.profileIconUrl,
+ event.target.value);
},
/**
- * Computed binding determining which profile icon button is toggled on.
+ * Handler for when the an image is activated.
+ * @param {!Event} event
* @private
- * @param {!string} iconUrl
- * @param {!string} paramIconUrl
- * @return {boolean}
*/
- isActiveIcon_: function(iconUrl, profileIconUrl) {
- return iconUrl == profileIconUrl;
+ onIconActivate_: function(event) {
+ /** @type {{iconUrl: string}} */
+ var buttonData = event.detail.item.dataset;
+ this.browserProxy_.setProfileIconAndName(buttonData.iconUrl,
+ this.profileName);
},
});
diff --git a/chromium/chrome/browser/resources/settings/people_page/manage_profile_browser_proxy.html b/chromium/chrome/browser/resources/settings/people_page/manage_profile_browser_proxy.html
new file mode 100644
index 00000000000..97382516771
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/people_page/manage_profile_browser_proxy.html
@@ -0,0 +1,2 @@
+<link rel="import" href="chrome://resources/html/cr.html">
+<script src="chrome://md-settings/people_page/manage_profile_browser_proxy.js"></script>
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
new file mode 100644
index 00000000000..48c03b7e780
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/people_page/manage_profile_browser_proxy.js
@@ -0,0 +1,52 @@
+// 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 "Manage Profile" subpage of
+ * the People section to interact with the browser. Chrome Browser only.
+ */
+cr.define('settings', function() {
+ /** @interface */
+ function ManageProfileBrowserProxy() {}
+
+ ManageProfileBrowserProxy.prototype = {
+ /**
+ * Gets the available profile icons to choose from.
+ * @return {!Promise<!Array<string>>}
+ */
+ getAvailableIcons: function() {},
+
+ /**
+ * Sets the profile's icon and name. There is no response.
+ * @param {!string} iconUrl The new profile URL.
+ * @param {!string} name The new profile name.
+ */
+ setProfileIconAndName: function(iconUrl, name) {},
+ };
+
+ /**
+ * @constructor
+ * @implements {ManageProfileBrowserProxy}
+ */
+ function ManageProfileBrowserProxyImpl() {}
+ // The singleton instance_ is replaced with a test version of this wrapper
+ // during testing.
+ cr.addSingletonGetter(ManageProfileBrowserProxyImpl);
+
+ ManageProfileBrowserProxyImpl.prototype = {
+ /** @override */
+ getAvailableIcons: function() {
+ return cr.sendWithPromise('getAvailableIcons');
+ },
+
+ /** @override */
+ setProfileIconAndName: function(iconUrl, name) {
+ chrome.send('setProfileIconAndName', [iconUrl, name]);
+ },
+ };
+
+ return {
+ ManageProfileBrowserProxyImpl: ManageProfileBrowserProxyImpl,
+ };
+});
diff --git a/chromium/chrome/browser/resources/settings/people_page/people_page.css b/chromium/chrome/browser/resources/settings/people_page/people_page.css
deleted file mode 100644
index 638237e078a..00000000000
--- a/chromium/chrome/browser/resources/settings/people_page/people_page.css
+++ /dev/null
@@ -1,21 +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. */
-
-#account-picture {
- border-radius: 28px;
- height: 56px;
- object-fit: cover;
- vertical-align: middle;
- width: 56px;
-}
-
-#account-picture:hover {
- cursor: pointer;
-}
-
-<if expr="not chromeos">
-#profile-name:hover {
- cursor: pointer;
-}
-</if>
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 9197e99a033..9ca6f77c773 100644
--- a/chromium/chrome/browser/resources/settings/people_page/people_page.html
+++ b/chromium/chrome/browser/resources/settings/people_page/people_page.html
@@ -1,16 +1,21 @@
<link rel="import" href="chrome://resources/html/i18n_behavior.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.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/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-checkbox/paper-checkbox.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-dialog/paper-dialog.html">
+<link rel="import" href="chrome://md-settings/controls/settings_checkbox.html">
<link rel="import" href="chrome://md-settings/people_page/sync_page.html">
<link rel="import" href="chrome://md-settings/people_page/sync_private_api.html">
<link rel="import" href="chrome://md-settings/settings_page/settings_animated_pages.html">
-<link rel="import" href="chrome://md-settings/settings_page/settings_subheader.html">
+<link rel="import" href="chrome://md-settings/settings_page/settings_subpage.html">
+<link rel="import" href="chrome://md-settings/settings_shared_css.html">
<if expr="chromeos">
<link rel="import" href="chrome://md-settings/people_page/change_picture.html">
+<link rel="import" href="chrome://md-settings/people_page/easy_unlock_browser_proxy.html">
+<link rel="import" href="chrome://md-settings/people_page/easy_unlock_turn_off_dialog.html">
<link rel="import" href="chrome://md-settings/people_page/users_page.html">
</if>
<if expr="not chromeos">
@@ -18,48 +23,67 @@
</if>
<dom-module id="settings-people-page">
- <link rel="import" type="css" href="chrome://md-settings/settings_shared.css">
- <link rel="import" type="css" href="people_page.css">
<template>
+ <style include="settings-shared">
+ #account-picture {
+ -webkit-margin-end: 4px;
+ border-radius: 20px;
+ height: 40px;
+ object-fit: cover;
+ vertical-align: middle;
+ width: 40px;
+ }
+
+ #account-picture:hover {
+ cursor: pointer;
+ }
+
+<if expr="not chromeos">
+ #profile-name:hover {
+ cursor: pointer;
+ }
+</if>
+ </style>
<settings-animated-pages id="pages" current-route="{{currentRoute}}"
section="people">
<neon-animatable id="main">
- <div class="settings-box">
- <div class="split">
- <span class="start">
- <img id="account-picture" src="[[profileIconUrl_]]"
- on-tap="onPictureTap_">
+ <div class="settings-box first two-line">
+ <img id="account-picture" src="[[profileIconUrl_]]"
+ on-tap="onPictureTap_">
+ <div class="middle">
<if expr="chromeos">
- <span id="profile-name" on-tap="onProfileNameTap_">
- [[profileName_]]
- </span>
+ <span id="profile-name" on-tap="onProfileNameTap_">
+ [[profileName_]]
+ </span>
</if>
<if expr="not chromeos">
- <span id="profile-name">
- [[profileName_]]
- </span>
-</if>
- </span>
- <span>
- <template is="dom-if" if="[[!syncStatus.signedIn]]">
- <paper-button on-tap="onSigninTap_" raised
- disabled="[[syncStatus.setupInProgress]]">
- [[i18n('syncSignin')]]
- </paper-button>
- </template>
- <template is="dom-if" if="[[syncStatus.signedIn]]">
- <paper-button on-tap="onDisconnectTap_"
- disabled="[[syncStatus.setupInProgress]]">
- [[i18n('syncDisconnect')]]
- </paper-button>
- </template>
+ <span id="profile-name">
+ [[profileName_]]
</span>
+</if>
</div>
- <div hidden="[[syncStatus.signedIn]]">[[i18n('syncOverview')]]</div>
+<if expr="not chromeos">
+ <template is="dom-if" if="[[!syncStatus.signedIn]]">
+ <paper-button class="action-button" on-tap="onSigninTap_"
+ disabled="[[syncStatus.setupInProgress]]">
+ [[i18n('syncSignin')]]
+ </paper-button>
+ </template>
+ <template is="dom-if" if="[[syncStatus.signedIn]]">
+ <span class="secondary-action">
+ <paper-button class="secondary-button" on-tap="onDisconnectTap_"
+ disabled="[[syncStatus.setupInProgress]]">
+ [[i18n('syncDisconnect')]]
+ </paper-button>
+ </span>
+ </template>
+</if>
+ </div>
+ <div class="settings-box two-line" hidden="[[syncStatus.signedIn]]">
+ [[i18n('syncOverview')]]
</div>
- <div class="settings-box split"
- hidden="[[!isStatusTextSet_(syncStatus)]]">
+ <div class="settings-box" hidden="[[!isStatusTextSet_(syncStatus)]]">
<span id="syncStatusText"></span>
<paper-button on-tap="onActionLinkTap_">
[[syncStatus.actionLinkText]]
@@ -69,44 +93,94 @@
<template is="dom-if"
if="[[isAdvancedSyncSettingsVisible_(syncStatus)]]">
<div class="settings-box">
- <paper-button on-tap="onSyncTap_" raised>
+ <paper-button on-tap="onSyncTap_" class="primary-button">
[[i18n('syncPageTitle')]]
</paper-button>
</div>
</template>
+<if expr="chromeos">
+ <div class="settings-box">
+ <settings-checkbox pref="{{prefs.settings.enable_screen_lock}}"
+ i18n-values="label:enableScreenlock">
+ </settings-checkbox>
+ </div>
+
+ <template is="dom-if" if=[[easyUnlockAllowed_]]>
+ <div class="settings-box">
+ <div class="middle">
+ <div>[[i18n('easyUnlockSectionTitle')]]</div>
+ <div class="secondary">
+ <template is="dom-if" if=[[!easyUnlockEnabled_]]>
+ [[i18n('easyUnlockSetupIntro')]]
+ </template>
+ <template is="dom-if" if=[[easyUnlockEnabled_]]>
+ [[i18n('easyUnlockDescription')]]
+ </template>
+ <a target="_blank" href$="[[i18n('easyUnlockLearnMoreURL')]]">
+ [[i18n('learnMore')]]
+ </a>
+ <template is="dom-if" if=[[easyUnlockEnabled_]]>
+ <template is="dom-if"
+ if=[[easyUnlockProximityDetectionAllowed_]]>
+ <settings-checkbox
+ pref="{{prefs.easy_unlock.proximity_required}}"
+ i18n-values="label:easyUnlockRequireProximityLabel">
+ </settings-checkbox>
+ </template>
+ </template>
+ </div>
+ </div>
+ <div class="secondary-action">
+ <template is="dom-if" if=[[!easyUnlockEnabled_]]>
+ <paper-button id="easyUnlockSetup" class="secondary-button"
+ on-tap="onEasyUnlockSetupTap_">
+ [[i18n('easyUnlockSetupButton')]]
+ </paper-button>
+ </template>
+ <template is="dom-if" if=[[easyUnlockEnabled_]]>
+ <paper-button id="easyUnlockTurnOff" class="secondary-button"
+ on-tap="onEasyUnlockTurnOffTap_">
+ [[i18n('easyUnlockTurnOffButton')]]
+ </paper-button>
+ </template>
+ </div>
+ </div>
+ </template>
+</if>
+
<div class="settings-box">
- <paper-button i18n-content="manageOtherPeople"
+ <paper-button class="primary-button" i18n-content="manageOtherPeople"
on-tap="onManageOtherPeople_">
</paper-button>
</div>
</neon-animatable>
- <neon-animatable id="sync">
- <settings-subheader i18n-values="page-title:syncPageTitle">
- </settings-subheader>
- <settings-sync-page current-route="[[currentRoute]]">
- </settings-sync-page>
- </neon-animatable>
+ <template is="dom-if" name="sync">
+ <settings-subpage page-title="[[i18n('syncPageTitle')]]">
+ <settings-sync-page current-route="[[currentRoute]]">
+ </settings-sync-page>
+ </settings-subpage>
+ </template>
<if expr="chromeos">
- <neon-animatable id="users">
- <settings-subheader i18n-values="page-title:usersPageTitle">
- </settings-subheader>
- <settings-users-page prefs="{{prefs}}"></settings-users-page>
- </neon-animatable>
- <neon-animatable id="changePicture">
- <settings-subheader i18n-values="page-title:changePictureTitle">
- </settings-subheader>
- <settings-change-picture></settings-change-picture>
- <neon-animatable>
+ <template is="dom-if" name="users">
+ <settings-subpage page-title="[[i18n('usersPageTitle')]]">
+ <settings-users-page prefs="{{prefs}}"></settings-users-page>
+ </settings-subpage>
+ </template>
+ <template is="dom-if" name="changePicture">
+ <settings-subpage page-title="[[i18n('changePictureTitle')]]">
+ <settings-change-picture></settings-change-picture>
+ </settings-subpage>
+ </template>
</if>
<if expr="not chromeos">
- <neon-animatable id="manageProfile">
- <settings-subheader i18n-values="page-title:editPerson">
- </settings-subheader>
- <settings-manage-profile profile-icon-url="[[profileIconUrl_]]"
- profile-name="[[profileName_]]">
- </settings-manage-profile>
- <neon-animatable>
+ <template is="dom-if" name="manageProfile">
+ <settings-subpage page-title="[[i18n('editPerson')]]">
+ <settings-manage-profile profile-icon-url="[[profileIconUrl_]]"
+ profile-name="[[profileName_]]">
+ </settings-manage-profile>
+ </settings-subpage>
+ </template>
</if>
</settings-animated-pages>
@@ -121,11 +195,18 @@
<div class="button-strip">
<paper-button dialog-dismiss i18n-content="cancel">
</paper-button>
- <paper-button dialog-confirm raised on-tap="onDisconnectConfirm_"
- i18n-content="syncDisconnectConfirm">
+ <paper-button dialog-confirm class="action-button"
+ on-tap="onDisconnectConfirm_" i18n-content="syncDisconnectConfirm">
</paper-button>
</div>
</paper-dialog>
+
+<if expr="chromeos">
+ <template is="dom-if" if="[[easyUnlockEnabled_]]">
+ <easy-unlock-turn-off-dialog id="easyUnlockTurnOffDialog">
+ </easy-unlock-turn-off-dialog>
+ </template>
+</if>
</template>
<script src="people_page.js"></script>
</dom-module>
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 8dc0afbb100..88d361689a4 100644
--- a/chromium/chrome/browser/resources/settings/people_page/people_page.js
+++ b/chromium/chrome/browser/resources/settings/people_page/people_page.js
@@ -12,15 +12,13 @@
* <settings-people-page prefs="{{prefs}}"></settings-people-page>
* ... other pages ...
* </iron-animated-pages>
- *
- * @group Chrome Settings Elements
- * @element settings-people-page
*/
Polymer({
is: 'settings-people-page',
behaviors: [
I18nBehavior,
+ WebUIListenerBehavior,
],
properties: {
@@ -48,22 +46,73 @@ Polymer({
/**
* The currently selected profile icon URL. May be a data URL.
- * @private {string}
*/
profileIconUrl_: String,
/**
* The current profile name.
- * @private {string}
*/
profileName_: String,
+
+<if expr="chromeos">
+ /** @private {!settings.EasyUnlockBrowserProxyImpl} */
+ browserProxy_: {
+ type: Object,
+ value: function() {
+ return settings.EasyUnlockBrowserProxyImpl.getInstance();
+ },
+ },
+
+ /**
+ * True if Easy Unlock is allowed on this machine.
+ */
+ easyUnlockAllowed_: {
+ type: Boolean,
+ value: function() {
+ return loadTimeData.getBoolean('easyUnlockAllowed');
+ },
+ readOnly: true,
+ },
+
+ /**
+ * True if Easy Unlock is enabled.
+ */
+ easyUnlockEnabled_: {
+ type: Boolean,
+ value: function() {
+ return loadTimeData.getBoolean('easyUnlockEnabled');
+ },
+ },
+
+ /**
+ * True if Easy Unlock's proximity detection feature is allowed.
+ */
+ easyUnlockProximityDetectionAllowed_: {
+ type: Boolean,
+ value: function() {
+ return loadTimeData.getBoolean('easyUnlockAllowed') &&
+ loadTimeData.getBoolean('easyUnlockProximityDetectionAllowed');
+ },
+ readOnly: true,
+ },
+</if>
},
/** @override */
- created: function() {
+ attached: function() {
settings.SyncPrivateApi.getProfileInfo(this.handleProfileInfo_.bind(this));
settings.SyncPrivateApi.getSyncStatus(
this.handleSyncStatusFetched_.bind(this));
+
+<if expr="chromeos">
+ if (this.easyUnlockAllowed_) {
+ this.addWebUIListener(
+ 'easy-unlock-enabled-status',
+ this.handleEasyUnlockEnabledStatusChanged_.bind(this));
+ this.browserProxy_.getEnabledStatus().then(
+ this.handleEasyUnlockEnabledStatusChanged_.bind(this));
+ }
+</if>
},
/**
@@ -89,6 +138,16 @@ Polymer({
this.$.syncStatusText.innerHTML = syncStatus.statusText;
},
+<if expr="chromeos">
+ /**
+ * Handler for when the Easy Unlock enabled status has changed.
+ * @private
+ */
+ handleEasyUnlockEnabledStatusChanged_: function(easyUnlockEnabled) {
+ this.easyUnlockEnabled_ = easyUnlockEnabled;
+ },
+</if>
+
/** @private */
onActionLinkTap_: function() {
settings.SyncPrivateApi.showSetupUI();
@@ -134,6 +193,18 @@ Polymer({
this.$.pages.setSubpageChain(['sync']);
},
+<if expr="chromeos">
+ /** @private */
+ onEasyUnlockSetupTap_: function() {
+ this.browserProxy_.startTurnOnFlow();
+ },
+
+ /** @private */
+ onEasyUnlockTurnOffTap_: function() {
+ this.$$('#easyUnlockTurnOffDialog').open();
+ },
+</if>
+
/** @private */
onManageOtherPeople_: function() {
<if expr="not chromeos">
diff --git a/chromium/chrome/browser/resources/settings/people_page/sync_page.css b/chromium/chrome/browser/resources/settings/people_page/sync_page.css
index 3b2eda8941e..743c1a6d271 100644
--- a/chromium/chrome/browser/resources/settings/people_page/sync_page.css
+++ b/chromium/chrome/browser/resources/settings/people_page/sync_page.css
@@ -11,7 +11,7 @@ paper-radio-button {
}
#sync-item-list {
- margin-left: 32px;
+ -webkit-margin-start: 32px;
}
#sync-item-list paper-checkbox {
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 4f42f341445..70437ff71d3 100644
--- a/chromium/chrome/browser/resources/settings/people_page/sync_page.html
+++ b/chromium/chrome/browser/resources/settings/people_page/sync_page.html
@@ -1,5 +1,5 @@
+<link rel="import" href="chrome://resources/html/polymer.html">
<link rel="import" href="chrome://resources/polymer/v1_0/iron-pages/iron-pages.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/polymer/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.html">
@@ -8,13 +8,13 @@
<link rel="import" href="chrome://resources/polymer/v1_0/paper-radio-group/paper-radio-group.html">
<link rel="import" href="chrome://md-settings/controls/settings_checkbox.html">
<link rel="import" href="chrome://md-settings/people_page/sync_private_api.html">
+<link rel="import" href="chrome://md-settings/settings_shared_css.html">
<link rel="import" href="chrome://resources/html/i18n_behavior.html">
<dom-module id="settings-sync-page">
- <link rel="import" type="css"
- href="chrome://md-settings/settings_shared.css">
<link rel="import" type="css" href="sync_page.css">
<template>
+ <style include="settings-shared"></style>
<iron-pages id="pages" selected="loading" attr-for-selected="id">
<div id="loading" i18n-content="syncLoading"></div>
<div id="timeout" i18n-content="syncTimeout"></div>
@@ -118,9 +118,10 @@
</div>
<div class="settings-box">
- <paper-button i18n-content="cancelButton" on-tap="onCancelTap_">
+ <paper-button i18n-content="cancel" on-tap="onCancelTap_">
</paper-button>
- <paper-button i18n-content="okButton" on-tap="onOkTap_" raised>
+ <paper-button i18n-content="ok" on-tap="onOkTap_"
+ class="action-button">
</paper-button>
</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 f8f436f2537..c7b2dcfa3c2 100644
--- a/chromium/chrome/browser/resources/settings/people_page/sync_page.js
+++ b/chromium/chrome/browser/resources/settings/people_page/sync_page.js
@@ -24,9 +24,6 @@ var RadioButtonNames = {
* <settings-sync-page></settings-sync-page>
* ... other pages ...
* </iron-animated-pages>
- *
- * @group Chrome Settings Elements
- * @element settings-sync-page
*/
Polymer({
is: 'settings-sync-page',
diff --git a/chromium/chrome/browser/resources/settings/people_page/sync_private_api.js b/chromium/chrome/browser/resources/settings/people_page/sync_private_api.js
index 1682433657b..17e4752163d 100644
--- a/chromium/chrome/browser/resources/settings/people_page/sync_private_api.js
+++ b/chromium/chrome/browser/resources/settings/people_page/sync_private_api.js
@@ -93,9 +93,6 @@ cr.define('settings', function() {
/** @private {?function(!string, !string)} */
SyncPrivateApi.getProfileInfoCallback_ = null;
- /** @private {?function(!Array<string>)} */
- SyncPrivateApi.getAvailableIconsCallback_ = null;
-
/** @private {?function(settings.SyncPrefs)} */
SyncPrivateApi.syncPrefsCallback_ = null;
@@ -121,42 +118,16 @@ cr.define('settings', function() {
SyncPrivateApi.getProfileInfoCallback_(name, iconUrl);
};
-<if expr="not chromeos">
- /**
- * Called from JavaScript. Gets the available profile icons to choose from.
- * @param {!function(!Array<string>)} callback
- */
- SyncPrivateApi.getAvailableIcons = function(callback) {
- SyncPrivateApi.getAvailableIconsCallback_ = callback;
- chrome.send('requestDefaultProfileIcons');
- };
-
- /**
- * Called from C++ as a response to getAvailableIcons.
- * @param {!Array<string>} iconUrls An array of icon URLs.
- */
- SyncPrivateApi.receiveAvailableIcons = function(iconUrls) {
- if (SyncPrivateApi.getAvailableIconsCallback_)
- SyncPrivateApi.getAvailableIconsCallback_(iconUrls);
- };
-
- /**
- * Called from JavaScript. Sets the profile icon and name.
- * @param {!string} iconUrl The new profile URL.
- * @param {!string} name The new profile name.
- */
- SyncPrivateApi.setProfileIconAndName = function(iconUrl, name) {
- chrome.send('setProfileIconAndName', [iconUrl, name]);
- };
-</if>
-
/**
* Starts the signin process for the user. Does nothing if the user is
* already signed in.
* @private
*/
SyncPrivateApi.startSignIn = function() {
- chrome.send('SyncSetupStartSignIn');
+ // 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]);
};
/**
diff --git a/chromium/chrome/browser/resources/settings/people_page/user_list.css b/chromium/chrome/browser/resources/settings/people_page/user_list.css
index 0db441cdcf4..c870237f7d4 100644
--- a/chromium/chrome/browser/resources/settings/people_page/user_list.css
+++ b/chromium/chrome/browser/resources/settings/people_page/user_list.css
@@ -2,15 +2,6 @@
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file. */
-.clear-icon {
- color: #6e6e6e;
-}
-
-.clear-icon::shadow iron-icon {
- height: 18px;
- width: 18px;
-}
-
.soft-border {
border: 1px solid #c4c4c4;
border-radius: 2px;
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 579424d645e..7a19bcf6fa3 100644
--- a/chromium/chrome/browser/resources/settings/people_page/user_list.html
+++ b/chromium/chrome/browser/resources/settings/people_page/user_list.html
@@ -1,12 +1,12 @@
-<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
+<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="chrome://md-settings/settings_shared_css.html">
<dom-module id="settings-user-list">
- <link rel="import" type="css"
- href="chrome://md-settings/settings_shared.css">
<link rel="import" type="css" href="user_list.css">
<template>
+ <style include="settings-shared"></style>
<div class="user-list soft-border">
<template is="dom-repeat" items="[[users]]">
<div class="user layout horizontal justified">
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 35bce238042..f1f4bcab03e 100644
--- a/chromium/chrome/browser/resources/settings/people_page/user_list.js
+++ b/chromium/chrome/browser/resources/settings/people_page/user_list.js
@@ -11,9 +11,6 @@
*
* <settings-user-list prefs="{{prefs}}">
* </settings-user-list>
- *
- * @group Chrome Settings Elements
- * @element settings-user-list
*/
Polymer({
is: 'settings-user-list',
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 1a421521639..a734ba01bbd 100644
--- a/chromium/chrome/browser/resources/settings/people_page/users_page.html
+++ b/chromium/chrome/browser/resources/settings/people_page/users_page.html
@@ -1,16 +1,17 @@
-<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
+<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-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="chrome://md-settings/controls/settings_checkbox.html">
<link rel="import" href="chrome://md-settings/settings_page/settings_section.html">
+<link rel="import" href="chrome://md-settings/settings_shared_css.html">
<link rel="import" href="user_list.html">
<dom-module id="settings-users-page">
- <link rel="import" type="css" href="chrome://md-settings/settings_shared.css">
<link rel="import" type="css" href="users_page.css">
<template>
+ <style include="settings-shared"></style>
<div class="settings-box" i18n-content="usersModifiedByOwnerLabel"
hidden$="{{computeHideOwnerLabel_(isOwner, isWhitelistManaged)}}">
</div>
@@ -52,8 +53,8 @@
disabled="[[editingUsersDisabled]]">
</paper-input>
<div class="add-user-button layout horizontal end-justified">
- <paper-button i18n-content="addLabel" on-tap="addUser_"
- disabled="[[editingUsersDisabled]]" raised>
+ <paper-button i18n-content="add" on-tap="addUser_"
+ disabled="[[editingUsersDisabled]]" class="action-button">
</paper-button>
</div>
</div>
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 da31d3901d2..3b7af7cebee 100644
--- a/chromium/chrome/browser/resources/settings/people_page/users_page.js
+++ b/chromium/chrome/browser/resources/settings/people_page/users_page.js
@@ -14,9 +14,6 @@
* </settings-users-page>
* ... other pages ...
* </neon-animated-pages>
- *
- * @group Chrome Settings Elements
- * @element settings-users-page
*/
Polymer({
is: 'settings-users-page',
diff --git a/chromium/chrome/browser/resources/settings/pref_tracker/pref_tracker.html b/chromium/chrome/browser/resources/settings/pref_tracker/pref_tracker.html
deleted file mode 100644
index 978dafeea99..00000000000
--- a/chromium/chrome/browser/resources/settings/pref_tracker/pref_tracker.html
+++ /dev/null
@@ -1,6 +0,0 @@
-<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
-<link rel="import" href="chrome://md-settings/prefs/prefs_types.html">
-
-<dom-module id="settings-pref-tracker">
- <script src="pref_tracker.js"></script>
-</dom-module>
diff --git a/chromium/chrome/browser/resources/settings/pref_tracker/pref_tracker.js b/chromium/chrome/browser/resources/settings/pref_tracker/pref_tracker.js
deleted file mode 100644
index 34d9473a3a1..00000000000
--- a/chromium/chrome/browser/resources/settings/pref_tracker/pref_tracker.js
+++ /dev/null
@@ -1,59 +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.
-
-/**
- * @fileoverview
- * `settings-pref-tracker` is a utility element used to track the
- * initialization of a specified preference and throw an error if the pref
- * is not defined after prefs have all been fetched.
- *
- * Example:
- *
- * <settings-pref-tracker pref="{{prefs.settings.foo.bar}}">
- * </settings-pref-tracker>
- *
- * @element settings-pref-tracker
- */
-(function() {
-
- Polymer({
- is: 'settings-pref-tracker',
-
- properties: {
- /**
- * The Preference object being tracked.
- * @type {?PrefObject}
- */
- pref: {
- type: Object,
- observer: 'validate_',
- },
- },
-
- /** @override */
- ready: function() {
- this.validate_();
- },
-
- /**
- * Logs an error once prefs are initialized if the tracked pref is
- * not found.
- * @private
- */
- validate_: function() {
- CrSettingsPrefs.initialized.then(function() {
- // Note that null == undefined.
- if (this.pref == null) {
- // HACK ALERT: This is the best clue we have as to the pref key for
- // this tracker. This value should not be relied upon anywhere or
- // actually used besides for this error message.
- var parentControlHTML = this.domHost && this.domHost.outerHTML;
-
- console.error('Pref not found. Parent control:' +
- (parentControlHTML || 'Unknown'));
- }
- }.bind(this));
- },
- });
-})();
diff --git a/chromium/chrome/browser/resources/settings/prefs/compiled_resources.gyp b/chromium/chrome/browser/resources/settings/prefs/compiled_resources.gyp
deleted file mode 100644
index 0738e33df4b..00000000000
--- a/chromium/chrome/browser/resources/settings/prefs/compiled_resources.gyp
+++ /dev/null
@@ -1,24 +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.
-{
- 'targets': [
- {
- 'target_name': 'prefs',
- 'variables': {
- 'depends': [
- '../../../../../third_party/closure_compiler/externs/settings_private_interface.js',
- '../../../../../ui/webui/resources/js/compiled_resources.gyp:assert',
- '../../../../../ui/webui/resources/js/compiled_resources.gyp:cr',
- 'pref_util.js',
- 'prefs_behavior.js',
- 'prefs_types.js',
- ],
- 'externs': [
- '../../../../../third_party/closure_compiler/externs/settings_private.js'
- ],
- },
- 'includes': ['../../../../../third_party/closure_compiler/compile_js.gypi'],
- },
- ],
-}
diff --git a/chromium/chrome/browser/resources/settings/prefs/compiled_resources2.gyp b/chromium/chrome/browser/resources/settings/prefs/compiled_resources2.gyp
new file mode 100644
index 00000000000..1446acb3227
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/prefs/compiled_resources2.gyp
@@ -0,0 +1,39 @@
+# 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': 'pref_util',
+ 'dependencies': [
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
+ '<(EXTERNS_GYP):settings_private',
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'prefs',
+ 'dependencies': [
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
+ '<(EXTERNS_GYP):settings_private',
+ '<(INTERFACES_GYP):settings_private_interface',
+ 'pref_util',
+ 'prefs_behavior',
+ 'prefs_types',
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'prefs_behavior',
+ 'dependencies': [
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:assert',
+ '<(EXTERNS_GYP):settings_private',
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'prefs_types',
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ ],
+}
diff --git a/chromium/chrome/browser/resources/settings/prefs/prefs.html b/chromium/chrome/browser/resources/settings/prefs/prefs.html
index 6a73790da49..9cf775153e5 100644
--- a/chromium/chrome/browser/resources/settings/prefs/prefs.html
+++ b/chromium/chrome/browser/resources/settings/prefs/prefs.html
@@ -1,7 +1,6 @@
-<link rel="import" href="chrome://resources/html/polymer_config.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
<link rel="import" href="chrome://resources/html/assert.html">
<link rel="import" href="chrome://resources/html/cr.html">
+<link rel="import" href="chrome://resources/html/polymer.html">
<link rel="import" href="prefs_types.html">
<script src="prefs.js"></script>
diff --git a/chromium/chrome/browser/resources/settings/prefs/prefs.js b/chromium/chrome/browser/resources/settings/prefs/prefs.js
index 7f624d3f481..54c0aa2fc77 100644
--- a/chromium/chrome/browser/resources/settings/prefs/prefs.js
+++ b/chromium/chrome/browser/resources/settings/prefs/prefs.js
@@ -16,9 +16,6 @@
* <settings-prefs prefs="{{prefs}}"></settings-prefs>
* <settings-checkbox pref="{{prefs.homepage_is_newtabpage}}">
* </settings-checkbox>
- *
- * @group Chrome Settings Elements
- * @element settings-prefs
*/
(function() {
@@ -414,7 +411,7 @@
getPrefKeyFromPath_: function(path) {
// Skip the first token, which refers to the member variable (this.prefs).
var parts = path.split('.');
- assert(parts.shift() == 'prefs');
+ assert(parts.shift() == 'prefs', "Path doesn't begin with 'prefs'");
for (let i = 1; i <= parts.length; i++) {
let key = parts.slice(0, i).join('.');
diff --git a/chromium/chrome/browser/resources/settings/privacy_page/privacy_page.css b/chromium/chrome/browser/resources/settings/privacy_page/privacy_page.css
deleted file mode 100644
index cebdb9ad06d..00000000000
--- a/chromium/chrome/browser/resources/settings/privacy_page/privacy_page.css
+++ /dev/null
@@ -1,11 +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. */
-
-paper-item {
- --paper-item-min-height: 24px;
-}
-
-.privacy-buttons {
- margin-top: 25px;
-}
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 2e6650a4263..8d52d8fff19 100644
--- a/chromium/chrome/browser/resources/settings/privacy_page/privacy_page.html
+++ b/chromium/chrome/browser/resources/settings/privacy_page/privacy_page.html
@@ -1,26 +1,33 @@
-<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.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-flex-layout/classes/iron-flex-layout.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.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/paper-item/paper-item-body.html">
-<link rel="import" href="chrome://md-settings/certificate_manager_page/certificate_manager_page.html">
-<link rel="import" href="chrome://md-settings/clear_browsing_data_page/clear_browsing_data_page.html">
+<link rel="import" href="chrome://md-settings/clear_browsing_data_dialog/clear_browsing_data_dialog.html">
<link rel="import" href="chrome://md-settings/controls/settings_checkbox.html">
<link rel="import" href="chrome://md-settings/settings_page/settings_animated_pages.html">
-<link rel="import" href="chrome://md-settings/settings_page/settings_subheader.html">
+<link rel="import" href="chrome://md-settings/settings_page/settings_subpage.html">
+<link rel="import" href="chrome://md-settings/settings_shared_css.html">
+<link rel="import" href="chrome://md-settings/site_settings/all_sites.html">
<link rel="import" href="chrome://md-settings/site_settings/constants.html">
<link rel="import" href="chrome://md-settings/site_settings_page/site_settings_page.html">
+<if expr="use_nss_certs">
+<link rel="import" href="chrome://md-settings/certificate_manager_page/certificate_manager_page.html">
+</if>
+<if expr="is_win or is_macosx">
+<link rel="import" href="chrome://md-settings/privacy_page/privacy_page_browser_proxy.html">
+</if>
+
<dom-module id="settings-privacy-page">
- <link rel="import" type="css"
- href="chrome://md-settings/settings_shared.css">
- <link rel="import" type="css" href="privacy_page.css">
<template>
+ <style include="settings-shared"></style>
<settings-animated-pages id="pages" current-route="{{currentRoute}}"
section="privacy">
<neon-animatable id="main">
- <div class="settings-box">
+ <settings-clear-browsing-data-dialog prefs="{{prefs}}">
+ </settings-clear-browsing-data-dialog>
+ <div class="settings-box block first">
<p class="privacy-explanation"
i18n-values=".innerHTML:improveBrowsingExperience">
</p>
@@ -70,136 +77,150 @@
</settings-checkbox>
</if>
</div>
- <div class="settings-box" on-tap="onManageCertificatesTap_">
+<if expr="use_nss_certs or is_win or is_macosx">
+ <div id="manageCertificates" class="settings-box two-line"
+ on-tap="onManageCertificatesTap_">
<div class="start">
<div i18n-content="manageCertificates"></div>
<div class="secondary">
- <!-- TODO(dschuyler) replace this placeholder text -->
+ <!-- TODO(dschuyler): replace this placeholder text -->
Contrary to popular belief, Lorem Ipsum is not simply random text.
</div>
</div>
</div>
- <div class="settings-box" on-tap="onSiteSettingsTap_">
+</if>
+ <div class="settings-box two-line" on-tap="onSiteSettingsTap_">
<div class="start">
<div i18n-content="siteSettings"></div>
<div class="secondary">
- <!-- TODO(dschuyler) replace this placeholder text -->
+ <!-- TODO(dschuyler): replace this placeholder text -->
Contrary to popular belief, Lorem Ipsum is not simply random text.
</div>
</div>
</div>
<div class="settings-box">
- <paper-button on-tap="onClearBrowsingDataTap_"
+ <paper-button on-tap="onClearBrowsingDataTap_" class="primary-button"
i18n-content="clearBrowsingData">
</paper-button>
</div>
</neon-animatable>
- <neon-animatable id="manage-certificates">
- <settings-subheader i18n-values="page-title:manageCertificates">
- </settings-subheader>
- <settings-certificate-manager-page>
- </settings-certificate-manager-page>
- </neon-animatable>
- <neon-animatable id="site-settings">
- <settings-subheader i18n-values="page-title:siteSettings">
- </settings-subheader>
- <settings-site-settings-page current-route="{{currentRoute}}"
- prefs="{{prefs}}">
- </settings-site-settings-page>
- </neon-animatable>
+<if expr="use_nss_certs">
+ <template is="dom-if" name="manage-certificates">
+ <settings-subpage page-title="[[i18n('manageCertificates')]]">
+ <settings-certificate-manager-page>
+ </settings-certificate-manager-page>
+ </settings-subpage>
+ </template>
+</if>
+ <template is="dom-if" name="site-settings">
+ <settings-subpage id="site-settings"
+ page-title="[[i18n('siteSettings')]]">
+ <settings-site-settings-page current-route="{{currentRoute}}"
+ category-selected="{{categorySelected}}">
+ </settings-site-settings-page>
+ </settings-subpage>
+ </template>
- <neon-animatable id="site-settings-category-camera">
- <settings-subheader i18n-values="page-title:siteSettings">
- </settings-subheader>
- <site-settings-category
- selected-origin="{{originSelected}}" prefs="{{prefs}}"
- current-route="{{currentRoute}}"
- category="{{ContentSettingsTypes.CAMERA}}">
- </site-settings-category>
- </neon-animatable>
- <neon-animatable id="site-settings-category-cookies">
- <settings-subheader i18n-values="page-title:siteSettings">
- </settings-subheader>
- <site-settings-category
- selected-origin="{{originSelected}}" prefs="{{prefs}}"
- current-route="{{currentRoute}}"
- category="{{ContentSettingsTypes.COOKIES}}">
- </site-settings-category>
- </neon-animatable>
- <neon-animatable id="site-settings-category-fullscreen">
- <settings-subheader i18n-values="page-title:siteSettings">
- </settings-subheader>
- <site-settings-category
- selected-origin="{{originSelected}}" prefs="{{prefs}}"
- current-route="{{currentRoute}}"
- category="{{ContentSettingsTypes.FULLSCREEN}}">
- </site-settings-category>
- </neon-animatable>
- <neon-animatable id="site-settings-category-images">
- <settings-subheader i18n-values="page-title:siteSettings">
- </settings-subheader>
- <site-settings-category
- selected-origin="{{originSelected}}" prefs="{{prefs}}"
- current-route="{{currentRoute}}"
- category="{{ContentSettingsTypes.IMAGES}}">
- </site-settings-category>
- </neon-animatable>
- <neon-animatable id="site-settings-category-location">
- <settings-subheader i18n-values="page-title:siteSettings">
- </settings-subheader>
- <site-settings-category
- selected-origin="{{originSelected}}" prefs="{{prefs}}"
- current-route="{{currentRoute}}"
- category="{{ContentSettingsTypes.GEOLOCATION}}">
- </site-settings-category>
- </neon-animatable>
- <neon-animatable id="site-settings-category-javascript">
- <settings-subheader i18n-values="page-title:siteSettings">
- </settings-subheader>
- <site-settings-category
- selected-origin="{{originSelected}}" prefs="{{prefs}}"
- current-route="{{currentRoute}}"
- category="{{ContentSettingsTypes.JAVASCRIPT}}">
- </site-settings-category>
- </neon-animatable>
- <neon-animatable id="site-settings-category-microphone">
- <settings-subheader i18n-values="page-title:siteSettings">
- </settings-subheader>
- <site-settings-category
- selected-origin="{{originSelected}}" prefs="{{prefs}}"
- current-route="{{currentRoute}}"
- category="{{ContentSettingsTypes.MIC}}">
- </site-settings-category>
- </neon-animatable>
- <neon-animatable id="site-settings-category-notifications">
- <settings-subheader i18n-values="page-title:siteSettings">
- </settings-subheader>
- <site-settings-category
- selected-origin="{{originSelected}}" prefs="{{prefs}}"
- current-route="{{currentRoute}}"
- category="{{ContentSettingsTypes.NOTIFICATIONS}}">
- </site-settings-category>
- </neon-animatable>
- <neon-animatable id="site-settings-category-popups">
- <settings-subheader i18n-values="page-title:siteSettings">
- </settings-subheader>
- <site-settings-category
- selected-origin="{{originSelected}}" prefs="{{prefs}}"
- current-route="{{currentRoute}}"
- category="{{ContentSettingsTypes.POPUPS}}">
- </site-settings-category>
- </neon-animatable>
+ <template is="dom-if" name="all-sites">
+ <settings-subpage page-title="[[i18n('siteSettingsCategoryAllSites')]]">
+ <all-sites
+ selected-site="{{selectedSite}}"
+ current-route="{{currentRoute}}">
+ </all-sites>
+ </settings-subpage>
+ </template>
+ <template is="dom-if" name="site-settings-category-camera">
+ <settings-subpage page-title="[[i18n('siteSettingsCategoryCamera')]]">
+ <site-settings-category
+ selected-site="{{selectedSite}}"
+ current-route="{{currentRoute}}"
+ category="{{ContentSettingsTypes.CAMERA}}">
+ </site-settings-category>
+ </settings-subpage>
+ </template>
+ <template is="dom-if" name="site-settings-category-cookies">
+ <settings-subpage page-title="[[i18n('siteSettingsCategoryCookies')]]">
+ <site-settings-category
+ selected-site="{{selectedSite}}"
+ current-route="{{currentRoute}}"
+ category="{{ContentSettingsTypes.COOKIES}}">
+ </site-settings-category>
+ </settings-subpage>
+ </template>
+ <template is="dom-if" name="site-settings-category-fullscreen">
+ <settings-subpage
+ page-title="[[i18n('siteSettingsCategoryFullscreen')]]">
+ <site-settings-category
+ selected-site="{{selectedSite}}"
+ current-route="{{currentRoute}}"
+ category="{{ContentSettingsTypes.FULLSCREEN}}">
+ </site-settings-category>
+ </settings-subpage>
+ </template>
+ <template is="dom-if" name="site-settings-category-images">
+ <settings-subpage page-title="[[i18n('siteSettingsCategoryImages')]]">
+ <site-settings-category
+ selected-site="{{selectedSite}}"
+ current-route="{{currentRoute}}"
+ category="{{ContentSettingsTypes.IMAGES}}">
+ </site-settings-category>
+ </settings-subpage>
+ </template>
+ <template is="dom-if" name="site-settings-category-location">
+ <settings-subpage page-title="[[i18n('siteSettingsCategoryLocation')]]">
+ <site-settings-category
+ selected-site="{{selectedSite}}"
+ current-route="{{currentRoute}}"
+ category="{{ContentSettingsTypes.GEOLOCATION}}">
+ </site-settings-category>
+ </settings-subpage>
+ </template>
+ <template is="dom-if" name="site-settings-category-javascript">
+ <settings-subpage
+ page-title="[[i18n('siteSettingsCategoryJavascript')]]">
+ <site-settings-category
+ selected-site="{{selectedSite}}"
+ current-route="{{currentRoute}}"
+ category="{{ContentSettingsTypes.JAVASCRIPT}}">
+ </site-settings-category>
+ </settings-subpage>
+ </template>
+ <template is="dom-if" name="site-settings-category-microphone">
+ <settings-subpage
+ page-title="[[i18n('siteSettingsCategoryMicrophone')]]">
+ <site-settings-category
+ selected-site="{{selectedSite}}"
+ current-route="{{currentRoute}}"
+ category="{{ContentSettingsTypes.MIC}}">
+ </site-settings-category>
+ </settings-subpage>
+ </template>
+ <template is="dom-if" name="site-settings-category-notifications">
+ <settings-subpage
+ page-title="[[i18n('siteSettingsCategoryNotifications')]]">
+ <site-settings-category
+ selected-site="{{selectedSite}}"
+ current-route="{{currentRoute}}"
+ category="{{ContentSettingsTypes.NOTIFICATIONS}}">
+ </site-settings-category>
+ </settings-subpage>
+ </template>
+ <template is="dom-if" name="site-settings-category-popups">
+ <settings-subpage page-title="[[i18n('siteSettingsCategoryPopups')]]">
+ <site-settings-category
+ selected-site="{{selectedSite}}"
+ current-route="{{currentRoute}}"
+ category="{{ContentSettingsTypes.POPUPS}}">
+ </site-settings-category>
+ </settings-subpage>
+ </template>
- <neon-animatable id="site-details">
- <site-details prefs="{{prefs}}" origin="{{originSelected}}">
- </site-details>
- </neon-animatable>
- <neon-animatable id="clear-browsing-data">
- <settings-subheader i18n-values="page-title:clearBrowsingData">
- </settings-subheader>
- <settings-clear-browsing-data-page prefs="{{prefs}}">
- </settings-clear-browsing-data-page>
- </neon-animatable>
+ <template is="dom-if" name="site-details">
+ <settings-subpage
+ page-title="[[i18n('siteSettingsSiteDetailsPageTitle')]]">
+ <site-details site="[[selectedSite]]"></site-details>
+ </settings-subpage>
+ </template>
</settings-animated-pages>
</template>
<script src="privacy_page.js"></script>
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 d5b122bf99c..f32e8538028 100644
--- a/chromium/chrome/browser/resources/settings/privacy_page/privacy_page.js
+++ b/chromium/chrome/browser/resources/settings/privacy_page/privacy_page.js
@@ -14,13 +14,14 @@
* </settings-privacy-page>
* ... other pages ...
* </iron-animated-pages>
- *
- * @group Chrome Settings Elements
- * @element settings-privacy-page
*/
Polymer({
is: 'settings-privacy-page',
+ behaviors: [
+ I18nBehavior,
+ ],
+
properties: {
/**
* Preferences state.
@@ -37,14 +38,6 @@ Polymer({
type: Object,
notify: true,
},
-
- /**
- * The origin selected by the user.
- */
- originSelected: {
- type: String,
- observer: 'onSelectedOriginChanged_',
- }
},
ready: function() {
@@ -53,7 +46,13 @@ Polymer({
/** @private */
onManageCertificatesTap_: function() {
+<if expr="use_nss_certs">
this.$.pages.setSubpageChain(['manage-certificates']);
+</if>
+<if expr="is_win or is_macosx">
+ settings.PrivacyPageBrowserProxyImpl.getInstance().
+ showManageSSLCertificates();
+</if>
},
/** @private */
@@ -63,11 +62,6 @@ Polymer({
/** @private */
onClearBrowsingDataTap_: function() {
- this.$.pages.setSubpageChain(['clear-browsing-data']);
- },
-
- onSelectedOriginChanged_: function() {
- this.$.pages.setSubpageChain(
- ['site-settings', 'site-settings-category', 'site-details']);
+ this.$.pages.querySelector('settings-clear-browsing-data-dialog').open();
},
});
diff --git a/chromium/chrome/browser/resources/settings/privacy_page/privacy_page_browser_proxy.html b/chromium/chrome/browser/resources/settings/privacy_page/privacy_page_browser_proxy.html
new file mode 100644
index 00000000000..39be7f4a4d6
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/privacy_page/privacy_page_browser_proxy.html
@@ -0,0 +1,3 @@
+<link rel="import" href="chrome://resources/html/cr.html">
+<script src="chrome://md-settings/privacy_page/privacy_page_browser_proxy.js">
+</script>
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
new file mode 100644
index 00000000000..98d9e507436
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/privacy_page/privacy_page_browser_proxy.js
@@ -0,0 +1,34 @@
+// 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 Handles interprocess communcation for the privacy page. */
+
+cr.define('settings', function() {
+ /** @interface */
+ function PrivacyPageBrowserProxy() {}
+
+ PrivacyPageBrowserProxy.prototype = {
+ /** Invokes the native certificate manager (used by win and mac). */
+ showManageSSLCertificates: function() {},
+ };
+
+ /**
+ * @constructor
+ * @implements {settings.PrivacyPageBrowserProxy}
+ */
+ function PrivacyPageBrowserProxyImpl() {}
+ cr.addSingletonGetter(PrivacyPageBrowserProxyImpl);
+
+ PrivacyPageBrowserProxyImpl.prototype = {
+ /** @override */
+ showManageSSLCertificates: function() {
+ chrome.send('showManageSSLCertificates');
+ },
+ };
+
+ return {
+ PrivacyPageBrowserProxy: PrivacyPageBrowserProxy,
+ PrivacyPageBrowserProxyImpl: PrivacyPageBrowserProxyImpl,
+ };
+});
diff --git a/chromium/chrome/browser/resources/settings/reset_page/compiled_resources2.gyp b/chromium/chrome/browser/resources/settings/reset_page/compiled_resources2.gyp
new file mode 100644
index 00000000000..8e32a677733
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/reset_page/compiled_resources2.gyp
@@ -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.
+{
+ 'targets': [
+ {
+ 'target_name': 'reset_page',
+ 'dependencies': [
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:load_time_data',
+ '<(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/reset_page/powerwash_dialog.html b/chromium/chrome/browser/resources/settings/reset_page/powerwash_dialog.html
index 82b07e550ac..a6942696e2c 100644
--- a/chromium/chrome/browser/resources/settings/reset_page/powerwash_dialog.html
+++ b/chromium/chrome/browser/resources/settings/reset_page/powerwash_dialog.html
@@ -1,37 +1,30 @@
-<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.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-dialog/paper-dialog.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button.html">
+<link rel="import" href="chrome://md-settings/reset_page/reset_browser_proxy.html">
+<link rel="import" href="chrome://md-settings/settings_dialog.html">
+<link rel="import" href="chrome://md-settings/settings_shared_css.html">
<dom-module id="settings-powerwash-dialog">
- <link rel="import" type="css" href="chrome://md-settings/settings_dialog.css">
<link rel="import" type="css" href="reset_page_dialog.css">
<template>
- <paper-dialog modal id="dialog">
- <div id="dialog-content">
- <div class="top-row">
- <span class="title" i18n-content="powerwashDialogTitle"></span>
- <paper-icon-button icon="clear" on-tap="onCancelTap_" id="close">
- </paper-icon-button>
- </div>
- <div class="body">
- <div class="explanation">
- <span i18n-content="powerwashDialogExplanation"></span>
- <a i18n-values="href:powerwashLearnMoreUrl"
- i18n-content="learnMore" target="_blank"></a>
- </div>
- <div class="button-container">
- <paper-button class="cancel-button" on-tap="onCancelTap_"
- id="cancel" i18n-content="cancel"></paper-button>
- <paper-button class="action-button" id="powerwash"
- on-tap="onRestartTap_" i18n-content="powerwashDialogButton">
- </paper-button>
- </div>
- </div>
+ <style include="settings-shared"></style>
+ <settings-dialog id="dialog">
+ <div class="title" i18n-content="powerwashDialogTitle"></div>
+ <div class="body">
+ <span i18n-content="powerwashDialogExplanation"></span>
+ <a i18n-values="href:powerwashLearnMoreUrl"
+ i18n-content="learnMore" target="_blank"></a>
</div>
- </paper-dialog>
+ <div class="button-container">
+ <paper-button class="cancel-button" on-tap="onCancelTap_"
+ id="cancel" i18n-content="cancel"></paper-button>
+ <paper-button class="action-button" id="powerwash"
+ on-tap="onRestartTap_" i18n-content="powerwashDialogButton">
+ </paper-button>
+ </div>
+ </settings-dialog>
</template>
<script src="powerwash_dialog.js"></script>
</dom-module>
diff --git a/chromium/chrome/browser/resources/settings/reset_page/powerwash_dialog.js b/chromium/chrome/browser/resources/settings/reset_page/powerwash_dialog.js
index b55bd9e0cb8..848f0b19a01 100644
--- a/chromium/chrome/browser/resources/settings/reset_page/powerwash_dialog.js
+++ b/chromium/chrome/browser/resources/settings/reset_page/powerwash_dialog.js
@@ -6,15 +6,12 @@
* @fileoverview
* 'settings-reset-page' is the settings page containing reset
* settings.
- *
- * @group Chrome Settings Elements
- * @element settings-reset-page
*/
Polymer({
is: 'settings-powerwash-dialog',
open: function() {
- chrome.send('onPowerwashDialogShow');
+ settings.ResetBrowserProxyImpl.getInstance().onPowerwashDialogShow();
this.$.dialog.open();
},
@@ -25,6 +22,6 @@ Polymer({
/** @private */
onRestartTap_: function() {
- chrome.send('requestFactoryResetRestart');
+ settings.ResetBrowserProxyImpl.getInstance().requestFactoryResetRestart();
},
});
diff --git a/chromium/chrome/browser/resources/settings/reset_page/reset_browser_proxy.html b/chromium/chrome/browser/resources/settings/reset_page/reset_browser_proxy.html
new file mode 100644
index 00000000000..d63cede0ad2
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/reset_page/reset_browser_proxy.html
@@ -0,0 +1,2 @@
+<link rel="import" href="chrome://resources/html/cr.html">
+<script src="chrome://md-settings/reset_page/reset_browser_proxy.js"></script>
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
new file mode 100644
index 00000000000..4390e04a128
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/reset_page/reset_browser_proxy.js
@@ -0,0 +1,89 @@
+// 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 ResetBrowserProxy() {}
+
+ ResetBrowserProxy.prototype = {
+ /**
+ * @param {boolean} sendSettings Whether the user gave consent to upload
+ * broken settings to Google for analysis.
+ * @return {!Promise} A promise firing once resetting has completed.
+ */
+ performResetProfileSettings: function(sendSettings) {},
+
+ /**
+ * A method to be called when the reset profile dialog is hidden.
+ */
+ onHideResetProfileDialog: function() {},
+
+ /**
+ * A method to be called when the reset profile banner is hidden.
+ */
+ onHideResetProfileBanner: function() {},
+
+ /**
+ * A method to be called when the reset profile dialog is shown.
+ */
+ onShowResetProfileDialog: function() {},
+
+<if expr="chromeos">
+ /**
+ * A method to be called when the reset powerwash dialog is shown.
+ */
+ onPowerwashDialogShow: function() {},
+
+ /**
+ * Initiates a factory reset and restarts ChromeOS.
+ */
+ requestFactoryResetRestart: function() {},
+</if>
+ };
+
+ /**
+ * @constructor
+ * @implements {settings.ResetBrowserProxy}
+ */
+ function ResetBrowserProxyImpl() {}
+ cr.addSingletonGetter(ResetBrowserProxyImpl);
+
+ ResetBrowserProxyImpl.prototype = {
+ /** @override */
+ performResetProfileSettings: function(sendSettings) {
+ return cr.sendWithPromise('performResetProfileSettings', sendSettings);
+ },
+
+ /** @override */
+ onHideResetProfileDialog: function() {
+ chrome.send('onHideResetProfileDialog');
+ },
+
+ /** @override */
+ onHideResetProfileBanner: function() {
+ chrome.send('onHideResetProfileBanner');
+ },
+
+ /** @override */
+ onShowResetProfileDialog: function() {
+ chrome.send('onShowResetProfileDialog');
+ },
+
+<if expr="chromeos">
+ /** @override */
+ onPowerwashDialogShow: function() {
+ chrome.send('onPowerwashDialogShow');
+ },
+
+ /** @override */
+ requestFactoryResetRestart: function() {
+ chrome.send('requestFactoryResetRestart');
+ },
+</if>
+ };
+
+ return {
+ ResetBrowserProxyImpl: ResetBrowserProxyImpl,
+ };
+});
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 ac6b8147ef4..be3d27f8e94 100644
--- a/chromium/chrome/browser/resources/settings/reset_page/reset_page.html
+++ b/chromium/chrome/browser/resources/settings/reset_page/reset_page.html
@@ -1,24 +1,29 @@
-<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
+<link rel="import" href="chrome://resources/html/polymer.html">
+<link rel="import" href="chrome://md-settings/i18n_setup.html">
<link rel="import" href="chrome://md-settings/reset_page/reset_profile_dialog.html">
+<link rel="import" href="chrome://md-settings/settings_shared_css.html">
<if expr="chromeos">
<link rel="import" href="chrome://md-settings/reset_page/powerwash_dialog.html">
</if>
<dom-module id="settings-reset-page">
- <link rel="import" type="css"
- href="chrome://md-settings/settings_shared.css">
<template>
- <div class="settings-box" id="resetProfile"
+ <style include="settings-shared"></style>
+ <div class="settings-box first two-line" id="resetProfile"
on-tap="onShowResetProfileDialog_">
- <div i18n-content="resetPageTitle"></div>
- <div i18n-content="resetPageDescription"></div>
+ <div>
+ <div i18n-content="resetPageTitle"></div>
+ <div class="secondary" i18n-content="resetPageDescription"></div>
+ </div>
</div>
<if expr="chromeos">
- <div class="settings-box" id="powerwash" on-tap="onShowPowerwashDialog_"
- hidden="[[!allowPowerwash_]]">
- <div i18n-content="powerwashTitle"></div>
- <div i18n-content="powerwashDescription"></div>
+ <div class="settings-box two-line" id="powerwash"
+ on-tap="onShowPowerwashDialog_" hidden="[[!allowPowerwash_]]">
+ <div>
+ <div i18n-content="powerwashTitle"></div>
+ <div class="secondary" i18n-content="powerwashDescription"></div>
+ </div>
</div>
</if>
</template>
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 81a02423511..19c9924afd0 100644
--- a/chromium/chrome/browser/resources/settings/reset_page/reset_page.js
+++ b/chromium/chrome/browser/resources/settings/reset_page/reset_page.js
@@ -14,9 +14,6 @@
* </settings-reset-page>
* ... other pages ...
* </iron-animated-pages>
- *
- * @group Chrome Settings Elements
- * @element settings-reset-page
*/
Polymer({
is: 'settings-reset-page',
diff --git a/chromium/chrome/browser/resources/settings/reset_page/reset_page_dialog.css b/chromium/chrome/browser/resources/settings/reset_page/reset_page_dialog.css
index 43afe64d8d9..6a832f3b390 100644
--- a/chromium/chrome/browser/resources/settings/reset_page/reset_page_dialog.css
+++ b/chromium/chrome/browser/resources/settings/reset_page/reset_page_dialog.css
@@ -2,10 +2,6 @@
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file. */
-paper-button {
- margin: 0;
-}
-
a {
color: rgb(66, 133, 244);
text-decoration: none;
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 688144490a6..611f7d0b43f 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
@@ -1,6 +1,7 @@
-<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.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-icon-button/paper-icon-button.html">
+<link rel="import" href="chrome://md-settings/reset_page/reset_browser_proxy.html">
<link rel="import" href="chrome://md-settings/reset_page/reset_profile_dialog.html">
<dom-module id="settings-reset-profile-banner">
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 549496c8670..4c5aa929d08 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
@@ -6,9 +6,6 @@
* @fileoverview
* 'settings-reset-profile-banner' is the banner shown for clearing profile
* settings.
- *
- * @group Chrome Settings Elements
- * @element settings-reset-profile-banner
*/
Polymer({
is: 'settings-reset-profile-banner',
@@ -22,7 +19,7 @@ Polymer({
/** @private */
onCloseTap_: function() {
- chrome.send('onHideResetProfileBanner');
+ settings.ResetBrowserProxyImpl.getInstance().onHideResetProfileBanner();
this.remove();
},
diff --git a/chromium/chrome/browser/resources/settings/reset_page/reset_profile_dialog.css b/chromium/chrome/browser/resources/settings/reset_page/reset_profile_dialog.css
deleted file mode 100644
index 805be9c671c..00000000000
--- a/chromium/chrome/browser/resources/settings/reset_page/reset_profile_dialog.css
+++ /dev/null
@@ -1,14 +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. */
-
-#dialog {
- min-width; 300px;
- width: 500px;
-}
-
-#feedbackBar {
- background-color: rgb(236, 236, 236);
- margin: 0;
- padding: 20px;
-}
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 9be9d87a44f..36f22602b8c 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
@@ -1,39 +1,32 @@
-<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.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-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-dialog/paper-dialog.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://md-settings/reset_page/reset_browser_proxy.html">
+<link rel="import" href="chrome://md-settings/settings_dialog.html">
+<link rel="import" href="chrome://md-settings/settings_shared_css.html">
<dom-module id="settings-reset-profile-dialog">
- <link rel="import" type="css" href="chrome://md-settings/settings_dialog.css">
<link rel="import" type="css" href="reset_page_dialog.css">
- <link rel="import" type="css" href="reset_profile_dialog.css">
<template>
- <paper-dialog modal id="dialog">
- <div id="dialog-content">
- <div class="top-row">
- <span class="title" i18n-content="resetPageTitle"></span>
- <paper-icon-button icon="clear" on-tap="onCancelTap_" id="close">
- </paper-icon-button>
- </div>
- <div class="body">
- <div class="explanation">
- <span i18n-content="resetPageExplanation"></span>
- <a i18n-values="href:resetPageLearnMoreUrl"
- i18n-content="learnMore" target="_blank"></a>
- </div>
- <div class="button-container">
- <paper-spinner id="resetSpinner"></paper-spinner>
- <paper-button class="cancel-button" on-tap="onCancelTap_"
- id="cancel" i18n-content="cancel"></paper-button>
- <paper-button class="action-button" i18n-content="resetPageCommit"
- on-tap="onResetTap_" id="reset"></paper-button>
- </div>
- </div>
+ <style include="settings-shared"></style>
+ <settings-dialog id="dialog">
+ <div class="title" i18n-content="resetPageTitle"></div>
+ <div class="body">
+ <span i18n-content="resetPageExplanation"></span>
+ <a i18n-values="href:resetPageLearnMoreUrl"
+ i18n-content="learnMore" target="_blank"></a>
+ </div>
+ <div class="button-container">
+ <paper-spinner id="resetSpinner"></paper-spinner>
+ <paper-button class="cancel-button" on-tap="onCancelTap_"
+ id="cancel" i18n-content="cancel"></paper-button>
+ <paper-button class="action-button" on-tap="onResetTap_"
+ id="reset" i18n-content="resetPageCommit"></paper-button>
</div>
- <div id="feedbackBar">
+ <div class="footer">
<paper-checkbox id="sendSettings" i18n-content="resetPageFeedback"
checked on-change="onSendSettingsChange_"></paper-checkbox>
<div id="settings">
@@ -42,7 +35,7 @@
</template>
</div>
</div>
- </paper-dialog>
+ </settings-dialog>
</template>
<script src="reset_profile_dialog.js"></script>
</dom-module>
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 b639054e66c..2d57d12fbc2 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
@@ -6,55 +6,51 @@
* @fileoverview
* 'settings-reset-profile-dialog' is the dialog shown for clearing profile
* settings.
- *
- * @group Chrome Settings Elements
- * @element settings-reset-profile-dialog
*/
Polymer({
is: 'settings-reset-profile-dialog',
+ behaviors: [WebUIListenerBehavior],
+
properties: {
feedbackInfo_: String,
},
- attached: function() {
- cr.define('SettingsResetPage', function() {
- return {
- doneResetting: function() {
- this.$.resetSpinner.active = false;
- this.$.dialog.close();
- this.dispatchResetDoneEvent();
- }.bind(this),
+ /** @private {!settings.ResetBrowserProxy} */
+ browserProxy_: null,
+
+ /** @override */
+ ready: function() {
+ this.browserProxy_ = settings.ResetBrowserProxyImpl.getInstance();
- setFeedbackInfo: function(data) {
- this.set('feedbackInfo_', data.feedbackInfo);
- this.async(function() {
- this.$.dialog.center();
- });
- }.bind(this),
- };
+ this.addEventListener('iron-overlay-canceled', function() {
+ this.browserProxy_.onHideResetProfileDialog();
}.bind(this));
- },
- dispatchResetDoneEvent: function() {
- this.dispatchEvent(new CustomEvent('reset-done'));
+ this.addWebUIListener('feedback-info-changed', function(feedbackInfo) {
+ this.feedbackInfo_ = feedbackInfo;
+ }.bind(this));
},
open: function() {
this.$.dialog.open();
- chrome.send('onShowResetProfileDialog');
+ this.browserProxy_.onShowResetProfileDialog();
},
/** @private */
onCancelTap_: function() {
- this.$.dialog.close();
- chrome.send('onHideResetProfileDialog');
+ this.$.dialog.cancel();
},
/** @private */
onResetTap_: function() {
this.$.resetSpinner.active = true;
- chrome.send('performResetProfileSettings', [this.$.sendSettings.checked]);
+ this.browserProxy_.performResetProfileSettings(
+ this.$.sendSettings.checked).then(function() {
+ this.$.resetSpinner.active = false;
+ this.$.dialog.close();
+ this.dispatchEvent(new CustomEvent('reset-done'));
+ }.bind(this));
},
/** @private */
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
new file mode 100644
index 00000000000..9615ec8f39f
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/search_engines_page/omnibox_extension_entry.html
@@ -0,0 +1,50 @@
+<link rel="import" href="chrome://resources/html/polymer.html">
+<link rel="import" href="chrome://md-settings/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/iron-icon/iron-icon.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/iron-icons/iron-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://md-settings/settings_shared_css.html">
+
+<dom-module id="settings-omnibox-extension-entry">
+ <link rel="import" type="css" href="chrome://md-settings/search_engines_page/search_engine_entry.css">
+ <template>
+ <style include="settings-shared"></style>
+ <style>
+ .name-column {
+ flex: 3;
+ }
+
+ .keyword-column {
+ flex: 7;
+ }
+ </style>
+ <div id="container" class="list-item">
+ <div class="name-column">
+ <span class="icon-container">
+ <template is="dom-if" if="[[engine.iconURL]]">
+ <iron-icon src="[[engine.iconURL]]"></iron-icon>
+ </template>
+ <template is="dom-if" if="[[!engine.iconURL]]">
+ <iron-icon icon="icons:find-in-page"></iron-icon>
+ </template>
+ </span>
+ <span class="name">[[engine.displayName]]</span>
+ </div>
+ <div class="keyword-column">[[engine.keyword]]</div>
+ <paper-icon-button icon="more-vert" toggles active="{{editMenuOpened}}">
+ </paper-icon-button>
+ <iron-dropdown opened="{{editMenuOpened}}" horizontal-align="right"
+ vertical-align="top">
+ <div class="dropdown-content">
+ <paper-item on-tap="onManageTap_" id="manage"
+ i18n-content="searchEnginesManageExtension"></paper-item>
+ <paper-item on-tap="onDisableTap_" id="disable"
+ i18n-content="disable"></paper-item>
+ <div>
+ </iron-dropdown>
+ </div>
+ </template>
+ <script src="omnibox_extension_entry.js"></script>
+</dom-module>
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
new file mode 100644
index 00000000000..162ce84dac5
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/search_engines_page/omnibox_extension_entry.js
@@ -0,0 +1,41 @@
+// 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-omnibox-extension-entry' is a component for showing
+ * an omnibox extension with its name and keyword.
+ */
+Polymer({
+ is: 'settings-omnibox-extension-entry',
+
+ properties: {
+ /** @type {!SearchEngine} */
+ engine: Object,
+
+ /** @private {!settings.SearchEnginesBrowserProxy} */
+ browserProxy_: Object,
+ },
+
+ /** @override */
+ created: function() {
+ this.browserProxy_ = settings.SearchEnginesBrowserProxyImpl.getInstance();
+ },
+
+ /** @private */
+ onManageTap_: function() {
+ this.closePopupMenu_();
+ this.browserProxy_.manageExtension(this.engine.extension.id);
+ },
+
+ /** @private */
+ onDisableTap_: function() {
+ this.closePopupMenu_();
+ this.browserProxy_.disableExtension(this.engine.extension.id);
+ },
+
+ /** @private */
+ closePopupMenu_: function() {
+ this.$$('iron-dropdown').close();
+ },
+});
diff --git a/chromium/chrome/browser/resources/settings/search_engines_page/search_engine_adder.css b/chromium/chrome/browser/resources/settings/search_engines_page/search_engine_adder.css
deleted file mode 100644
index dd0a80165de..00000000000
--- a/chromium/chrome/browser/resources/settings/search_engines_page/search_engine_adder.css
+++ /dev/null
@@ -1,15 +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. */
-
-.input-label {
- font-size: 0.75em;
-}
-
-.container {
- margin-top: 14px;
-}
-
-.input-field {
- -webkit-margin-end: 20px;
-}
diff --git a/chromium/chrome/browser/resources/settings/search_engines_page/search_engine_adder.html b/chromium/chrome/browser/resources/settings/search_engines_page/search_engine_adder.html
deleted file mode 100644
index 1db68ba5304..00000000000
--- a/chromium/chrome/browser/resources/settings/search_engines_page/search_engine_adder.html
+++ /dev/null
@@ -1,45 +0,0 @@
-<link rel="import" href="chrome://resources/polymer/v1_0/polymer/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-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">
-
-<dom-module id="cr-search-engine-adder">
- <link rel="import" type="css" href="search_engine_adder.css">
- <template>
- <div class="layout horizontal center justified">
- <span i18n-content="searchEnginesAddSearchEngineLabel"></span>
- <cr-expand-button expanded="{{opened}}"></cr-expand-button>
- </div>
- <iron-collapse opened="{{opened}}">
- <div class="settings-box">
- <div class="container layout horizontal">
- <div class="input-field flex two">
- <div class="input-label" i18n-content="searchEnginesDomainLabel">
- </div>
- <paper-input id="domainField" auto-validate="false" required>
- </paper-input>
- </div>
- <div class="input-field flex two">
- <div class="input-label" i18n-content="searchEnginesKeywordLabel">
- </div>
- <paper-input id="keywordField" auto-validate="false" required>
- </paper-input>
- </div>
- <div class="input-field flex four">
- <div class="input-label" i18n-content="searchEnginesQueryURLLabel">
- </div>
- <paper-input id="queryURLField" auto-validate="false" required>
- </paper-input>
- </div>
- <div class="layout horizontal center">
- <paper-button i18n-content="searchEnginesAddButtonLabel"
- on-tap="add_" raised>
- </paper-button>
- </div>
- </div>
- </div>
- </iron-collapse>
- </template>
- <script src="search_engine_adder.js"></script>
-</dom-module>
diff --git a/chromium/chrome/browser/resources/settings/search_engines_page/search_engine_adder.js b/chromium/chrome/browser/resources/settings/search_engines_page/search_engine_adder.js
deleted file mode 100644
index 927912e5c44..00000000000
--- a/chromium/chrome/browser/resources/settings/search_engines_page/search_engine_adder.js
+++ /dev/null
@@ -1,29 +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.
-
-/**
- * @fileoverview 'cr-search-engine-adder' is a component for adding a new search
- * engine.
- *
- * @group Chrome Settings Elements
- * @element settings-search-engine-adder
- */
-Polymer({
- is: 'cr-search-engine-adder',
-
- /** @private */
- add_: function() {
- if (!this.$.domainField.isInvalid &&
- !this.$.keywordField.isInvalid &&
- !this.$.queryURLField.isInvalid) {
- chrome.searchEnginesPrivate.addOtherSearchEngine(
- /* name */ this.$.domainField.value,
- /* keyword */ this.$.keywordField.value,
- /* url */ this.$.queryURLField.value);
- this.$.domainField.value = '';
- this.$.keywordField.value = '';
- this.$.queryURLField.value = '';
- }
- },
-});
diff --git a/chromium/chrome/browser/resources/settings/search_engines_page/search_engine_dialog.html b/chromium/chrome/browser/resources/settings/search_engines_page/search_engine_dialog.html
new file mode 100644
index 00000000000..c4d7a505c6c
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/search_engines_page/search_engine_dialog.html
@@ -0,0 +1,40 @@
+<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-input/paper-input.html">
+<link rel="import" href="chrome://md-settings/i18n_setup.html">
+<link rel="import" href="chrome://md-settings/search_engines_page/search_engines_browser_proxy.html">
+<link rel="import" href="chrome://md-settings/settings_dialog.html">
+
+<dom-module id="settings-search-engine-dialog">
+ <template>
+ <style include="settings-shared"></style>
+ <settings-dialog id="dialog">
+ <div class="title">[[dialogTitle_]]</div>
+ <div class="body">
+ <paper-input always-float-label id="searchEngine"
+ i18n-values="label:searchEnginesSearchEngine;error-message:searchEnginesNotValid"
+ value="{{searchEngine_}}" on-focus="validate_"
+ on-input="validate_">
+ </paper-input>
+ <paper-input always-float-label id="keyword"
+ i18n-values="label:searchEnginesKeyword;error-message:searchEnginesNotValid"
+ value="{{keyword_}}" on-focus="validate_" on-input="validate_">
+ </paper-input>
+ <paper-input always-float-label id="queryUrl"
+ i18n-values="label:searchEnginesQueryURLExplanation;error-message:searchEnginesNotValid"
+ value="{{queryUrl_}}" on-focus="validate_" on-input="validate_"
+ disabled$="[[model.urlLocked]]">
+ </paper-input>
+ </div>
+ <div class="button-container">
+ <paper-button class="cancel-button" on-tap="cancel_"
+ i18n-content="cancel" id="cancel"></paper-button>
+ <paper-button id="actionButton" class="action-button"
+ on-tap="onActionButtonTap_">
+ [[actionButtonText_]]
+ </paper-button>
+ </div>
+ </settings-dialog>
+ </template>
+ <script src="search_engine_dialog.js"></script>
+</dom-module>
diff --git a/chromium/chrome/browser/resources/settings/search_engines_page/search_engine_dialog.js b/chromium/chrome/browser/resources/settings/search_engines_page/search_engine_dialog.js
new file mode 100644
index 00000000000..a1a44946e9c
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/search_engines_page/search_engine_dialog.js
@@ -0,0 +1,117 @@
+// 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-search-engine-dialog' is a component for adding
+ * or editing a search engine entry.
+ */
+Polymer({
+ is: 'settings-search-engine-dialog',
+
+ properties: {
+ /**
+ * The search engine to be edited. If not populated a new search engine
+ * should be added.
+ * @type {?SearchEngine}
+ */
+ model: Object,
+
+ /** @private {string} */
+ searchEngine_: String,
+
+ /** @private {string} */
+ keyword_: String,
+
+ /** @private {string} */
+ queryUrl_: String,
+
+ /** @private {string} */
+ dialogTitle_: String,
+
+ /** @private {string} */
+ actionButtonText_: String,
+ },
+
+ /** @private {!settings.SearchEnginesBrowserProxy} */
+ browserProxy_: null,
+
+ /**
+ * The |modelIndex| to use when a new search engine is added. Must match with
+ * kNewSearchEngineIndex constant specified at
+ * chrome/browser/ui/webui/settings/search_engines_handler.cc
+ * @const {number}
+ */
+ DEFAULT_MODEL_INDEX: -1,
+
+ /** @override */
+ created: function() {
+ this.browserProxy_ = settings.SearchEnginesBrowserProxyImpl.getInstance();
+ },
+
+ /** @override */
+ ready: function() {
+ if (this.model) {
+ this.dialogTitle_ =
+ loadTimeData.getString('searchEnginesEditSearchEngine');
+ this.actionButtonText_ = loadTimeData.getString('save');
+
+ // If editing an existing search engine, pre-populate the input fields.
+ this.searchEngine_ = this.model.displayName;
+ this.keyword_ = this.model.keyword;
+ this.queryUrl_ = this.model.url;
+ } else {
+ this.dialogTitle_ =
+ loadTimeData.getString('searchEnginesAddSearchEngine');
+ this.actionButtonText_ = loadTimeData.getString('add');
+ }
+
+ this.addEventListener('iron-overlay-canceled', function() {
+ this.browserProxy_.searchEngineEditCancelled();
+ }.bind(this));
+ },
+
+ /** @override */
+ attached: function() {
+ this.updateActionButtonState_();
+ this.browserProxy_.searchEngineEditStarted(
+ this.model ? this.model.modelIndex : this.DEFAULT_MODEL_INDEX);
+ this.$.dialog.open();
+ },
+
+ /** @private */
+ cancel_: function() {
+ this.$.dialog.cancel();
+ },
+
+ /** @private */
+ onActionButtonTap_: function() {
+ this.browserProxy_.searchEngineEditCompleted(
+ this.searchEngine_, this.keyword_, this.queryUrl_);
+ this.$.dialog.close();
+ },
+
+ /**
+ * @param {!Event} event
+ * @private
+ */
+ validate_: function(event) {
+ var inputElement = Polymer.dom(event).localTarget;
+
+ this.browserProxy_.validateSearchEngineInput(
+ inputElement.id, inputElement.value).then(function(isValid) {
+ inputElement.invalid = !isValid;
+ this.updateActionButtonState_();
+ }.bind(this));
+ },
+
+ /** @private */
+ updateActionButtonState_: function() {
+ var allValid = [
+ this.$.searchEngine, this.$.keyword, this.$.queryUrl
+ ].every(function(inputElement) {
+ return !inputElement.invalid && inputElement.value.length != 0;
+ });
+ this.$.actionButton.disabled = !allValid;
+ },
+});
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
index 0d207edc4e0..e8a10865dfe 100644
--- 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
@@ -2,18 +2,31 @@
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file. */
-.icons {
- display: inline-block;
+.icon-container {
+ -webkit-margin-end: 8px;
}
-.inputs {
+.name {
+ margin: auto;
+}
+
+#container {
+ border-top: 1px solid lightgray;
display: flex;
+ padding: 2px 0;
+}
+
+.dropdown-content {
+ background: white;
+ box-shadow: 0 2px 6px grey;
}
-.narrow-input {
- flex: 1;
+paper-item:hover {
+ background-color: var(--settings-hover-color);
}
-.wide-input {
- flex: 3;
+paper-icon-button {
+ -webkit-padding-end: 0;
+ padding-bottom: var(--search-engines-list-item-vertical-space);
+ padding-top: var(--search-engines-list-item-vertical-space);
}
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 77f262e2468..95d61f3c860 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,32 +1,69 @@
-<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
+<link rel="import" href="chrome://resources/html/polymer.html">
+<link rel="import" href="chrome://md-settings/search_engines_page/search_engine_dialog.html">
+<link rel="import" href="chrome://md-settings/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/iron-icon/iron-icon.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/paper-input/paper-input.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/iron-icons/iron-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://md-settings/settings_shared_css.html">
-<dom-module id="cr-search-engine-entry">
- <link rel="import" type="css" href="search_engine_entry.css">
+<dom-module id="settings-search-engine-entry">
+ <link rel="import" type="css" href="chrome://md-settings/search_engines_page/search_engine_entry.css">
<template>
- <div class="entry">
- <div class="inputs">
- <paper-input id="domainField" disabled required
- class="narrow-input" auto-validate="false"
- value="{{engine.name}}" on-change="fieldChanged_">
- </paper-input>
- <paper-input id="keywordField" disabled required
- class="narrow-input" auto-validate="false"
- value="{{engine.keyword}}" on-change="fieldChanged_">
- </paper-input>
- <paper-input id="queryURLField" disabled required
- class="wide-input" auto-validate="false"
- value="{{engine.url}}" on-change="fieldChanged_">
- </paper-input>
- </div>
- <div class="icons">
- <iron-icon icon="settings" on-tap="toggleEditable_"></iron-icon>
- <iron-icon id="checkIcon" icon="check" on-tap="makeDefault_">
- </iron-icon>
- <iron-icon id="deleteIcon" icon="clear" on-tap="deleteEngine_">
- </iron-icon>
+ <style include="settings-shared"></style>
+ <style>
+ :host([is-default]) {
+ font-weight: 500;
+ }
+
+ .name-column,
+ .keyword-column {
+ flex: 3;
+ }
+
+ .url-column {
+ flex: 4;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ }
+ </style>
+
+ <template is="dom-if" if="[[showEditSearchEngineDialog_]]" restamp>
+ <settings-search-engine-dialog model="[[engine]]">
+ </settings-search-engine-dialog>
+ </template>
+ <div id="container" class="list-item">
+ <div class="name-column">
+ <span class="icon-container">
+ <template is="dom-if" if="[[engine.iconURL]]">
+ <iron-icon src="[[engine.iconURL]]"></iron-icon>
+ </template>
+ <template is="dom-if" if="[[!engine.iconURL]]">
+ <iron-icon icon="icons:find-in-page"></iron-icon>
+ </template>
+ </span>
+ <span class="name">[[engine.displayName]]</span>
</div>
+ <div class="keyword-column">[[engine.keyword]]</div>
+ <div class="url-column">[[engine.url]]</div>
+ <paper-icon-button icon="more-vert" toggles active="{{editMenuOpened}}">
+ </paper-icon-button>
+ <iron-dropdown opened="{{editMenuOpened}}" horizontal-align="right"
+ vertical-align="top">
+ <div class="dropdown-content">
+ <paper-item on-tap="onMakeDefaultTap_"
+ i18n-content="searchEnginesMakeDefault"
+ hidden$="[[!engine.canBeDefault]]" id="makeDefault"></paper-item>
+ <paper-item on-tap="onEditTap_"
+ i18n-content="searchEnginesEdit"
+ hidden$="[[!engine.canBeEdited]]" id="edit"></paper-item>
+ <paper-item on-tap="onDeleteTap_"
+ i18n-content="searchEnginesRemoveFromList"
+ hidden$="[[!engine.canBeRemoved]]" id="delete"></paper-item>
+ <div>
+ </iron-dropdown>
</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 9e3a00940ab..fd02264bc12 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
@@ -3,63 +3,72 @@
// found in the LICENSE file.
/**
- * @fileoverview 'cr-search-engine-entry' is a component for showing a search
- * engine with its name, domain and query URL.
- *
- * @group Chrome Settings Elements
- * @element cr-search-engine-entry
+ * @fileoverview 'settings-search-engine-entry' is a component for showing a
+ * search engine with its name, domain and query URL.
*/
Polymer({
- is: 'cr-search-engine-entry',
+ is: 'settings-search-engine-entry',
properties: {
/** @type {!SearchEngine} */
- engine: Object
+ engine: Object,
+
+ /** @private {boolean} */
+ showEditSearchEngineDialog_: Boolean,
+
+ /** @type {boolean} */
+ isDefault: {
+ reflectToAttribute: true,
+ type: Boolean,
+ computed: 'computeIsDefault_(engine)'
+ },
},
- /** @private */
- deleteEngine_: function() {
- chrome.searchEnginesPrivate.removeSearchEngine(this.engine.guid);
+ /** @private {!settings.SearchEnginesBrowserProxy} */
+ browserProxy_: null,
+
+ /** @override */
+ created: function() {
+ this.browserProxy_ = settings.SearchEnginesBrowserProxyImpl.getInstance();
+ },
+
+ /**
+ * @return {boolean}
+ * @private
+ */
+ computeIsDefault_: function() {
+ return this.engine.default;
},
/** @private */
- makeDefault_: function() {
- chrome.searchEnginesPrivate.setSelectedSearchEngine(this.engine.guid);
- this.makeNotEditable_();
+ onDeleteTap_: function() {
+ this.browserProxy_.removeSearchEngine(this.engine.modelIndex);
},
/** @private */
- toggleEditable_: function() {
- this.$.domainField.disabled = !this.$.domainField.disabled;
- this.$.keywordField.disabled = !this.$.keywordField.disabled;
- this.$.queryURLField.disabled = !this.$.queryURLField.disabled;
+ onEditTap_: function() {
+ this.closePopupMenu_();
- this.$.checkIcon.hidden =
- !this.$.checkIcon.hidden || this.engine.isSelected;
- this.$.deleteIcon.hidden =
- !this.$.deleteIcon.hidden || this.engine.isSelected;
+ this.showEditSearchEngineDialog_ = true;
+ this.async(function() {
+ var dialog = this.$$('settings-search-engine-dialog');
+ // Register listener to detect when the dialog is closed. Flip the boolean
+ // once closed to force a restamp next time it is shown such that the
+ // previous dialog's contents are cleared.
+ dialog.addEventListener('iron-overlay-closed', function() {
+ this.showEditSearchEngineDialog_ = false;
+ }.bind(this));
+ }.bind(this));
},
/** @private */
- makeNotEditable_: function() {
- this.$.domainField.disabled = true;
- this.$.keywordField.disabled = true;
- this.$.queryURLField.disabled = true;
-
- this.$.checkIcon.hidden = true;
- this.$.deleteIcon.hidden = true;
+ onMakeDefaultTap_: function() {
+ this.closePopupMenu_();
+ this.browserProxy_.setDefaultSearchEngine(this.engine.modelIndex);
},
/** @private */
- fieldChanged_: function() {
- // NOTE: This currently doesn't fire in response to a change event from the
- // paper-input, even though it should. This Polymer change should fix the
- // issue: https://github.com/PolymerElements/paper-input/pull/33
- chrome.searchEnginesPrivate.updateSearchEngine(
- this.engine.guid,
- this.$.domainField.value,
- this.$.keywordField.value,
- this.$.queryURLField.value);
- this.makeNotEditable_();
- }
+ closePopupMenu_: function() {
+ this.$$('iron-dropdown').close();
+ },
});
diff --git a/chromium/chrome/browser/resources/settings/search_engines_page/search_engines_browser_proxy.html b/chromium/chrome/browser/resources/settings/search_engines_page/search_engines_browser_proxy.html
new file mode 100644
index 00000000000..6b977e46ebf
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/search_engines_page/search_engines_browser_proxy.html
@@ -0,0 +1 @@
+<script src="chrome://md-settings/search_engines_page/search_engines_browser_proxy.js"></script>
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
new file mode 100644
index 00000000000..570085c07c8
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/search_engines_page/search_engines_browser_proxy.js
@@ -0,0 +1,141 @@
+// 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 "Manage search engines" section
+ * to interact with the browser.
+ */
+
+/**
+ * @typedef {{canBeDefault: boolean,
+ * canBeEdited: boolean,
+ * canBeRemoved: boolean,
+ * default: boolean,
+ * displayName: string,
+ * extension: (Object|undefined),
+ * iconURL: (string|undefined),
+ * isOmniboxExtension: boolean,
+ * keyword: string,
+ * modelIndex: number,
+ * name: string,
+ * url: string,
+ * urlLocked: boolean}}
+ * @see chrome/browser/ui/webui/settings/search_engine_manager_handler.cc
+ */
+var SearchEngine;
+
+/**
+ * @typedef {{
+ * defaults: !Array<!SearchEngine>,
+ * others: !Array<!SearchEngine>,
+ * extensions: !Array<!SearchEngine>
+ * }}
+ */
+var SearchEnginesInfo;
+
+cr.define('settings', function() {
+ /** @interface */
+ function SearchEnginesBrowserProxy() {}
+
+ SearchEnginesBrowserProxy.prototype = {
+ /** @param {number} modelIndex */
+ setDefaultSearchEngine: function(modelIndex) {},
+
+ /** @param {number} modelIndex */
+ removeSearchEngine: function(modelIndex) {},
+
+ /** @param {number} modelIndex */
+ searchEngineEditStarted: function(modelIndex) {},
+
+ searchEngineEditCancelled: function() {},
+
+ /**
+ * @param {string} searchEngine
+ * @param {string} keyword
+ * @param {string} queryUrl
+ */
+ searchEngineEditCompleted: function(searchEngine, keyword, queryUrl) {},
+
+ /**
+ * @return {!Promise<!SearchEnginesInfo>}
+ */
+ getSearchEnginesList: function() {},
+
+ /**
+ * @param {string} fieldName
+ * @param {string} fieldValue
+ * @return {!Promise<boolean>}
+ */
+ validateSearchEngineInput: function(fieldName, fieldValue) {},
+
+ /** @param {string} extensionId */
+ disableExtension: function(extensionId) {},
+
+ /** @param {string} extensionId */
+ manageExtension: function(extensionId) {},
+ };
+
+ /**
+ * @constructor
+ * @implements {settings.SearchEnginesBrowserProxy}
+ */
+ function SearchEnginesBrowserProxyImpl() {}
+ // The singleton instance_ is replaced with a test version of this wrapper
+ // during testing.
+ cr.addSingletonGetter(SearchEnginesBrowserProxyImpl);
+
+ SearchEnginesBrowserProxyImpl.prototype = {
+ /** @override */
+ setDefaultSearchEngine: function(modelIndex) {
+ chrome.send('setDefaultSearchEngine', [modelIndex]);
+ },
+
+ /** @override */
+ removeSearchEngine: function(modelIndex) {
+ chrome.send('removeSearchEngine', [modelIndex]);
+ },
+
+ /** @override */
+ searchEngineEditStarted: function(modelIndex) {
+ chrome.send('searchEngineEditStarted', [modelIndex]);
+ },
+
+ /** @override */
+ searchEngineEditCancelled: function() {
+ chrome.send('searchEngineEditCancelled');
+ },
+
+ /** @override */
+ searchEngineEditCompleted: function(searchEngine, keyword, queryUrl) {
+ chrome.send('searchEngineEditCompleted', [
+ searchEngine, keyword, queryUrl,
+ ]);
+ },
+
+ /** @override */
+ getSearchEnginesList: function() {
+ return cr.sendWithPromise('getSearchEnginesList');
+ },
+
+ /** @override */
+ validateSearchEngineInput: function(fieldName, fieldValue) {
+ return cr.sendWithPromise(
+ 'validateSearchEngineInput', fieldName, fieldValue);
+ },
+
+ /** @override */
+ disableExtension: function(extensionId) {
+ chrome.send('disableExtension', [extensionId]);
+ },
+
+ /** @override */
+ manageExtension: function(extensionId) {
+ window.location = 'chrome://extensions?id=' + extensionId;
+ },
+ };
+
+ return {
+ SearchEnginesBrowserProxyImpl: SearchEnginesBrowserProxyImpl,
+ };
+});
diff --git a/chromium/chrome/browser/resources/settings/search_engines_page/search_engines_list.css b/chromium/chrome/browser/resources/settings/search_engines_page/search_engines_list.css
index 54ed7d6e995..2a53354d0e1 100644
--- a/chromium/chrome/browser/resources/settings/search_engines_page/search_engines_list.css
+++ b/chromium/chrome/browser/resources/settings/search_engines_page/search_engines_list.css
@@ -2,24 +2,24 @@
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file. */
-.container {
- max-height: 400px;
-}
-
.headers {
display: flex;
+ padding: 10px 0;
+}
+
+.headers .name,
+.headers .keyword {
+ flex: 3;
}
-.headers > div {
- background-color: #6c6c6c;
- color: white;
- padding: 5px;
+.headers .url {
+ flex: 4.5;
}
-.narrow-label {
- flex: 1;
+div {
+ margin: var(--search-engines-list-margin);
}
-.wide-label {
- flex: 3;
+::content [is='action-link'] {
+ margin: var(--search-engines-list-item-vertical-space) 0;
}
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 f8868b8192d..3c48452b28e 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,22 +1,15 @@
-<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html">
-<link rel="import" href="search_engine_entry.html">
+<link rel="import" href="chrome://resources/html/polymer.html">
+<link rel="import" href="chrome://md-settings/search_engines_page/search_engine_entry.html">
-<dom-module id="cr-search-engines-list">
+<dom-module id="settings-search-engines-list">
<link rel="import" type="css" href="search_engines_list.css">
<template>
- <div class="container">
- <div class="headers">
- <div class="narrow-label" i18n-content="searchEnginesDomainLabel"></div>
- <div class="narrow-label" i18n-content="searchEnginesKeywordLabel">
- </div>
- <div class="wide-label" i18n-content="searchEnginesQueryURLLabel"></div>
- </div>
- <div class="entries">
- <template is="dom-repeat" items="[[engines]]">
- <cr-search-engine-entry engine="[[item]]"></cr-search-engine-entry>
- </template>
- </div>
+ <div>
+ <content></content>
+ <template is="dom-repeat" items="[[engines]]">
+ <settings-search-engine-entry engine="[[item]]">
+ </settings-search-engine-entry>
+ </template>
</div>
</template>
<script src="search_engines_list.js"></script>
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 88259065525..f9f4fdd2da6 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
@@ -3,14 +3,11 @@
// found in the LICENSE file.
/**
- * @fileoverview 'cr-search-engines-list' is a component for showing a list of
- * search engines.
- *
- * @group Chrome Settings Elements
- * @element cr-search-engines-list
+ * @fileoverview 'settings-search-engines-list' is a component for showing a
+ * list of search engines.
*/
Polymer({
- is: 'cr-search-engines-list',
+ is: 'settings-search-engines-list',
properties: {
/** @type {!Array<!SearchEngine>} */
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 184dd5b5dca..267e4720515 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,21 +1,58 @@
-<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
-<link rel="import" href="search_engine_adder.html">
-<link rel="import" href="search_engines_list.html">
+<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="chrome://resources/html/action_link.html">
+<link rel="import" href="chrome://md-settings/search_engines_page/search_engines_browser_proxy.html">
+<link rel="import" href="chrome://md-settings/search_engines_page/search_engine_dialog.html">
+<link rel="import" href="chrome://md-settings/search_engines_page/search_engines_list.html">
+<link rel="import" href="chrome://md-settings/search_engines_page/omnibox_extension_entry.html">
+<link rel="import" href="chrome://md-settings/settings_shared_css.html">
<dom-module id="settings-search-engines-page">
- <link rel="import" type="css" href="chrome://md-settings/settings_shared.css">
<template>
- <div class="settings-box">
- <cr-search-engine-adder></cr-search-engine-adder>
-
- <h2 i18n-content="searchEnginesLabel"></h2>
- <cr-search-engines-list engines="[[defaultEngines]]">
- </cr-search-engines-list>
+ <style include="settings-shared">
+ :host {
+ --search-engines-list-item-vertical-space: 8px;
+ --search-engines-list-margin: 0 40px;
+ }
+ .label {
+ margin: 20px;
+ }
+ .extension-engines {
+ margin: var(--search-engines-list-margin);
+ }
+ </style>
+ <div>
+ <div class="label" i18n-content="searchEnginesDefault"></div>
+ <settings-search-engines-list engines="[[defaultEngines]]">
+ </settings-search-engines-list>
+ </div>
+ <template is="dom-if" if="[[showAddSearchEngineDialog_]]" restamp>
+ <settings-search-engine-dialog></settings-search-engine-dialog>
+ </template>
+ <div>
+ <div class="label" i18n-content="searchEnginesOther"></div>
+ <!-- TODO(dbeam): why does on-click work with keyboard but on-tap
+ doesn't? -->
+ <settings-search-engines-list engines="[[otherEngines]]">
+ <a is="action-link" i18n-content="searchEnginesAddSearchEngine"
+ on-tap="onAddSearchEngineTap_" id="addSearchEngine"></a>
+ </settings-search-engines-list>
- <h2 i18n-content="searchEnginesOtherLabel"></h2>
- <cr-search-engines-list engines="[[otherEngines]]">
- </cr-search-engines-list>
+ <template is="dom-if" if="[[showExtensionsList_]]">
+ <div class="label" i18n-content="searchEnginesExtension"></div>
+ <div class="extension-engines">
+ <template is="dom-repeat" items="[[extensions]]">
+ <settings-omnibox-extension-entry engine="[[item]]">
+ </settings-omnibox-extension-entry>
+ </template>
+ </div>
+ </template>
</div>
</template>
+ <link rel="import" type="css" href="chrome://resources/css/action_link.css">
<script src="search_engines_page.js"></script>
</dom-module>
diff --git a/chromium/chrome/browser/resources/settings/search_engines_page/search_engines_page.js b/chromium/chrome/browser/resources/settings/search_engines_page/search_engines_page.js
index 9aeb8599072..7fe11631b62 100644
--- a/chromium/chrome/browser/resources/settings/search_engines_page/search_engines_page.js
+++ b/chromium/chrome/browser/resources/settings/search_engines_page/search_engines_page.js
@@ -5,21 +5,12 @@
/**
* @fileoverview 'settings-search-engines-page' is the settings page
* containing search engines settings.
- *
- * Example:
- *
- * <core-animated-pages>
- * <settings-search-engines-page prefs="{{prefs}}">
- * </settings-search-engines-page>
- * ... other pages ...
- * </core-animated-pages>
- *
- * @group Chrome Settings Elements
- * @element settings-search-engines-page
*/
Polymer({
is: 'settings-search-engines-page',
+ behaviors: [WebUIListenerBehavior],
+
properties: {
/** @type {!Array<!SearchEngine>} */
defaultEngines: {
@@ -32,27 +23,57 @@ Polymer({
type: Array,
value: function() { return []; }
},
+
+ /** @type {!Array<!SearchEngine>} */
+ extensions: {
+ type: Array,
+ value: function() { return []; }
+ },
+
+ /** @private {boolean} */
+ showAddSearchEngineDialog_: Boolean,
+
+ /** @private {boolean} */
+ showExtensionsList_: {
+ type: Boolean,
+ computed: 'computeShowExtensionsList_(extensions)',
+ }
},
/** @override */
ready: function() {
- chrome.searchEnginesPrivate.onSearchEnginesChanged.addListener(
- this.enginesChanged_.bind(this));
- this.enginesChanged_();
+ settings.SearchEnginesBrowserProxyImpl.getInstance().
+ getSearchEnginesList().then(this.enginesChanged_.bind(this));
+ this.addWebUIListener(
+ 'search-engines-changed', this.enginesChanged_.bind(this));
+ },
+
+ /**
+ * @param {!SearchEnginesInfo} searchEnginesInfo
+ * @private
+ */
+ enginesChanged_: function(searchEnginesInfo) {
+ this.defaultEngines = searchEnginesInfo['defaults'];
+ this.otherEngines = searchEnginesInfo['others'];
+ this.extensions = searchEnginesInfo['extensions'];
},
/** @private */
- enginesChanged_: function() {
- chrome.searchEnginesPrivate.getSearchEngines(function(engines) {
- this.defaultEngines = engines.filter(function(engine) {
- return engine.type ==
- chrome.searchEnginesPrivate.SearchEngineType.DEFAULT;
- }, this);
-
- this.otherEngines = engines.filter(function(engine) {
- return engine.type ==
- chrome.searchEnginesPrivate.SearchEngineType.OTHER;
- }, this);
+ onAddSearchEngineTap_: function() {
+ this.showAddSearchEngineDialog_ = true;
+ this.async(function() {
+ var dialog = this.$$('settings-search-engine-dialog');
+ // Register listener to detect when the dialog is closed. Flip the boolean
+ // once closed to force a restamp next time it is shown such that the
+ // previous dialog's contents are cleared.
+ dialog.addEventListener('iron-overlay-closed', function() {
+ this.showAddSearchEngineDialog_ = false;
+ }.bind(this));
}.bind(this));
- }
+ },
+
+ /** @private */
+ computeShowExtensionsList_: function() {
+ return this.extensions.length > 0;
+ },
});
diff --git a/chromium/chrome/browser/resources/settings/search_page/search_page.css b/chromium/chrome/browser/resources/settings/search_page/search_page.css
deleted file mode 100644
index 24b3126fbef..00000000000
--- a/chromium/chrome/browser/resources/settings/search_page/search_page.css
+++ /dev/null
@@ -1,11 +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. */
-
-paper-button.search-engines-advanced {
- margin-top: 10px;
-}
-
-#searchEnginesMenu {
- min-width: 150px;
-}
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 a51296f369a..d89382bfa76 100644
--- a/chromium/chrome/browser/resources/settings/search_page/search_page.html
+++ b/chromium/chrome/browser/resources/settings/search_page/search_page.html
@@ -1,40 +1,71 @@
-<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.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/neon-animation/neon-animatable.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html">
-<link rel="import" href="chrome://md-settings/controls/settings_checkbox.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-dropdown-menu/paper-dropdown-menu.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-listbox/paper-listbox.html">
<link rel="import" href="chrome://md-settings/search_engines_page/search_engines_page.html">
+<link rel="import" href="chrome://md-settings/search_engines_page/search_engines_browser_proxy.html">
<link rel="import" href="chrome://md-settings/settings_page/settings_animated_pages.html">
-<link rel="import" href="chrome://md-settings/settings_page/settings_subheader.html">
+<link rel="import" href="chrome://md-settings/settings_page/settings_subpage.html">
+<link rel="import" href="chrome://md-settings/settings_shared_css.html">
<dom-module id="settings-search-page">
- <link rel="import" type="css"
- href="chrome://md-settings/settings_shared.css">
- <link rel="import" type="css" href="search_page.css">
<template>
+ <style include="settings-shared">
+ paper-dropdown-menu {
+ /* TODO(dschuyler): share styling with settings-dropdown-menu */
+ --iron-icon-fill-color: var(--paper-grey-600);
+ }
+
+ paper-listbox div {
+ align-items: center;
+ display: flex;
+ font-size: 16px;
+ font-weight: 400;
+ line-height: 24px;
+ min-height: 48px;
+ padding: 0px 16px;
+ }
+
+ paper-listbox div.iron-selected {
+ font-weight: bold;
+ }
+
+ paper-listbox div:focus {
+ outline: none;
+ }
+
+ paper-listbox div:hover {
+ background-color: var(--settings-hover-color);
+ }
+ </style>
<settings-animated-pages id="pages" current-route="{{currentRoute}}"
section="search">
<neon-animatable id="main">
- <div class="settings-box split">
+ <div class="settings-box first">
<p class="start" i18n-content="searchExplanation"></p>
- <select id="searchEnginesMenu"
- on-change="defaultEngineGuidChanged_">
- <template is="dom-repeat" items="[[searchEngines]]">
- <option value="[[item.guid]]">[[item.name]]</option>
- </template>
- </select>
+ <paper-dropdown-menu>
+ <paper-listbox class="dropdown-content"
+ selected="[[getSelectedSearchEngineIndex_(searchEngines_)]]"
+ on-iron-select="onIronSelect_">
+ <template is="dom-repeat" items="[[searchEngines_]]">
+ <div>[[item.name]]</div>
+ </template>
+ </paper-listbox>
+ </paper-dropdown-menu>
</div>
<div class="settings-box">
- <paper-button class="link-button"
- i18n-content="searchManageButtonLabel"
- on-tap="onSearchEnginesTap_">
+ <paper-button i18n-content="searchEnginesManage"
+ on-tap="onManageSearchEnginesTap_" class="primary-button">
</paper-button>
</div>
</neon-animatable>
- <neon-animatable id="search-engines">
- <settings-subheader i18n-values="page-title:searchEnginesLabel">
- </settings-subheader>
- <settings-search-engines-page></settings-search-engines-page>
- </neon-animatable>
+ <template is="dom-if" name="search-engines">
+ <settings-subpage page-title="[[i18n('searchEnginesManage')]]">
+ <settings-search-engines-page></settings-search-engines-page>
+ </settings-subpage>
+ </template>
</settings-animated-pages>
</template>
<script src="search_page.js"></script>
diff --git a/chromium/chrome/browser/resources/settings/search_page/search_page.js b/chromium/chrome/browser/resources/settings/search_page/search_page.js
index 0f8b3cbad16..5851043091b 100644
--- a/chromium/chrome/browser/resources/settings/search_page/search_page.js
+++ b/chromium/chrome/browser/resources/settings/search_page/search_page.js
@@ -5,20 +5,14 @@
/**
* @fileoverview
* 'settings-search-page' is the settings page containing search settings.
- *
- * Example:
- *
- * <iron-animated-pages>
- * <settings-search-page prefs="{{prefs}}"></settings-search-page>
- * ... other pages ...
- * </iron-animated-pages>
- *
- * @group Chrome Settings Elements
- * @element settings-search-page
*/
Polymer({
is: 'settings-search-page',
+ behaviors: [
+ I18nBehavior,
+ ],
+
properties: {
/**
* The current active route.
@@ -30,56 +24,58 @@ Polymer({
/**
* List of default search engines available.
- * @type {?Array<!SearchEngine>}
+ * @private {!Array<!SearchEngine>}
*/
- searchEngines: {
+ searchEngines_: {
type: Array,
- value: function() { return []; },
+ value: function() { return []; }
},
+
+ /** @private {!settings.SearchEnginesBrowserProxy} */
+ browserProxy_: Object,
},
/** @override */
created: function() {
- chrome.searchEnginesPrivate.onSearchEnginesChanged.addListener(
- this.updateSearchEngines_.bind(this));
- chrome.searchEnginesPrivate.getSearchEngines(
- this.updateSearchEngines_.bind(this));
+ this.browserProxy_ = settings.SearchEnginesBrowserProxyImpl.getInstance();
},
- /**
- * Persists the new default search engine back to Chrome. Called when the
- * user selects a new default in the search engines dropdown.
- * @private
- */
- defaultEngineGuidChanged_: function() {
- chrome.searchEnginesPrivate.setSelectedSearchEngine(
- this.$.searchEnginesMenu.value);
+ /** @override */
+ ready: function() {
+ var updateSearchEngines = function(searchEngines) {
+ this.set('searchEngines_', searchEngines.defaults);
+ }.bind(this);
+ this.browserProxy_.getSearchEnginesList().then(updateSearchEngines);
+ cr.addWebUIListener('search-engines-changed', updateSearchEngines);
},
+ /** @private */
+ onManageSearchEnginesTap_: function() {
+ this.$.pages.setSubpageChain(['search-engines']);
+ },
- /**
- * Updates the list of default search engines based on the given |engines|.
- * @param {!Array<!SearchEngine>} engines All the search engines.
- * @private
- */
- updateSearchEngines_: function(engines) {
- var defaultEngines = [];
-
- engines.forEach(function(engine) {
- if (engine.type ==
- chrome.searchEnginesPrivate.SearchEngineType.DEFAULT) {
- defaultEngines.push(engine);
- if (engine.isSelected) {
- this.$.searchEnginesMenu.value = engine.guid;
- }
- }
- }, this);
+ /** @private */
+ onIronSelect_: function() {
+ var searchEngine = this.searchEngines_[this.$$('paper-listbox').selected];
+ if (searchEngine.default) {
+ // If the selected search engine is already marked as the default one,
+ // this change originated in some other tab, and nothing should be done
+ // here.
+ return;
+ }
- this.searchEngines = defaultEngines;
+ // Otherwise, this change originated by an explicit user action in this tab.
+ // Submit the default search engine change.
+ this.browserProxy_.setDefaultSearchEngine(searchEngine.modelIndex);
},
- /** @private */
- onSearchEnginesTap_: function() {
- this.$.pages.setSubpageChain(['search-engines']);
+ /**
+ * @return {number}
+ * @private
+ */
+ getSelectedSearchEngineIndex_: function() {
+ return this.searchEngines_.findIndex(function(searchEngine) {
+ return searchEngine.default;
+ });
},
});
diff --git a/chromium/chrome/browser/resources/settings/settings.html b/chromium/chrome/browser/resources/settings/settings.html
index c3cdadf9704..2b210fcc197 100644
--- a/chromium/chrome/browser/resources/settings/settings.html
+++ b/chromium/chrome/browser/resources/settings/settings.html
@@ -1,26 +1,27 @@
<!doctype html>
-<html>
+<html i18n-values="dir:textdirection;lang:language">
<head>
<meta charset="utf-8">
- <title>Settings</title>
+ <title i18n-content="settings"></title>
<base href="chrome://md-settings">
- <link rel="import" href="chrome://resources/html/polymer_config.html">
+ <link rel="import" href="chrome://resources/html/polymer.html">
<link rel="import" href="chrome://md-settings/i18n_setup.html">
- <link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
+ <link rel="import" href="chrome://md-settings/direction_delegate.html">
<link rel="import" href="chrome://md-settings/settings_ui/settings_ui.html">
<link rel="import" href="chrome://md-settings/prefs/prefs.html">
+ <link rel="stylesheet" href="chrome://resources/css/text_defaults_md.css">
</head>
<body>
<dom-module id="cr-settings">
<template>
<settings-prefs id="prefs" prefs="{{prefs_}}"></settings-prefs>
- <settings-ui prefs="{{prefs_}}"></settings-ui>
+ <settings-ui id="ui" prefs="{{prefs_}}"></settings-ui>
</template>
<script src="settings.js"></script>
</dom-module>
<cr-settings></cr-settings>
- <script src="chrome://resources/js/i18n_template.js"></script>
+ <link rel="import" href="chrome://resources/html/i18n_template.html">
</body>
</html>
diff --git a/chromium/chrome/browser/resources/settings/settings.js b/chromium/chrome/browser/resources/settings/settings.js
index 6995f58e39d..8de03239b7a 100644
--- a/chromium/chrome/browser/resources/settings/settings.js
+++ b/chromium/chrome/browser/resources/settings/settings.js
@@ -9,8 +9,11 @@
* Example:
*
* <cr-settings></cr-settings>
- *
- * @group Chrome Settings Elements
- * @element cr-settings
*/
-Polymer({is: 'cr-settings'});
+Polymer({
+ is: 'cr-settings',
+
+ ready: function() {
+ this.$.ui.directionDelegate = new settings.DirectionDelegateImpl;
+ },
+});
diff --git a/chromium/chrome/browser/resources/settings/settings_dialog.css b/chromium/chrome/browser/resources/settings/settings_dialog.css
deleted file mode 100644
index 786f04c198d..00000000000
--- a/chromium/chrome/browser/resources/settings/settings_dialog.css
+++ /dev/null
@@ -1,69 +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. */
-
-/**
- * @fileoverview
- * Common dialog styles for Material Design settings.
- */
-
-#dialog-content {
- -webkit-padding-end: 0;
- -webkit-padding-start: 0;
- margin-bottom: 0;
- margin-top: 0;
-}
-
-paper-dialog .top-row {
- align-items: center;
- border-bottom: 1px solid gainsboro;
- display: flex;
- padding-bottom: 5px;
- padding-top: 5px;
-}
-
-paper-dialog .title {
- flex: 1;
- font-size: 1.13em;
-}
-
-paper-dialog .body {
- font-size: 1em;
- margin: 20px 0;
-}
-
-paper-dialog .title,
-paper-dialog .body {
- -webkit-padding-end: 24px;
- -webkit-padding-start: 24px;
-}
-
-paper-dialog .action-button {
- -webkit-margin-start: 10px;
- background-color: rgb(66, 133, 244);
- color: white;
- font-weight: 500;
-}
-
-paper-dialog .cancel-button {
- color: rgb(109, 109, 109);
- font-weight: 500;
-}
-
-paper-dialog .explanation {
- margin-bottom: 35px;
-}
-
-paper-dialog .button-container {
- display: flex;
- justify-content: flex-end;
-}
-
-paper-dialog paper-button {
- margin: 0;
- min-width: auto;
-}
-
-paper-dialog paper-button[toggles][active] {
- background-color: LightGray;
-}
diff --git a/chromium/chrome/browser/resources/settings/settings_dialog.html b/chromium/chrome/browser/resources/settings/settings_dialog.html
new file mode 100644
index 00000000000..df72a0df54e
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/settings_dialog.html
@@ -0,0 +1,99 @@
+<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/paper-dialog-behavior/paper-dialog-behavior.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-dialog-behavior/paper-dialog-shared-styles.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button.html">
+
+<dom-module id="settings-dialog">
+ <template>
+ <style include="paper-dialog-shared-styles"></style>
+ <style>
+ .body-content {
+ font-size: 1em;
+ margin: 20px 0;
+ }
+
+ .dialog-content {
+ -webkit-padding-end: 0;
+ -webkit-padding-start: 0;
+ margin-bottom: 0;
+ margin-top: 0;
+ }
+
+ .footer-container {
+ margin: 0;
+ padding: 0;
+ }
+
+ .top-row {
+ align-items: center;
+ border-bottom: 1px solid var(--paper-grey-300);
+ display: flex;
+ padding-bottom: 5px;
+ padding-top: 5px;
+ }
+
+ :host {
+ max-width: 800px;
+ min-width: 500px;
+ overflow: auto;
+ }
+
+ :host ::content .body {
+ margin-bottom: 35px;
+ }
+
+ :host ::content .button-container {
+ display: flex;
+ justify-content: flex-end;
+ }
+
+ :host ::content .button-container .cancel-button {
+ color: var(--paper-grey-600);
+ font-weight: 500;
+ }
+
+ :host ::content .footer {
+ background-color: var(--paper-grey-200);
+ margin: 0;
+ padding: 20px;
+ }
+
+ :host ::content .row {
+ align-items: center;
+ display: flex;
+ min-height: 40px;
+ }
+
+ :host ::content .row .start {
+ flex: 1;
+ }
+
+ :host ::content .title {
+ flex: 1;
+ font-size: 1.13em;
+ }
+
+ :host ::content .title,
+ .body-content {
+ -webkit-padding-end: 24px;
+ -webkit-padding-start: 24px;
+ }
+ </style>
+ <div class="dialog-content">
+ <div class="top-row">
+ <content select=".title"></content>
+ <paper-icon-button icon="clear" on-tap="cancel" id="close">
+ </paper-icon-button>
+ </div>
+ <div class="body-content">
+ <content select=".body"></content>
+ <content select=".button-container"></content>
+ </div>
+ </div>
+ <div class="footer-container">
+ <content select=".footer"></content>
+ </div>
+ </template>
+ <script src="settings_dialog.js"></script>
+</dom-module>
diff --git a/chromium/chrome/browser/resources/settings/settings_dialog.js b/chromium/chrome/browser/resources/settings/settings_dialog.js
new file mode 100644
index 00000000000..888ae0d4c5c
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/settings_dialog.js
@@ -0,0 +1,37 @@
+// 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-dialog' is a component for showing a modal dialog.
+ */
+Polymer({
+ is: 'settings-dialog',
+
+ properties: {
+ /** @override */
+ noCancelOnOutsideClick: {
+ type: Boolean,
+ value: true,
+ },
+
+ /** @override */
+ noCancelOnEscKey: {
+ type: Boolean,
+ value: false,
+ },
+
+ /** @override */
+ withBackdrop: {
+ type: Boolean,
+ value: true,
+ },
+ },
+
+ behaviors: [Polymer.PaperDialogBehavior],
+
+ /** @return {!PaperIconButtonElement} */
+ getCloseButton: function() {
+ return this.$.close;
+ },
+});
diff --git a/chromium/chrome/browser/resources/settings/settings_main/settings_main.css b/chromium/chrome/browser/resources/settings/settings_main/settings_main.css
index da0487e2e40..7932a8db24f 100644
--- a/chromium/chrome/browser/resources/settings/settings_main/settings_main.css
+++ b/chromium/chrome/browser/resources/settings/settings_main/settings_main.css
@@ -6,10 +6,6 @@
box-sizing: border-box;
height: 100%;
overflow: auto;
- padding: 34px 16px;
-}
-
-#pageContainer.expanded {
padding: 0 16px;
}
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 2b8eac5d366..1a1cabc869c 100644
--- a/chromium/chrome/browser/resources/settings/settings_main/settings_main.html
+++ b/chromium/chrome/browser/resources/settings/settings_main/settings_main.html
@@ -1,4 +1,4 @@
-<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
+<link rel="import" href="chrome://resources/html/polymer.html">
<link rel="import" href="chrome://md-settings/advanced_page/advanced_page.html">
<link rel="import" href="chrome://md-settings/basic_page/basic_page.html">
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 f683d4799e3..766e9dde50e 100644
--- a/chromium/chrome/browser/resources/settings/settings_main/settings_main.js
+++ b/chromium/chrome/browser/resources/settings/settings_main/settings_main.js
@@ -12,9 +12,6 @@
* </settings-main>
*
* See settings-drawer for example of use in 'paper-drawer-panel'.
- *
- * @group Chrome Settings Elements
- * @element settings-main
*/
Polymer({
is: 'settings-main',
@@ -46,35 +43,8 @@ Polymer({
}
},
- listeners: {
- 'expand-animation-complete': 'onExpandAnimationComplete_',
- },
-
/** @private */
currentRouteChanged_: function(newRoute, oldRoute) {
this.showAdvancedPage_ = newRoute.page == 'advanced';
-
- var pageContainer = this.$.pageContainer;
- if (!oldRoute) {
- pageContainer.classList.toggle('expanded', newRoute.section);
- return;
- }
-
- // For contraction only, apply new styling immediately.
- if (!newRoute.section && oldRoute.section) {
- pageContainer.classList.remove('expanded');
-
- // TODO(tommycli): Save and restore scroll position. crbug.com/537359.
- pageContainer.scrollTop = 0;
- }
- },
-
- /** @private */
- onExpandAnimationComplete_: function() {
- if (this.currentRoute.section) {
- var pageContainer = this.$.pageContainer;
- pageContainer.classList.add('expanded');
- pageContainer.scrollTop = 0;
- }
},
});
diff --git a/chromium/chrome/browser/resources/settings/settings_menu/settings_menu.css b/chromium/chrome/browser/resources/settings/settings_menu/settings_menu.css
deleted file mode 100644
index 598ff641a60..00000000000
--- a/chromium/chrome/browser/resources/settings/settings_menu/settings_menu.css
+++ /dev/null
@@ -1,8 +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. */
-
-paper-menu {
- background-color: transparent;
- color: #5a5a5a;
-}
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 d615b8e6309..0e6dcbea743 100644
--- a/chromium/chrome/browser/resources/settings/settings_menu/settings_menu.html
+++ b/chromium/chrome/browser/resources/settings/settings_menu/settings_menu.html
@@ -1,107 +1,167 @@
-<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.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/polymer/v1_0/iron-icons/av-icons.html">
<link rel="import" href="chrome://resources/polymer/v1_0/iron-icons/device-icons.html">
<link rel="import" href="chrome://resources/polymer/v1_0/iron-icons/hardware-icons.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/iron-icons/image-icons.html">
<link rel="import" href="chrome://resources/polymer/v1_0/iron-icons/iron-icons.html">
<link rel="import" href="chrome://resources/polymer/v1_0/iron-icons/social-icons.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-menu/paper-menu.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-menu/paper-submenu.html">
+<link rel="import" href="chrome://md-settings/settings_shared_css.html">
<if expr="chromeos">
<link rel="import" href="chrome://resources/polymer/v1_0/iron-icons/device-icons.html">
</if>
<dom-module id="settings-menu">
- <link rel="import" type="css" href="settings_menu.css">
<template>
+ <style include="settings-shared">
+ iron-icon {
+ -webkit-margin-end: 16px;
+ }
+
+ .menu-trigger span {
+ -webkit-margin-end: 16px;
+ flex: 1;
+ }
+
+ paper-menu {
+ background-color: var(--settings-background-color);
+ color: var(--settings-nav-grey);
+ font-size: 13px;
+ --paper-menu-selected-item: {
+ font-weight: 500;
+ };
+ --paper-menu-focused-item-after: {
+ background: none;
+ };
+ }
+
+ paper-submenu {
+ --paper-menu-selected-item: {
+ font-weight: 500;
+ };
+ }
+
+ paper-submenu paper-menu {
+ --paper-menu-selected-item: {
+ color: var(--google-blue-500);
+ font-weight: 500;
+ };
+ padding: 0;
+ }
+
+ paper-submenu div {
+ @apply(--layout-center);
+ -webkit-margin-start: 24px;
+ display: flex;
+ font-size: 13px;
+ font-weight: 500;
+ min-height: 40px;
+ }
+ </style>
<paper-menu name="root-menu">
- <paper-submenu data-page="basic" on-tap="openPage_">
- <paper-icon-item class="menu-trigger">
- <iron-icon icon="expand-more" item-icon></iron-icon>
+ <paper-submenu opened="{{basicOpened_}}" data-page="basic"
+ on-tap="openPage_">
+ <div class="menu-trigger">
<span i18n-content="basicPageTitle"></span>
- </paper-icon-item>
+ <iron-icon icon="{{arrowState_(basicOpened_)}}" item-icon></iron-icon>
+ </div>
<paper-menu class="menu-content">
<if expr="chromeos">
- <paper-icon-item>
- <iron-icon icon="settings-ethernet" item-icon></iron-icon>
+ <div>
+ <iron-icon icon="device:network-wifi" item-icon></iron-icon>
<span i18n-content="internetPageTitle"></span>
- </paper-icon-item>
+ </div>
</if>
- <paper-icon-item>
- <iron-icon icon="social:person" item-icon></iron-icon>
+ <div>
+ <iron-icon icon="social:people" item-icon></iron-icon>
<span i18n-content="peoplePageTitle"></span>
- </paper-icon-item>
- <paper-icon-item>
- <iron-icon icon="home" item-icon></iron-icon>
+ </div>
+ <div>
+ <iron-icon icon="image:palette" item-icon></iron-icon>
<span i18n-content="appearancePageTitle"></span>
- </paper-icon-item>
- <paper-icon-item>
- <iron-icon icon="image:brightness-1" item-icon></iron-icon>
- <span i18n-content="onStartup"></span>
- </paper-icon-item>
- <paper-icon-item>
+ </div>
+<if expr="chromeos">
+ <div>
+ <iron-icon icon="hardware:laptop-chromebook" item-icon></iron-icon>
+ <span i18n-content="devicePageTitle"></span>
+ </div>
+</if>
+ <div>
<iron-icon icon="search" item-icon></iron-icon>
<span i18n-content="searchPageTitle"></span>
- </paper-icon-item>
+ </div>
<if expr="not chromeos">
- <paper-icon-item>
- <iron-icon icon="open-in-browser" item-icon></iron-icon>
+ <div>
+ <iron-icon icon="av:web" item-icon></iron-icon>
<span i18n-content="defaultBrowser"></span>
- </paper-icon-item>
+ </div>
</if>
+ <div>
+ <iron-icon icon="icons:power-settings-new" item-icon></iron-icon>
+ <span i18n-content="onStartup"></span>
+ </div>
</paper-menu>
</paper-submenu>
- <paper-submenu data-page="advanced" on-tap="openPage_">
- <paper-icon-item class="menu-trigger">
- <iron-icon icon="expand-more" item-icon></iron-icon>
+ <paper-submenu opened="{{advancedOpened_}}" data-page="advanced"
+ on-tap="openPage_">
+ <div class="menu-trigger">
<span i18n-content="advancedPageTitle"></span>
- </paper-icon-item>
+ <iron-icon icon="{{arrowState_(advancedOpened_)}}" item-icon>
+ </iron-icon>
+ </div>
<paper-menu class="menu-content">
- <paper-icon-item>
- <iron-icon icon="communication:location-on" item-icon></iron-icon>
- <span i18n-content="siteSettingsLocation"></span>
- </paper-icon-item>
<if expr="chromeos">
- <paper-icon-item>
+ <div>
<iron-icon icon="device:access-time" item-icon></iron-icon>
<span i18n-content="dateTimePageTitle"></span>
- </paper-icon-item>
+ </div>
</if>
- <paper-icon-item>
+ <div>
<iron-icon icon="hardware:security" item-icon></iron-icon>
<span i18n-content="privacyPageTitle"></span>
- </paper-icon-item>
+ </div>
<if expr="chromeos">
- <paper-icon-item>
+ <div>
<iron-icon icon="device:bluetooth" item-icon></iron-icon>
<span i18n-content="bluetoothPageTitle"></span>
- </paper-icon-item>
+ </div>
</if>
- <paper-icon-item>
- <iron-icon icon="lock" item-icon></iron-icon>
+ <div>
+ <iron-icon icon="icons:assignment" item-icon></iron-icon>
<span i18n-content="passwordsAndAutofillPageTitle"></span>
- </paper-icon-item>
- <paper-icon-item>
- <iron-icon icon="language" item-icon></iron-icon>
+ </div>
+ <div>
+ <iron-icon icon="icons:language" item-icon></iron-icon>
<span i18n-content="languagesPageTitle"></span>
- </paper-icon-item>
- <paper-icon-item>
- <iron-icon icon="file-download" item-icon></iron-icon>
+ </div>
+ <div>
+ <iron-icon icon="icons:file-download" item-icon></iron-icon>
<span i18n-content="downloadsPageTitle"></span>
- </paper-icon-item>
- <paper-icon-item>
- <iron-icon icon="settings-backup-restore" item-icon></iron-icon>
- <span i18n-content="resetPageTitle"></span>
- </paper-icon-item>
-<if expr="chromeos">
- <paper-icon-item>
- <iron-icon icon="accessibility" item-icon></iron-icon>
+ </div>
+ <div>
+ <iron-icon icon="icons:accessibility" item-icon></iron-icon>
<span i18n-content="a11yPageTitle"></span>
- </paper-icon-item>
+ </div>
+<if expr="not chromeos">
+ <div>
+ <iron-icon icon="icons:build" item-icon></iron-icon>
+ <span i18n-content="systemPageTitle"></span>
+ </div>
</if>
+ <div>
+ <iron-icon icon="icons:restore" item-icon></iron-icon>
+ <span i18n-content="resetPageTitle"></span>
+ </div>
</paper-menu>
</paper-submenu>
+ <paper-submenu on-tap="openPage_">
+ <div class="menu-trigger">
+ <span i18n-content="aboutProgram"></span>
+ </div>
+ </paper-submenu>
</paper-menu>
</template>
<script src="settings_menu.js"></script>
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 9c873a1999e..d701db5b5a7 100644
--- a/chromium/chrome/browser/resources/settings/settings_menu/settings_menu.js
+++ b/chromium/chrome/browser/resources/settings/settings_menu/settings_menu.js
@@ -10,14 +10,17 @@
*
* <settings-menu selected-page-id="{{selectedPageId}}">
* </settings-menu>
- *
- * @group Chrome Settings Elements
- * @element settings-menu
*/
Polymer({
is: 'settings-menu',
properties: {
+ /** @private */
+ advancedOpened_: Boolean,
+
+ /** @private */
+ basicOpened_: Boolean,
+
/**
* The current active route.
*/
@@ -46,5 +49,14 @@ Polymer({
subpage: [],
};
}
- }
+ },
+
+ /**
+ * @param {boolean} opened Whether the menu is expanded.
+ * @return {string} Which icon to use.
+ * @private
+ * */
+ arrowState_: function(opened) {
+ return opened ? 'arrow-drop-up' : 'arrow-drop-down';
+ },
});
diff --git a/chromium/chrome/browser/resources/settings/basic_page/basic_page.css b/chromium/chrome/browser/resources/settings/settings_page.css
index 1a33ff32ef5..78d34a063d4 100644
--- a/chromium/chrome/browser/resources/settings/basic_page/basic_page.css
+++ b/chromium/chrome/browser/resources/settings/settings_page.css
@@ -5,5 +5,13 @@
:host {
display: block;
height: 100%;
- width: 605px;
+ margin: 24px auto;
+ max-width: 960px;
+ min-width: 622px;
+ position: relative;
+ width: 80%;
+}
+
+:host > * {
+ margin-bottom: 16px;
}
diff --git a/chromium/chrome/browser/resources/settings/settings_page/compiled_resources.gyp b/chromium/chrome/browser/resources/settings/settings_page/compiled_resources.gyp
deleted file mode 100644
index a36c51a8e14..00000000000
--- a/chromium/chrome/browser/resources/settings/settings_page/compiled_resources.gyp
+++ /dev/null
@@ -1,21 +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.
-{
- 'targets': [
- {
- 'target_name': 'settings_page_visibility',
- 'includes': ['../../../../../third_party/closure_compiler/compile_js.gypi'],
- },
- {
- 'target_name': 'settings_router',
- 'variables': {
- 'depends': [
- '../../../../../ui/webui/resources/js/compiled_resources.gyp:assert',
- '../../../../../ui/webui/resources/js/compiled_resources.gyp:load_time_data',
- ],
- },
- 'includes': ['../../../../../third_party/closure_compiler/compile_js.gypi'],
- },
- ],
-}
diff --git a/chromium/chrome/browser/resources/settings/settings_page/compiled_resources2.gyp b/chromium/chrome/browser/resources/settings/settings_page/compiled_resources2.gyp
new file mode 100644
index 00000000000..c81eb68f972
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/settings_page/compiled_resources2.gyp
@@ -0,0 +1,58 @@
+# 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': 'main_page_behavior',
+ 'dependencies': [
+ 'settings_section',
+ 'transition_behavior',
+ '<(EXTERNS_GYP):settings_private',
+ '<(EXTERNS_GYP):web_animations',
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'settings_animated_pages',
+ 'dependencies': [
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:assert',
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:load_time_data',
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'settings_page_visibility',
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'settings_router',
+ 'dependencies': [
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:assert',
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:load_time_data',
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'settings_section',
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'settings_subpage',
+ '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/neon-animation/compiled_resources2.gyp:neon-animatable-behavior-extracted',
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:assert',
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'transition_behavior',
+ 'dependencies': [
+ '<(EXTERNS_GYP):settings_private',
+ '<(EXTERNS_GYP):web_animations',
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ ],
+}
diff --git a/chromium/chrome/browser/resources/settings/settings_page/main_page_behavior.html b/chromium/chrome/browser/resources/settings/settings_page/main_page_behavior.html
new file mode 100644
index 00000000000..3d1c94f2e79
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/settings_page/main_page_behavior.html
@@ -0,0 +1,18 @@
+<link rel="import" href="chrome://resources/html/polymer.html">
+<link rel="import" href="chrome://md-settings/settings_page/transition_behavior.html">
+<script src="chrome://md-settings/settings_page/main_page_behavior.js"></script>
+
+<dom-module id="main-page-styles">
+ <template>
+ <style>
+ .expanding,
+ .collapsing {
+ z-index: 2;
+ }
+
+ .expanded {
+ min-height: 100%;
+ }
+ </style>
+ </template>
+</dom-module>
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
new file mode 100644
index 00000000000..99dbc67c618
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/settings_page/main_page_behavior.js
@@ -0,0 +1,379 @@
+// 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.
+
+// Fast out, slow in.
+var EASING_FUNCTION = 'cubic-bezier(0.4, 0, 0.2, 1)';
+var EXPAND_DURATION = 350;
+
+/**
+ * Provides animations to expand and collapse individual sections in a page.
+ * Expanded sections take up the full height of the container. At most one
+ * section should be expanded at any given time.
+ * @polymerBehavior Polymer.MainPageBehavior
+ */
+var MainPageBehaviorImpl = {
+ /**
+ * @type {string} Selector to get the sections. Derived elements
+ * must override.
+ */
+ sectionSelector: '',
+
+ /** @type {?Element} The scrolling container. Elements must set this. */
+ scroller: null,
+
+ /**
+ * Hides or unhides the sections not being expanded.
+ * @param {string} sectionName The section to keep visible.
+ * @param {boolean} hidden Whether the sections should be hidden.
+ * @private
+ */
+ toggleOtherSectionsHidden_: function(sectionName, hidden) {
+ var sections = Polymer.dom(this.root).querySelectorAll(
+ this.sectionSelector + ':not([section=' + sectionName + '])');
+ for (var section of sections)
+ section.hidden = hidden;
+ },
+
+ /**
+ * Animates the card in |section|, expanding it to fill the page.
+ * @param {!SettingsSectionElement} section
+ */
+ expandSection: function(section) {
+ // If another section's card is expanding, cancel that animation first.
+ var expanding = this.$$('.expanding');
+ if (expanding) {
+ if (expanding == section)
+ return;
+
+ if (this.animations['section']) {
+ // Cancel the animation, then call startExpandSection_.
+ this.cancelAnimation('section', function() {
+ this.startExpandSection_(section);
+ }.bind(this));
+ } else {
+ // The animation must have finished but its promise hasn't resolved yet.
+ // When it resolves, collapse that section's card before expanding
+ // this one.
+ setTimeout(function() {
+ this.collapseSection(
+ /** @type {!SettingsSectionElement} */(expanding));
+ this.finishAnimation('section', function() {
+ this.startExpandSection_(section);
+ }.bind(this));
+ }.bind(this));
+ }
+
+ return;
+ }
+
+ if (this.$$('.collapsing') && this.animations['section']) {
+ // Finish the collapse animation before expanding.
+ this.finishAnimation('section', function() {
+ this.startExpandSection_(section);
+ }.bind(this));
+ return;
+ }
+
+ this.startExpandSection_(section);
+ },
+
+ /**
+ * Helper function to set up and start the expand animation.
+ * @param {!SettingsSectionElement} section
+ */
+ startExpandSection_: function(section) {
+ if (section.classList.contains('expanded'))
+ return;
+
+ // Freeze the scroller and save its position.
+ this.listScrollTop_ = this.scroller.scrollTop;
+
+ var scrollerWidth = this.scroller.clientWidth;
+ this.scroller.style.overflow = 'hidden';
+ // Adjust width to compensate for scroller.
+ var scrollbarWidth = this.scroller.clientWidth - scrollerWidth;
+ this.scroller.style.width = 'calc(100% - ' + scrollbarWidth + 'px)';
+
+ // Freezes the section's height so its card can be removed from the flow.
+ this.freezeSection_(section);
+
+ // Expand the section's card to fill the parent.
+ var animationPromise = this.playExpandSection_(section);
+
+ animationPromise.then(function() {
+ this.scroller.scrollTop = 0;
+ this.toggleOtherSectionsHidden_(section.section, true);
+ }.bind(this), function() {
+ // Animation was canceled; restore the section.
+ this.unfreezeSection_(section);
+ }.bind(this)).then(function() {
+ this.scroller.style.overflow = '';
+ this.scroller.style.width = '';
+ }.bind(this));
+ },
+
+ /**
+ * Animates the card in |section|, collapsing it back into its section.
+ * @param {!SettingsSectionElement} section
+ */
+ collapseSection: function(section) {
+ // If the section's card is still expanding, cancel the expand animation.
+ if (section.classList.contains('expanding')) {
+ if (this.animations['section']) {
+ this.cancelAnimation('section');
+ } else {
+ // The animation must have finished but its promise hasn't finished
+ // resolving; try again asynchronously.
+ this.async(function() {
+ this.collapseSection(section);
+ });
+ }
+ return;
+ }
+
+ if (!section.classList.contains('expanded'))
+ return;
+
+ this.toggleOtherSectionsHidden_(section.section, false);
+
+ var scrollerWidth = this.scroller.clientWidth;
+ this.scroller.style.overflow = 'hidden';
+ // Adjust width to compensate for scroller.
+ var scrollbarWidth = this.scroller.clientWidth - scrollerWidth;
+ this.scroller.style.width = 'calc(100% - ' + scrollbarWidth + 'px)';
+
+ this.playCollapseSection_(section).then(function() {
+ this.unfreezeSection_(section);
+ this.scroller.style.overflow = '';
+ this.scroller.style.width = '';
+ section.classList.remove('collapsing');
+ }.bind(this));
+ },
+
+ /**
+ * Freezes a section's height so its card can be removed from the flow without
+ * affecting the layout of the surrounding sections.
+ * @param {!SettingsSectionElement} section
+ * @private
+ */
+ freezeSection_: function(section) {
+ var card = section.$.card;
+ section.style.height = section.clientHeight + 'px';
+
+ var cardHeight = card.offsetHeight;
+ var cardWidth = card.offsetWidth;
+ // If the section is not displayed yet (e.g., navigated directly to a
+ // sub-page), cardHeight and cardWidth are 0, so do not set the height or
+ // width explicitly.
+ // TODO(michaelpg): Improve this logic when refactoring
+ // settings-animated-pages.
+ if (cardHeight && cardWidth) {
+ // TODO(michaelpg): Temporary hack to store the height the section should
+ // collapse to when it closes.
+ card.origHeight_ = cardHeight;
+
+ card.style.height = cardHeight + 'px';
+ card.style.width = cardWidth + 'px';
+ } else {
+ // Set an invalid value so we don't try to use it later.
+ card.origHeight_ = NaN;
+ }
+
+ // Place the section's card at its current position but removed from the
+ // flow.
+ card.style.top = card.getBoundingClientRect().top + 'px';
+ section.classList.add('frozen');
+ },
+
+ /**
+ * After freezeSection_, restores the section to its normal height.
+ * @param {!SettingsSectionElement} section
+ * @private
+ */
+ unfreezeSection_: function(section) {
+ if (!section.classList.contains('frozen'))
+ return;
+ var card = section.$.card;
+ section.classList.remove('frozen');
+ card.style.top = '';
+ card.style.height = '';
+ card.style.width = '';
+ section.style.height = '';
+ },
+
+ /**
+ * Expands the card in |section| to fill the page.
+ * @param {!SettingsSectionElement} section
+ * @return {!Promise}
+ * @private
+ */
+ playExpandSection_: function(section) {
+ var card = section.$.card;
+
+ // The card should start at the top of the page.
+ var targetTop = this.parentElement.getBoundingClientRect().top;
+
+ section.classList.add('expanding');
+
+ // Expand the card, using minHeight. (The card must span the container's
+ // client height, so it must be at least 100% in case the card is too short.
+ // If the card is already taller than the container's client height, we
+ // don't want to shrink the card to 100% or the content will overflow, so
+ // we can't use height, and animating height wouldn't look right anyway.)
+ var keyframes = [{
+ top: card.style.top,
+ minHeight: card.style.height,
+ easing: EASING_FUNCTION,
+ }, {
+ top: targetTop + 'px',
+ minHeight: 'calc(100% - ' + targetTop + 'px)',
+ }];
+ var options = /** @type {!KeyframeEffectOptions} */({
+ duration: EXPAND_DURATION
+ });
+ // TODO(michaelpg): Change elevation of sections.
+ var promise;
+ if (keyframes[0].top && keyframes[0].minHeight)
+ promise = this.animateElement('section', card, keyframes, options);
+ else
+ promise = Promise.resolve();
+
+ promise.then(function() {
+ section.classList.add('expanded');
+ card.style.top = '';
+ this.style.margin = 'auto';
+ section.$.header.hidden = true;
+ section.style.height = '';
+ }.bind(this), function() {
+ // The animation was canceled; catch the error and continue.
+ }).then(function() {
+ // Whether finished or canceled, clean up the animation.
+ section.classList.remove('expanding');
+ card.style.height = '';
+ });
+
+ return promise;
+ },
+
+ /**
+ * Collapses the card in |section| back to its normal position.
+ * @param {!SettingsSectionElement} section
+ * @return {!Promise}
+ * @private
+ */
+ playCollapseSection_: function(section) {
+ var card = section.$.card;
+ var cardStyle = getComputedStyle(card);
+
+ this.style.margin = '';
+ section.$.header.hidden = false;
+
+ var startingTop = this.parentElement.getBoundingClientRect().top;
+
+ var cardHeightStart = card.clientHeight;
+
+ section.classList.add('collapsing');
+ section.classList.remove('expanding', 'expanded');
+
+ // If we navigated here directly, we don't know the original height of the
+ // section, so we skip the animation.
+ // TODO(michaelpg): remove this condition once sliding is implemented.
+ if (isNaN(card.origHeight_))
+ return Promise.resolve();
+
+ // Restore the section to its proper height to make room for the card.
+ section.style.height = section.clientHeight + card.origHeight_ + 'px';
+
+ // TODO(michaelpg): this should be in collapseSection(), but we need to wait
+ // until the full page height is available (setting the section height).
+ this.scroller.scrollTop = this.listScrollTop_;
+
+ // The card is unpositioned, so use its position as the ending state,
+ // but account for scroll.
+ var targetTop = card.getBoundingClientRect().top - this.scroller.scrollTop;
+
+ var keyframes = [{
+ top: startingTop + 'px',
+ minHeight: cardHeightStart + 'px',
+ easing: EASING_FUNCTION,
+ }, {
+ top: targetTop + 'px',
+ minHeight: card.origHeight_ + 'px',
+ }];
+ var options = /** @type {!KeyframeEffectOptions} */({
+ duration: EXPAND_DURATION
+ });
+ var promise = this.animateElement('section', card, keyframes, options);
+ return promise;
+ },
+};
+
+/** @polymerBehavior */
+var MainPageBehavior = [
+ TransitionBehavior,
+ MainPageBehaviorImpl
+];
+
+/**
+ * TODO(michaelpg): integrate slide animations.
+ * @polymerBehavior RoutableBehavior
+ */
+var RoutableBehaviorImpl = {
+ properties: {
+ /** Contains the current route. */
+ currentRoute: {
+ type: Object,
+ notify: true,
+ observer: 'currentRouteChanged_',
+ },
+ },
+
+ /** @private */
+ currentRouteChanged_: function(newRoute, oldRoute) {
+ // route.section is only non-empty when the user is within a subpage.
+ // When the user is not in a subpage, but on the Basic page, route.section
+ // is an empty string.
+ var newRouteIsSubpage = newRoute && newRoute.section;
+ var oldRouteIsSubpage = oldRoute && oldRoute.section;
+
+ if (!oldRoute && newRouteIsSubpage) {
+ // Allow the page to load before expanding the section. TODO(michaelpg):
+ // Time this better when refactoring settings-animated-pages.
+ setTimeout(function() {
+ var section = this.getSection_(newRoute.section);
+ if (section)
+ this.expandSection(section);
+ }.bind(this));
+ return;
+ }
+
+ if (!newRouteIsSubpage && oldRouteIsSubpage) {
+ var section = this.getSection_(oldRoute.section);
+ if (section)
+ this.collapseSection(section);
+ } else if (newRouteIsSubpage &&
+ (!oldRouteIsSubpage || newRoute.section != oldRoute.section)) {
+ var section = this.getSection_(newRoute.section);
+ if (section)
+ this.expandSection(section);
+ }
+ },
+
+ /**
+ * Helper function to get a section from the local DOM.
+ * @param {string} section Section name of the element to get.
+ * @return {?SettingsSectionElement}
+ * @private
+ */
+ getSection_: function(section) {
+ return /** @type {?SettingsSectionElement} */(
+ this.$$('[section=' + section + ']'));
+ },
+};
+
+/** @polymerBehavior */
+var RoutableBehavior = [
+ MainPageBehavior,
+ RoutableBehaviorImpl
+];
diff --git a/chromium/chrome/browser/resources/settings/settings_page/settings_animated_pages.css b/chromium/chrome/browser/resources/settings/settings_page/settings_animated_pages.css
deleted file mode 100644
index 6de1938cea8..00000000000
--- a/chromium/chrome/browser/resources/settings/settings_page/settings_animated_pages.css
+++ /dev/null
@@ -1,11 +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. */
-
-/**
- * @fileoverview
- * Styles used for animating settings subpages.
- */
-neon-animated-pages ::content > .iron-selected {
- position: static;
-}
diff --git a/chromium/chrome/browser/resources/settings/settings_page/settings_animated_pages.html b/chromium/chrome/browser/resources/settings/settings_page/settings_animated_pages.html
index fcd6b9d5d7e..3d9a761d9c9 100644
--- a/chromium/chrome/browser/resources/settings/settings_page/settings_animated_pages.html
+++ b/chromium/chrome/browser/resources/settings/settings_page/settings_animated_pages.html
@@ -1,4 +1,5 @@
-<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
+<link rel="import" href="chrome://resources/html/assert.html">
+<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/neon-animation/animations/fade-in-animation.html">
<link rel="import" href="chrome://resources/polymer/v1_0/neon-animation/animations/fade-out-animation.html">
@@ -11,8 +12,12 @@
<link rel="import" href="chrome://resources/polymer/v1_0/neon-animation/neon-animation-runner-behavior.html">
<dom-module id="settings-animated-pages">
- <link rel="import" type="css" href="settings_animated_pages.css">
<template>
+ <style>
+ neon-animated-pages ::content > .iron-selected {
+ position: static;
+ }
+ </style>
<neon-animated-pages id="animatedPages" attr-for-selected="id">
<content select="*"></content>
</neon-animated-pages>
diff --git a/chromium/chrome/browser/resources/settings/settings_page/settings_animated_pages.js b/chromium/chrome/browser/resources/settings/settings_page/settings_animated_pages.js
index 27eb63401fe..574350715c0 100644
--- a/chromium/chrome/browser/resources/settings/settings_page/settings_animated_pages.js
+++ b/chromium/chrome/browser/resources/settings/settings_page/settings_animated_pages.js
@@ -13,9 +13,6 @@
* section="privacy">
* <!-- Insert your section controls here -->
* </settings-animated-pages>
- *
- * @group Chrome Settings Elements
- * @element settings-animated-pages
*/
Polymer({
is: 'settings-animated-pages',
@@ -44,6 +41,10 @@ Polymer({
/** @override */
created: function() {
+ // Observe the light DOM so we know when it's ready.
+ this.lightDomObserver_ = Polymer.dom(this).observeNodes(
+ this.lightDomChanged_.bind(this));
+
this.addEventListener('subpage-back', function() {
assert(this.currentRoute.section == this.section);
assert(this.currentRoute.subpage.length >= 1);
@@ -52,14 +53,50 @@ Polymer({
}.bind(this));
},
+ /**
+ * Called initially once the effective children are ready.
+ * @private
+ */
+ lightDomChanged_: function() {
+ if (this.lightDomReady_)
+ return;
+
+ this.lightDomReady_ = true;
+ Polymer.dom(this).unobserveNodes(this.lightDomObserver_);
+ this.runQueuedRouteChange_();
+ },
+
+ /**
+ * Calls currentRouteChanged_ with the deferred route change info.
+ * @private
+ */
+ runQueuedRouteChange_: function() {
+ if (!this.queuedRouteChange_)
+ return;
+ this.async(this.currentRouteChanged_.bind(
+ this,
+ this.queuedRouteChange_.newRoute,
+ this.queuedRouteChange_.oldRoute));
+ },
+
/** @private */
currentRouteChanged_: function(newRoute, oldRoute) {
+ // Don't manipulate the light DOM until it's ready.
+ if (!this.lightDomReady_) {
+ this.queuedRouteChange_ = this.queuedRouteChange_ || {oldRoute: oldRoute};
+ this.queuedRouteChange_.newRoute = newRoute;
+ return;
+ }
+
// route.section is only non-empty when the user is within a subpage.
// When the user is not in a subpage, but on the Basic page, route.section
// is an empty string.
var newRouteIsSubpage = newRoute && newRoute.section == this.section;
var oldRouteIsSubpage = oldRoute && oldRoute.section == this.section;
+ if (newRouteIsSubpage)
+ this.ensureSubpageInstance_();
+
if (!newRouteIsSubpage || !oldRouteIsSubpage ||
newRoute.subpage.length == oldRoute.subpage.length) {
// If two routes are at the same level, or if either the new or old route
@@ -82,6 +119,30 @@ Polymer({
},
/**
+ * Ensures that the template enclosing the subpage is stamped.
+ * @private
+ */
+ ensureSubpageInstance_: function() {
+ var id = this.currentRoute.subpage.slice(-1)[0];
+ var template = Polymer.dom(this).querySelector(
+ 'template[name="' + id + '"]');
+
+ // Do nothing if the subpage is already stamped.
+ if (template.if)
+ return;
+
+ // Set the subpage's id for use by neon-animated-pages.
+ var subpage = /** @type {{_content: DocumentFragment}} */(template)._content
+ .querySelector('settings-subpage');
+ if (!subpage.id)
+ subpage.id = id;
+
+ // Render synchronously so neon-animated-pages can select the subpage.
+ template.if = true;
+ template.render();
+ },
+
+ /**
* Buttons in this pageset should use this method to transition to subpages.
*/
setSubpageChain: function(subpage) {
diff --git a/chromium/chrome/browser/resources/settings/settings_page/settings_page_visibility.js b/chromium/chrome/browser/resources/settings/settings_page/settings_page_visibility.js
index 660d8e17d8b..3dcfce2d988 100644
--- a/chromium/chrome/browser/resources/settings/settings_page/settings_page_visibility.js
+++ b/chromium/chrome/browser/resources/settings/settings_page/settings_page_visibility.js
@@ -8,8 +8,6 @@
*
* Example:
* behaviors: [SettingsPageVisibility],
- *
- * @group Chrome UI Behavior
*/
/**
diff --git a/chromium/chrome/browser/resources/settings/settings_page/settings_router.html b/chromium/chrome/browser/resources/settings/settings_page/settings_router.html
index 73b4b74d2fe..bd2e5e9b07b 100644
--- a/chromium/chrome/browser/resources/settings/settings_page/settings_router.html
+++ b/chromium/chrome/browser/resources/settings/settings_page/settings_router.html
@@ -1,3 +1,3 @@
-<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
+<link rel="import" href="chrome://resources/html/polymer.html">
<script src="settings_router.js"></script>
diff --git a/chromium/chrome/browser/resources/settings/settings_page/settings_router.js b/chromium/chrome/browser/resources/settings/settings_page/settings_router.js
index 518f0721891..8c32e900c8b 100644
--- a/chromium/chrome/browser/resources/settings/settings_page/settings_router.js
+++ b/chromium/chrome/browser/resources/settings/settings_page/settings_router.js
@@ -13,9 +13,6 @@
*
* <settings-router current-route="{{currentRoute}}">
* </settings-router>
- *
- * @group Chrome Settings Elements
- * @element settings-router
*/
Polymer({
is: 'settings-router',
@@ -61,7 +58,7 @@ Polymer({
/**
* Page titles for the currently active route. Updated by the currentRoute
* property observer.
- * @type {{pageTitle: string, subpageTitles: Array<string>}}
+ * @type {{pageTitle: string}}
*/
currentRouteTitles: {
notify: true,
@@ -69,7 +66,6 @@ Polymer({
value: function() {
return {
pageTitle: '',
- subpageTitles: [],
};
},
},
@@ -86,14 +82,12 @@ Polymer({
page: 'basic',
section: '',
subpage: [],
- subpageTitles: [],
},
{
url: '/advanced',
page: 'advanced',
section: '',
subpage: [],
- subpageTitles: [],
},
<if expr="chromeos">
{
@@ -101,14 +95,12 @@ Polymer({
page: 'basic',
section: 'internet',
subpage: ['network-detail'],
- subpageTitles: ['internetDetailPageTitle'],
},
{
url: '/knownNetworks',
page: 'basic',
section: 'internet',
subpage: ['known-networks'],
- subpageTitles: ['internetKnownNetworksPageTitle'],
},
</if>
{
@@ -116,21 +108,18 @@ Polymer({
page: 'basic',
section: 'appearance',
subpage: ['appearance-fonts'],
- subpageTitles: ['customizeFonts'],
},
{
url: '/searchEngines',
page: 'basic',
section: 'search',
subpage: ['search-engines'],
- subpageTitles: ['searchEnginesPageTitle'],
},
{
url: '/searchEngines/advanced',
page: 'basic',
section: 'search',
subpage: ['search-engines', 'search-engines-advanced'],
- subpageTitles: ['searchEnginesPageTitle', 'advancedPageTitle'],
},
<if expr="chromeos">
{
@@ -138,7 +127,6 @@ Polymer({
page: 'basic',
section: 'people',
subpage: ['changePicture'],
- subpageTitles: ['changePictureTitle'],
},
</if>
<if expr="not chromeos">
@@ -147,7 +135,6 @@ Polymer({
page: 'basic',
section: 'people',
subpage: ['manageProfile'],
- subpageTitles: ['editPerson'],
},
</if>
{
@@ -155,7 +142,6 @@ Polymer({
page: 'basic',
section: 'people',
subpage: ['sync'],
- subpageTitles: ['syncPageTitle'],
},
<if expr="chromeos">
{
@@ -163,7 +149,6 @@ Polymer({
page: 'basic',
section: 'people',
subpage: ['users'],
- subpageTitles: ['usersPageTitle'],
},
</if>
{
@@ -171,92 +156,149 @@ Polymer({
page: 'advanced',
section: 'privacy',
subpage: ['manage-certificates'],
- subpageTitles: ['manageCertificates'],
},
{
url: '/siteSettings',
page: 'advanced',
section: 'privacy',
subpage: ['site-settings'],
- subpageTitles: ['siteSettings'],
},
+ // Site Category routes.
{
- url: '/siteSettings/category/camera',
+ url: '/siteSettings/all',
+ page: 'advanced',
+ section: 'privacy',
+ subpage: ['site-settings', 'all-sites'],
+ },
+ {
+ url: '/siteSettings/camera',
page: 'advanced',
section: 'privacy',
subpage: ['site-settings', 'site-settings-category-camera'],
- subpageTitles: ['siteSettings', 'siteSettingsCamera'],
},
{
- url: '/siteSettings/category/cookies',
+ url: '/siteSettings/cookies',
page: 'advanced',
section: 'privacy',
subpage: ['site-settings', 'site-settings-category-cookies'],
- subpageTitles: ['siteSettings', 'siteSettingsCategoryCookies'],
},
{
- url: '/siteSettings/category/fullscreen',
+ url: '/siteSettings/fullscreen',
page: 'advanced',
section: 'privacy',
subpage: ['site-settings', 'site-settings-category-fullscreen'],
- subpageTitles: ['siteSettings', 'siteSettingsCategoryFullscreen'],
},
{
- url: '/siteSettings/category/images',
+ url: '/siteSettings/images',
page: 'advanced',
section: 'privacy',
subpage: ['site-settings', 'site-settings-category-images'],
- subpageTitles: ['siteSettings', 'siteSettingsCategoryImages'],
},
{
- url: '/siteSettings/category/location',
+ url: '/siteSettings/location',
page: 'advanced',
section: 'privacy',
subpage: ['site-settings', 'site-settings-category-location'],
- subpageTitles: ['siteSettings', 'siteSettingsCategoryLocation'],
},
{
- url: '/siteSettings/category/javascript',
+ url: '/siteSettings/javascript',
page: 'advanced',
section: 'privacy',
subpage: ['site-settings', 'site-settings-category-javascript'],
- subpageTitles: ['siteSettings', 'siteSettingsCategoryJavascript'],
},
{
- url: '/siteSettings/category/microphone',
+ url: '/siteSettings/microphone',
page: 'advanced',
section: 'privacy',
subpage: ['site-settings', 'site-settings-category-microphone'],
- subpageTitles: ['siteSettings', 'siteSettingsCategoryMicrophone'],
},
{
- url: '/siteSettings/category/notifications',
+ url: '/siteSettings/notifications',
page: 'advanced',
section: 'privacy',
subpage: ['site-settings', 'site-settings-category-notifications'],
- subpageTitles: ['siteSettings', 'siteSettingsCategoryNotifications'],
},
{
- url: '/siteSettings/category/popups',
+ url: '/siteSettings/popups',
page: 'advanced',
section: 'privacy',
subpage: ['site-settings', 'site-settings-category-popups'],
- subpageTitles: ['siteSettings', 'siteSettingsCategoryPopups'],
+ },
+ // Site details routes.
+ {
+ url: '/siteSettings/all/details',
+ page: 'advanced',
+ section: 'privacy',
+ subpage: ['site-settings', 'all-sites', 'site-details'],
+ },
+ {
+ url: '/siteSettings/camera/details',
+ page: 'advanced',
+ section: 'privacy',
+ subpage: ['site-settings', 'site-settings-category-camera',
+ 'site-details'],
+ },
+ {
+ url: '/siteSettings/cookies/details',
+ page: 'advanced',
+ section: 'privacy',
+ subpage: ['site-settings', 'site-settings-category-cookies',
+ 'site-details'],
+ },
+ {
+ url: '/siteSettings/fullscreen/details',
+ page: 'advanced',
+ section: 'privacy',
+ subpage: ['site-settings', 'site-settings-category-fullscreen',
+ 'site-details'],
},
{
- url: '/siteSettings/category/details',
+ url: '/siteSettings/images/details',
page: 'advanced',
section: 'privacy',
- subpage: ['site-settings', 'site-settings-category', 'site-details'],
- subpageTitles: ['siteSettings', 'siteSettingsCategoryPageTitle',
- 'siteSettingsSiteDetailsPageTitle'],
+ subpage: ['site-settings', 'site-settings-category-images',
+ 'site-details'],
+ },
+ {
+ url: '/siteSettings/location/details',
+ page: 'advanced',
+ section: 'privacy',
+ subpage: ['site-settings', 'site-settings-category-location',
+ 'site-details'],
+ },
+ {
+ url: '/siteSettings/javascript/details',
+ page: 'advanced',
+ section: 'privacy',
+ subpage: ['site-settings', 'site-settings-category-javascript',
+ 'site-details'],
+ },
+ {
+ url: '/siteSettings/microphone/details',
+ page: 'advanced',
+ section: 'privacy',
+ subpage: ['site-settings', 'site-settings-category-microphone',
+ 'site-details'],
+ },
+ {
+ url: '/siteSettings/notifications/details',
+ page: 'advanced',
+ section: 'privacy',
+ subpage: ['site-settings', 'site-settings-category-notifications',
+ 'site-details'],
+ },
+ {
+ url: '/siteSettings/popups/details',
+ page: 'advanced',
+ section: 'privacy',
+ subpage: ['site-settings', 'site-settings-category-popups',
+ 'site-details'],
},
{
url: '/clearBrowserData',
page: 'advanced',
section: 'privacy',
subpage: ['clear-browsing-data'],
- subpageTitles: ['clearBrowsingData'],
},
<if expr="chromeos">
{
@@ -264,30 +306,31 @@ Polymer({
page: 'advanced',
section: 'bluetooth',
subpage: ['bluetooth-add-device'],
- subpageTitles: ['bluetoothAddDevicePageTitle'],
},
{
url: '/bluetoothAddDevice/bluetoothPairDevice',
page: 'advanced',
section: 'bluetooth',
subpage: ['bluetooth-add-device', 'bluetooth-pair-device'],
- subpageTitles: ['bluetoothAddDevicePageTitle',
- 'bluetoothPairDevicePageTitle'],
},
</if>
{
+ url: '/passwords',
+ page: 'advanced',
+ section: 'passwordsAndForms',
+ subpage: ['manage-passwords'],
+ },
+ {
url: '/languages',
page: 'advanced',
section: 'languages',
subpage: ['manage-languages'],
- subpageTitles: ['manageLanguagesPageTitle'],
},
{
url: '/languages/edit',
page: 'advanced',
section: 'languages',
subpage: ['language-detail'],
- subpageTitles: ['manageLanguagesPageTitle'],
},
<if expr="not is_macosx">
{
@@ -295,7 +338,26 @@ Polymer({
page: 'advanced',
section: 'languages',
subpage: ['edit-dictionary'],
- subpageTitles: ['editDictionaryPageTitle'],
+ },
+</if>
+<if expr="chromeos">
+ {
+ url: '/pointer-overlay',
+ page: 'basic',
+ section: 'device',
+ subpage: ['touchpad'],
+ },
+ {
+ url: '/keyboard-overlay',
+ page: 'basic',
+ section: 'device',
+ subpage: ['keyboard'],
+ },
+ {
+ url: '/display-overlay',
+ page: 'basic',
+ section: 'device',
+ subpage: ['display'],
},
</if>
],
@@ -328,9 +390,6 @@ Polymer({
// Update the property containing the titles for the current route.
this.currentRouteTitles = {
pageTitle: loadTimeData.getString(route.page + 'PageTitle'),
- subpageTitles: route.subpageTitles.map(function(titleCode) {
- return loadTimeData.getString(titleCode);
- }),
};
// If we are restoring a state from history, don't push it again.
diff --git a/chromium/chrome/browser/resources/settings/settings_page/settings_section.css b/chromium/chrome/browser/resources/settings/settings_page/settings_section.css
index 91a81fcc8ab..85d6e9166f0 100644
--- a/chromium/chrome/browser/resources/settings/settings_page/settings_section.css
+++ b/chromium/chrome/browser/resources/settings/settings_page/settings_section.css
@@ -7,46 +7,43 @@
* Common styles for Settings pages.
*/
:host {
- display: block;
+ display: flex;
+ flex-direction: column;
+ position: relative;
}
-:host(.expanded) {
- height: 100%;
-}
-
-:host(.expanded) #header {
- display: none;
+#header {
+ margin-bottom: 12px;
}
#header .title {
- @apply(--paper-font-body2);
+ color: rgb(104, 113, 116);
+ font-size: 13px;
+ font-weight: 500;
}
-paper-material {
+#card {
background-color: white;
- box-sizing: border-box;
overflow: hidden;
}
-paper-material,
-#placeholder {
- margin-bottom: 16px;
+#card {
+ flex: 1;
}
-:host(.neon-animating) paper-material {
- position: fixed;
- z-index: 1;
+:host(.expanded) {
+ margin-bottom: 0;
}
-:host(.expanded) paper-material {
- margin-bottom: 0;
- min-height: 100%;
+:host(.expanded) #header {
+ display: none;
}
-#placeholder {
- visibility: hidden;
+:host(.frozen) #card {
+ position: fixed;
+ width: 100%;
}
-:host(:not(.neon-animating)) #placeholder {
- position: absolute;
+:host(.expanded.frozen) #card {
+ position: relative;
}
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 6204a0728a0..ed4e2632c1b 100644
--- a/chromium/chrome/browser/resources/settings/settings_page/settings_section.html
+++ b/chromium/chrome/browser/resources/settings/settings_page/settings_section.html
@@ -1,4 +1,4 @@
-<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
+<link rel="import" href="chrome://resources/html/polymer.html">
<link rel="import" href="chrome://resources/polymer/v1_0/neon-animation/neon-animation-runner-behavior.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-material/paper-material.html">
@@ -11,7 +11,6 @@
<paper-material id="card" animated>
<content id="content"></content>
</paper-material>
- <div id="placeholder"></div>
</template>
<script src="settings_section.js"></script>
</dom-module>
diff --git a/chromium/chrome/browser/resources/settings/settings_page/settings_section.js b/chromium/chrome/browser/resources/settings/settings_page/settings_section.js
index 7a39fd72ac1..1149e2ea81b 100644
--- a/chromium/chrome/browser/resources/settings/settings_page/settings_section.js
+++ b/chromium/chrome/browser/resources/settings/settings_page/settings_section.js
@@ -12,25 +12,15 @@
* <settings-section page-title="[[pageTitle]]" section="privacy">
* <!-- Insert your section controls here -->
* </settings-section>
- *
- * @group Chrome Settings Elements
- * @element settings-section
*/
Polymer({
is: 'settings-section',
- behaviors: [
- Polymer.NeonAnimationRunnerBehavior,
- ],
-
properties: {
/**
* The current active route.
*/
- currentRoute: {
- type: Object,
- observer: 'currentRouteChanged_',
- },
+ currentRoute: Object,
/**
* The section is expanded to a full-page view when this property matches
@@ -46,143 +36,5 @@ Polymer({
* Title for the page header and navigation menu.
*/
pageTitle: String,
-
- animationConfig: {
- value: function() {
- return {
- collapse: {
- name: 'collapse-card-animation',
- node: this,
- },
- expand: {
- name: 'expand-card-animation',
- node: this,
- },
- };
- },
- },
- },
-
- listeners: {
- 'expand-animation-complete': 'onExpandAnimationComplete_',
- },
-
- /** @private */
- currentRouteChanged_: function(newRoute, oldRoute) {
- var newExpanded = newRoute.section == this.section;
- var oldExpanded = oldRoute && oldRoute.section == this.section;
-
- var visible = newExpanded || this.currentRoute.section == '';
-
- // If the user navigates directly to a subpage, skip all the animations.
- if (!oldRoute) {
- if (newExpanded) {
- // If we navigate directly to a subpage, skip animations.
- this.classList.add('expanded');
- } else if (!visible) {
- this.hidden = true;
- this.$.card.elevation = 0;
- }
-
- return;
- }
-
- if (newExpanded && !oldExpanded) {
- this.playAnimation('expand');
- } else if (oldExpanded && !newExpanded) {
- // For contraction, we defer the animation to allow
- // settings-animated-pages to reflow the new page correctly.
- this.async(function() {
- this.playAnimation('collapse');
- }.bind(this));
- }
-
- this.$.card.elevation = visible ? 1 : 0;
-
- // Remove 'hidden' class immediately, but defer adding it if we are invisble
- // until the animation is complete.
- if (visible)
- this.hidden = false;
- },
-
- /** @private */
- onExpandAnimationComplete_: function() {
- this.hidden = this.currentRoute.section != '' &&
- this.currentRoute.section != this.section;
- },
-});
-
-Polymer({
- is: 'expand-card-animation',
-
- behaviors: [
- Polymer.NeonAnimationBehavior
- ],
-
- configure: function(config) {
- var section = config.node;
- var card = section.$.card;
- var containerRect = section.offsetParent.getBoundingClientRect();
- var cardRect = card.getBoundingClientRect();
-
- // Set placeholder height so the page does not reflow during animation.
- // TODO(tommycli): For URLs that directly load subpages, this does not work.
- var placeholder = section.$.placeholder;
- placeholder.style.top = card.offsetTop + 'px';
- placeholder.style.height = card.offsetHeight + 'px';
-
- section.classList.add('neon-animating');
-
- this._effect = new KeyframeEffect(card, [
- {'top': cardRect.top + 'px', 'height': cardRect.height + 'px'},
- {'top': containerRect.top + 'px', 'height': containerRect.height + 'px'},
- ], this.timingFromConfig(config));
- return this._effect;
- },
-
- complete: function(config) {
- var section = config.node;
- section.classList.remove('neon-animating');
- section.classList.add('expanded');
-
- // This event fires on itself as well, but that is benign.
- var sections = section.parentNode.querySelectorAll('settings-section');
- for (var i = 0; i < sections.length; ++i) {
- sections[i].fire('expand-animation-complete');
- }
- }
-});
-
-Polymer({
- is: 'collapse-card-animation',
-
- behaviors: [
- Polymer.NeonAnimationBehavior
- ],
-
- configure: function(config) {
- var section = config.node;
- var oldRect = section.offsetParent.getBoundingClientRect();
-
- section.classList.remove('expanded');
-
- var card = section.$.card;
- var placeholder = section.$.placeholder;
- placeholder.style.top = card.offsetTop + 'px';
- placeholder.style.height = card.offsetHeight + 'px';
-
- var newRect = card.getBoundingClientRect();
-
- section.classList.add('neon-animating');
-
- this._effect = new KeyframeEffect(card, [
- {'top': oldRect.top + 'px', 'height': oldRect.height + 'px'},
- {'top': newRect.top + 'px', 'height': newRect.height + 'px'},
- ], this.timingFromConfig(config));
- return this._effect;
},
-
- complete: function(config) {
- config.node.classList.remove('neon-animating');
- }
});
diff --git a/chromium/chrome/browser/resources/settings/settings_page/settings_subheader.css b/chromium/chrome/browser/resources/settings/settings_page/settings_subheader.css
deleted file mode 100644
index 331762baa41..00000000000
--- a/chromium/chrome/browser/resources/settings/settings_page/settings_subheader.css
+++ /dev/null
@@ -1,13 +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. */
-
-:host {
- @apply(--layout-center);
- @apply(--layout-horizontal);
- margin-bottom: 16px;
-}
-
-h2 {
- @apply(--paper-font-subhead);
-}
diff --git a/chromium/chrome/browser/resources/settings/settings_page/settings_subheader.html b/chromium/chrome/browser/resources/settings/settings_page/settings_subheader.html
deleted file mode 100644
index 7edeb3b9b39..00000000000
--- a/chromium/chrome/browser/resources/settings/settings_page/settings_subheader.html
+++ /dev/null
@@ -1,13 +0,0 @@
-<link rel="import" href="chrome://resources/polymer/v1_0/polymer/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/iron-icons/iron-icons.html">
-
-<dom-module id="settings-subheader">
- <link rel="import" type="css" href="settings_subheader.css">
- <template>
- <paper-icon-button icon="arrow-back" on-tap="onTapBack_">
- </paper-icon-button>
- <h2>[[pageTitle]]</h2>
- </template>
- <script src="settings_subheader.js"></script>
-</dom-module>
diff --git a/chromium/chrome/browser/resources/settings/settings_page/settings_subpage.html b/chromium/chrome/browser/resources/settings/settings_page/settings_subpage.html
new file mode 100644
index 00000000000..fcef1ebe182
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/settings_page/settings_subpage.html
@@ -0,0 +1,37 @@
+<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/iron-resizable-behavior/iron-resizable-behavior.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://md-settings/settings_shared_css.html">
+
+<dom-module id="settings-subpage">
+ <template>
+ <style include="settings-shared">
+ :host {
+ display: block;
+ margin: 8px 0 16px 0;
+ }
+
+ paper-icon-button {
+ /* The inner icon is 20px in size. paper-icon-button has 8px padding. */
+ height: 36px;
+ /* Centers the ripple on the icon with appropriate margin on right. */
+ margin: 0 12px 0 -8px;
+ width: 36px;
+ }
+
+ h2 {
+ color: var(--settings-nav-grey);
+ font-size: 107.6923%; /* go to 14px from 13px */
+ }
+ </style>
+ <div class="settings-box first">
+ <paper-icon-button icon="arrow-back" on-tap="onTapBack_">
+ </paper-icon-button>
+ <h2>[[pageTitle]]</h2>
+ </div>
+ <content></content>
+ </template>
+ <script src="settings_subpage.js"></script>
+</dom-module>
diff --git a/chromium/chrome/browser/resources/settings/settings_page/settings_subheader.js b/chromium/chrome/browser/resources/settings/settings_page/settings_subpage.js
index ff89b89cece..397e89addb8 100644
--- a/chromium/chrome/browser/resources/settings/settings_page/settings_subheader.js
+++ b/chromium/chrome/browser/resources/settings/settings_page/settings_subpage.js
@@ -1,23 +1,26 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
+// 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-subheader' shows a subheader for subpages. This header contains
+ * 'settings-subpage' shows a subpage beneath a subheader. The header contains
* the subpage title and a back icon. The back icon fires an event which
* is caught by settings-animated-pages, so it requires no separate handling.
- *
- * Examples:
- *
- * <settings-subheader i18n-values="page-title:internetPageTitle">
- * </settings-subheader>
- *
- * @group Chrome Settings Elements
- * @element settings-subheader
*/
+
Polymer({
- is: 'settings-subheader',
+ is: 'settings-subpage',
+
+ behaviors: [
+ // TODO(michaelpg): phase out NeonAnimatableBehavior.
+ Polymer.NeonAnimatableBehavior,
+ Polymer.IronResizableBehavior,
+ ],
+
+ properties: {
+ pageTitle: String,
+ },
/** @private */
onTapBack_: function() {
diff --git a/chromium/chrome/browser/resources/settings/settings_page/transition_behavior.html b/chromium/chrome/browser/resources/settings/settings_page/transition_behavior.html
new file mode 100644
index 00000000000..c7c60bd08d1
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/settings_page/transition_behavior.html
@@ -0,0 +1,2 @@
+<link rel="import" href="chrome://resources/html/polymer.html">
+<script src="chrome://md-settings/settings_page/transition_behavior.js"></script>
diff --git a/chromium/chrome/browser/resources/settings/settings_page/transition_behavior.js b/chromium/chrome/browser/resources/settings/settings_page/transition_behavior.js
new file mode 100644
index 00000000000..0aecfb3968e
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/settings_page/transition_behavior.js
@@ -0,0 +1,86 @@
+// 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.
+
+/**
+ * Adds convenience functions to control native Web Animations. The
+ * implementation details may change as Chrome support evolves.
+ * @polymerBehavior
+ */
+var TransitionBehavior = {
+ ready: function() {
+ /**
+ * @type {!Object<!Animation>}
+ * Map of running animations by animation name. Animation names are
+ * arbitrary but used to prevent multiple animations of the same type (e.g.,
+ * expand/collapse section) from running simultaneously.
+ */
+ this.animations = {};
+
+ /**
+ * @private {!Object<!Promise>}
+ * Map of Promises for each running animation. Key names and existence
+ * should correspond with |animations|.
+ */
+ this.promises_ = {};
+ },
+
+ /**
+ * Calls el.animate(keyframes, opt_options). Returns a Promise which is
+ * resolved when the transition ends, or rejected when the transition is
+ * canceled. If an animation with the same name is in progress, that
+ * animation is finished immediately before creating the new animation.
+ * @param {string} name Name of the animation, used to finish this animation
+ * when playing the same type of animation again.
+ * @param {!HTMLElement} el The element to animate.
+ * @param {!Array|!Object} keyframes Keyframes, as in Element.animate.
+ * @param {number|!KeyframeEffectOptions=} opt_options Options, as in
+ * Element.animate.
+ * @return {!Promise} A promise which is resolved when the animation finishes
+ * or rejected if the animation is canceled.
+ */
+ animateElement: function(name, el, keyframes, opt_options) {
+ if (this.animations[name])
+ this.animations[name].finish();
+
+ var animation = el.animate(keyframes, opt_options);
+ this.animations[name] = animation;
+
+ this.promises_[name] = new Promise(function(resolve, reject) {
+ animation.addEventListener('finish', function() {
+ this.animations[name] = undefined;
+ resolve();
+ }.bind(this));
+
+ animation.addEventListener('cancel', function() {
+ this.animations[name] = undefined;
+ reject();
+ }.bind(this));
+ }.bind(this));
+ return this.promises_[name];
+ },
+
+ /**
+ * Finishes the ongoing named animation, waits for the animation's Promise
+ * to be resolved, then calls the callback.
+ * @param {string} name Name of the animation passed to animateElement.
+ * @param {function()=} opt_callback Called once the animation finishes.
+ */
+ finishAnimation: function(name, opt_callback) {
+ if (opt_callback)
+ this.promises_[name].then(opt_callback);
+ this.animations[name].finish();
+ },
+
+ /**
+ * Cancels the ongoing named animation, waits for the animation's Promise
+ * to be rejected, then calls the callback.
+ * @param {string} name Name of the animation passed to animateElement.
+ * @param {function()=} opt_callback Called once the animation cancels.
+ */
+ cancelAnimation: function(name, opt_callback) {
+ if (opt_callback)
+ this.promises_[name].catch(opt_callback);
+ this.animations[name].cancel();
+ },
+};
diff --git a/chromium/chrome/browser/resources/settings/settings_resources.grd b/chromium/chrome/browser/resources/settings/settings_resources.grd
index e9041029afb..4efe8913589 100644
--- a/chromium/chrome/browser/resources/settings/settings_resources.grd
+++ b/chromium/chrome/browser/resources/settings/settings_resources.grd
@@ -14,28 +14,30 @@
<structures>
<structure name="IDR_SETTINGS_A11Y_PAGE_JS"
file="a11y_page/a11y_page.js"
+ flattenhtml="true"
type="chrome_html" />
<structure name="IDR_SETTINGS_A11Y_PAGE_HTML"
file="a11y_page/a11y_page.html"
type="chrome_html"
flattenhtml="true"
allowexternalscript="true" />
- <structure name="IDR_SETTINGS_A11Y_PAGE_CSS"
- file="a11y_page/a11y_page.css"
- type="chrome_html" />
<structure name="IDR_SETTINGS_ADVANCED_PAGE_JS"
file="advanced_page/advanced_page.js"
+ flattenhtml="true"
type="chrome_html" />
<structure name="IDR_SETTINGS_ADVANCED_PAGE_HTML"
file="advanced_page/advanced_page.html"
type="chrome_html"
flattenhtml="true"
allowexternalscript="true" />
- <structure name="IDR_SETTINGS_ADVANCED_PAGE_CSS"
- file="advanced_page/advanced_page.css"
+ <structure name="IDR_SETTINGS_ALL_SITES_CSS"
+ file="site_settings/all_sites.css"
+ type="chrome_html" />
+ <structure name="IDR_SETTINGS_ALL_SITES_HTML"
+ file="site_settings/all_sites.html"
type="chrome_html" />
- <structure name="IDR_SETTINGS_CR_SETTINGS_ANIMATED_PAGES_CSS"
- file="settings_page/settings_animated_pages.css"
+ <structure name="IDR_SETTINGS_ALL_SITES_JS"
+ file="site_settings/all_sites.js"
type="chrome_html" />
<structure name="IDR_SETTINGS_CR_SETTINGS_ANIMATED_PAGES_HTML"
file="settings_page/settings_animated_pages.html"
@@ -69,8 +71,11 @@
type="chrome_html"
flattenhtml="true"
allowexternalscript="true" />
- <structure name="IDR_SETTINGS_BASIC_PAGE_CSS"
- file="basic_page/basic_page.css"
+ <structure name="IDR_SETTINGS_FONTS_BROWSER_PROXY_HTML"
+ file="appearance_page/fonts_browser_proxy.html"
+ type="chrome_html" />
+ <structure name="IDR_SETTINGS_FONTS_BROWSER_PROXY_JS"
+ file="appearance_page/fonts_browser_proxy.js"
type="chrome_html" />
<structure name="IDR_SETTINGS_ON_STARTUP_PAGE_HTML"
file="on_startup_page/on_startup_page.html"
@@ -87,6 +92,12 @@
<structure name="IDR_SETTINGS_STARTUP_URLS_PAGE_JS"
file="on_startup_page/startup_urls_page.js"
type="chrome_html" />
+ <structure name="IDR_SETTINGS_STARTUP_URLS_PAGE_BROWSER_PROXY_JS"
+ file="on_startup_page/startup_urls_page_browser_proxy.js"
+ type="chrome_html" />
+ <structure name="IDR_SETTINGS_STARTUP_URLS_PAGE_BROWSER_PROXY_HTML"
+ file="on_startup_page/startup_urls_page_browser_proxy.html"
+ type="chrome_html" />
<structure name="IDR_SETTINGS_CR_SETTINGS_MAIN_CSS"
file="settings_main/settings_main.css"
type="chrome_html" />
@@ -98,9 +109,6 @@
<structure name="IDR_SETTINGS_CR_SETTINGS_MAIN_JS"
file="settings_main/settings_main.js"
type="chrome_html" />
- <structure name="IDR_SETTINGS_CR_SETTINGS_MENU_CSS"
- file="settings_menu/settings_menu.css"
- type="chrome_html" />
<structure name="IDR_SETTINGS_CR_SETTINGS_MENU_HTML"
file="settings_menu/settings_menu.html"
type="chrome_html"
@@ -124,34 +132,35 @@
<structure name="IDR_SETTINGS_CR_SETTINGS_SECTION_JS"
file="settings_page/settings_section.js"
type="chrome_html" />
- <structure name="IDR_SETTINGS_CR_SETTINGS_SUBHEADER_CSS"
- file="settings_page/settings_subheader.css"
+ <structure name="IDR_SETTINGS_CR_SETTINGS_SUBPAGE_HTML"
+ file="settings_page/settings_subpage.html"
type="chrome_html" />
- <structure name="IDR_SETTINGS_CR_SETTINGS_SUBHEADER_HTML"
- file="settings_page/settings_subheader.html"
+ <structure name="IDR_SETTINGS_CR_SETTINGS_SUBPAGE_JS"
+ file="settings_page/settings_subpage.js"
type="chrome_html" />
- <structure name="IDR_SETTINGS_CR_SETTINGS_SUBHEADER_JS"
- file="settings_page/settings_subheader.js"
+ <structure name="IDR_SETTINGS_CR_SETTINGS_DIALOG_HTML"
+ file="settings_dialog.html"
type="chrome_html" />
- <structure name="IDR_SETTINGS_CR_SETTINGS_DIALOG_CSS"
- file="settings_dialog.css"
+ <structure name="IDR_SETTINGS_CR_SETTINGS_DIALOG_JS"
+ file="settings_dialog.js"
type="chrome_html" />
- <structure name="IDR_SETTINGS_CR_SETTINGS_SHARED_CSS"
- file="settings_shared.css"
+ <structure name="IDR_SETTINGS_CR_SETTINGS_PAGE_CSS"
+ file="settings_page.css"
type="chrome_html" />
- <structure name="IDR_SETTINGS_BREADCRUMB_CSS"
- file="settings_ui/breadcrumb.css"
+ <structure name="IDR_SETTINGS_MAIN_PAGE_BEHAVIOR_HTML"
+ file="settings_page/main_page_behavior.html"
type="chrome_html" />
- <structure name="IDR_SETTINGS_BREADCRUMB_HTML"
- file="settings_ui/breadcrumb.html"
- type="chrome_html"
- flattenhtml="true"
- allowexternalscript="true" />
- <structure name="IDR_SETTINGS_BREADCRUMB_JS"
- file="settings_ui/breadcrumb.js"
+ <structure name="IDR_SETTINGS_MAIN_PAGE_BEHAVIOR_JS"
+ file="settings_page/main_page_behavior.js"
+ type="chrome_html" />
+ <structure name="IDR_SETTINGS_SETTINGS_SHARED_CSS_HTML"
+ file="settings_shared_css.html"
type="chrome_html" />
- <structure name="IDR_SETTINGS_CR_SETTINGS_UI_CSS"
- file="settings_ui/settings_ui.css"
+ <structure name="IDR_SETTINGS_TRANSITION_BEHAVIOR_HTML"
+ file="settings_page/transition_behavior.html"
+ type="chrome_html" />
+ <structure name="IDR_SETTINGS_TRANSITION_BEHAVIOR_JS"
+ file="settings_page/transition_behavior.js"
type="chrome_html" />
<structure name="IDR_SETTINGS_CR_SETTINGS_UI_HTML"
file="settings_ui/settings_ui.html"
@@ -159,23 +168,73 @@
<structure name="IDR_SETTINGS_CR_SETTINGS_UI_JS"
file="settings_ui/settings_ui.js"
type="chrome_html" />
- <structure name="IDR_SETTINGS_CERTIFICATE_MANAGER_PAGE_CSS"
- file="certificate_manager_page/certificate_manager_page.css"
- type="chrome_html" />
- <structure name="IDR_SETTINGS_CERTIFICATE_MANAGER_PAGE_HTML"
- file="certificate_manager_page/certificate_manager_page.html"
- type="chrome_html" />
- <structure name="IDR_SETTINGS_CERTIFICATE_MANAGER_PAGE_JS"
- file="certificate_manager_page/certificate_manager_page.js"
- type="chrome_html" />
- <structure name="IDR_SETTINGS_CLEAR_BROWSING_DATA_PAGE_CSS"
- file="clear_browsing_data_page/clear_browsing_data_page.css"
- type="chrome_html" />
- <structure name="IDR_SETTINGS_CLEAR_BROWSING_DATA_PAGE_HTML"
- file="clear_browsing_data_page/clear_browsing_data_page.html"
+ <if expr="use_nss_certs">
+ <structure name="IDR_SETTINGS_CERTIFICATE_MANAGER_PAGE_HTML"
+ file="certificate_manager_page/certificate_manager_page.html"
+ type="chrome_html" />
+ <structure name="IDR_SETTINGS_CERTIFICATE_MANAGER_PAGE_JS"
+ file="certificate_manager_page/certificate_manager_page.js"
+ type="chrome_html" />
+ <structure name="IDR_SETTINGS_CERTIFICATE_LIST_HTML"
+ file="certificate_manager_page/certificate_list.html"
+ type="chrome_html" />
+ <structure name="IDR_SETTINGS_CERTIFICATE_LIST_JS"
+ file="certificate_manager_page/certificate_list.js"
+ type="chrome_html" />
+ <structure name="IDR_SETTINGS_CERTIFICATE_ENTRY_HTML"
+ file="certificate_manager_page/certificate_entry.html"
+ type="chrome_html" />
+ <structure name="IDR_SETTINGS_CERTIFICATE_ENTRY_JS"
+ file="certificate_manager_page/certificate_entry.js"
+ type="chrome_html" />
+ <structure name="IDR_SETTINGS_CERTIFICATE_SUBENTRY_HTML"
+ file="certificate_manager_page/certificate_subentry.html"
+ type="chrome_html" />
+ <structure name="IDR_SETTINGS_CERTIFICATE_SUBENTRY_JS"
+ file="certificate_manager_page/certificate_subentry.js"
+ type="chrome_html" />
+ <structure name="IDR_SETTINGS_CERTIFICATES_BROWSER_PROXY_HTML"
+ file="certificate_manager_page/certificates_browser_proxy.html"
+ type="chrome_html" />
+ <structure name="IDR_SETTINGS_CERTIFICATES_BROWSER_PROXY_JS"
+ file="certificate_manager_page/certificates_browser_proxy.js"
+ type="chrome_html" />
+ <structure name="IDR_SETTINGS_CA_TRUST_EDIT_DIALOG_JS"
+ file="certificate_manager_page/ca_trust_edit_dialog.js"
+ type="chrome_html" />
+ <structure name="IDR_SETTINGS_CA_TRUST_EDIT_DIALOG_HTML"
+ file="certificate_manager_page/ca_trust_edit_dialog.html"
+ type="chrome_html" />
+ <structure name="IDR_SETTINGS_CERTIFICATE_DELETE_CONFIRMATION_DIALOG_JS"
+ file="certificate_manager_page/certificate_delete_confirmation_dialog.js"
+ type="chrome_html" />
+ <structure name="IDR_SETTINGS_CERTIFICATE_DELETE_CONFIRMATION_DIALOG_HTML"
+ file="certificate_manager_page/certificate_delete_confirmation_dialog.html"
+ type="chrome_html" />
+ <structure name="IDR_SETTINGS_CERTIFICATE_PASSWORD_ENCRYPTION_DIALOG_JS"
+ file="certificate_manager_page/certificate_password_encryption_dialog.js"
+ type="chrome_html" />
+ <structure name="IDR_SETTINGS_CERTIFICATE_PASSWORD_ENCRYPTION_DIALOG_HTML"
+ file="certificate_manager_page/certificate_password_encryption_dialog.html"
+ type="chrome_html" />
+ <structure name="IDR_SETTINGS_CERTIFICATE_PASSWORD_DECRYPTION_DIALOG_JS"
+ file="certificate_manager_page/certificate_password_decryption_dialog.js"
+ type="chrome_html" />
+ <structure name="IDR_SETTINGS_CERTIFICATE_PASSWORD_DECRYPTION_DIALOG_HTML"
+ file="certificate_manager_page/certificate_password_decryption_dialog.html"
+ type="chrome_html" />
+ <structure name="IDR_SETTINGS_CERTIFICATES_ERROR_DIALOG_JS"
+ file="certificate_manager_page/certificates_error_dialog.js"
+ type="chrome_html" />
+ <structure name="IDR_SETTINGS_CERTIFICATES_ERROR_DIALOG_HTML"
+ file="certificate_manager_page/certificates_error_dialog.html"
+ type="chrome_html" />
+ </if>
+ <structure name="IDR_SETTINGS_CLEAR_BROWSING_DATA_DIALOG_HTML"
+ file="clear_browsing_data_dialog/clear_browsing_data_dialog.html"
type="chrome_html" />
- <structure name="IDR_SETTINGS_CLEAR_BROWSING_DATA_PAGE_JS"
- file="clear_browsing_data_page/clear_browsing_data_page.js"
+ <structure name="IDR_SETTINGS_CLEAR_BROWSING_DATA_DIALOG_JS"
+ file="clear_browsing_data_dialog/clear_browsing_data_dialog.js"
type="chrome_html" />
<structure name="IDR_SETTINGS_CONTROLS_CHECKBOX_HTML"
file="controls/settings_checkbox.html"
@@ -183,9 +242,6 @@
<structure name="IDR_SETTINGS_CONTROLS_CHECKBOX_JS"
file="controls/settings_checkbox.js"
type="chrome_html" />
- <structure name="IDR_SETTINGS_CONTROLS_CHECKBOX_CSS"
- file="controls/settings_checkbox.css"
- type="chrome_html" />
<structure name="IDR_SETTINGS_CONTROLS_DROPDOWN_MENU_HTML"
file="controls/settings_dropdown_menu.html"
type="chrome_html" />
@@ -201,6 +257,12 @@
<structure name="IDR_SETTINGS_CONTROLS_INPUT_CSS"
file="controls/settings_input.css"
type="chrome_html" />
+ <structure name="IDR_SETTINGS_CONTROLS_PREF_CONTROL_BEHAVIOR_HTML"
+ file="controls/pref_control_behavior.html"
+ type="chrome_html" />
+ <structure name="IDR_SETTINGS_CONTROLS_PREF_CONTROL_BEHAVIOR_JS"
+ file="controls/pref_control_behavior.js"
+ type="chrome_html" />
<structure name="IDR_SETTINGS_CONTROLS_RADIO_GROUP_HTML"
file="controls/settings_radio_group.html"
type="chrome_html" />
@@ -223,12 +285,46 @@
file="default_browser_page/default_browser_page.js"
type="chrome_html" />
</if>
+ <if expr="chromeos">
+ <structure name="IDR_SETTINGS_DEVICE_DISPLAY_HTML"
+ file="device_page/display.html"
+ type="chrome_html" />
+ <structure name="IDR_SETTINGS_DEVICE_DISPLAY_JS"
+ file="device_page/display.js"
+ type="chrome_html" />
+ <structure name="IDR_SETTINGS_DEVICE_KEYBOARD_HTML"
+ file="device_page/keyboard.html"
+ type="chrome_html" />
+ <structure name="IDR_SETTINGS_DEVICE_KEYBOARD_JS"
+ file="device_page/keyboard.js"
+ type="chrome_html" />
+ <structure name="IDR_SETTINGS_DEVICE_PAGE_HTML"
+ file="device_page/device_page.html"
+ type="chrome_html" />
+ <structure name="IDR_SETTINGS_DEVICE_PAGE_JS"
+ file="device_page/device_page.js"
+ type="chrome_html" />
+ <structure name="IDR_SETTINGS_DEVICE_TOUCHPAD_HTML"
+ file="device_page/touchpad.html"
+ type="chrome_html" />
+ <structure name="IDR_SETTINGS_DEVICE_TOUCHPAD_JS"
+ file="device_page/touchpad.js"
+ type="chrome_html" />
+ </if>
+ <structure name="IDR_SETTINGS_DIRECTION_DELEGATE_HTML"
+ file="direction_delegate.html"
+ type="chrome_html" />
+ <structure name="IDR_SETTINGS_DIRECTION_DELEGATE_JS"
+ file="direction_delegate.js"
+ type="chrome_html" />
<structure name="IDR_SETTINGS_DOWNLOADS_PAGE_CSS"
file="downloads_page/downloads_page.css"
type="chrome_html" />
<structure name="IDR_SETTINGS_DOWNLOADS_PAGE_HTML"
file="downloads_page/downloads_page.html"
- type="chrome_html" />
+ type="chrome_html"
+ flattenhtml="true"
+ allowexternalscript="true" />
<structure name="IDR_SETTINGS_DOWNLOADS_PAGE_JS"
file="downloads_page/downloads_page.js"
type="chrome_html" />
@@ -254,9 +350,6 @@
<structure name="IDR_SETTINGS_RESET_PAGE_JS"
file="reset_page/reset_page.js"
type="chrome_html" />
- <structure name="IDR_SETTINGS_RESET_PROFILE_DIALOG_CSS"
- file="reset_page/reset_profile_dialog.css"
- type="chrome_html" />
<structure name="IDR_SETTINGS_RESET_PROFILE_DIALOG_HTML"
file="reset_page/reset_profile_dialog.html"
type="chrome_html" />
@@ -272,6 +365,13 @@
<structure name="IDR_SETTINGS_RESET_PROFILE_BANNER_JS"
file="reset_page/reset_profile_banner.js"
type="chrome_html"/>
+ <structure name="IDR_SETTINGS_RESET_BROWSER_PROXY_JS"
+ file="reset_page/reset_browser_proxy.js"
+ flattenhtml="true"
+ type="chrome_html" />
+ <structure name="IDR_SETTINGS_RESET_BROWSER_PROXY_HTML"
+ file="reset_page/reset_browser_proxy.html"
+ type="chrome_html" />
<structure name="IDR_SETTINGS_LANGUAGES_HTML"
file="languages_page/languages.html"
type="chrome_html" />
@@ -280,9 +380,6 @@
type="chrome_html"
flattenhtml="true"
allowexternalscript="true" />
- <structure name="IDR_SETTINGS_LANGUAGES_PAGE_CSS"
- file="languages_page/languages_page.css"
- type="chrome_html" />
<structure name="IDR_SETTINGS_LANGUAGES_PAGE_HTML"
file="languages_page/languages_page.html"
type="chrome_html"
@@ -293,18 +390,12 @@
type="chrome_html"
flattenhtml="true"
allowexternalscript="true" />
- <structure name="IDR_SETTINGS_LANGUAGES_MANAGE_LANGUAGES_PAGE_CSS"
- file="languages_page/manage_languages_page.css"
- type="chrome_html" />
<structure name="IDR_SETTINGS_LANGUAGES_MANAGE_LANGUAGES_PAGE_HTML"
file="languages_page/manage_languages_page.html"
type="chrome_html" />
<structure name="IDR_SETTINGS_LANGUAGES_MANAGE_LANGUAGES_PAGE_JS"
file="languages_page/manage_languages_page.js"
type="chrome_html" />
- <structure name="IDR_SETTINGS_LANGUAGES_LANGUAGE_DETAIL_PAGE_CSS"
- file="languages_page/language_detail_page.css"
- type="chrome_html" />
<structure name="IDR_SETTINGS_LANGUAGES_LANGUAGE_DETAIL_PAGE_HTML"
file="languages_page/language_detail_page.html"
type="chrome_html"
@@ -316,9 +407,6 @@
flattenhtml="true"
allowexternalscript="true" />
<if expr="not is_macosx">
- <structure name="IDR_SETTINGS_LANGUAGES_EDIT_DICTIONARY_PAGE_CSS"
- file="languages_page/edit_dictionary_page.css"
- type="chrome_html" />
<structure name="IDR_SETTINGS_LANGUAGES_EDIT_DICTIONARY_PAGE_HTML"
file="languages_page/edit_dictionary_page.html"
type="chrome_html" />
@@ -332,20 +420,18 @@
<structure name="IDR_SETTINGS_PASSWORDS_AND_FORMS_PAGE_JS"
file="passwords_and_forms_page/passwords_and_forms_page.js"
type="chrome_html" />
- <structure name="IDR_SETTINGS_PASSWORDS_SECTION_CSS"
- file="passwords_and_forms_page/passwords_section.css"
- type="chrome_html" />
<structure name="IDR_SETTINGS_PASSWORDS_SECTION_HTML"
file="passwords_and_forms_page/passwords_section.html"
type="chrome_html" />
<structure name="IDR_SETTINGS_PASSWORDS_SECTION_JS"
file="passwords_and_forms_page/passwords_section.js"
type="chrome_html" />
- <structure name="IDR_SETTINGS_PEOPLE_PAGE_CSS"
- file="people_page/people_page.css"
- type="chrome_html"
- flattenhtml="true"
- allowexternalscript="true" />
+ <structure name="IDR_SETTINGS_PASSWORD_EDIT_DIALOG_HTML"
+ file="passwords_and_forms_page/password_edit_dialog.html"
+ type="chrome_html" />
+ <structure name="IDR_SETTINGS_PASSWORD_EDIT_DIALOG_JS"
+ file="passwords_and_forms_page/password_edit_dialog.js"
+ type="chrome_html" />
<structure name="IDR_SETTINGS_PEOPLE_PAGE_HTML"
file="people_page/people_page.html"
type="chrome_html"
@@ -357,9 +443,6 @@
flattenhtml="true"
allowexternalscript="true" />
<if expr="not chromeos">
- <structure name="IDR_SETTINGS_PEOPLE_PAGE_MANAGE_PROFILE_CSS"
- file="people_page/manage_profile.css"
- type="chrome_html" />
<structure name="IDR_SETTINGS_PEOPLE_PAGE_MANAGE_PROFILE_HTML"
file="people_page/manage_profile.html"
type="chrome_html"
@@ -368,6 +451,14 @@
<structure name="IDR_SETTINGS_PEOPLE_PAGE_MANAGE_PROFILE_JS"
file="people_page/manage_profile.js"
type="chrome_html" />
+ <structure name="IDR_SETTINGS_PEOPLE_PAGE_MANAGE_PROFILE_BROWSER_PROXY_HTML"
+ file="people_page/manage_profile_browser_proxy.html"
+ type="chrome_html"
+ flattenhtml="true"
+ allowexternalscript="true" />
+ <structure name="IDR_SETTINGS_PEOPLE_PAGE_MANAGE_PROFILE_BROWSER_PROXY_JS"
+ file="people_page/manage_profile_browser_proxy.js"
+ type="chrome_html" />
</if>
<structure name="IDR_SETTINGS_PREF_UTIL_HTML"
file="prefs/pref_util.html"
@@ -393,15 +484,6 @@
<structure name="IDR_SETTINGS_PREFS_TYPES_JS"
file="prefs/prefs_types.js"
type="chrome_html" />
- <structure name="IDR_SETTINGS_PREF_TRACKER_HTML"
- file="pref_tracker/pref_tracker.html"
- type="chrome_html" />
- <structure name="IDR_SETTINGS_PREF_TRACKER_JS"
- file="pref_tracker/pref_tracker.js"
- type="chrome_html" />
- <structure name="IDR_SETTINGS_PRIVACY_PAGE_CSS"
- file="privacy_page/privacy_page.css"
- type="chrome_html" />
<structure name="IDR_SETTINGS_PRIVACY_PAGE_HTML"
file="privacy_page/privacy_page.html"
type="chrome_html"
@@ -409,7 +491,16 @@
allowexternalscript="true" />
<structure name="IDR_SETTINGS_PRIVACY_PAGE_JS"
file="privacy_page/privacy_page.js"
+ flattenhtml="true"
type="chrome_html" />
+ <if expr="is_win or is_macosx">
+ <structure name="IDR_SETTINGS_PRIVACY_PAGE_BROWSER_PROXY_HTML"
+ file="privacy_page/privacy_page_browser_proxy.html"
+ type="chrome_html" />
+ <structure name="IDR_SETTINGS_PRIVACY_PAGE_BROWSER_PROXY_JS"
+ file="privacy_page/privacy_page_browser_proxy.js"
+ type="chrome_html" />
+ </if>
<structure name="IDR_SETTINGS_CR_SETTINGS_ROUTER_HTML"
file="settings_page/settings_router.html"
type="chrome_html" />
@@ -442,10 +533,10 @@
<structure name="IDR_SETTINGS_SITE_SETTINGS_CATEGORY_JS"
file="site_settings/site_settings_category.js"
type="chrome_html" />
- <structure name="IDR_SETTINGS_SITE_SETTINGS_CONSTANTS_JS"
+ <structure name="IDR_SETTINGS_CONSTANTS_JS"
file="site_settings/constants.js"
type="chrome_html" />
- <structure name="IDR_SETTINGS_SITE_SETTINGS_CONSTANTS_HTML"
+ <structure name="IDR_SETTINGS_CONSTANTS_HTML"
file="site_settings/constants.html"
type="chrome_html" />
<structure name="IDR_SETTINGS_SITE_SETTINGS_PAGE_CSS"
@@ -457,35 +548,38 @@
<structure name="IDR_SETTINGS_SITE_SETTINGS_PAGE_JS"
file="site_settings_page/site_settings_page.js"
type="chrome_html" />
- <structure name="IDR_SETTINGS_SITE_SETTINGS_SITE_DETAILS_CSS"
+ <structure name="IDR_SETTINGS_SITE_SETTINGS_PREFS_BROWSER_PROXY_HTML"
+ file="site_settings/site_settings_prefs_browser_proxy.html"
+ type="chrome_html" />
+ <structure name="IDR_SETTINGS_SITE_SETTINGS_PREFS_BROWSER_PROXY_JS"
+ file="site_settings/site_settings_prefs_browser_proxy.js"
+ type="chrome_html" />
+ <structure name="IDR_SETTINGS_SITE_DETAILS_CSS"
file="site_settings/site_details.css"
type="chrome_html" />
- <structure name="IDR_SETTINGS_SITE_SETTINGS_SITE_DETAILS_HTML"
+ <structure name="IDR_SETTINGS_SITE_DETAILS_HTML"
file="site_settings/site_details.html"
type="chrome_html" />
- <structure name="IDR_SETTINGS_SITE_SETTINGS_SITE_DETAILS_JS"
+ <structure name="IDR_SETTINGS_SITE_DETAILS_JS"
file="site_settings/site_details.js"
type="chrome_html" />
- <structure name="IDR_SETTINGS_SITE_SETTINGS_SITE_DETAILS_PERMISSION_CSS"
+ <structure name="IDR_SETTINGS_SITE_DETAILS_PERMISSION_CSS"
file="site_settings/site_details_permission.css"
type="chrome_html" />
- <structure name="IDR_SETTINGS_SITE_SETTINGS_SITE_DETAILS_PERMISSION_HTML"
+ <structure name="IDR_SETTINGS_SITE_DETAILS_PERMISSION_HTML"
file="site_settings/site_details_permission.html"
type="chrome_html" />
- <structure name="IDR_SETTINGS_SITE_SETTINGS_SITE_DETAILS_PERMISSION_JS"
+ <structure name="IDR_SETTINGS_SITE_DETAILS_PERMISSION_JS"
file="site_settings/site_details_permission.js"
type="chrome_html" />
- <structure name="IDR_SETTINGS_SEARCH_ENGINES_PAGE_SEARCH_ENGINE_ADDER_JS"
- file="search_engines_page/search_engine_adder.js"
+ <structure name="IDR_SETTINGS_SEARCH_ENGINES_PAGE_SEARCH_ENGINE_DIALOG_JS"
+ file="search_engines_page/search_engine_dialog.js"
type="chrome_html" />
- <structure name="IDR_SETTINGS_SEARCH_ENGINES_PAGE_SEARCH_ENGINE_ADDER_HTML"
- file="search_engines_page/search_engine_adder.html"
+ <structure name="IDR_SETTINGS_SEARCH_ENGINES_PAGE_SEARCH_ENGINE_DIALOG_HTML"
+ file="search_engines_page/search_engine_dialog.html"
type="chrome_html"
flattenhtml="true"
allowexternalscript="true" />
- <structure name="IDR_SETTINGS_SEARCH_ENGINES_PAGE_SEARCH_ENGINE_ADDER_CSS"
- file="search_engines_page/search_engine_adder.css"
- type="chrome_html" />
<structure name="IDR_SETTINGS_SEARCH_ENGINES_PAGE_SEARCH_ENGINE_ENTRY_JS"
file="search_engines_page/search_engine_entry.js"
type="chrome_html" />
@@ -497,6 +591,14 @@
<structure name="IDR_SETTINGS_SEARCH_ENGINES_PAGE_SEARCH_ENGINE_ENTRY_CSS"
file="search_engines_page/search_engine_entry.css"
type="chrome_html" />
+ <structure name="IDR_SETTINGS_SEARCH_ENGINES_PAGE_OMNIBOX_EXTENSION_ENTRY_JS"
+ file="search_engines_page/omnibox_extension_entry.js"
+ type="chrome_html" />
+ <structure name="IDR_SETTINGS_SEARCH_ENGINES_PAGE_OMNIBOX_EXTENSION_ENTRY_HTML"
+ file="search_engines_page/omnibox_extension_entry.html"
+ type="chrome_html"
+ flattenhtml="true"
+ allowexternalscript="true" />
<structure name="IDR_SETTINGS_SEARCH_ENGINES_PAGE_SEARCH_ENGINES_LIST_JS"
file="search_engines_page/search_engines_list.js"
type="chrome_html" />
@@ -516,6 +618,16 @@
type="chrome_html"
flattenhtml="true"
allowexternalscript="true" />
+ <structure name="IDR_SETTINGS_SEARCH_ENGINES_BROWSER_PROXY_JS"
+ file="search_engines_page/search_engines_browser_proxy.js"
+ type="chrome_html"
+ flattenhtml="true"
+ allowexternalscript="true" />
+ <structure name="IDR_SETTINGS_SEARCH_ENGINES_BROWSER_PROXY_HTML"
+ file="search_engines_page/search_engines_browser_proxy.html"
+ type="chrome_html"
+ flattenhtml="true"
+ allowexternalscript="true" />
<structure name="IDR_SETTINGS_SEARCH_PAGE_JS"
file="search_page/search_page.js"
type="chrome_html" />
@@ -524,9 +636,6 @@
type="chrome_html"
flattenhtml="true"
allowexternalscript="true" />
- <structure name="IDR_SETTINGS_SEARCH_PAGE_CSS"
- file="search_page/search_page.css"
- type="chrome_html" />
<structure name="IDR_SETTINGS_SYNC_PAGE_JS"
file="people_page/sync_page.js"
type="chrome_html" />
@@ -548,12 +657,31 @@
type="chrome_html"
flattenhtml="true"
allowexternalscript="true" />
+ <structure name="IDR_SETTINGS_SYSTEM_PAGE_BROWSER_PROXY_HTML"
+ file="system_page/system_page_browser_proxy.html"
+ type="chrome_html" />
+ <structure name="IDR_SETTINGS_SYSTEM_PAGE_BROWSER_PROXY"
+ file="system_page/system_page_browser_proxy.js"
+ type="chrome_html" />
+ <structure name="IDR_SETTINGS_SYSTEM_PAGE_HTML"
+ file="system_page/system_page.html"
+ flattenhtml="true"
+ type="chrome_html" />
+ <structure name="IDR_SETTINGS_SYSTEM_PAGE_JS"
+ file="system_page/system_page.js"
+ type="chrome_html" />
<structure name="IDR_SETTINGS_SETTINGS_HTML"
file="settings.html"
type="chrome_html" />
<structure name="IDR_SETTINGS_SETTINGS_JS"
file="settings.js"
type="chrome_html" />
+ <structure name="IDR_SETTINGS_WEBSITE_USAGE_PRIVATE_API_HTML"
+ file="site_settings/website_usage_private_api.html"
+ type="chrome_html" />
+ <structure name="IDR_SETTINGS_WEBSITE_USAGE_PRIVATE_API_JS"
+ file="site_settings/website_usage_private_api.js"
+ type="chrome_html" />
<if expr="chromeos">
<structure name="IDR_SETTINGS_BLUETOOTH_DEVICE_LIST_ITEM_CSS"
file="bluetooth_page/bluetooth_device_list_item.css"
@@ -588,9 +716,6 @@
<structure name="IDR_SETTINGS_BLUETOOTH_PAIR_DEVICE_DIALOG_JS"
file="bluetooth_page/bluetooth_pair_device_dialog.js"
type="chrome_html" />
- <structure name="IDR_SETTINGS_DATE_TIME_PAGE_CSS"
- file="date_time_page/date_time_page.css"
- type="chrome_html" />
<structure name="IDR_SETTINGS_DATE_TIME_PAGE_HTML"
file="date_time_page/date_time_page.html"
type="chrome_html" />
@@ -708,27 +833,52 @@
<structure name="IDR_SETTINGS_NETWORK_SUMMARY_ITEM_JS"
file="internet_page/network_summary_item.js"
type="chrome_html" />
- <structure name="IDR_SETTINGS_PEOPLE_CHANGE_PICTURE_PRIVATE_API_JS"
- file="people_page/change_picture_private_api.js"
- type="chrome_html"
- flattenhtml="true"
- allowexternalscript="true" />
+ <structure name="IDR_SETTINGS_PEOPLE_PAGE_CAMERA_CSS"
+ file="people_page/camera.css"
+ type="chrome_html" />
+ <structure name="IDR_SETTINGS_PEOPLE_PAGE_CAMERA_HTML"
+ file="people_page/camera.html"
+ type="chrome_html"
+ flattenhtml="true"
+ allowexternalscript="true" />
+ <structure name="IDR_SETTINGS_PEOPLE_PAGE_CAMERA_JS"
+ file="people_page/camera.js"
+ type="chrome_html" />
<structure name="IDR_SETTINGS_PEOPLE_PAGE_CHANGE_PICTURE_CSS"
- file="people_page/change_picture.css"
- type="chrome_html" />
+ file="people_page/change_picture.css"
+ type="chrome_html" />
<structure name="IDR_SETTINGS_PEOPLE_PAGE_CHANGE_PICTURE_HTML"
- file="people_page/change_picture.html"
- type="chrome_html"
- flattenhtml="true"
- allowexternalscript="true" />
+ file="people_page/change_picture.html"
+ type="chrome_html"
+ flattenhtml="true"
+ allowexternalscript="true" />
<structure name="IDR_SETTINGS_PEOPLE_PAGE_CHANGE_PICTURE_JS"
- file="people_page/change_picture.js"
- type="chrome_html" />
- <structure name="IDR_SETTINGS_PEOPLE_CHANGE_PICTURE_PRIVATE_API_HTML"
- file="people_page/change_picture_private_api.html"
- type="chrome_html"
- flattenhtml="true"
- allowexternalscript="true" />
+ file="people_page/change_picture.js"
+ type="chrome_html" />
+ <structure name="IDR_SETTINGS_PEOPLE_CHANGE_PICTURE_BROWSER_PROXY_JS"
+ file="people_page/change_picture_browser_proxy.js"
+ type="chrome_html" />
+ <structure name="IDR_SETTINGS_PEOPLE_CHANGE_PICTURE_BROWSER_PROXY_HTML"
+ file="people_page/change_picture_browser_proxy.html"
+ type="chrome_html"
+ flattenhtml="true"
+ allowexternalscript="true" />
+ <structure name="IDR_SETTINGS_PEOPLE_EASY_UNLOCK_BROWSER_PROXY_JS"
+ file="people_page/easy_unlock_browser_proxy.js"
+ type="chrome_html" />
+ <structure name="IDR_SETTINGS_PEOPLE_EASY_UNLOCK_BROWSER_PROXY_HTML"
+ file="people_page/easy_unlock_browser_proxy.html"
+ type="chrome_html"
+ flattenhtml="true"
+ allowexternalscript="true" />
+ <structure name="IDR_SETTINGS_PEOPLE_EASY_UNLOCK_TURN_OFF_DIALOG_JS"
+ file="people_page/easy_unlock_turn_off_dialog.js"
+ type="chrome_html" />
+ <structure name="IDR_SETTINGS_PEOPLE_EASY_UNLOCK_TURN_OFF_DIALOG_HTML"
+ file="people_page/easy_unlock_turn_off_dialog.html"
+ type="chrome_html"
+ flattenhtml="true"
+ allowexternalscript="true" />
<structure name="IDR_SETTINGS_USERS_PAGE_USER_LIST_JS"
file="people_page/user_list.js"
type="chrome_html" />
diff --git a/chromium/chrome/browser/resources/settings/settings_shared.css b/chromium/chrome/browser/resources/settings/settings_shared.css
deleted file mode 100644
index ba6bb13a2f6..00000000000
--- a/chromium/chrome/browser/resources/settings/settings_shared.css
+++ /dev/null
@@ -1,115 +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. */
-
-/**
- * @fileoverview
- * Common styles for Material Design settings.
- */
-
-paper-button {
- margin: 0;
- min-width: auto;
-}
-
-paper-button[toggles][active] {
- background-color: LightGray;
-}
-
-.text-elide {
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
-}
-
-h2 {
- color: #9e9e9e;
- font-size: 100%;
- font-weight: normal;
- margin-bottom: 20px;
- margin-top: 30px;
-}
-
-.button-row {
- display: flex;
- margin-top: 25px;
-}
-
-.button-strip {
- text-align: end;
-}
-
-.list-frame {
- @apply(--layout-center);
- display: block;
- margin-left: 48px;
- padding: 0;
-}
-
-.list-item {
- @apply(--layout-center);
- border-top: 1px solid #e0e0e0;
- display: flex;
- padding: 0;
-}
-
-.list-item:first-of-type {
- border-top: none;
-}
-
-.list-item .middle {
- flex: 1;
- margin: 8px 12px;
- overflow: hidden;
- white-space: nowrap;
-}
-
-.list-item .secondary {
- color: #969696;
-}
-
-.list-item > paper-icon-item {
- padding: 0;
-}
-
-.link-button {
- color: rgb(61, 130, 243);
- padding-bottom: 6px;
- padding-left: 0;
- padding-right: 0;
- padding-top: 6px;
- text-transform: none;
-}
-
-.settings-box {
- @apply(--layout-center);
- border-top: 1px solid #e0e0e0;
- display: block;
- min-height: 40px;
- padding: 8px 16px;
-}
-
-.settings-box .two-line {
- min-height: 52px;
-}
-
-.settings-box:first-of-type {
- border-top: none;
-}
-
-.settings-box .secondary {
- color: #969696;
-}
-
-.split {
- display: flex;
-}
-
-.split .start {
- flex: auto;
-}
-
-.settings-box paper-item iron-icon {
- /* Same padding as paper-icon-button. */
- padding: 8px;
-}
diff --git a/chromium/chrome/browser/resources/settings/settings_shared_css.html b/chromium/chrome/browser/resources/settings/settings_shared_css.html
new file mode 100644
index 00000000000..33e504aaa0e
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/settings_shared_css.html
@@ -0,0 +1,258 @@
+<!-- Common styles for Material Design settings. -->
+<dom-module id="settings-shared">
+ <template>
+ <style>
+ :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;
+ --paper-icon-button: {
+ width: 36px;
+ height: 36px;
+ };
+ --paper-input-max-width: 264px;
+ --settings-background-color: var(--paper-blue-grey-50);
+ --settings-secondary: {
+ color: var(--paper-grey-600);
+ font-weight: 400;
+ };
+ --settings-error-color: var(--paper-red-700);
+ --settings-hover-color: var(--google-grey-300);
+
+ /* Some colors use non-MD colors. These custom colors are specified by
+ * UX design (bettes@). */
+ --settings-nav-grey: rgb(90, 90, 90);
+ --settings-title-bar-background-color: rgb(52, 73, 94);
+ --settings-title-bar-color: rgb(255, 255, 255);
+ }
+
+ h2 {
+ @apply(--layout-center);
+ color: var(--paper-grey-500);
+ display: flex;
+ font-size: 100%;
+ font-weight: 500;
+ margin: 0;
+ min-height: 40px;
+ }
+
+ iron-icon[icon=check],
+ iron-icon[icon=done] {
+ --iron-icon-fill-color: var(--google-green-500);
+ }
+
+ paper-button {
+ margin: 0;
+ min-width: auto;
+ }
+
+ paper-button[toggles][active] {
+ background-color: var(--paper-grey-300);
+ }
+
+ span ~ a {
+ -webkit-margin-start: 4px;
+ }
+
+ [is='action-link'],
+ [is='action-link']:active,
+ [is='action-link']:hover,
+ [is='action-link']:visited,
+ paper-button.primary-button,
+ paper-button.tertiary-button {
+ color: var(--google-blue-700);
+ }
+
+ [is='action-link']:hover {
+ /* TODO(dbeam): check with bettes@ on this one, but I'm pretty sure we
+ * shouldn't be showing much :hover stuff on Polymer pages. */
+ text-decoration: none;
+ }
+
+ paper-button.primary-button {
+ --paper-button: {
+ font-weight: 500;
+ text-align: start;
+ };
+ margin: 0 -0.57em; /* Offsets default paper-button padding. */
+ }
+
+ paper-button.secondary-button {
+ --paper-button: {
+ color: var(--paper-grey-700);
+ text-decoration: none;
+ font-weight: 500;
+ };
+ }
+
+ paper-button.tertiary-button {
+ --paper-button: {
+ font-weight: 400;
+ text-decoration: none;
+ };
+ }
+
+ paper-radio-button {
+ --paper-radio-button-checked-color: var(--google-blue-500);
+ --paper-radio-button-label-spacing: 18px;
+ --paper-radio-button-unchecked-color: var(--paper-grey-600);
+ -webkit-margin-start: 2px;
+ }
+
+ .text-elide {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ }
+
+ .button-row {
+ display: flex;
+ margin-top: 25px;
+ }
+
+ .button-strip {
+ text-align: end;
+ }
+
+ .action-button {
+ background: var(--google-blue-500);
+ color: white;
+ font-weight: 500;
+ }
+
+ .action-button[disabled] {
+ opacity: .25; /* TODO(dbeam): check this value with bettes. */
+ }
+
+ .list-frame {
+ @apply(--layout-center);
+ -webkit-padding-end: 20px;
+ -webkit-padding-start: 48px;
+ display: block;
+ padding-bottom: 0;
+ padding-top: 0;
+ }
+
+ .list-frame .secondary,
+ .list-item .secondary {
+ @apply(--settings-secondary);
+ }
+
+ .list-item {
+ @apply(--layout-center);
+ display: flex;
+ min-height: 40px;
+ padding: 0;
+ }
+
+ .list-item.underbar {
+ border-bottom: 1px solid var(--paper-grey-300);
+ }
+
+ .list-item.selected {
+ font-weight: 500;
+ }
+
+ .list-item select {
+ -webkit-margin-start: 4px;
+ }
+
+ .list-item > .middle {
+ flex: 1;
+ margin: 8px 12px;
+ overflow: hidden;
+ white-space: nowrap;
+ }
+
+ .list-item > .start {
+ flex: 1;
+ overflow: hidden;
+ white-space: nowrap;
+ }
+
+ .list-item > paper-icon-item {
+ padding: 0;
+ }
+
+ /* This button has no ink ripple. */
+ .list-item.list-button {
+ @apply(--layout-center);
+ color: rgb(66, 133, 244);
+ font-weight: 500;
+ }
+
+ .settings-box {
+ @apply(--layout-center);
+ border-top: 1px solid var(--paper-grey-300);
+ display: flex;
+ min-height: 40px;
+ padding: 0 20px;
+ }
+
+ .settings-box.first {
+ border-top: none;
+ }
+
+ .settings-box.block {
+ display: block;
+ }
+
+ .settings-box.two-line {
+ min-height: 52px;
+ }
+
+ .settings-box .secondary {
+ @apply(--settings-secondary);
+ }
+
+ .settings-box .middle {
+ -webkit-margin-start: 16px;
+ align-items: center;
+ flex: auto;
+ }
+
+ .settings-box .start {
+ align-items: center;
+ flex: auto;
+ }
+
+ /* 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:
+ *
+ * +-------------------------------------------------------+
+ * | Main action area .settings-box | .secondary-action |
+ * +-------------------------------------------------------+
+ * | Another setting-box without a secondary-action |
+ * +-------------------------------------------------------+
+ */
+ .settings-box .secondary-action {
+ -webkit-border-start: 1px solid var(--paper-grey-300);
+ -webkit-padding-start: 20px;
+ }
+
+ .settings-box paper-item iron-icon {
+ /* Same padding as paper-icon-button. */
+ padding: 8px;
+ }
+
+ .vertical-list > div:first-of-type {
+ border-top: none;
+ }
+
+ .vertical-list > div {
+ border-top: 1px solid var(--paper-grey-300);
+ }
+
+ .settings-checkbox-spacer {
+ -webkit-margin-start: calc(
+ var(--checkbox-margin-start) +
+ var(--checkbox-size) +
+ var(--checkbox-spacing));
+ }
+ </style>
+ </template>
+</dom-module>
diff --git a/chromium/chrome/browser/resources/settings/settings_ui/breadcrumb.css b/chromium/chrome/browser/resources/settings/settings_ui/breadcrumb.css
deleted file mode 100644
index 6667a3e5b32..00000000000
--- a/chromium/chrome/browser/resources/settings/settings_ui/breadcrumb.css
+++ /dev/null
@@ -1,3 +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. */
diff --git a/chromium/chrome/browser/resources/settings/settings_ui/breadcrumb.html b/chromium/chrome/browser/resources/settings/settings_ui/breadcrumb.html
deleted file mode 100644
index c0dc1f2fbc8..00000000000
--- a/chromium/chrome/browser/resources/settings/settings_ui/breadcrumb.html
+++ /dev/null
@@ -1,17 +0,0 @@
-<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
-
-<dom-module id="settings-breadcrumb">
- <link rel="import" type="css" href="breadcrumb.css">
- <template>
- <template is="dom-if" if="{{currentRouteTitles}}">
- <span on-tap="onTapPage_">{{currentRouteTitles.pageTitle}}</span>
-
- <template is="dom-repeat" items="{{currentRouteTitles.subpageTitles}}">
- &gt;
- <span on-tap="onTapSubpage_"
- data-subpage-index$="{{index}}">{{item}}</span>
- </template>
- </template>
- </template>
- <script src="breadcrumb.js"></script>
-</dom-module>
diff --git a/chromium/chrome/browser/resources/settings/settings_ui/breadcrumb.js b/chromium/chrome/browser/resources/settings/settings_ui/breadcrumb.js
deleted file mode 100644
index a4fcb5f9698..00000000000
--- a/chromium/chrome/browser/resources/settings/settings_ui/breadcrumb.js
+++ /dev/null
@@ -1,55 +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.
-
-/**
- * @fileoverview
- * 'settings-breadcrumb' displays the breadcrumb.
- *
- * Example:
- *
- * <settings-breadcrumb current-route="{{currentRoute}}">
- * </settings-breadcrumb>
- *
- * @group Chrome Settings Elements
- * @element settings-breadcrumb
- */
-Polymer({
- is: 'settings-breadcrumb',
-
- properties: {
- /**
- * The current active route.
- */
- currentRoute: {
- type: Object,
- notify: true,
- },
-
- /**
- * Page titles for the currently active route.
- */
- currentRouteTitles: {
- type: Object,
- },
- },
-
- /** @private */
- onTapPage_: function() {
- this.currentRoute = {
- page: this.currentRoute.page,
- section: '',
- subpage: [],
- };
- },
-
- /** @private */
- onTapSubpage_: function(event) {
- var clickedIndex = event.target.dataset.subpageIndex;
- this.currentRoute = {
- page: this.currentRoute.page,
- section: this.currentRoute.section,
- subpage: this.currentRoute.subpage.slice(0, clickedIndex + 1),
- };
- },
-});
diff --git a/chromium/chrome/browser/resources/settings/settings_ui/compiled_resources2.gyp b/chromium/chrome/browser/resources/settings/settings_ui/compiled_resources2.gyp
new file mode 100644
index 00000000000..c4156666924
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/settings_ui/compiled_resources2.gyp
@@ -0,0 +1,12 @@
+# 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': 'settings_ui',
+ 'dependencies': ['../compiled_resources2.gyp:direction_delegate'],
+ 'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ ],
+}
diff --git a/chromium/chrome/browser/resources/settings/settings_ui/settings_ui.css b/chromium/chrome/browser/resources/settings/settings_ui/settings_ui.css
deleted file mode 100644
index 7b94109fe6f..00000000000
--- a/chromium/chrome/browser/resources/settings/settings_ui/settings_ui.css
+++ /dev/null
@@ -1,32 +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. */
-
-:host {
- @apply(--layout-vertical);
- @apply(--layout-fit);
- @apply(--paper-font-body1);
- -webkit-user-select: none;
- background-color: #f2f2f2;
- color: rgba(0, 0, 0, .87);
-}
-
-paper-toolbar {
- @apply(--shadow-elevation-4dp);
- background-color: rgb(63, 85, 102);
- position: relative;
- z-index: 10;
-}
-
-paper-drawer-panel {
- @apply(--layout-flex);
- --paper-drawer-panel-left-drawer-container: {
- background-color: #f2f2f2;
- margin-top: 34px;
- };
- position: relative;
-}
-
-settings-main paper-icon-button {
- z-index: 10;
-}
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 5a65e761ba2..e7fb6486d56 100644
--- a/chromium/chrome/browser/resources/settings/settings_ui/settings_ui.html
+++ b/chromium/chrome/browser/resources/settings/settings_ui/settings_ui.html
@@ -1,28 +1,70 @@
-<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
+<link rel="import" href="chrome://resources/html/polymer.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-drawer-panel/paper-drawer-panel.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/shadow.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-styles/typography.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-toolbar/paper-toolbar.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://md-settings/direction_delegate.html">
+<link rel="import" href="chrome://md-settings/i18n_setup.html">
+<link rel="import" href="chrome://md-settings/icons.html">
<link rel="import" href="chrome://md-settings/settings_main/settings_main.html">
<link rel="import" href="chrome://md-settings/settings_menu/settings_menu.html">
<link rel="import" href="chrome://md-settings/settings_page/settings_router.html">
-<link rel="import" href="chrome://md-settings/settings_ui/breadcrumb.html">
+<link rel="import" href="chrome://md-settings/settings_shared_css.html">
<dom-module id="settings-ui">
- <link rel="import" type="css" href="settings_ui.css">
<template>
+ <style include="settings-shared">
+ :host {
+ @apply(--layout-vertical);
+ @apply(--layout-fit);
+ -webkit-user-select: none;
+ background-color: var(--settings-background-color);
+ }
+
+ iron-icon {
+ --iron-icon-fill-color: var(--settings-title-bar-color);
+ }
+
+ paper-toolbar {
+ @apply(--shadow-elevation-4dp);
+ --paper-toolbar-title: {
+ font-size: 123.08%;
+ };
+ background-color: var(--settings-title-bar-background-color);
+ min-height: 56px;
+ position: relative;
+ z-index: 10;
+ }
+
+ paper-drawer-panel {
+ @apply(--layout-center);
+ --paper-drawer-panel-left-drawer-container: {
+ background-color: var(--settings-background-color);
+ margin-top: 8px;
+ };
+ --paper-drawer-panel-right-drawer-container: {
+ background-color: var(--settings-background-color);
+ margin-top: 8px;
+ };
+ position: relative;
+ }
+
+ settings-main paper-icon-button {
+ z-index: 10;
+ }
+ </style>
<settings-router current-route="{{currentRoute}}"
current-route-titles="{{currentRouteTitles}}">
</settings-router>
<paper-toolbar>
- <div class="title">Settings</div>
- <settings-breadcrumb current-route="{{currentRoute}}"
- current-route-titles="[[currentRouteTitles]]">
- </settings-breadcrumb>
+ <div class="title" i18n-content="settings"></div>
+ <!-- TODO(dschuyler): implement internal search. -->
+ <iron-icon icon="md-settings-icons:search"></iron-icon>
</paper-toolbar>
- <paper-drawer-panel drawer-width="256px">
+ <paper-drawer-panel drawer-width="256px" id="panel">
<settings-menu drawer class="flex" current-route="{{currentRoute}}">
</settings-menu>
<settings-main main prefs="{{prefs}}" current-route="{{currentRoute}}">
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 513aa521d50..9e5a531d3d0 100644
--- a/chromium/chrome/browser/resources/settings/settings_ui/settings_ui.js
+++ b/chromium/chrome/browser/resources/settings/settings_ui/settings_ui.js
@@ -9,9 +9,6 @@
* Example:
*
* <settings-ui prefs="{{prefs}}"></settings-ui>
- *
- * @group Chrome Settings Elements
- * @element settings-ui
*/
Polymer({
is: 'settings-ui',
@@ -22,5 +19,16 @@ Polymer({
* @type {?CrSettingsPrefsElement}
*/
prefs: Object,
+
+ /** @type {?settings.DirectionDelegate} */
+ directionDelegate: {
+ observer: 'directionDelegateChanged_',
+ type: Object,
+ },
+ },
+
+ /** @private */
+ directionDelegateChanged_: function() {
+ this.$.panel.rightDrawer = this.directionDelegate.isRtl();
},
});
diff --git a/chromium/chrome/browser/resources/settings/advanced_page/advanced_page.css b/chromium/chrome/browser/resources/settings/site_settings/all_sites.css
index 1a33ff32ef5..fdd8e4b6ed4 100644
--- a/chromium/chrome/browser/resources/settings/advanced_page/advanced_page.css
+++ b/chromium/chrome/browser/resources/settings/site_settings/all_sites.css
@@ -1,9 +1,7 @@
-/* Copyright 2015 The Chromium Authors. All rights reserved.
+/* 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. */
:host {
display: block;
- height: 100%;
- width: 605px;
}
diff --git a/chromium/chrome/browser/resources/settings/site_settings/all_sites.html b/chromium/chrome/browser/resources/settings/site_settings/all_sites.html
new file mode 100644
index 00000000000..5766aee857f
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/site_settings/all_sites.html
@@ -0,0 +1,16 @@
+<link rel="import" href="chrome://resources/html/polymer.html">
+<link rel="import" href="chrome://md-settings/settings_shared_css.html">
+<link rel="import" href="chrome://md-settings/site_settings/constants.html">
+<link rel="import" href="chrome://md-settings/site_settings/site_list.html">
+<link rel="import" href="chrome://md-settings/site_settings/site_settings_behavior.html">
+
+<dom-module id="all-sites">
+ <link rel="import" type="css" href="all_sites.css">
+ <template>
+ <style include="settings-shared"></style>
+ <settings-site-list id="siteList" all-sites
+ category="-1" current-route="{{currentRoute}}"
+ selected-site="{{selectedSite}}"></settings-site-list>
+ </template>
+ <script src="all_sites.js"></script>
+</dom-module>
diff --git a/chromium/chrome/browser/resources/settings/site_settings/all_sites.js b/chromium/chrome/browser/resources/settings/site_settings/all_sites.js
new file mode 100644
index 00000000000..58c895672c6
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/site_settings/all_sites.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.
+
+/**
+ * @fileoverview
+ * 'all-sites' is the polymer element for showing the list of all sites under
+ * Site Settings.
+ */
+Polymer({
+ is: 'all-sites',
+
+ behaviors: [SiteSettingsBehavior],
+
+ properties: {
+ /**
+ * The current active route.
+ */
+ currentRoute: {
+ type: Object,
+ notify: true,
+ },
+
+ /**
+ * The site that was selected by the user in the dropdown list.
+ * @type {SiteException}
+ */
+ selectedSite: {
+ type: Object,
+ notify: true,
+ },
+ },
+});
diff --git a/chromium/chrome/browser/resources/settings/site_settings/compiled_resources.gyp b/chromium/chrome/browser/resources/settings/site_settings/compiled_resources.gyp
deleted file mode 100644
index 16fa38a3535..00000000000
--- a/chromium/chrome/browser/resources/settings/site_settings/compiled_resources.gyp
+++ /dev/null
@@ -1,95 +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.
-{
- 'targets': [
- {
- 'target_name': 'site_details',
- 'variables': {
- 'depends': [
- '../../../../../ui/webui/resources/js/compiled_resources.gyp:assert',
- '../../../../../ui/webui/resources/js/compiled_resources.gyp:cr',
- '../../../../../ui/webui/resources/js/compiled_resources.gyp:load_time_data',
- '../prefs/prefs_behavior.js',
- 'constants.js',
- 'site_settings_behavior.js',
- 'site_details_permission.js',
- ],
- 'externs': [
- '../../../../../third_party/closure_compiler/externs/settings_private.js',
- ],
- },
- 'includes': ['../../../../../third_party/closure_compiler/compile_js.gypi'],
- },
- {
- 'target_name': 'site_details_permission',
- 'variables': {
- 'depends': [
- '../../../../../ui/webui/resources/js/compiled_resources.gyp:assert',
- '../../../../../ui/webui/resources/js/compiled_resources.gyp:cr',
- '../../../../../ui/webui/resources/js/compiled_resources.gyp:load_time_data',
- '../prefs/prefs_behavior.js',
- 'constants.js',
- 'site_settings_behavior.js',
- ],
- 'externs': [
- '../../../../../third_party/closure_compiler/externs/settings_private.js',
- ],
- },
- 'includes': ['../../../../../third_party/closure_compiler/compile_js.gypi'],
- },
- {
- 'target_name': 'site_list',
- 'variables': {
- 'depends': [
- '../../../../../ui/webui/resources/js/compiled_resources.gyp:assert',
- '../../../../../ui/webui/resources/js/compiled_resources.gyp:cr',
- '../../../../../ui/webui/resources/js/compiled_resources.gyp:load_time_data',
- '../prefs/prefs_behavior.js',
- '../prefs/prefs_types.js',
- 'constants.js',
- 'site_settings_behavior.js',
- ],
- 'externs': [
- '../../../../../third_party/closure_compiler/externs/settings_private.js',
- ],
- },
- 'includes': ['../../../../../third_party/closure_compiler/compile_js.gypi'],
- },
- {
- 'target_name': 'site_settings_behavior',
- 'variables': {
- 'depends': [
- '../../../../../ui/webui/resources/js/compiled_resources.gyp:assert',
- '../../../../../ui/webui/resources/js/compiled_resources.gyp:cr',
- '../../../../../ui/webui/resources/js/compiled_resources.gyp:load_time_data',
- '../prefs/prefs_behavior.js',
- 'constants.js',
- ],
- 'externs': [
- '../../../../../third_party/closure_compiler/externs/settings_private.js',
- ],
- },
- 'includes': ['../../../../../third_party/closure_compiler/compile_js.gypi'],
- },
- {
- 'target_name': 'site_settings_category',
- 'variables': {
- 'depends': [
- '../../../../../ui/webui/resources/js/compiled_resources.gyp:assert',
- '../../../../../ui/webui/resources/js/compiled_resources.gyp:cr',
- '../../../../../ui/webui/resources/js/compiled_resources.gyp:load_time_data',
- '../prefs/prefs_behavior.js',
- '../prefs/prefs_types.js',
- '../settings_page/settings_animated_pages.js',
- 'constants.js',
- 'site_settings_behavior.js',
- ],
- 'externs': [
- '../../../../../third_party/closure_compiler/externs/settings_private.js',
- ],
- },
- 'includes': ['../../../../../third_party/closure_compiler/compile_js.gypi'],
- },
- ],
-}
diff --git a/chromium/chrome/browser/resources/settings/site_settings/compiled_resources2.gyp b/chromium/chrome/browser/resources/settings/site_settings/compiled_resources2.gyp
new file mode 100644
index 00000000000..6bd41c03590
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/site_settings/compiled_resources2.gyp
@@ -0,0 +1,109 @@
+# 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': 'all_sites',
+ '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):settings_private',
+ 'constants',
+ 'site_settings_behavior',
+ 'site_settings_prefs_browser_proxy',
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'constants',
+ 'dependencies': [
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'site_details',
+ '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):settings_private',
+ 'constants',
+ 'site_settings_behavior',
+ 'site_details_permission',
+ 'website_usage_private_api',
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'site_details_permission',
+ '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',
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:web_ui_listener_behavior',
+ 'constants',
+ 'site_settings_behavior',
+ 'site_settings_prefs_browser_proxy',
+ ],
+ 'externs': [
+ '<(EXTERNS_GYP):settings_private',
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'site_list',
+ 'dependencies': [
+ '<(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',
+ 'site_settings_prefs_browser_proxy',
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'site_settings_behavior',
+ 'dependencies': [
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:assert',
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:load_time_data',
+ '<(EXTERNS_GYP):settings_private',
+ 'constants',
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'site_settings_category',
+ '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:web_ui_listener_behavior',
+ '<(EXTERNS_GYP):settings_private',
+ '../settings_page/compiled_resources2.gyp:settings_animated_pages',
+ 'constants',
+ 'site_settings_behavior',
+ 'site_settings_prefs_browser_proxy',
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'site_settings_prefs_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': 'website_usage_private_api',
+ 'dependencies': [
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
+ '<(EXTERNS_GYP):chrome_send',
+ ],
+ '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 c0de36a2bd4..55f871efa94 100644
--- a/chromium/chrome/browser/resources/settings/site_settings/constants.js
+++ b/chromium/chrome/browser/resources/settings/site_settings/constants.js
@@ -33,8 +33,32 @@ cr.define('settings', function() {
ASK: 3,
};
+ /**
+ * Contains the possible string values for a given contentSettingsType.
+ * @enum {string}
+ */
+ var PermissionStringValues = {
+ ALLOW: 'allow',
+ BLOCK: 'block',
+ };
+
+ /**
+ * A category value to use for the All Sites list.
+ * @const {number}
+ */
+ var ALL_SITES = -1;
+
+ /**
+ * An invalid subtype value.
+ * @const {number}
+ */
+ var INVALID_CATEGORY_SUBTYPE = -1;
+
return {
ContentSettingsTypes: ContentSettingsTypes,
PermissionValues: PermissionValues,
+ PermissionStringValues: PermissionStringValues,
+ ALL_SITES: ALL_SITES,
+ INVALID_CATEGORY_SUBTYPE: INVALID_CATEGORY_SUBTYPE,
};
});
diff --git a/chromium/chrome/browser/resources/settings/site_settings/site_details.css b/chromium/chrome/browser/resources/settings/site_settings/site_details.css
index 8d0ff6714ef..5bc14097827 100644
--- a/chromium/chrome/browser/resources/settings/site_settings/site_details.css
+++ b/chromium/chrome/browser/resources/settings/site_settings/site_details.css
@@ -7,7 +7,10 @@
}
.origin {
- font-weight: bold;
+ font-size: 110%;
+ font-weight: 500;
+ margin-bottom: 20px;
+ margin-top: 35px;
}
.reset-button {
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 33d96f74409..c029fb86f63 100644
--- a/chromium/chrome/browser/resources/settings/site_settings/site_details.html
+++ b/chromium/chrome/browser/resources/settings/site_settings/site_details.html
@@ -1,53 +1,61 @@
-<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
+<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-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://md-settings/settings_shared_css.html">
+<link rel="import" href="chrome://md-settings/site_settings/constants.html">
<link rel="import" href="chrome://md-settings/site_settings/site_details_permission.html">
+<link rel="import" href="chrome://md-settings/site_settings/site_settings_behavior.html">
+<link rel="import" href="chrome://md-settings/site_settings/website_usage_private_api.html">
<dom-module id="site-details">
- <link rel="import" type="css"
- href="chrome://md-settings/settings_shared.css">
<link rel="import" type="css" href="site_details.css">
<template>
- <div class="settings-box">
- <div class="origin">[[origin]]</div>
- <h2 i18n-content="siteSettingsUsage" id="usage" hidden></h2>
- <paper-item id="storage" hidden>
+ <style include="settings-shared"></style>
+ <div class="settings-box block">
+ <div class="origin">[[site.origin]]</div>
+ <h2 i18n-content="siteSettingsUsage" id="usage"
+ hidden$="[[!storedData_]]"></h2>
+ <paper-item id="storage" hidden$="[[!storedData_]]">
<div class="flex">[[storedData_]]</div>
<paper-icon-button icon="delete"
on-tap="onClearStorage_"
i18n-values="alt:siteSettingsDelete"></paper-icon-button>
</paper-item>
<h2 i18n-content="siteSettingsPermissions"></h2>
- <site-details-permission prefs="{{prefs}}" id="cookies"
- origin="[[origin]]">
+ <site-details-permission site="[[site]]" id="cookies"
+ category="{{ContentSettingsTypes.COOKIES}}">
</site-details-permission>
- <site-details-permission prefs="{{prefs}}" id="javascript"
- origin="[[origin]]">
+ <site-details-permission site="[[site]]" id="javascript"
+ category="{{ContentSettingsTypes.JAVASCRIPT}}">
</site-details-permission>
- <site-details-permission prefs="{{prefs}}" id="popups"
- origin="[[origin]]">
+ <site-details-permission site="[[site]]" id="popups"
+ category="{{ContentSettingsTypes.POPUPS}}">
</site-details-permission>
- <site-details-permission prefs="{{prefs}}" id="geolocation"
- origin="[[origin]]">
+ <site-details-permission site="[[site]]" id="geolocation"
+ category="{{ContentSettingsTypes.GEOLOCATION}}">
</site-details-permission>
- <site-details-permission prefs="{{prefs}}" id="notification"
- origin="[[origin]]">
+ <site-details-permission site="[[site]]" id="notification"
+ category="{{ContentSettingsTypes.NOTIFICATIONS}}">
</site-details-permission>
- <site-details-permission prefs="{{prefs}}" id="fullscreen"
- origin="[[origin]]">
+ <site-details-permission site="[[site]]" id="fullscreen"
+ category="{{ContentSettingsTypes.FULLSCREEN}}">
</site-details-permission>
- <site-details-permission prefs="{{prefs}}" id="camera"
- origin="[[origin]]">
+ <site-details-permission site="[[site]]" id="camera"
+ category="{{ContentSettingsTypes.CAMERA}}">
</site-details-permission>
- <site-details-permission prefs="{{prefs}}" id="mic"
- origin="[[origin]]">
+ <site-details-permission site="[[site]]" id="mic"
+ category="{{ContentSettingsTypes.MIC}}">
</site-details-permission>
<paper-button
on-tap="onClearAndReset_"
raised i18n-content="siteSettingsClearAndReset"
class="reset-button"></paper-button>
</div>
+ <website-usage-private-api id="usageApi"
+ website-data-usage="{{storedData_}}"
+ website-storage-type="{{storageType_}}">
+ </website-usage-private-api>
</template>
<script src="site_details.js"></script>
</dom-module>
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 a6a8db7bccd..5fa776485ed 100644
--- a/chromium/chrome/browser/resources/settings/site_settings/site_details.js
+++ b/chromium/chrome/browser/resources/settings/site_settings/site_details.js
@@ -6,69 +6,97 @@
* @fileoverview
* 'site-details' show the details (permissions and usage) for a given origin
* under Site Settings.
- *
- * Example:
- *
- * <site-details prefs="{{prefs}}" origin="{{origin}}">
- * </site-details>
- * ... other pages ...
- *
- * @group Chrome Settings Elements
- * @element site-details
*/
Polymer({
is: 'site-details',
+ behaviors: [SiteSettingsBehavior],
+
properties: {
/**
- * Preferences state.
+ * The site that this widget is showing details for.
+ * @type {SiteException}
*/
- prefs: {
+ site: {
type: Object,
- notify: true,
+ observer: 'onSiteChanged_',
},
/**
- * The origin that this widget is showing details for.
- */
- origin: String,
-
- /**
* The amount of data stored for the origin.
*/
storedData_: {
type: String,
- observer: 'onStoredDataChanged_',
+ value: '',
},
+
+ /**
+ * The type of storage for the origin.
+ */
+ storageType_: Number,
},
- ready: function() {
- this.$.cookies.category = settings.ContentSettingsTypes.COOKIES;
- this.$.javascript.category = settings.ContentSettingsTypes.JAVASCRIPT;
- this.$.popups.category = settings.ContentSettingsTypes.POPUPS;
- this.$.geolocation.category = settings.ContentSettingsTypes.GEOLOCATION;
- this.$.notification.category = settings.ContentSettingsTypes.NOTIFICATIONS;
- this.$.fullscreen.category = settings.ContentSettingsTypes.FULLSCREEN;
- this.$.camera.category = settings.ContentSettingsTypes.CAMERA;
- this.$.mic.category = settings.ContentSettingsTypes.MIC;
+ listeners: {
+ 'usage-deleted': 'onUsageDeleted',
+ },
- this.storedData_ = '1337 MB'; // TODO(finnur): Fetch actual data.
+ ready: function() {
+ this.ContentSettingsTypes = settings.ContentSettingsTypes;
},
- onStoredDataChanged_: function() {
- this.$.usage.hidden = false;
- this.$.storage.hidden = false;
+ /**
+ * Handler for when the origin changes.
+ */
+ onSiteChanged_: function() {
+ var url = new URL(this.site.origin);
+ this.$.usageApi.fetchUsageTotal(url.hostname);
},
+ /**
+ * Clears all data stored for the current origin.
+ */
onClearStorage_: function() {
- // TODO(finnur): Implement.
+ this.$.usageApi.clearUsage(this.site.origin, this.storageType_);
+ },
+
+ /**
+ * Called when usage has been deleted for an origin.
+ */
+ onUsageDeleted: function(event) {
+ if (event.detail.origin == this.site.origin) {
+ this.storedData_ = '';
+ this.navigateBackIfNoData_();
+ }
},
+ /**
+ * Resets all permissions and clears all data stored for the current origin.
+ */
onClearAndReset_: function() {
Array.prototype.forEach.call(
this.root.querySelectorAll('site-details-permission'),
function(element) { element.resetPermission(); });
- this.onClearStorage_();
+ if (this.storedData_ != '')
+ this.onClearStorage_();
+ else
+ this.navigateBackIfNoData_();
+ },
+
+ /**
+ * Navigate back if the UI is empty (everything been cleared).
+ */
+ navigateBackIfNoData_: function() {
+ if (this.storedData_ == '' && !this.permissionShowing_())
+ this.fire('subpage-back');
+ },
+
+ /**
+ * Returns true if one or more permission is showing.
+ */
+ permissionShowing_: function() {
+ return Array.prototype.some.call(
+ this.root.querySelectorAll('site-details-permission'),
+ function(element) { return element.offsetHeight > 0; });
},
});
diff --git a/chromium/chrome/browser/resources/settings/site_settings/site_details_permission.css b/chromium/chrome/browser/resources/settings/site_settings/site_details_permission.css
index 152713dbedf..d8c541f2aea 100644
--- a/chromium/chrome/browser/resources/settings/site_settings/site_details_permission.css
+++ b/chromium/chrome/browser/resources/settings/site_settings/site_details_permission.css
@@ -15,7 +15,7 @@
}
.permission-header {
- -webkit-margin-start: 6px;
+ -webkit-margin-start: -1px;
}
.permission-list {
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 0c65a9933ab..728fe930537 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,4 +1,4 @@
-<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
+<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/iron-icon/iron-icon.html">
<link rel="import" href="chrome://resources/polymer/v1_0/iron-icons/av-icons.html">
@@ -7,14 +7,16 @@
<link rel="import" href="chrome://resources/polymer/v1_0/paper-dropdown-menu/paper-dropdown-menu.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://md-settings/prefs/prefs_behavior.html">
+<link rel="import" href="chrome://resources/html/web_ui_listener_behavior.html">
+<link rel="import" href="chrome://md-settings/i18n_setup.html">
+<link rel="import" href="chrome://md-settings/settings_shared_css.html">
<link rel="import" href="chrome://md-settings/site_settings/site_settings_behavior.html">
+<link rel="import" href="chrome://md-settings/site_settings/site_settings_prefs_browser_proxy.html">
<dom-module id="site-details-permission">
- <link rel="import" type="css"
- href="chrome://md-settings/settings_shared.css">
<link rel="import" type="css" href="site_details_permission.css">
<template>
+ <style include="settings-shared"></style>
<div id="details" class="horizontal layout top" hidden>
<div class="left-column">
<iron-icon icon="[[computeIconForContentCategory(category)]]"
@@ -27,7 +29,7 @@
<div class="permission-list">
<paper-dropdown-menu>
<paper-menu id="permission" class="dropdown-content"
- on-iron-select="onPermissionMenuIronSelect_">
+ on-iron-activate="onPermissionMenuIronActivate_">
<paper-item id="allow">[[i18n_.allowAction]]</paper-item>
<paper-item id="block">[[i18n_.blockAction]]</paper-item>
</paper-menu>
diff --git a/chromium/chrome/browser/resources/settings/site_settings/site_details_permission.js b/chromium/chrome/browser/resources/settings/site_settings/site_details_permission.js
index a55969003d8..5a3fa05f9b5 100644
--- a/chromium/chrome/browser/resources/settings/site_settings/site_details_permission.js
+++ b/chromium/chrome/browser/resources/settings/site_settings/site_details_permission.js
@@ -6,34 +6,18 @@
* @fileoverview
* 'site-details-permission' handles showing the state of one permission, such
* as Geolocation, for a given origin.
- *
- * Example:
- *
- * <site-details-permission prefs="{{prefs}}">
- * </site-details-permission>
- * ... other pages ...
- *
- * @group Chrome Settings Elements
- * @element site-details-permission
*/
Polymer({
is: 'site-details-permission',
- behaviors: [PrefsBehavior, SiteSettingsBehavior],
+ behaviors: [SiteSettingsBehavior, WebUIListenerBehavior],
properties: {
/**
- * Preferences state.
+ * The site that this widget is showing details for.
+ * @type {SiteException}
*/
- prefs: {
- type: Object,
- notify: true,
- },
-
- /**
- * The origin, which this permission affects.
- */
- origin: String,
+ site: Object,
i18n_: {
readOnly: true,
@@ -47,32 +31,50 @@ Polymer({
},
},
- observers: [
- 'initialize_(' +
- 'prefs.profile.content_settings.exceptions.*, category, origin)',
- ],
+ observers: ['siteChanged_(site, category)'],
+
+ /** @override */
+ attached: function() {
+ this.addWebUIListener('contentSettingSitePermissionChanged',
+ this.sitePermissionChanged_.bind(this));
+ },
- initialize_: function() {
+ /**
+ * Sets the site to display.
+ * @param {!SiteException} site The site to display.
+ * @private
+ */
+ siteChanged_: function(site) {
this.$.details.hidden = true;
- if (this.get('prefs.' +
- this.computeCategoryExceptionsPrefName(this.category)) === undefined)
- return;
- var pref = this.getPref(
- this.computeCategoryExceptionsPrefName(this.category));
- var originPref = pref.value[this.origin + ',*'];
- if (originPref === undefined)
- originPref = pref.value[this.origin + ',' + this.origin];
- if (originPref === undefined)
- return;
+ var prefsProxy = settings.SiteSettingsPrefsBrowserProxyImpl.getInstance();
+ prefsProxy.getExceptionList(this.category).then(function(exceptionList) {
+ for (var i = 0; i < exceptionList.length; ++i) {
+ if (exceptionList[i].origin == site.origin) {
+ // TODO(finnur): Convert to use attrForSelected.
+ this.$.permission.selected = exceptionList[i].setting ==
+ settings.PermissionStringValues.ALLOW ? 0 : 1;
+ this.$.details.hidden = false;
+ }
+ }
+ }.bind(this));
+ },
- if (/** @type {{setting: number}} */(originPref.setting) ==
- settings.PermissionValues.ALLOW) {
- this.$.permission.selected = 0;
- this.$.details.hidden = false;
- } else if (originPref.setting == settings.PermissionValues.BLOCK) {
- this.$.permission.selected = 1;
- this.$.details.hidden = false;
+ /**
+ * Called when a site within a category has been changed.
+ * @param {number} category The category that changed.
+ * @param {string} site The site that changed.
+ * @private
+ */
+ sitePermissionChanged_: function(category, site) {
+ if (category == this.category && (site == '' || site == this.site.origin)) {
+ // TODO(finnur): Send down the full SiteException, not just a string.
+ this.siteChanged_({
+ origin: site,
+ embeddingOrigin: '',
+ setting: '',
+ source: '',
+ });
}
},
@@ -80,19 +82,22 @@ Polymer({
* Resets the category permission for this origin.
*/
resetPermission: function() {
- this.resetCategoryPermissionForOrigin(this.origin, this.category);
+ this.resetCategoryPermissionForOrigin(this.site.origin, '', this.category);
this.$.details.hidden = true;
},
/**
* Handles the category permission changing for this origin.
- * @param {!{target: !{selectedItem: !{innerText: string}}}} event
+ * @param {!{detail: !{item: !{innerText: string}}}} event
*/
- onPermissionMenuIronSelect_: function(event) {
- var action = event.target.selectedItem.innerText;
+ onPermissionMenuIronActivate_: function(event) {
+ // TODO(finnur): Compare with event.detail.item.dataset.permission directly
+ // once attrForSelected is in use.
+ var action = event.detail.item.innerText;
var value = (action == this.i18n_.allowAction) ?
settings.PermissionValues.ALLOW :
settings.PermissionValues.BLOCK;
- this.setCategoryPermissionForOrigin(this.origin, value, this.category);
+ this.setCategoryPermissionForOrigin(
+ this.site.origin, '', value, this.category);
},
});
diff --git a/chromium/chrome/browser/resources/settings/site_settings/site_list.css b/chromium/chrome/browser/resources/settings/site_settings/site_list.css
index feeacafdbe1..f0b3678cf36 100644
--- a/chromium/chrome/browser/resources/settings/site_settings/site_list.css
+++ b/chromium/chrome/browser/resources/settings/site_settings/site_list.css
@@ -11,5 +11,10 @@
}
.site-list {
- -webkit-margin-start: 16px;
+ -webkit-margin-end: -16px;
+}
+
+.origin {
+ --paper-item-body-two-line-min-height: 0;
+ -webkit-margin-start: 12px;
}
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 51414d12d57..643f85f8546 100644
--- a/chromium/chrome/browser/resources/settings/site_settings/site_list.html
+++ b/chromium/chrome/browser/resources/settings/site_settings/site_list.html
@@ -1,54 +1,63 @@
-<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.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/iron-icons/communication-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-item/paper-item-body.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/paper-submenu.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-menu-button/paper-menu-button.html">
-<link rel="import" href="chrome://md-settings/prefs/prefs_behavior.html">
-<link rel="import" href="chrome://md-settings/prefs/prefs_types.html">
+<link rel="import" href="chrome://resources/html/web_ui_listener_behavior.html">
+<link rel="import" href="chrome://md-settings/settings_shared_css.html">
<link rel="import" href="chrome://md-settings/site_settings/constants.html">
<link rel="import" href="chrome://md-settings/site_settings/site_settings_behavior.html">
+<link rel="import" href="chrome://md-settings/site_settings/site_settings_prefs_browser_proxy.html">
<dom-module id="settings-site-list">
- <link rel="import" type="css" href="../settings_shared.css">
<link rel="import" type="css" href="site_list.css">
<template>
+ <style include="settings-shared"></style>
<paper-submenu id="category" hidden on-paper-submenu-open="onToggle_"
on-paper-submenu-close="onToggle_">
- <paper-item class="menu-trigger">
+ <paper-item class="menu-trigger" hidden$="[[allSites]]">
<div class="site-header horizontal layout">
- <div class="flex"
- >[[computeSiteListHeader_(sites_, categoryEnabled)]]</div>
+ <div class="flex" id="header"
+ >[[computeSiteListHeader_(sites, categoryEnabled)]]</div>
<iron-icon id="icon" icon="icons:expand-more"></iron-icon>
</div>
</paper-item>
+
<paper-menu class="menu-content" id="listContainer">
- <template is="dom-repeat" items="{{sites_}}">
+ <template is="dom-repeat" items="[[sites]]">
<div class="site-list horizontal layout center">
- <iron-icon icon="[[computeSiteIcon_(item.url)]]"
- item-icon></iron-icon>
- <div class="flex"><paper-item
- on-tap="onOriginTap_">[[item.url]]</paper-item></div>
- <paper-menu-button>
- <paper-icon-button icon="menu"
- class="dropdown-trigger"></paper-icon-button>
- <paper-menu id="actionMenu" class="dropdown-content"
- on-iron-select="onActionMenuIronSelect_">
- <paper-item value="[[actions_.ALLOW]]"
- hidden="[[!showAllowAction_]]"
- >[[i18n_.allowAction]]</paper-item>
- <paper-item value="[[actions_.BLOCK]]"
- hidden="[[!showBlockAction_]]"
- >[[i18n_.blockAction]]</paper-item>
- <paper-item value="[[actions_.RESET]]"
- >[[i18n_.resetAction]]</paper-item>
- </paper-menu>
- </paper-menu-button>
+ <paper-item class="flex">
+ <iron-icon icon="[[computeSiteIcon_(item)]]" item-icon>
+ </iron-icon>
+ <paper-item-body two-line on-tap="onOriginTap_" class="origin">
+ <div>[[item.origin]]</div>
+ <div secondary>[[item.embeddingOriginForDisplay]]</div>
+ </paper-item-body>
+
+ <paper-menu-button hidden$="[[allSites]]">
+ <paper-icon-button icon="menu"
+ class="dropdown-trigger"></paper-icon-button>
+ <paper-menu id="actionMenu" class="dropdown-content"
+ on-iron-activate="onActionMenuIronActivate_">
+ <paper-item value="[[actions_.ALLOW]]"
+ hidden="[[!showAllowAction_]]"
+ >[[i18n_.allowAction]]</paper-item>
+ <paper-item value="[[actions_.BLOCK]]"
+ hidden="[[!showBlockAction_]]"
+ >[[i18n_.blockAction]]</paper-item>
+ <paper-item value="[[actions_.RESET]]"
+ >[[i18n_.resetAction]]</paper-item>
+ </paper-menu>
+ </paper-menu-button>
+ </paper-item>
</div>
</template>
+
</paper-menu>
</paper-submenu>
</template>
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 79e64e41a09..e724ab81998 100644
--- a/chromium/chrome/browser/resources/settings/site_settings/site_list.js
+++ b/chromium/chrome/browser/resources/settings/site_settings/site_list.js
@@ -6,44 +6,46 @@
* @fileoverview
* 'settings-site-list' shows a list of Allowed and Blocked sites for a given
* category.
- *
- * Example:
- * <settings-site-list prefs="{{prefs}}"
- * category="[[category]]">
- * </settings-site-list>
- *
- * @group Chrome Settings Elements
- * @element settings-site-list
*/
Polymer({
+
is: 'settings-site-list',
- behaviors: [PrefsBehavior, SiteSettingsBehavior],
+ behaviors: [SiteSettingsBehavior, WebUIListenerBehavior],
properties: {
/**
- * Preferences state.
+ * The current active route.
*/
- prefs: {
+ currentRoute: {
type: Object,
notify: true,
},
/**
- * The origin that was selected by the user in the dropdown list.
+ * The site that was selected by the user in the dropdown list.
+ * @type {SiteException}
*/
- selectedOrigin: {
- type: String,
+ selectedSite: {
+ type: Object,
notify: true,
},
/**
* Array of sites to display in the widget.
+ * @type {!Array<SiteException>}
*/
- sites_: {
+ sites: {
type: Array,
value: function() { return []; },
- observer: 'onDataChanged_',
+ },
+
+ /**
+ * Whether this list is for the All Sites category.
+ */
+ allSites: {
+ type: Boolean,
+ value: false,
},
/**
@@ -51,7 +53,10 @@ Polymer({
* either ALLOW or BLOCK, representing which sites are allowed or blocked
* respectively.
*/
- categorySubtype: Number,
+ categorySubtype: {
+ type: Number,
+ value: settings.INVALID_CATEGORY_SUBTYPE,
+ },
/**
* Represents the state of the main toggle shown for the category. For
@@ -60,7 +65,7 @@ Polymer({
*/
categoryEnabled: {
type: Boolean,
- observer: 'onDataChanged_',
+ value: true,
},
/**
@@ -100,55 +105,80 @@ Polymer({
},
observers: [
- 'initialize_(prefs.profile.content_settings.exceptions.*,' +
- 'category, categorySubtype)'
+ 'configureWidget_(category, categorySubtype, categoryEnabled, allSites)'
],
+ ready: function() {
+ this.addWebUIListener('contentSettingSitePermissionChanged',
+ this.siteWithinCategoryChanged_.bind(this));
+ },
+
+ /**
+ * Called when a site changes permission.
+ * @param {number} category The category of the site that changed.
+ * @param {string} site The site that changed.
+ * @private
+ */
+ siteWithinCategoryChanged_: function(category, site) {
+ if (category == this.category)
+ this.configureWidget_();
+ },
+
/**
- * One-time initialization routines for this class.
+ * Configures the action menu, visibility of the widget and shows the list.
* @private
*/
- initialize_: function() {
- CrSettingsPrefs.initialized.then(function() {
- this.setUpActionMenu_();
- this.ensureOpened_();
- }.bind(this));
+ configureWidget_: function() {
+ // The observer for All Sites fires before the attached/ready event, so
+ // initialize this here.
+ if (this.browserProxy_ === undefined) {
+ this.browserProxy_ =
+ settings.SiteSettingsPrefsBrowserProxyImpl.getInstance();
+ }
+ this.setUpActionMenu_();
+ this.ensureOpened_();
this.populateList_();
},
/**
* Ensures the widget is |opened| when needed when displayed initially.
+ * @private
*/
ensureOpened_: function() {
- // Allowed list is always shown opened by default.
- if (this.categorySubtype == settings.PermissionValues.ALLOW) {
+ // Allowed list is 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.$.category.opened = true;
return;
}
// Block list should only be shown opened if there is nothing to show in
// the allowed list.
- var pref = this.getPref(
- this.computeCategoryExceptionsPrefName(this.category));
- var sites = pref.value;
- for (var origin in sites) {
- var site = /** @type {{setting: number}} */(sites[origin]);
- if (site.setting == settings.PermissionValues.ALLOW)
- return;
+ if (this.category != settings.INVALID_CATEGORY_SUBTYPE) {
+ this.browserProxy_.getExceptionList(this.category).then(
+ function(exceptionList) {
+ var allowExists = exceptionList.some(function(exception) {
+ return exception.setting == settings.PermissionStringValues.ALLOW;
+ });
+ if (allowExists)
+ return;
+ this.$.category.opened = true;
+ }.bind(this));
+ } else {
+ this.$.category.opened = true;
}
-
- this.$.category.opened = true;
},
/**
- * Handles the data changing, for example when the category is flipped from
- * ALLOW to BLOCK or sites are added to the list.
+ * Makes sure the visibility is correct for this widget (e.g. hidden if the
+ * block list is empty).
* @private
*/
- onDataChanged_: function(newValue, oldValue) {
+ updateCategoryVisibility_: function() {
this.$.category.hidden =
- !this.showSiteList_(this.sites_, this.categoryEnabled);
+ !this.showSiteList_(this.sites, this.categoryEnabled);
},
/**
@@ -167,19 +197,141 @@ Polymer({
* @private
*/
populateList_: function() {
- var newList = [];
- var pref = this.getPref(
- this.computeCategoryExceptionsPrefName(this.category));
- var sites = pref.value;
- for (var origin in sites) {
- var site = /** @type {{setting: number}} */(sites[origin]);
- if (site.setting == this.categorySubtype) {
- var tokens = origin.split(',');
- newList.push({url: tokens[0]});
+ if (this.allSites) {
+ this.getAllSitesList_().then(function(lists) {
+ this.processExceptions_(lists);
+ }.bind(this));
+ } else {
+ this.browserProxy_.getExceptionList(this.category).then(
+ function(exceptionList) {
+ this.processExceptions_([exceptionList]);
+ }.bind(this));
+ }
+ },
+
+ /**
+ * Process the exception list returned from the native layer.
+ * @param {!Array<!Array<SiteException>>} data List of sites (exceptions) to
+ * process.
+ * @private
+ */
+ processExceptions_: function(data) {
+ var sites = [];
+ for (var i = 0; i < data.length; ++i)
+ sites = this.appendSiteList_(sites, data[i]);
+ this.sites = this.toSiteArray_(sites);
+ this.updateCategoryVisibility_();
+ },
+
+ /**
+ * Retrieves a list of all known sites (any category/setting).
+ * @return {!Promise}
+ * @private
+ */
+ getAllSitesList_: function() {
+ var promiseList = [];
+ for (var type in settings.ContentSettingsTypes) {
+ promiseList.push(
+ this.browserProxy_.getExceptionList(
+ settings.ContentSettingsTypes[type]));
+ }
+
+ return Promise.all(promiseList);
+ },
+
+ /**
+ * Appends to |list| the sites for a given category and subtype.
+ * @param {!Array<SiteException>} sites The site list to add to.
+ * @param {!Array<SiteException>} exceptionList List of sites (exceptions) to
+ * add.
+ * @return {!Array<SiteException>} The list of sites.
+ * @private
+ */
+ appendSiteList_: function(sites, exceptionList) {
+ for (var i = 0; i < exceptionList.length; ++i) {
+ if (this.category != settings.ALL_SITES) {
+ // Filter out 'Block' values if this list is handling 'Allow' items.
+ if (exceptionList[i].setting == settings.PermissionStringValues.BLOCK &&
+ this.categorySubtype != settings.PermissionValues.BLOCK) {
+ continue;
+ }
+ // Filter out 'Allow' values if this list is handling 'Block' items.
+ if (exceptionList[i].setting == settings.PermissionStringValues.ALLOW &&
+ this.categorySubtype != settings.PermissionValues.ALLOW) {
+ continue;
+ }
}
+
+ sites.push(exceptionList[i]);
}
+ return sites;
+ },
- this.sites_ = newList;
+ /**
+ * Ensures the URL has a scheme (assumes http if omitted).
+ */
+ ensureUrlHasScheme_: function(url) {
+ if (url.length == 0) return url;
+ return url.indexOf('://') != -1 ? url : 'http://' + url;
+ },
+
+ /**
+ * Converts an unordered site list to an ordered array, sorted by site name
+ * then protocol and de-duped (by origin).
+ * @param {!Array<SiteException>} sites A list of sites to sort and de-dup.
+ * @private
+ */
+ toSiteArray_: function(sites) {
+ var self = this;
+ sites.sort(function(a, b) {
+ // TODO(finnur): Hmm, it would probably be better to ensure scheme on the
+ // JS/C++ boundary.
+ var originA = self.ensureUrlHasScheme_(a.origin);
+ var originB = self.ensureUrlHasScheme_(b.origin);
+ var embeddingOriginA = self.ensureUrlHasScheme_(a.embeddingOrigin);
+ var embeddingOriginB = self.ensureUrlHasScheme_(b.embeddingOrigin);
+ var url1 = new URL(originA);
+ var url2 = new URL(originB);
+ var embeddingUrl1 = embeddingOriginA.length == 0 ? '' :
+ new URL(embeddingOriginA);
+ var embeddingUrl2 = embeddingOriginB.length == 0 ? '' :
+ new URL(embeddingOriginB);
+ var comparison = url1.host.localeCompare(url2.host);
+ if (comparison == 0) {
+ comparison = url1.protocol.localeCompare(url2.protocol);
+ if (comparison == 0) {
+ comparison = url1.port.localeCompare(url2.port);
+ if (comparison == 0)
+ return embeddingUrl1.host.localeCompare(embeddingUrl2.host);
+ }
+ }
+ return comparison;
+ });
+ var results = [];
+ var lastOrigin = '';
+ var lastEmbeddingOrigin = '';
+ for (var i = 0; i < sites.length; ++i) {
+ var origin = sites[i].origin;
+ var embeddingOrigin = sites[i].embeddingOrigin;
+
+ // The All Sites category can contain duplicates (from other categories).
+ if (origin == lastOrigin && embeddingOrigin == lastEmbeddingOrigin)
+ continue;
+
+ var embeddingOriginForDisplay = '';
+ if (embeddingOrigin != '*' && origin != embeddingOrigin)
+ embeddingOriginForDisplay = embeddingOrigin;
+
+ results.push({
+ origin: origin,
+ embeddingOrigin: embeddingOrigin,
+ embeddingOriginForDisplay: embeddingOriginForDisplay,
+ });
+
+ lastOrigin = origin;
+ lastEmbeddingOrigin = embeddingOrigin;
+ }
+ return results;
},
/**
@@ -196,29 +348,40 @@ Polymer({
/**
* A handler for selecting a site (by clicking on the origin).
- * @param {!{model: !{item: !{url: string}}}} event
* @private
*/
onOriginTap_: function(event) {
- this.selectedOrigin = event.model.item.url;
+ this.selectedSite = event.model.item;
+ var categorySelected =
+ this.allSites ?
+ 'all-sites' :
+ 'site-settings-category-' + this.computeCategoryTextId(this.category);
+ this.currentRoute = {
+ page: this.currentRoute.page,
+ section: 'privacy',
+ subpage: ['site-settings', categorySelected, 'site-details'],
+ };
},
/**
* A handler for activating one of the menu action items.
- * @param {!{model: !{item: !{url: string}},
- * target: !{selectedItems: !{textContent: string}}}} event
+ * @param {!{model: !{item: !{origin: string}},
+ * detail: !{item: !{textContent: string}}}} event
* @private
*/
- onActionMenuIronSelect_: function(event) {
- var origin = event.model.item.url;
- var action = event.target.selectedItems[0].textContent;
+ onActionMenuIronActivate_: function(event) {
+ var origin = event.model.item.origin;
+ var embeddingOrigin = event.model.item.embeddingOrigin;
+ var action = event.detail.item.textContent;
if (action == this.i18n_.resetAction) {
- this.resetCategoryPermissionForOrigin(origin, this.category);
+ this.resetCategoryPermissionForOrigin(
+ origin, embeddingOrigin, this.category);
} else {
var value = (action == this.i18n_.allowAction) ?
settings.PermissionValues.ALLOW :
settings.PermissionValues.BLOCK;
- this.setCategoryPermissionForOrigin(origin, value, this.category);
+ this.setCategoryPermissionForOrigin(
+ origin, embeddingOrigin, value, this.category);
}
},
@@ -264,6 +427,7 @@ Polymer({
showSiteList_: function(siteList, toggleState) {
if (siteList.length == 0)
return false;
+
// 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_())
diff --git a/chromium/chrome/browser/resources/settings/site_settings/site_settings_behavior.html b/chromium/chrome/browser/resources/settings/site_settings/site_settings_behavior.html
index 0684af28b61..ec5addf3d33 100644
--- a/chromium/chrome/browser/resources/settings/site_settings/site_settings_behavior.html
+++ b/chromium/chrome/browser/resources/settings/site_settings/site_settings_behavior.html
@@ -1,5 +1,5 @@
<link rel="import" href="chrome://md-settings/icons.html">
-<link rel="import" href="chrome://md-settings/prefs/prefs_behavior.html">
<link rel="import" href="chrome://md-settings/site_settings/constants.html">
+<link rel="import" href="chrome://md-settings/site_settings/site_settings_prefs_browser_proxy.html">
<link rel="import" href="chrome://resources/html/assert.html">
<script src="site_settings_behavior.js"></script> \ No newline at end of file
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 4cfadfae91a..31310a6701e 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
@@ -13,60 +13,50 @@ var SiteSettingsBehaviorImpl = {
* The ID of the category this element is displaying data for.
* See site_settings/constants.js for possible values.
*/
- category: {
- type: Number,
- },
- },
-
- /**
- * Returns whether the category default is set to enabled or not.
- * @param {number} category The category to check.
- * @return {boolean} True if the category default is set to enabled.
- * @protected
- */
- isCategoryAllowed: function(category) {
- var pref = this.getPref(this.computeCategoryPrefName(category));
+ category: Number,
- // FullScreen is Allow vs. Ask.
- if (category == settings.ContentSettingsTypes.FULLSCREEN)
- return pref.value != settings.PermissionValues.ASK;
+ /**
+ * The browser proxy used to retrieve and change information about site
+ * settings categories and the sites within.
+ * @type {settings.SiteSettingsPrefsBrowserProxyImpl}
+ */
+ browserProxy: Object,
+ },
- return pref.value != settings.PermissionValues.BLOCK;
+ created: function() {
+ this.browserProxy =
+ settings.SiteSettingsPrefsBrowserProxyImpl.getInstance();
},
/**
* Re-sets the category permission for a given origin.
- * @param {string} origin The origin to change the permission for.
+ * @param {string} primaryPattern The primary pattern to reset the permission
+ * for.
+ * @param {string} secondaryPattern The secondary pattern to reset the
+ * permission for.
* @param {number} category The category permission to change.
* @protected
*/
- resetCategoryPermissionForOrigin: function(origin, category) {
- var pref = JSON.parse(JSON.stringify(this.getPref(
- this.computeCategoryExceptionsPrefName(category))));
- delete pref.value[origin + ',' + origin];
- delete pref.value[origin + ',*'];
- this.setPrefValue(
- this.computeCategoryExceptionsPrefName(category), pref.value);
+ resetCategoryPermissionForOrigin: function(
+ primaryPattern, secondaryPattern, category) {
+ this.browserProxy.resetCategoryPermissionForOrigin(
+ primaryPattern, secondaryPattern, category);
},
/**
* Sets the category permission for a given origin.
- * @param {string} origin The origin to change the permission for.
+ * @param {string} primaryPattern The primary pattern to change the permission
+ * for.
+ * @param {string} secondaryPattern The secondary pattern to change the
+ * permission for.
* @param {number} value What value to set the permission to.
* @param {number} category The category permission to change.
* @protected
*/
- setCategoryPermissionForOrigin: function(origin, value, category) {
- var pref = JSON.parse(JSON.stringify(this.getPref(
- this.computeCategoryExceptionsPrefName(category))));
- var key1 = origin + ',' + origin;
- var key2 = origin + ',*';
- if (pref.value[key1] != undefined)
- pref.value[key1].setting = value;
- if (pref.value[key2] != undefined)
- pref.value[key2].setting = value;
- this.setPrefValue(
- this.computeCategoryExceptionsPrefName(category), pref.value);
+ setCategoryPermissionForOrigin: function(
+ primaryPattern, secondaryPattern, value, category) {
+ this.browserProxy.setCategoryPermissionForOrigin(
+ primaryPattern, secondaryPattern, category, value);
},
/**
@@ -127,7 +117,7 @@ var SiteSettingsBehaviorImpl = {
case settings.ContentSettingsTypes.POPUPS:
return 'icons:open-in-new';
default:
- assertNotReached();
+ assertNotReached('Invalid category: ' + category);
return '';
}
},
@@ -159,7 +149,7 @@ var SiteSettingsBehaviorImpl = {
case settings.ContentSettingsTypes.POPUPS:
return loadTimeData.getString('siteSettingsPopups');
default:
- assertNotReached();
+ assertNotReached('Invalid category: ' + category);
return '';
}
},
@@ -294,24 +284,7 @@ var SiteSettingsBehaviorImpl = {
return '';
}
},
-
- /**
- * A utility function to compute the category given the description.
- * @param {string} description The category description to look up.
- * @return {number} category The category id to return.
- * @protected
- */
- computeCategoryFromDesc: function(description) {
- for (var type in settings.ContentSettingsTypes) {
- if (description == this.computeTitleForContentCategory(
- settings.ContentSettingsTypes[type])) {
- return settings.ContentSettingsTypes[type];
- }
- }
- assertNotReached();
- return 0;
- },
};
/** @polymerBehavior */
-var SiteSettingsBehavior = [PrefsBehavior, SiteSettingsBehaviorImpl];
+var SiteSettingsBehavior = [SiteSettingsBehaviorImpl];
diff --git a/chromium/chrome/browser/resources/settings/site_settings/site_settings_category.css b/chromium/chrome/browser/resources/settings/site_settings/site_settings_category.css
index 305e68ab8f2..b5339ee99fc 100644
--- a/chromium/chrome/browser/resources/settings/site_settings/site_settings_category.css
+++ b/chromium/chrome/browser/resources/settings/site_settings/site_settings_category.css
@@ -7,7 +7,7 @@
}
settings-site-list {
- border-bottom: 1px solid #e0e0e0;
+ border-bottom: 1px solid var(--paper-grey-300);
}
settings-site-list:last-of-type {
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 da257106c00..8454782d0fe 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,24 +1,22 @@
-<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
+<link rel="import" href="chrome://resources/html/polymer.html">
<link rel="import" href="chrome://resources/polymer/v1_0/iron-icons/av-icons.html">
<link rel="import" href="chrome://resources/polymer/v1_0/iron-icons/communication-icons.html">
<link rel="import" href="chrome://resources/polymer/v1_0/iron-icons/social-icons.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-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://md-settings/prefs/prefs_types.html">
-<link rel="import" href="chrome://md-settings/settings_page/settings_animated_pages.html">
-<link rel="import" href="chrome://md-settings/settings_page/settings_subheader.html">
+<link rel="import" href="chrome://resources/html/web_ui_listener_behavior.html">
+<link rel="import" href="chrome://md-settings/settings_shared_css.html">
<link rel="import" href="chrome://md-settings/site_settings/constants.html">
+<link rel="import" href="chrome://md-settings/site_settings/site_details.html">
<link rel="import" href="chrome://md-settings/site_settings/site_list.html">
<link rel="import" href="chrome://md-settings/site_settings/site_settings_behavior.html">
-<link rel="import" href="chrome://md-settings/site_settings/site_details.html">
+<link rel="import" href="chrome://md-settings/site_settings/site_settings_prefs_browser_proxy.html">
<dom-module id="site-settings-category">
- <link rel="import" type="css"
- href="chrome://md-settings/settings_shared.css">
<link rel="import" type="css" href="site_settings_category.css">
<template>
+ <style include="settings-shared"></style>
<paper-icon-item>
<iron-icon icon="[[computeIconForContentCategory(category)]]"
item-icon></iron-icon>
@@ -32,13 +30,17 @@
on-change="onToggleChange_"></paper-toggle-button>
</paper-icon-item>
<settings-site-list id="blockList"
- prefs="{{prefs}}" category="[[category]]"
+ category="[[category]]"
+ current-route="{{currentRoute}}"
category-enabled="[[categoryEnabled]]"
- selected-origin="{{selectedOrigin}}"></settings-site-list>
+ selected-site="{{selectedSite}}">
+ </settings-site-list>
<settings-site-list id="allowList"
- prefs="{{prefs}}" category="[[category]]"
+ category="[[category]]"
+ current-route="{{currentRoute}}"
category-enabled="[[categoryEnabled]]"
- selected-origin="{{selectedOrigin}}"></settings-site-list>
+ selected-site="{{selectedSite}}">
+ </settings-site-list>
</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 22a334737b4..7016b2490a9 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
@@ -6,26 +6,17 @@
* @fileoverview
* 'site-settings-category' is the polymer element for showing a certain
* category under Site Settings.
- *
- * Example:
- *
- * <site-settings-category prefs="{{prefs}}">
- * </site-settings-category>
- * ... other pages ...
- *
- * @group Chrome Settings Elements
- * @element site-settings-category
*/
Polymer({
is: 'site-settings-category',
- behaviors: [SiteSettingsBehavior],
+ behaviors: [SiteSettingsBehavior, WebUIListenerBehavior],
properties: {
/**
- * Preferences state.
+ * The current active route.
*/
- prefs: {
+ currentRoute: {
type: Object,
notify: true,
},
@@ -38,10 +29,11 @@ Polymer({
categoryEnabled: Boolean,
/**
- * The origin that was selected by the user in the dropdown list.
+ * The site that was selected by the user in the dropdown list.
+ * @type {SiteException}
*/
- selectedOrigin: {
- type: String,
+ selectedSite: {
+ type: Object,
notify: true,
},
@@ -55,13 +47,26 @@ Polymer({
},
observers: [
- 'onCategoryChanged_(prefs.profile.default_content_setting_values.*, ' +
- 'category)',
+ 'onCategoryChanged_(category)',
],
ready: function() {
this.$.blockList.categorySubtype = settings.PermissionValues.BLOCK;
this.$.allowList.categorySubtype = settings.PermissionValues.ALLOW;
+
+ this.prefsProxy_ = settings.SiteSettingsPrefsBrowserProxyImpl.getInstance();
+ this.addWebUIListener('contentSettingCategoryChanged',
+ this.defaultValueForCategoryChanged_.bind(this));
+ },
+
+ /**
+ * Called when the default value for a category has been changed.
+ * @param {number} category The category that changed.
+ * @private
+ */
+ defaultValueForCategoryChanged_: function(category) {
+ if (category == this.category)
+ this.onCategoryChanged_();
},
/**
@@ -71,33 +76,37 @@ Polymer({
onToggleChange_: function(event) {
switch (this.category) {
case settings.ContentSettingsTypes.COOKIES:
+ case settings.ContentSettingsTypes.IMAGES:
case settings.ContentSettingsTypes.JAVASCRIPT:
case settings.ContentSettingsTypes.POPUPS:
// "Allowed" vs "Blocked".
- this.setPrefValue(this.computeCategoryPrefName(this.category),
- this.categoryEnabled ?
- settings.PermissionValues.ALLOW :
- settings.PermissionValues.BLOCK);
+ this.prefsProxy_.setDefaultValueForContentType(
+ this.category,
+ this.categoryEnabled ?
+ settings.PermissionValues.ALLOW :
+ settings.PermissionValues.BLOCK);
break;
case settings.ContentSettingsTypes.NOTIFICATIONS:
case settings.ContentSettingsTypes.GEOLOCATION:
case settings.ContentSettingsTypes.CAMERA:
case settings.ContentSettingsTypes.MIC:
// "Ask" vs "Blocked".
- this.setPrefValue(this.computeCategoryPrefName(this.category),
- this.categoryEnabled ?
- settings.PermissionValues.ASK :
- settings.PermissionValues.BLOCK);
+ this.prefsProxy_.setDefaultValueForContentType(
+ this.category,
+ this.categoryEnabled ?
+ settings.PermissionValues.ASK :
+ settings.PermissionValues.BLOCK);
break;
case settings.ContentSettingsTypes.FULLSCREEN:
// "Allowed" vs. "Ask first".
- this.setPrefValue(this.computeCategoryPrefName(this.category),
- this.categoryEnabled ?
- settings.PermissionValues.ALLOW :
- settings.PermissionValues.ASK);
+ this.prefsProxy_.setDefaultValueForContentType(
+ this.category,
+ this.categoryEnabled ?
+ settings.PermissionValues.ALLOW :
+ settings.PermissionValues.ASK);
break;
default:
- assertNotReached();
+ assertNotReached('Invalid category: ' + this.category);
}
},
@@ -106,6 +115,10 @@ Polymer({
* @private
*/
onCategoryChanged_: function() {
- this.categoryEnabled = this.isCategoryAllowed(this.category);
+ settings.SiteSettingsPrefsBrowserProxyImpl.getInstance()
+ .getDefaultValueForContentType(
+ this.category).then(function(enabled) {
+ this.categoryEnabled = enabled;
+ }.bind(this));
},
});
diff --git a/chromium/chrome/browser/resources/settings/site_settings/site_settings_prefs_browser_proxy.html b/chromium/chrome/browser/resources/settings/site_settings/site_settings_prefs_browser_proxy.html
new file mode 100644
index 00000000000..d8c97979ed9
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/site_settings/site_settings_prefs_browser_proxy.html
@@ -0,0 +1 @@
+<script src="chrome://md-settings/site_settings/site_settings_prefs_browser_proxy.js"></script>
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
new file mode 100644
index 00000000000..b27395f0b17
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/site_settings/site_settings_prefs_browser_proxy.js
@@ -0,0 +1,130 @@
+// 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 "Site Settings" section to
+ * interact with the content settings prefs.
+ */
+
+/**
+ * @typedef {{embeddingOrigin: string,
+ * origin: string,
+ * setting: string,
+ * source: string}}
+ */
+var SiteException;
+
+/**
+ * @typedef {{location: string,
+ * notifications: string}}
+ */
+var CategoryDefaultsPref;
+
+/**
+ * @typedef {{location: Array<SiteException>,
+ * notifications: Array<SiteException>}}
+ */
+var ExceptionListPref;
+
+/**
+ * @typedef {{defaults: CategoryDefaultsPref,
+ * exceptions: ExceptionListPref}}
+ */
+var SiteSettingsPref;
+
+cr.define('settings', function() {
+ /** @interface */
+ function SiteSettingsPrefsBrowserProxy() {}
+
+ SiteSettingsPrefsBrowserProxy.prototype = {
+ /**
+ * Sets the default value for a site settings category.
+ * @param {number} contentType The category to change.
+ * @param {number} defaultValue The value to set as default.
+ */
+ setDefaultValueForContentType: function(contentType, defaultValue) {},
+
+ /**
+ * Gets the default value for a site settings category.
+ * @param {number} contentType The category to change.
+ * @return {Promise<boolean>}
+ */
+ getDefaultValueForContentType: function(contentType) {},
+
+ /**
+ * Gets the exceptions (site list) for a particular category.
+ * @param {number} contentType The category to change.
+ * @return {Promise<Array<SiteException>>}
+ */
+ getExceptionList: function(contentType) {},
+
+ /**
+ * Resets the category permission for a given origin (expressed as primary
+ * and secondary patterns).
+ * @param {!string} primaryPattern The origin to change (primary pattern).
+ * @param {!string} secondaryPattern The embedding origin to change
+ * (secondary pattern).
+ * @param {!number} contentType The category to change.
+ */
+ resetCategoryPermissionForOrigin: function(
+ primaryPattern, secondaryPattern, contentType) {},
+
+ /**
+ * Sets the category permission for a given origin (expressed as primary
+ * and secondary patterns).
+ * @param {!string} primaryPattern The origin to change (primary pattern).
+ * @param {!string} secondaryPattern The embedding origin to change
+ * (secondary pattern).
+ * @param {!number} contentType The category to change.
+ * @param {!number} value The value to change the permission to.
+ */
+ setCategoryPermissionForOrigin: function(
+ primaryPattern, secondaryPattern, contentType, value) {},
+ };
+
+ /**
+ * @constructor
+ * @implements {SiteSettingsPrefsBrowserProxy}
+ */
+ function SiteSettingsPrefsBrowserProxyImpl() {}
+
+ // The singleton instance_ is replaced with a test version of this wrapper
+ // during testing.
+ cr.addSingletonGetter(SiteSettingsPrefsBrowserProxyImpl);
+
+ SiteSettingsPrefsBrowserProxyImpl.prototype = {
+ /** @override */
+ setDefaultValueForContentType: function(contentType, defaultValue) {
+ chrome.send('setDefaultValueForContentType', [contentType, defaultValue]);
+ },
+
+ /** @override */
+ getDefaultValueForContentType: function(contentType) {
+ return cr.sendWithPromise('getDefaultValueForContentType', contentType);
+ },
+
+ /** @override */
+ getExceptionList: function(contentType) {
+ return cr.sendWithPromise('getExceptionList', contentType);
+ },
+
+ /** @override */
+ resetCategoryPermissionForOrigin: function(
+ primaryPattern, secondaryPattern, contentType) {
+ chrome.send('resetCategoryPermissionForOrigin',
+ [primaryPattern, secondaryPattern, contentType]);
+ },
+
+ /** @override */
+ setCategoryPermissionForOrigin: function(
+ primaryPattern, secondaryPattern, contentType, value) {
+ chrome.send('setCategoryPermissionForOrigin',
+ [primaryPattern, secondaryPattern, contentType, value]);
+ },
+ };
+
+ return {
+ SiteSettingsPrefsBrowserProxyImpl: SiteSettingsPrefsBrowserProxyImpl,
+ };
+});
diff --git a/chromium/chrome/browser/resources/settings/site_settings/website_usage_private_api.html b/chromium/chrome/browser/resources/settings/site_settings/website_usage_private_api.html
new file mode 100644
index 00000000000..b3990d0c17f
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/site_settings/website_usage_private_api.html
@@ -0,0 +1,3 @@
+<link rel="import" href="chrome://resources/html/cr.html">
+<link rel="import" href="chrome://resources/html/polymer.html">
+<script src="chrome://md-settings/site_settings/website_usage_private_api.js"></script>
diff --git a/chromium/chrome/browser/resources/settings/site_settings/website_usage_private_api.js b/chromium/chrome/browser/resources/settings/site_settings/website_usage_private_api.js
new file mode 100644
index 00000000000..33c874da37e
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/site_settings/website_usage_private_api.js
@@ -0,0 +1,123 @@
+// 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.
+
+(function() {
+'use strict';
+
+Polymer({
+ is: 'website-usage-private-api',
+
+ properties: {
+ /**
+ * The amount of data used by the given website.
+ */
+ websiteDataUsage: {
+ type: String,
+ notify: true,
+ },
+
+ /**
+ * The type of data used by the given website.
+ */
+ websiteStorageType: {
+ type: Number,
+ notify: true,
+ },
+ },
+
+ attached: function() {
+ settings.WebsiteUsagePrivateApi.websiteUsagePolymerInstance = this;
+ },
+
+ /** @param {string} host */
+ fetchUsageTotal: function(host) {
+ settings.WebsiteUsagePrivateApi.fetchUsageTotal(host);
+ },
+
+ /**
+ * @param {string} origin
+ * @param {number} type
+ */
+ clearUsage: function(origin, type) {
+ settings.WebsiteUsagePrivateApi.clearUsage(origin, type);
+ },
+
+ /** @param {string} origin */
+ notifyUsageDeleted: function(origin) {
+ this.fire('usage-deleted', {origin: origin});
+ },
+});
+})();
+
+cr.define('settings.WebsiteUsagePrivateApi', function() {
+ /**
+ * @type {Object} An instance of the polymer object defined above.
+ * All data will be set here.
+ */
+ var websiteUsagePolymerInstance = null;
+
+ /**
+ * @type {string} The host for which the usage total is being fetched.
+ */
+ var hostName_;
+
+ /**
+ * Encapsulates the calls between JS and C++ to fetch how much storage the
+ * host is using.
+ * Will update the data in |websiteUsagePolymerInstance|.
+ */
+ var fetchUsageTotal = function(host) {
+ var instance = settings.WebsiteUsagePrivateApi.websiteUsagePolymerInstance;
+ if (instance != null)
+ instance.websiteDataUsage = '';
+
+ hostName_ = host;
+ chrome.send('fetchUsageTotal', [host]);
+ };
+
+ /**
+ * Callback for when the usage total is known.
+ * @param {string} host The host that the usage was fetched for.
+ * @param {string} usage The string showing how much data the given host
+ * is using.
+ * @param {number} type The storage type.
+ */
+ var returnUsageTotal = function(host, usage, type) {
+ var instance = settings.WebsiteUsagePrivateApi.websiteUsagePolymerInstance;
+ if (instance == null)
+ return;
+
+ if (hostName_ == host) {
+ instance.websiteDataUsage = usage;
+ instance.websiteStorageType = type;
+ }
+ };
+
+ /**
+ * Deletes the storage being used for a given origin.
+ * @param {string} origin The origin to delete storage for.
+ * @param {number} type The type of storage to delete.
+ */
+ var clearUsage = function(origin, type) {
+ chrome.send('clearUsage', [origin, type]);
+ };
+
+ /**
+ * Callback for when the usage has been cleared.
+ * @param {string} origin The origin that the usage was fetched for.
+ */
+ var onUsageCleared = function(origin) {
+ var instance = settings.WebsiteUsagePrivateApi.websiteUsagePolymerInstance;
+ if (instance == null)
+ return;
+
+ instance.notifyUsageDeleted(origin);
+ };
+
+ return { websiteUsagePolymerInstance: websiteUsagePolymerInstance,
+ fetchUsageTotal: fetchUsageTotal,
+ returnUsageTotal: returnUsageTotal,
+ clearUsage: clearUsage,
+ onUsageCleared: onUsageCleared, };
+});
diff --git a/chromium/chrome/browser/resources/settings/site_settings_page/compiled_resources.gyp b/chromium/chrome/browser/resources/settings/site_settings_page/compiled_resources.gyp
deleted file mode 100644
index 033958e5ec3..00000000000
--- a/chromium/chrome/browser/resources/settings/site_settings_page/compiled_resources.gyp
+++ /dev/null
@@ -1,26 +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.
-{
- 'targets': [
- {
- 'target_name': 'site_settings_page',
- 'variables': {
- 'depends': [
- '../../../../../ui/webui/resources/js/compiled_resources.gyp:assert',
- '../../../../../ui/webui/resources/js/compiled_resources.gyp:cr',
- '../../../../../ui/webui/resources/js/compiled_resources.gyp:load_time_data',
- '../prefs/prefs_behavior.js',
- '../prefs/prefs_types.js',
- '../settings_page/settings_animated_pages.js',
- '../site_settings/constants.js',
- '../site_settings/site_settings_behavior.js',
- ],
- 'externs': [
- '../../../../../third_party/closure_compiler/externs/settings_private.js',
- ],
- },
- 'includes': ['../../../../../third_party/closure_compiler/compile_js.gypi'],
- },
- ],
-}
diff --git a/chromium/chrome/browser/resources/settings/site_settings_page/compiled_resources2.gyp b/chromium/chrome/browser/resources/settings/site_settings_page/compiled_resources2.gyp
new file mode 100644
index 00000000000..58ee3d526cc
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/site_settings_page/compiled_resources2.gyp
@@ -0,0 +1,19 @@
+# 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': 'site_settings_page',
+ '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',
+ '../site_settings/compiled_resources2.gyp:constants',
+ '../site_settings/compiled_resources2.gyp:site_settings_behavior',
+ '../site_settings/compiled_resources2.gyp:site_settings_prefs_browser_proxy',
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ ],
+}
diff --git a/chromium/chrome/browser/resources/settings/site_settings_page/site_settings_page.css b/chromium/chrome/browser/resources/settings/site_settings_page/site_settings_page.css
index 04c26df5902..6f590de24cd 100644
--- a/chromium/chrome/browser/resources/settings/site_settings_page/site_settings_page.css
+++ b/chromium/chrome/browser/resources/settings/site_settings_page/site_settings_page.css
@@ -7,7 +7,7 @@
}
.settings-list > paper-icon-item {
- border-bottom: 1px solid #e0e0e0;
+ border-bottom: 1px solid var(--paper-grey-300);
}
.settings-list > paper-icon-item:last-of-type {
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 b8383326d65..0ae0e0678c5 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
@@ -1,10 +1,11 @@
-<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
+<link rel="import" href="chrome://resources/html/polymer.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-item/paper-item.html">
<link rel="import" href="chrome://resources/polymer/v1_0/iron-icons/image-icons.html">
<link rel="import" href="chrome://resources/polymer/v1_0/iron-icons/communication-icons.html">
<link rel="import" href="chrome://resources/polymer/v1_0/iron-icons/social-icons.html">
<link rel="import" href="chrome://md-settings/site_settings/constants.html">
<link rel="import" href="chrome://md-settings/site_settings/site_settings_behavior.html">
+<link rel="import" href="chrome://md-settings/site_settings/site_settings_prefs_browser_proxy.html">
<dom-module id="settings-site-settings-page">
<link rel="import" type="css" href="site_settings_page.css">
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 17ab458cd36..6734247e374 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
@@ -6,17 +6,6 @@
* @fileoverview
* 'settings-site-settings-page' is the settings page containing privacy and
* security site settings.
- *
- * Example:
- *
- * <iron-animated-pages>
- * <settings-site-settings-page prefs="{{prefs}}">
- * </settings-site-settings-page>
- * ... other pages ...
- * </iron-animated-pages>
- *
- * @group Chrome Settings Elements
- * @element settings-site-settings-page
*/
Polymer({
is: 'settings-site-settings-page',
@@ -25,60 +14,85 @@ Polymer({
properties: {
/**
- * Preferences state.
+ * The current active route.
*/
- prefs: {
+ currentRoute: {
type: Object,
notify: true,
},
/**
- * The current active route.
+ * The category selected by the user.
*/
- currentRoute: {
- type: Object,
+ categorySelected: {
+ type: String,
notify: true,
},
},
ready: function() {
- CrSettingsPrefs.initialized.then(function() {
- // TODO(finnur): Implement 'All Sites' list.
- this.addCategory(settings.ContentSettingsTypes.COOKIES);
- this.addCategory(settings.ContentSettingsTypes.GEOLOCATION);
- this.addCategory(settings.ContentSettingsTypes.CAMERA);
- this.addCategory(settings.ContentSettingsTypes.MIC);
- this.addCategory(settings.ContentSettingsTypes.JAVASCRIPT);
- this.addCategory(settings.ContentSettingsTypes.POPUPS);
- this.addCategory(settings.ContentSettingsTypes.FULLSCREEN);
- this.addCategory(settings.ContentSettingsTypes.NOTIFICATIONS);
- this.addCategory(settings.ContentSettingsTypes.IMAGES);
- }.bind(this));
+ this.addAllSitesCategory_();
+ this.addCategory_(settings.ContentSettingsTypes.COOKIES);
+ this.addCategory_(settings.ContentSettingsTypes.GEOLOCATION);
+ this.addCategory_(settings.ContentSettingsTypes.CAMERA);
+ this.addCategory_(settings.ContentSettingsTypes.MIC);
+ this.addCategory_(settings.ContentSettingsTypes.JAVASCRIPT);
+ this.addCategory_(settings.ContentSettingsTypes.POPUPS);
+ this.addCategory_(settings.ContentSettingsTypes.FULLSCREEN);
+ this.addCategory_(settings.ContentSettingsTypes.NOTIFICATIONS);
+ this.addCategory_(settings.ContentSettingsTypes.IMAGES);
+ },
+
+ /**
+ * Adds the All Sites category to the page.
+ * @private
+ */
+ addAllSitesCategory_: function() {
+ var description = loadTimeData.getString('siteSettingsCategoryAllSites');
+ this.addCategoryImpl_(-1, 'list', description, '');
},
/**
* Adds a single category to the page.
* @param {number} category The category to add.
+ * @private
+ */
+ addCategory_: function(category) {
+ var icon = this.computeIconForContentCategory(category);
+ var title = this.computeTitleForContentCategory(category);
+ var prefsProxy = settings.SiteSettingsPrefsBrowserProxyImpl.getInstance();
+ prefsProxy.getDefaultValueForContentType(
+ category).then(function(enabled) {
+ var description = this.computeCategoryDesc(category, enabled, false);
+ this.addCategoryImpl_(category, icon, title, description);
+ }.bind(this));
+ },
+
+ /**
+ * Constructs the actual HTML elements for the category.
+ * @param {number} category The category to add.
+ * @param {string} icon The icon to show with it.
+ * @param {string} title The title to show for the category.
+ * @param {string} defaultValue The default value (permission) for the
+ * category.
+ * @private
*/
- addCategory: function(category) {
+ addCategoryImpl_: function(category, icon, title, defaultValue) {
var root = this.$.list;
var paperIcon = document.createElement('paper-icon-item');
- paperIcon.addEventListener('tap', this.onTapCategory.bind(this));
+ paperIcon.addEventListener('tap', this.onTapCategory.bind(this, category));
var ironIcon = document.createElement('iron-icon');
- ironIcon.setAttribute('icon', this.computeIconForContentCategory(category));
+ ironIcon.setAttribute('icon', icon);
ironIcon.setAttribute('item-icon', '');
var description = document.createElement('div');
description.setAttribute('class', 'flex');
- description.appendChild(
- document.createTextNode(this.computeTitleForContentCategory(category)));
+ description.appendChild(document.createTextNode(title));
var setting = document.createElement('div');
setting.setAttribute('class', 'option-value');
- setting.appendChild(document.createTextNode(
- this.computeCategoryDesc(
- category, this.isCategoryAllowed(category), false)));
+ setting.appendChild(document.createTextNode(defaultValue));
paperIcon.appendChild(ironIcon);
paperIcon.appendChild(description);
@@ -89,15 +103,24 @@ Polymer({
/**
* Handles selection of a single category and navigates to the details for
* that category.
+ * @param {number} category The category selected by the user.
+ * @param {!Event} event The tap event.
*/
- onTapCategory: function(event) {
- var description = event.currentTarget.querySelector('.flex').innerText;
- var page = this.computeCategoryTextId(
- this.computeCategoryFromDesc(description));
- this.currentRoute = {
- page: this.currentRoute.page,
- section: 'privacy',
- subpage: ['site-settings', 'site-settings-category-' + page],
- };
+ onTapCategory: function(category, event) {
+ if (category == -1) {
+ this.currentRoute = {
+ page: this.currentRoute.page,
+ section: 'privacy',
+ subpage: ['site-settings', 'all-sites'],
+ };
+ } else {
+ this.categorySelected = this.computeCategoryTextId(category);
+ this.currentRoute = {
+ page: this.currentRoute.page,
+ section: 'privacy',
+ subpage: ['site-settings', 'site-settings-category-' +
+ this.categorySelected],
+ };
+ }
},
});
diff --git a/chromium/chrome/browser/resources/settings/system_page/compiled_resources2.gyp b/chromium/chrome/browser/resources/settings/system_page/compiled_resources2.gyp
new file mode 100644
index 00000000000..7da27f25cd2
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/system_page/compiled_resources2.gyp
@@ -0,0 +1,23 @@
+# 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': 'system_page_browser_proxy',
+ 'dependencies': [
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:load_time_data',
+ '<(EXTERNS_GYP):chrome_send',
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'system_page',
+ 'dependencies': [
+ 'system_page_browser_proxy',
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ ],
+}
diff --git a/chromium/chrome/browser/resources/settings/system_page/system_page.html b/chromium/chrome/browser/resources/settings/system_page/system_page.html
new file mode 100644
index 00000000000..1ce9f830706
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/system_page/system_page.html
@@ -0,0 +1,46 @@
+<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://md-settings/controls/settings_checkbox.html">
+<link rel="import" href="chrome://md-settings/prefs/prefs.html">
+<link rel="import" href="chrome://md-settings/settings_shared_css.html">
+<link rel="import" href="chrome://md-settings/system_page/system_page_browser_proxy.html">
+
+<dom-module id="settings-system-page">
+ <template>
+ <style include="settings-shared">
+ /* TODO(dbeam): is it worth generalizing this style? Does something like
+ * this already exist (buttons after a checkbox in the same row)? */
+ #hardware-acceleration {
+ align-items: center;
+ display: flex;
+ }
+
+ #hardware-acceleration settings-checkbox {
+ flex: 1;
+ }
+ </style>
+ <div class="settings-box block first">
+<if expr="not is_macosx">
+ <settings-checkbox i18n-values="label:backgroundAppsLabel"
+ pref="{{prefs.background_mode.enabled}}">
+ </settings-checkbox>
+</if>
+ <div id="hardware-acceleration">
+ <settings-checkbox i18n-values="label:hardwareAccelerationLabel"
+ pref="{{prefs.hardware_acceleration_mode.enabled}}">
+ </settings-checkbox>
+ <template is="dom-if" if="[[shouldShowRestart_(prefs.hardware_acceleration_mode.enabled.value)]]">
+ <paper-button on-tap="onRestartTap_">$i18n{restart}</paper-button>
+ </template>
+ </div>
+ </div>
+ <div class="settings-box">
+ <div class="button-strip">
+ <paper-button class="primary-button" on-tap="onChangeProxySettingsTap_">
+ $i18n{changeProxySettings}
+ </paper-button>
+ </div>
+ </div>
+ </template>
+ <script src="chrome://md-settings/system_page/system_page.js"></script>
+</dom-module>
diff --git a/chromium/chrome/browser/resources/settings/system_page/system_page.js b/chromium/chrome/browser/resources/settings/system_page/system_page.js
new file mode 100644
index 00000000000..088f928e5ca
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/system_page/system_page.js
@@ -0,0 +1,40 @@
+// 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 that affect how Chrome interacts with the underlying
+ * operating system (i.e. network, background processes, hardware).
+ */
+
+Polymer({
+ is: 'settings-system-page',
+
+ properties: {
+ prefs: {
+ type: Object,
+ notify: true,
+ },
+ },
+
+ /**
+ * @param {boolean} enabled Whether hardware acceleration is currently
+ * enabled.
+ * @private
+ */
+ shouldShowRestart_: function(enabled) {
+ var proxy = settings.SystemPageBrowserProxyImpl.getInstance();
+ return enabled != proxy.wasHardwareAccelerationEnabledAtStartup();
+ },
+
+ /** @private */
+ onChangeProxySettingsTap_: function() {
+ settings.SystemPageBrowserProxyImpl.getInstance().changeProxySettings();
+ },
+
+ /** @private */
+ onRestartTap_: function() {
+ // TODO(dbeam): we should prompt before restarting the browser.
+ settings.SystemPageBrowserProxyImpl.getInstance().restartBrowser();
+ },
+});
diff --git a/chromium/chrome/browser/resources/settings/system_page/system_page_browser_proxy.html b/chromium/chrome/browser/resources/settings/system_page/system_page_browser_proxy.html
new file mode 100644
index 00000000000..8cdd1f7aa2b
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/system_page/system_page_browser_proxy.html
@@ -0,0 +1,2 @@
+<link rel="import" href="chrome://resources/html/cr.html">
+<script src="chrome://md-settings/system_page/system_page_browser_proxy.js"></script>
diff --git a/chromium/chrome/browser/resources/settings/system_page/system_page_browser_proxy.js b/chromium/chrome/browser/resources/settings/system_page/system_page_browser_proxy.js
new file mode 100644
index 00000000000..654e6afc93e
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/system_page/system_page_browser_proxy.js
@@ -0,0 +1,54 @@
+// 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 Handles interprocess communcation for the system page. */
+
+cr.define('settings', function() {
+ /** @interface */
+ function SystemPageBrowserProxy() {}
+
+ SystemPageBrowserProxy.prototype = {
+ /** Allows the user to change native system proxy settings. */
+ changeProxySettings: function() {},
+
+ /** Restarts Chrome so "Use hardware acceleration" can take effect. */
+ restartBrowser: function() {},
+
+ /**
+ * @return {boolean} Whether hardware acceleration was enabled when the user
+ * started Chrome.
+ */
+ wasHardwareAccelerationEnabledAtStartup: function() {},
+ };
+
+ /**
+ * @constructor
+ * @implements {settings.SystemPageBrowserProxy}
+ */
+ function SystemPageBrowserProxyImpl() {}
+
+ cr.addSingletonGetter(SystemPageBrowserProxyImpl);
+
+ SystemPageBrowserProxyImpl.prototype = {
+ /** @override */
+ changeProxySettings: function() {
+ chrome.send('changeProxySettings');
+ },
+
+ /** @override */
+ restartBrowser: function() {
+ chrome.send('restartBrowser');
+ },
+
+ /** @override */
+ wasHardwareAccelerationEnabledAtStartup: function() {
+ return loadTimeData.getBoolean('hardwareAccelerationEnabledAtStartup');
+ },
+ };
+
+ return {
+ SystemPageBrowserProxy: SystemPageBrowserProxy,
+ SystemPageBrowserProxyImpl: SystemPageBrowserProxyImpl,
+ };
+});
diff --git a/chromium/chrome/browser/resources/signin_internals/signin_index.css b/chromium/chrome/browser/resources/signin_internals/signin_index.css
deleted file mode 100644
index ebcc78732f1..00000000000
--- a/chromium/chrome/browser/resources/signin_internals/signin_index.css
+++ /dev/null
@@ -1,78 +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. */
-
-h2 {
- color: rgb(74, 142, 230);
- font-size: 100%;
- margin-bottom: 0;
-}
-
-.zero {
- color: rgb(127, 127, 127);
-}
-
-.ok {
- background: rgb(204, 255, 204);
-}
-
-tr.header {
- font-weight: bold;
-}
-
-div {
- -webkit-column-break-inside: avoid;
- display: inline-block;
- width: 100%;
-}
-
-div#signin-info {
- -webkit-columns: 2;
-}
-
-div#token-info,
-div#cookie-info {
- -webkit-columns: 1;
-}
-
-table.signin-details {
- width: 100%;
-}
-
-tr:nth-child(odd) {
- background: rgb(239, 243, 255);
-}
-
-table.signin-details tr:nth-child(odd).ok {
- background: rgb(204, 243, 204);
-}
-
-@-webkit-keyframes highlight1 {
- 0% {
- background: rgb(255, 255, 0);
- }
- 100% {
- background: rgb(255, 255, 255);
- }
-}
-
-@-webkit-keyframes highlight2 {
- 0% {
- background: rgb(155, 158, 166);
- }
- 100% {
- background: rgb(239, 243, 255);
- }
-}
-
-tr[highlighted] {
- -webkit-animation-duration: 3s;
- -webkit-animation-name: highlight1;
- -webkit-animation-timing-function: linear;
-}
-
-tr[highlighted]:nth-child(odd) {
- -webkit-animation-duration: 3s;
- -webkit-animation-name: highlight2;
- -webkit-animation-timing-function: linear;
-}
diff --git a/chromium/chrome/browser/resources/signin_internals/signin_index.html b/chromium/chrome/browser/resources/signin_internals/signin_index.html
deleted file mode 100644
index 9ab71977acd..00000000000
--- a/chromium/chrome/browser/resources/signin_internals/signin_index.html
+++ /dev/null
@@ -1,89 +0,0 @@
-<!doctype html>
-<html i18n-values="dir:textdirection;lang:language">
-<head>
- <meta charset="utf-8">
- <title>Signin Internals</title>
- <script src="chrome://resources/js/cr.js"></script>
- <script src="chrome://resources/js/util.js"></script>
- <script src="chrome://resources/js/load_time_data.js"></script>
- <script src="chrome://signin-internals/strings.js"></script>
- <link rel="stylesheet" href="chrome://resources/css/text_defaults.css">
- <link rel="stylesheet" type="text/css" href="signin_index.css">
-</head>
-<body>
- <div id='signin-info'>
- <div class="section" jsselect="signin_info">
- <h2 jscontent="title"></h2>
- <table class="signin-details">
- <tr jsselect="data"
- jsvalues="class:chrome.signin.setClassFromValue($this.value)"
- jseval="chrome.signin.highlightIfChanged(this,
- this.children[1].innerText, value)">
- <td jscontent="label"></td>
- <td jscontent="status"></td>
- <td jscontent="time" jsdisplay="time"></td>
- <td jsdisplay="time.length==0">&nbsp;</td>
- </tr>
- </table>
- </div>
- </div>
- <div id='token-info'>
- <h2>Access Token Details By Account</h2>
- <div class="tokenSection" jsselect="token_info">
- <h3 jscontent="title"></h3>
- <table class="signin-details">
- <tr class="header">
- <td>Service</td>
- <td>Requested Scopes</td>
- <td>Request Time</td>
- <td>Request Status</td>
- </tr>
- <tr jsselect="data"
- jsvalues="class:chrome.signin.setClassFromValue($this.status)"
- jseval="chrome.signin.highlightIfAnyChanged(this,
- [[this.children[1].innerText, scopes],
- [this.children[2].innerText, request_time],
- [this.children[3].innerText, status]])">
- <td jscontent="service"></td>
- <td jsvalues=".innerHTML: scopes"></td>
- <td jscontent="request_time"></td>
- <td jsvalues=".innerHTML: status"></td>
- </tr>
- </table>
- </div>
- </div>
- <div id='cookie-info'>
- <h2>Accounts in Cookie Jar</h2>
- <div class="cookieSection">
- <table class="signin-details">
- <tr class="header">
- <td>Email Address</td>
- <td>Gaia ID</td>
- <td>Validity</td>
- </tr>
- <tr jsselect="cookie_info">
- <td jscontent="email"></td>
- <td jscontent="gaia_id"></td>
- <td jscontent="valid"></td>
- </tr>
- </table>
- </div>
- </div>
- <div id="account-info">
- <h2>Accounts in Token Service</h2>
- <div class="account-section">
- <table class="signin-details">
- <tr class="header">
- <td>Accound Id</td>
- </tr>
- <tr jsselect="accountInfo">
- <td jscontent="accountId"></td>
- </tr>
- </table>
- </div>
- </div>
- <script src="chrome://resources/js/i18n_template.js"></script>
- <script src="chrome://resources/js/jstemplate_compiled.js"></script>
- <script src="chrome://signin-internals/signin_internals.js"></script>
-</body>
-</html>
diff --git a/chromium/chrome/browser/resources/signin_internals/signin_internals.js b/chromium/chrome/browser/resources/signin_internals/signin_internals.js
deleted file mode 100644
index 5ac1b25eeb8..00000000000
--- a/chromium/chrome/browser/resources/signin_internals/signin_internals.js
+++ /dev/null
@@ -1,189 +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.
-
-var chrome = chrome || {};
-
-/**
- * Organizes all signin event listeners and asynchronous requests.
- * This object has no public constructor.
- * @type {Object}
- */
-chrome.signin = chrome.signin || {};
-
-(function() {
-
-// TODO(vishwath): This function is identical to the one in sync_internals.js
-// Merge both if possible.
-// Accepts a DOM node and sets its highlighted attribute oldVal != newVal
-function highlightIfChanged(node, oldVal, newVal) {
- var oldStr = oldVal.toString();
- var newStr = newVal.toString();
- if (oldStr != '' && oldStr != newStr) {
- // Note the addListener function does not end up creating duplicate
- // listeners. There can be only one listener per event at a time.
- // Reference: https://developer.mozilla.org/en/DOM/element.addEventListener
- node.addEventListener('webkitAnimationEnd',
- function() { this.removeAttribute('highlighted'); },
- false);
- node.setAttribute('highlighted', '');
- }
-}
-
-// Wraps highlightIfChanged for multiple conditions.
-function highlightIfAnyChanged(node, oldToNewValList) {
- for (var i = 0; i < oldToNewValList.length; i++)
- highlightIfChanged(node, oldToNewValList[i][0], oldToNewValList[i][1]);
-}
-
-function setClassFromValue(value) {
- if (value == 0)
- return 'zero';
- if (value == 'Successful')
- return 'ok';
-
- return '';
-}
-
-// Allow signin_index.html to access the functions above using the
-// corresponding chrome.signin<method> calls.
-chrome.signin['highlightIfChanged'] = highlightIfChanged;
-chrome.signin['highlightIfAnyChanged'] = highlightIfAnyChanged;
-chrome.signin['setClassFromValue'] = setClassFromValue;
-
-// Simplified Event class, borrowed (ok, stolen) from chrome_sync.js
-function Event() {
- this.listeners_ = [];
-}
-
-// Add a new listener to the list.
-Event.prototype.addListener = function(listener) {
- this.listeners_.push(listener);
-};
-
-// Remove a listener from the list.
-Event.prototype.removeListener = function(listener) {
- var i = this.findListener_(listener);
- if (i == -1) {
- return;
- }
- this.listeners_.splice(i, 1);
-};
-
-// Check if the listener has already been registered so we can prevent
-// duplicate registrations.
-Event.prototype.hasListener = function(listener) {
- return this.findListener_(listener) > -1;
-};
-
-// Are there any listeners registered yet?
-Event.prototype.hasListeners = function() {
- return this.listeners_.length > 0;
-};
-
-// Returns the index of the given listener, or -1 if not found.
-Event.prototype.findListener_ = function(listener) {
- for (var i = 0; i < this.listeners_.length; i++) {
- if (this.listeners_[i] == listener) {
- return i;
- }
- }
- return -1;
-};
-
-// Fires the event. Called by the actual event callback. Any
-// exceptions thrown by a listener are caught and logged.
-Event.prototype.fire = function() {
- var args = Array.prototype.slice.call(arguments);
- for (var i = 0; i < this.listeners_.length; i++) {
- try {
- this.listeners_[i].apply(null, args);
- } catch (e) {
- if (e instanceof Error) {
- // Non-standard, but useful.
- console.error(e.stack);
- } else {
- console.error(e);
- }
- }
- }
-};
-
-// These are the events that will be registered.
-chrome.signin.events = {
- 'signin_manager': [
- 'onSigninInfoChanged',
- 'onCookieAccountsFetched'
- ]
-};
-
-for (var eventType in chrome.signin.events) {
- var events = chrome.signin.events[eventType];
- for (var i = 0; i < events.length; ++i) {
- var event = events[i];
- chrome.signin[event] = new Event();
- }
-}
-
-// Creates functions that call into SigninInternalsUI.
-function makeSigninFunction(name) {
- var callbacks = [];
-
- // Calls the function, assuming the last argument is a callback to be
- // called with the return value.
- var fn = function() {
- var args = Array.prototype.slice.call(arguments);
- callbacks.push(args.pop());
- chrome.send(name, args);
- };
-
- // Handle a reply, assuming that messages are processed in FIFO order.
- // Called by SigninInternalsUI::HandleJsReply().
- fn.handleReply = function() {
- var args = Array.prototype.slice.call(arguments);
- // Remove the callback before we call it since the callback may
- // throw.
- var callback = callbacks.shift();
- callback.apply(null, args);
- };
-
- return fn;
-}
-
-// The list of js functions that call into SigninInternalsUI
-var signinFunctions = [
- // Signin Summary Info
- 'getSigninInfo'
-];
-
-for (var i = 0; i < signinFunctions.length; ++i) {
- var signinFunction = signinFunctions[i];
- chrome.signin[signinFunction] = makeSigninFunction(signinFunction);
-}
-
-chrome.signin.internalsInfo = {};
-
-// Replace the displayed values with the latest fetched ones.
-function refreshSigninInfo(signinInfo) {
- chrome.signin.internalsInfo = signinInfo;
- jstProcess(new JsEvalContext(signinInfo), $('signin-info'));
- jstProcess(new JsEvalContext(signinInfo), $('token-info'));
- jstProcess(new JsEvalContext(signinInfo), $('account-info'));
-}
-
-// Replace the cookie information with the fetched values.
-function updateCookieAccounts(cookieAccountsInfo) {
- jstProcess(new JsEvalContext(cookieAccountsInfo), $('cookie-info'));
-}
-
-// On load, do an initial refresh and register refreshSigninInfo to be invoked
-// whenever we get new signin information from SigninInternalsUI.
-function onLoad() {
- chrome.signin.getSigninInfo(refreshSigninInfo);
-
- chrome.signin.onSigninInfoChanged.addListener(refreshSigninInfo);
- chrome.signin.onCookieAccountsFetched.addListener(updateCookieAccounts);
-}
-
-document.addEventListener('DOMContentLoaded', onLoad, false);
-})();
diff --git a/chromium/chrome/browser/resources/signin_internals_resources.grd b/chromium/chrome/browser/resources/signin_internals_resources.grd
deleted file mode 100644
index 0bffb4985ea..00000000000
--- a/chromium/chrome/browser/resources/signin_internals_resources.grd
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<grit latest_public_release="0" current_release="1">
- <outputs>
- <output filename="grit/signin_internals_resources.h" type="rc_header">
- <emit emit_type='prepend'></emit>
- </output>
- <output filename="signin_internals_resources.pak" type="data_package" />
- </outputs>
- <release seq="1">
- <includes>
- <include name="IDR_SIGNIN_INTERNALS_INDEX_HTML"
- file="signin_internals/signin_index.html"
- flattenhtml="true" allowexternalscript="true" type="BINDATA" />
- <include name="IDR_SIGNIN_INTERNALS_INDEX_JS"
- file="signin_internals/signin_internals.js" type="BINDATA" />
- </includes>
- </release>
-</grit>
diff --git a/chromium/chrome/browser/resources/supervised_user_block_interstitial.css b/chromium/chrome/browser/resources/supervised_user_block_interstitial.css
deleted file mode 100644
index 0c666f05bd1..00000000000
--- a/chromium/chrome/browser/resources/supervised_user_block_interstitial.css
+++ /dev/null
@@ -1,141 +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. */
-body {
- background-color: rgb(247, 247, 247);
- font-size: 10pt;
- margin: 150px 60px 0 30px;
-}
-
-#main-frame-blocked {
- margin: auto;
- max-width: 600px;
- min-width: 200px;
-}
-
-h1 {
- font-size: 1.8em;
- font-weight: normal;
- margin: 5px 0 25px 0;
-}
-
-.avatar-img {
- -webkit-user-select: none;
- border: 3px solid rgb(251, 251, 251);
- border-radius: 50%;
- content: -webkit-image-set(
- url(../../app/theme/default_100_percent/cros/logo_avatar_circle_blue_color.png) 1x,
- url(../../app/theme/default_200_percent/cros/logo_avatar_circle_blue_color.png) 2x);
- margin-bottom: 5px;
- margin-right: 15px;
- margin-top: 5px;
- max-width: 45px;
- position: relative;
-}
-
-#feedback-link {
- font-size: 80%;
- margin-top: 10px;
-}
-
-#request-access-button {
- background-color: rgb(66, 133, 244);
- color: rgb(255, 255, 255);
- cursor: pointer;
- font-size: 12px;
- font-weight: bold;
- min-width: 88px;
- padding: 10px 15px;
- transition: box-shadow 200ms cubic-bezier(0.4, 0, 0.2, 1);
- transition-delay: 200ms;
-}
-
-#request-access-button:hover {
- background-color: rgb(30, 136, 229);
-}
-
-#request-access-button:active {
- background-color: rgb(25,118,210);
- box-shadow: 0 8px 17px 0 rgba(0, 0, 0, 0.2);
- transition-delay: 0s;
-}
-
-#details-button-container {
- color: rgb(97,97,97);
- cursor: pointer;
- display: inline;
- font-size: 12px;
- text-decoration: underline;
-}
-
-#button-container {
- align-items: baseline;
- display: flex;
- justify-content: space-between;
- margin-top: 60px;
-}
-
-#details {
- color: rgb(97,97,97);
- font-size: 14px;
-}
-
-#details-header {
- font-weight: bold;
-}
-
-.custodian-information {
- align-items: center;
- display: flex;
- font-size: 12px;
-}
-
-.custodian-name {
- color: rgb(97,97,97);
- padding: 1px 0;
-}
-
-.custodian-email {
- color: rgb(183, 183, 183);
- padding: 1px 0;
-}
-
-@media (max-width: 600px) {
- #button-container {
- display: flex;
- flex-flow: column;
- justify-content: flex-start;
- order: 2;
- text-transform: uppercase;
- }
-
- #details-button-container {
- font-weight: bold;
- margin: auto;
- order: 2;
- }
-
- #request-access-button {
- margin-bottom: 30px;
- order: 1;
- text-align: center
- }
-
- .button {
- width: 100%;
- }
-
- #details {
- margin: auto;
- order: 1;
- }
-
- .hidden-on-mobile {
- display: none;
- }
-
- #main-frame-blocked {
- display: flex;
- flex-flow: column;
- }
-}
diff --git a/chromium/chrome/browser/resources/supervised_user_block_interstitial.html b/chromium/chrome/browser/resources/supervised_user_block_interstitial.html
deleted file mode 100644
index 45946eebfd8..00000000000
--- a/chromium/chrome/browser/resources/supervised_user_block_interstitial.html
+++ /dev/null
@@ -1,64 +0,0 @@
-<!doctype html>
-<html i18n-values="dir:textdirection;lang:language">
-<head>
-<meta name="viewport" content="width=device-width">
-<meta charset="utf-8">
-<title i18n-content="blockPageTitle"></title>
-<link rel="stylesheet" href="../../../ui/webui/resources/css/widgets.css">
-<link rel="stylesheet" href="supervised_user_block_interstitial.css">
-<script src="../../../ui/webui/resources/js/cr.js"></script>
-<script src="../../../ui/webui/resources/js/util.js"></script>
-<script src="supervised_user_block_interstitial.js"></script>
-</head>
-
-<body>
-<div id="main-frame-blocked">
- <div id="information-container">
- <h1>
- <div id="block-page-message" i18n-content="blockPageMessage"></div>
- <div id="request-failed-message" i18n-content="requestFailedMessage"
- hidden></div>
- <div id="request-sent-message" i18n-content="requestSentMessage" hidden>
- </div>
- </h1>
- <div id="custodians-information" hidden>
- <div id="custodian-information" class="custodian-information">
- <img id="custodian-avatar-img" class="avatar-img">
- <div id="custodian-contact">
- <div id="custodian-name" class="custodian-name"></div>
- <div id="custodian-email" class="custodian-email"></div>
- </div>
- </div>
- <div id="second-custodian-information" class="custodian-information" hidden>
- <img id="second-custodian-avatar-img" class="avatar-img" hidden>
- <div id="second-custodian-contact">
- <div id="second-custodian-name" class="custodian-name"></div>
- <div id="second-custodian-email" class="custodian-email"></div>
- </div>
- </div>
- </div>
- </div>
- <div id="button-container">
- <div id="details-button-container">
- <a id="show-details-link" i18n-content="showDetailsLink"
- hidden class="button">
- </a>
- <a id="hide-details-link" i18n-content="hideDetailsLink"
- hidden class="button"></a>
- <a id="back-button" i18n-content="backButton"
- hidden class="button"></a>
- </div>
- <div id="request-access-button" class="button"
- i18n-content="requestAccessButton">
- </div>
- </div>
- <h1>
- <a id="feedback-link" is="action-link" i18n-content="feedbackLink"></a>
- </h1>
- <div id="details" hidden>
- <p id="details-header" i18n-content="blockReasonHeader"></p>
- <p id="details-message" i18n-content="blockReasonMessage"></p>
- </div>
-</div>
-</body>
-</html>
diff --git a/chromium/chrome/browser/resources/supervised_user_block_interstitial.js b/chromium/chrome/browser/resources/supervised_user_block_interstitial.js
deleted file mode 100644
index e41ab19fc34..00000000000
--- a/chromium/chrome/browser/resources/supervised_user_block_interstitial.js
+++ /dev/null
@@ -1,98 +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.
-
-function sendCommand(cmd) {
- window.domAutomationController.setAutomationId(1);
- window.domAutomationController.send(cmd);
-}
-
-function makeImageSet(url1x, url2x) {
- return '-webkit-image-set(url(' + url1x + ') 1x, url(' + url2x + ') 2x)';
-}
-
-function initialize() {
- if (loadTimeData.getBoolean('allowAccessRequests')) {
- $('request-access-button').onclick = function(event) {
- $('request-access-button').hidden = true;
- sendCommand('request');
- };
- } else {
- $('request-access-button').hidden = true;
- }
- var avatarURL1x = loadTimeData.getString('avatarURL1x');
- var avatarURL2x = loadTimeData.getString('avatarURL2x');
- var custodianName = loadTimeData.getString('custodianName');
- if (custodianName) {
- $('custodians-information').hidden = false;
- if (avatarURL1x) {
- $('custodian-avatar-img').style.content =
- makeImageSet(avatarURL1x, avatarURL2x);
- }
- $('custodian-name').innerHTML = custodianName;
- $('custodian-email').innerHTML = loadTimeData.getString('custodianEmail');
- var secondAvatarURL1x = loadTimeData.getString('secondAvatarURL1x');
- var secondAvatarURL2x = loadTimeData.getString('secondAvatarURL2x');
- var secondCustodianName = loadTimeData.getString('secondCustodianName');
- if (secondCustodianName) {
- $('second-custodian-information').hidden = false;
- $('second-custodian-avatar-img').hidden = false;
- if (secondAvatarURL1x) {
- $('second-custodian-avatar-img').style.content =
- makeImageSet(secondAvatarURL1x, secondAvatarURL2x);
- }
- $('second-custodian-name').innerHTML = secondCustodianName;
- $('second-custodian-email').innerHTML = loadTimeData.getString(
- 'secondCustodianEmail');
- }
- }
- var showDetailsLink = loadTimeData.getString('showDetailsLink');
- $('show-details-link').hidden = !showDetailsLink;
- $('back-button').hidden = showDetailsLink;
- $('back-button').onclick = function(event) {
- sendCommand('back');
- };
- $('show-details-link').onclick = function(event) {
- $('details').hidden = false;
- $('show-details-link').hidden = true;
- $('hide-details-link').hidden = false;
- $('information-container').classList.add('hidden-on-mobile');
- $('request-access-button').classList.add('hidden-on-mobile');
- };
- $('hide-details-link').onclick = function(event) {
- $('details').hidden = true;
- $('show-details-link').hidden = false;
- $('hide-details-link').hidden = true;
- $('information-container').classList.remove('hidden-on-mobile');
- $('request-access-button').classList.remove('hidden-on-mobile');
- };
- if (loadTimeData.getBoolean('showFeedbackLink')) {
- $('feedback-link').onclick = function(event) {
- sendCommand('feedback');
- };
- } else {
- $('feedback-link').style.display = 'none';
- }
-}
-
-/**
- * Updates the interstitial to show that the request failed or was sent.
- * @param {boolean} isSuccessful Whether the request was successful or not.
- */
-function setRequestStatus(isSuccessful) {
- $('block-page-message').hidden = true;
- if (isSuccessful) {
- $('request-failed-message').hidden = true;
- $('request-sent-message').hidden = false;
- $('show-details-link').hidden = true;
- $('hide-details-link').hidden = true;
- $('details').hidden = true;
- $('back-button').hidden = false;
- $('request-access-button').hidden = true;
- } else {
- $('request-failed-message').hidden = false;
- $('request-access-button').hidden = false;
- }
-}
-
-document.addEventListener('DOMContentLoaded', initialize);
diff --git a/chromium/chrome/browser/resources/sync_confirmation/sync_confirmation.css b/chromium/chrome/browser/resources/sync_confirmation/sync_confirmation.css
new file mode 100644
index 00000000000..4fedebfd34b
--- /dev/null
+++ b/chromium/chrome/browser/resources/sync_confirmation/sync_confirmation.css
@@ -0,0 +1,325 @@
+/* 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. */
+
+body {
+ margin: 0;
+ padding: 0;
+}
+
+a {
+ color: rgb(85, 149, 254);
+ text-decoration: none;
+}
+
+.picture img {
+ border-radius: 50%;
+ max-height: 100%;
+ max-width: 100%;
+}
+
+.container {
+ background-color: white;
+ overflow: hidden;
+ width: 448px;
+}
+
+.top-title-bar {
+ -webkit-padding-start: 24px;
+ align-items: center;
+ border-bottom: 1px solid lightgray;
+ color: #333;
+ display: flex;
+ font-size: 16px;
+ height: 52px;
+}
+
+.details {
+ font-size: 13px;
+ padding: 20px 24px;
+}
+
+.sync-message {
+ color: #595959;
+ line-height: 150%;
+ padding-bottom: 32px;
+}
+
+#picture-container {
+ align-items: center;
+ display: flex;
+ justify-content: center;
+ padding-bottom: 32px;
+}
+
+.picture {
+ -webkit-margin-start: 84px;
+ height: 96px;
+ position: relative;
+ width: 96px;
+}
+
+#profile-picture,
+.checkmark-circle {
+ position: absolute;
+}
+
+.action-container {
+ align-items: baseline;
+ display: flex;
+ justify-content: flex-end;
+}
+
+paper-button {
+ font-weight: 500;
+ line-height: 16px;
+ margin: 0;
+ padding: 8px 16px;
+}
+
+paper-button + paper-button {
+ -webkit-margin-start: 8px;
+}
+
+#confirmButton {
+ background-color: rgb(66, 133, 244);
+ color: white;
+}
+
+#undoButton {
+ color: #5A5A5A;
+}
+
+#illustration {
+ height: 96px;
+ margin: 0 auto;
+ position: relative;
+ width: 264px;
+}
+
+#checkmark-circle {
+ background: rgb(66, 133, 244);
+ border: 2px solid #fff;
+ border-radius: 50%;
+ bottom: 0;
+ height: 24px;
+ position: absolute;
+ right: 0;
+ transform: scale(0);
+ width: 24px;
+}
+
+.loaded #checkmark-circle {
+ animation: scale-circle 300ms cubic-bezier(0, 0, 0.2, 1) forwards;
+}
+
+@keyframes scale-circle {
+ from { transform: scale(0); }
+ to { transform: scale(1); }
+}
+
+#checkmark-check {
+ left: 5px;
+ position: absolute;
+ top: 7px;
+}
+
+.loaded #checkmark-path {
+ animation: draw-path 300ms cubic-bezier(0, 0, 0.2, 1) 100ms forwards;
+}
+
+@keyframes draw-path {
+ from { stroke-dashoffset: 16; }
+ to { stroke-dashoffset: 0; }
+}
+
+#icons {
+ height: 96px;
+ position: absolute;
+ width: 264px;
+}
+
+#icons > div {
+ animation-delay: 200ms;
+ animation-duration: 1.4s;
+ animation-fill-mode: forwards;
+ animation-timing-function: cubic-bezier(0.25, 0.45, 0.4, 0.7);
+ background-size: cover;
+ opacity: 0;
+ position: absolute;
+}
+
+#icon-bookmarks {
+ background: url(../../../../ui/webui/resources/images/icon_bookmarks.svg);
+ height: 36px;
+ left: 58px;
+ top: 0;
+ width: 36px;
+}
+
+#icon-extensions {
+ background: url(../../../../ui/webui/resources/images/icon_extensions.svg);
+ height: 24px;
+ left: 30px;
+ top: 30px;
+ width: 24px;
+}
+
+
+#icon-passwords {
+ background: url(../../../../ui/webui/resources/images/icon_passwords.svg);
+ height: 30px;
+ left: 38px;
+ top: 66px;
+ width: 40px;
+}
+
+#icon-history {
+ background: url(../../../../ui/webui/resources/images/icon_history.svg);
+ height: 36px;
+ left: 190px;
+ top: 6px;
+ width: 36px;
+}
+
+#icon-tabs {
+ background: url(../../../../ui/webui/resources/images/icon_tabs.svg);
+ height: 24px;
+ left: 222px;
+ top: 44px;
+ width: 24px;
+}
+
+#icon-themes {
+ background: url(../../../../ui/webui/resources/images/icon_themes.svg);
+ height: 30px;
+ left: 184px;
+ top: 62px;
+ width: 32px;
+}
+
+#icon-circle-open {
+ border: 2px solid #000;
+ border-radius: 50%;
+ height: 8px;
+ left: 6px;
+ top: 56px;
+ width: 8px;
+}
+
+.icon-circle {
+ background: #000;
+ border-radius: 50%;
+ height: 4px;
+ width: 4px;
+}
+
+#icon-circle-1 {
+ left: 64px;
+ top: 50px;
+}
+
+#icon-circle-2 {
+ left: 178px;
+ top: 18px;
+}
+
+#icon-circle-3 {
+ left: 194px;
+ top: 50px;
+}
+
+#icon-circle-4 {
+ left: 258px;
+ top: 36px;
+}
+
+.loaded .fade-top-left {
+ animation-name: fade-in-icon-top-left;
+}
+
+.loaded .fade-top-right {
+ animation-name: fade-in-icon-top-right;
+}
+
+.loaded .fade-middle-left {
+ animation-name: fade-in-icon-middle-left;
+}
+
+.loaded .fade-middle-right {
+ animation-name: fade-in-icon-middle-right;
+}
+
+.loaded .fade-bottom-left {
+ animation-name: fade-in-icon-bottom-left;
+}
+
+.loaded .fade-bottom-right {
+ animation-name: fade-in-icon-bottom-right;
+}
+
+@keyframes fade-in-icon-top-left {
+ from {
+ opacity: 0;
+ transform: translate(0, 0);
+ }
+ to {
+ opacity: 0.1;
+ transform: translate(-4px, -4px);
+ }
+}
+
+@keyframes fade-in-icon-top-right {
+ from {
+ opacity: 0;
+ transform: translate(0, 0);
+ }
+ to {
+ opacity: 0.1;
+ transform: translate(4px, -4px);
+ }
+}
+
+@keyframes fade-in-icon-middle-left {
+ from {
+ opacity: 0;
+ transform: translate(0, 0);
+ }
+ to {
+ opacity: 0.1;
+ transform: translate(-4px, 0);
+ }
+}
+
+@keyframes fade-in-icon-middle-right {
+ from {
+ opacity: 0;
+ transform: translate(0, 0);
+ }
+ to {
+ opacity: 0.1;
+ transform: translate(4px, 0);
+ }
+}
+
+@keyframes fade-in-icon-bottom-left {
+ from {
+ opacity: 0;
+ transform: translate(0, 0);
+ }
+ to {
+ opacity: 0.1;
+ transform: translate(-4px, 4px);
+ }
+}
+
+@keyframes fade-in-icon-bottom-right {
+ from {
+ opacity: 0;
+ transform: translate(0, 0);
+ }
+ to {
+ opacity: 0.1;
+ transform: translate(4px, 4px);
+ }
+}
diff --git a/chromium/chrome/browser/resources/sync_confirmation/sync_confirmation.html b/chromium/chrome/browser/resources/sync_confirmation/sync_confirmation.html
new file mode 100644
index 00000000000..4b1135e0e85
--- /dev/null
+++ b/chromium/chrome/browser/resources/sync_confirmation/sync_confirmation.html
@@ -0,0 +1,71 @@
+<!doctype html>
+<html i18n-values="dir:textdirection;lang:language">
+ <head>
+ <meta charset="utf-8">
+ <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="stylesheet" href="chrome://resources/css/text_defaults_md.css">
+ <link rel="stylesheet" href="sync_confirmation.css"></link>
+ <style is="custom-style">
+ a {
+ color: var(--google-blue-700);
+ text-decoration: none;
+ }
+
+ .action-container {
+<if expr="is_macosx or is_linux">
+ flex-flow: row-reverse;
+ justify-content: flex-start;
+</if>
+ }
+ </style>
+ </head>
+ <body>
+ <div class="container">
+ <div class="top-title-bar" i18n-content="syncConfirmationTitle"></div>
+ <div class="details">
+ <div id="picture-container">
+ <div id="illustration">
+ <div id="icons">
+ <div id="icon-bookmarks" class="fade-top-left"></div>
+ <div id="icon-extensions" class="fade-top-left"></div>
+ <div id="icon-passwords" class="fade-bottom-left"></div>
+ <div id="icon-history" class="fade-top-right"></div>
+ <div id="icon-tabs" class="fade-middle-right"></div>
+ <div id="icon-themes" class="fade-bottom-right"></div>
+ <div id="icon-circle-open" class="fade-middle-left"></div>
+ <div id="icon-circle-1" class="icon-circle fade-middle-left"></div>
+ <div id="icon-circle-2" class="icon-circle fade-top-right"></div>
+ <div id="icon-circle-3" class="icon-circle fade-middle-right"></div>
+ <div id="icon-circle-4" class="icon-circle fade-top-right"></div>
+ </div>
+ <div class="picture">
+ <img id="profile-picture"></img>
+ <div id="checkmark-circle">
+ <svg id="checkmark-check" width="13" height="10" viewBox="0 0 13 10">
+ <path id="checkmark-path" d="M1 5l3.5 3.5L12 1" stroke="#FFF"
+ stroke-width="2" stroke-dasharray="16"
+ stroke-dashoffset="16" fill="none"></path>
+ </svg>
+ </div>
+ </div>
+ </div>
+ </div>
+ <div class="sync-message"
+ i18n-values=".innerHTML:syncConfirmationChromeSyncBody"></div>
+ <div class="action-container">
+ <paper-button id="confirmButton"
+ i18n-content="syncConfirmationConfirmLabel"></paper-button>
+ <paper-button id="undoButton"
+ i18n-content="syncConfirmationUndoLabel"></paper-button>
+ </div>
+ </div>
+ </div>
+ </body>
+ <script src="chrome://resources/js/cr.js"></script>
+ <script src="chrome://resources/js/load_time_data.js"></script>
+ <script src="chrome://resources/js/util.js"></script>
+ <script src="sync_confirmation.js"></script>
+ <script src="chrome://sync-confirmation/strings.js"></script>
+ <script src="chrome://resources/js/i18n_template.js"></script>
+</html>
diff --git a/chromium/chrome/browser/resources/sync_confirmation/sync_confirmation.js b/chromium/chrome/browser/resources/sync_confirmation/sync_confirmation.js
new file mode 100644
index 00000000000..f3273fb28b5
--- /dev/null
+++ b/chromium/chrome/browser/resources/sync_confirmation/sync_confirmation.js
@@ -0,0 +1,54 @@
+/* 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('sync.confirmation', function() {
+ 'use strict';
+
+ function onConfirm(e) {
+ chrome.send('confirm');
+ }
+
+ function onUndo(e) {
+ chrome.send('undo');
+ }
+
+ function onGoToSettings(e) {
+ chrome.send('goToSettings');
+ }
+
+ function initialize() {
+ 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]);
+ }
+
+ function setUserImageURL(url) {
+ $('profile-picture').src = url;
+ }
+
+ function onPictureLoaded(e) {
+ $('picture-container').classList.add('loaded');
+ }
+
+ function onKeyDown(e) {
+ // If the currently focused element isn't something that performs an action
+ // on "enter" being pressed and the user hits "enter", perform the default
+ // action of the dialog, which is "OK, Got It".
+ if (e.keyIdentifier == 'Enter' &&
+ !/^(A|PAPER-BUTTON)$/.test(document.activeElement.tagName)) {
+ $('confirmButton').click();
+ e.preventDefault();
+ }
+ }
+
+ return {
+ initialize: initialize,
+ setUserImageURL: setUserImageURL
+ };
+});
+
+document.addEventListener('DOMContentLoaded', sync.confirmation.initialize);
diff --git a/chromium/chrome/browser/resources/uber/compiled_resources.gyp b/chromium/chrome/browser/resources/uber/compiled_resources.gyp
deleted file mode 100644
index 87b82741801..00000000000
--- a/chromium/chrome/browser/resources/uber/compiled_resources.gyp
+++ /dev/null
@@ -1,32 +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.
-{
- 'targets': [
- {
- 'target_name': 'uber_utils',
- 'variables': {
- 'depends': [
- '../../../../ui/webui/resources/js/cr.js',
- '../../../../ui/webui/resources/js/compiled_resources.gyp:load_time_data',
- '../../../../ui/webui/resources/js/util.js',
- ],
- 'externs': ['<(EXTERNS_DIR)/chrome_send.js'],
- },
- 'includes': ['../../../../third_party/closure_compiler/compile_js.gypi'],
- },
- {
- 'target_name': 'uber',
- 'variables': {
- 'depends': [
- '../../../../ui/webui/resources/js/cr.js',
- '../../../../ui/webui/resources/js/compiled_resources.gyp:load_time_data',
- '../../../../ui/webui/resources/js/util.js',
- 'uber_utils.js',
- ],
- 'externs': ['<(EXTERNS_DIR)/chrome_send.js'],
- },
- 'includes': ['../../../../third_party/closure_compiler/compile_js.gypi'],
- },
- ],
-}
diff --git a/chromium/chrome/browser/resources/uber/compiled_resources2.gyp b/chromium/chrome/browser/resources/uber/compiled_resources2.gyp
new file mode 100644
index 00000000000..960d088d392
--- /dev/null
+++ b/chromium/chrome/browser/resources/uber/compiled_resources2.gyp
@@ -0,0 +1,41 @@
+# 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': 'uber_frame',
+ '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',
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:util',
+ '<(DEPTH)/ui/webui/resources/js/cr/ui/compiled_resources2.gyp:focus_outline_manager',
+ 'uber_utils',
+ ],
+ 'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'uber_utils',
+ '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',
+ '<(EXTERNS_GYP):chrome_send',
+ ],
+ 'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'uber',
+ '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',
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:util',
+ 'uber_utils',
+ '<(EXTERNS_GYP):chrome_send',
+ ],
+ 'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ ],
+}
diff --git a/chromium/chrome/browser/resources/uber/uber_frame.js b/chromium/chrome/browser/resources/uber/uber_frame.js
index 1b3e967f5af..cf3f3a43279 100644
--- a/chromium/chrome/browser/resources/uber/uber_frame.js
+++ b/chromium/chrome/browser/resources/uber/uber_frame.js
@@ -53,7 +53,7 @@ cr.define('uber_frame', function() {
uber.invokeMethodOnParent('showPage',
{pageId: e.currentTarget.getAttribute('controls')});
- setSelection(e.currentTarget);
+ setSelection(/** @type {Element} */(e.currentTarget));
}
/**
@@ -116,7 +116,7 @@ cr.define('uber_frame', function() {
* Adjusts this frame's content to scrolls from the outer frame. This is done
* to obscure text in RTL as a user scrolls over the content of this frame (as
* currently RTL scrollbars still draw on the right).
- * @param {number} scroll document.body.scrollLeft of the content frame.
+ * @param {number} scrollLeft document.body.scrollLeft of the content frame.
*/
function adjustToScroll(scrollLeft) {
assert(isRTL());
diff --git a/chromium/chrome/browser/resources/user_manager/user_manager.js b/chromium/chrome/browser/resources/user_manager/user_manager.js
index 39d76d4764a..96ddf6588a4 100644
--- a/chromium/chrome/browser/resources/user_manager/user_manager.js
+++ b/chromium/chrome/browser/resources/user_manager/user_manager.js
@@ -21,12 +21,12 @@ cr.define('cr.ui', function() {
* @extends {DisplayManager}
* @constructor
*/
- function Oobe() {
+ function UserManager() {
}
- cr.addSingletonGetter(Oobe);
+ cr.addSingletonGetter(UserManager);
- Oobe.prototype = {
+ UserManager.prototype = {
__proto__: DisplayManager.prototype,
};
@@ -35,8 +35,8 @@ cr.define('cr.ui', function() {
* @param {bool} showGuest Whether the 'Browse as Guest' button is displayed.
* @param {bool} showAddPerson Whether the 'Add Person' button is displayed.
*/
- Oobe.showUserManagerScreen = function(showGuest, showAddPerson) {
- Oobe.getInstance().showScreen({id: 'account-picker',
+ 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
@@ -60,14 +60,14 @@ cr.define('cr.ui', function() {
* Open a new browser for the given profile.
* @param {string} profilePath The profile's path.
*/
- Oobe.launchUser = function(profilePath) {
+ UserManager.launchUser = function(profilePath) {
chrome.send('launchUser', [profilePath]);
};
/**
* Disables signin UI.
*/
- Oobe.disableSigninUI = function() {
+ UserManager.disableSigninUI = function() {
DisplayManager.disableSigninUI();
};
@@ -75,7 +75,7 @@ cr.define('cr.ui', function() {
* Shows signin UI.
* @param {string} opt_email An optional email for signin UI.
*/
- Oobe.showSigninUI = function(opt_email) {
+ UserManager.showSigninUI = function(opt_email) {
DisplayManager.showSigninUI(opt_email);
};
@@ -86,28 +86,28 @@ cr.define('cr.ui', function() {
* @param {string} link Text to use for help link.
* @param {number} helpId Help topic Id associated with help link.
*/
- Oobe.showSignInError = function(loginAttempts, message, link, helpId) {
+ 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.
*/
- Oobe.clearErrors = function() {
+ UserManager.clearErrors = function() {
DisplayManager.clearErrors();
};
/**
* Clears password field in user-pod.
*/
- Oobe.clearUserPodPassword = function() {
+ UserManager.clearUserPodPassword = function() {
DisplayManager.clearUserPodPassword();
};
/**
* Restores input focus to currently selected pod.
*/
- Oobe.refocusCurrentPod = function() {
+ UserManager.refocusCurrentPod = function() {
DisplayManager.refocusCurrentPod();
};
@@ -116,13 +116,13 @@ cr.define('cr.ui', function() {
* @param {string} email The user's email, if signed in.
* @param {string} displayName The user's display name.
*/
- Oobe.showUserManagerTutorial = function() {
+ UserManager.showUserManagerTutorial = function() {
UserManagerTutorial.startTutorial();
};
// Export
return {
- Oobe: Oobe
+ UserManager: UserManager
};
});
@@ -149,7 +149,8 @@ cr.define('UserManager', function() {
};
});
-var Oobe = cr.ui.Oobe;
+// 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)