summaryrefslogtreecommitdiffstats
path: root/chromium/chrome/browser/resources
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2018-01-29 16:35:13 +0100
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2018-02-01 15:33:35 +0000
commitc8c2d1901aec01e934adf561a9fdf0cc776cdef8 (patch)
tree9157c3d9815e5870799e070b113813bec53e0535 /chromium/chrome/browser/resources
parentabefd5095b41dac94ca451d784ab6e27372e981a (diff)
BASELINE: Update Chromium to 64.0.3282.139
Change-Id: I1cae68fe9c94ff7608b26b8382fc19862cdb293a Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io>
Diffstat (limited to 'chromium/chrome/browser/resources')
-rw-r--r--chromium/chrome/browser/resources/BUILD.gn24
-rw-r--r--chromium/chrome/browser/resources/bluetooth_internals/bluetooth_internals.css4
-rw-r--r--chromium/chrome/browser/resources/bluetooth_internals/characteristic_list.js12
-rw-r--r--chromium/chrome/browser/resources/bluetooth_internals/object_fieldset.js14
-rw-r--r--chromium/chrome/browser/resources/bluetooth_internals/value_control.js4
-rw-r--r--chromium/chrome/browser/resources/chromeos/chromevox/strings/chromevox_strings.grd2
-rw-r--r--chromium/chrome/browser/resources/chromeos/compiled_resources2.gyp3
-rw-r--r--chromium/chrome/browser/resources/chromeos/input_method/google_xkb_manifest.json8
-rw-r--r--chromium/chrome/browser/resources/chromeos/login/BUILD.gn30
-rw-r--r--chromium/chrome/browser/resources/chromeos/select_to_speak/BUILD.gn1
-rw-r--r--chromium/chrome/browser/resources/chromeos/select_to_speak/compiled_resources2.gyp13
-rw-r--r--chromium/chrome/browser/resources/chromeos/select_to_speak/strings/select_to_speak_strings.grd30
-rw-r--r--chromium/chrome/browser/resources/component_extension_resources.grd46
-rw-r--r--chromium/chrome/browser/resources/discards/.eslintrc.js13
-rw-r--r--chromium/chrome/browser/resources/discards/OWNERS1
-rw-r--r--chromium/chrome/browser/resources/discards/discards.css84
-rw-r--r--chromium/chrome/browser/resources/discards/discards.html84
-rw-r--r--chromium/chrome/browser/resources/discards/discards.js433
-rw-r--r--chromium/chrome/browser/resources/download_internals/download_internals.css4
-rw-r--r--chromium/chrome/browser/resources/download_internals/download_internals.html4
-rw-r--r--chromium/chrome/browser/resources/extensions/extensions.js2
-rw-r--r--chromium/chrome/browser/resources/feedback/js/feedback.js37
-rw-r--r--chromium/chrome/browser/resources/gaia_auth_host/authenticator.js99
-rw-r--r--chromium/chrome/browser/resources/gaia_auth_host/saml_handler.js39
-rw-r--r--chromium/chrome/browser/resources/gaia_auth_host/webview_event_manager.js66
-rw-r--r--chromium/chrome/browser/resources/hangout_services/manifest.json2
-rw-r--r--chromium/chrome/browser/resources/hangout_services/thunk.js5
-rw-r--r--chromium/chrome/browser/resources/hotword/OWNERS2
-rw-r--r--chromium/chrome/browser/resources/hotword/always_on_manager.js38
-rw-r--r--chromium/chrome/browser/resources/hotword/audio_client.js375
-rw-r--r--chromium/chrome/browser/resources/hotword/base_session_manager.js152
-rw-r--r--chromium/chrome/browser/resources/hotword/constants.js299
-rw-r--r--chromium/chrome/browser/resources/hotword/keep_alive.js52
-rw-r--r--chromium/chrome/browser/resources/hotword/launcher_manager.js35
-rw-r--r--chromium/chrome/browser/resources/hotword/logging.js19
-rw-r--r--chromium/chrome/browser/resources/hotword/manager.js50
-rw-r--r--chromium/chrome/browser/resources/hotword/manifest.json88
-rw-r--r--chromium/chrome/browser/resources/hotword/metrics.js26
-rw-r--r--chromium/chrome/browser/resources/hotword/nacl_manager.js612
-rw-r--r--chromium/chrome/browser/resources/hotword/page_audio_manager.js541
-rw-r--r--chromium/chrome/browser/resources/hotword/state_manager.js641
-rw-r--r--chromium/chrome/browser/resources/hotword/training_manager.js201
-rw-r--r--chromium/chrome/browser/resources/hotword_audio_verification/OWNERS1
-rw-r--r--chromium/chrome/browser/resources/hotword_audio_verification/event_page.js27
-rw-r--r--chromium/chrome/browser/resources/hotword_audio_verification/flow.js566
-rw-r--r--chromium/chrome/browser/resources/hotword_audio_verification/images/gradient-1x.pngbin2275 -> 0 bytes
-rw-r--r--chromium/chrome/browser/resources/hotword_audio_verification/images/gradient-2x.pngbin4493 -> 0 bytes
-rw-r--r--chromium/chrome/browser/resources/hotword_audio_verification/images/ic-check-blue-1x.pngbin289 -> 0 bytes
-rw-r--r--chromium/chrome/browser/resources/hotword_audio_verification/images/ic-check-blue-2x.pngbin526 -> 0 bytes
-rw-r--r--chromium/chrome/browser/resources/hotword_audio_verification/images/ic-check-gray-1x.pngbin221 -> 0 bytes
-rw-r--r--chromium/chrome/browser/resources/hotword_audio_verification/images/ic-check-gray-2x.pngbin385 -> 0 bytes
-rw-r--r--chromium/chrome/browser/resources/hotword_audio_verification/images/ic-error-1x.pngbin216 -> 0 bytes
-rw-r--r--chromium/chrome/browser/resources/hotword_audio_verification/images/ic-error-2x.pngbin299 -> 0 bytes
-rw-r--r--chromium/chrome/browser/resources/hotword_audio_verification/images/ic-x-white-1x.pngbin370 -> 0 bytes
-rw-r--r--chromium/chrome/browser/resources/hotword_audio_verification/images/ic-x-white-2x.pngbin191 -> 0 bytes
-rw-r--r--chromium/chrome/browser/resources/hotword_audio_verification/images/icon-128.pngbin910 -> 0 bytes
-rw-r--r--chromium/chrome/browser/resources/hotword_audio_verification/images/icon-16.pngbin182 -> 0 bytes
-rw-r--r--chromium/chrome/browser/resources/hotword_audio_verification/images/icon-48.pngbin373 -> 0 bytes
-rw-r--r--chromium/chrome/browser/resources/hotword_audio_verification/images/intro-1x.pngbin7920 -> 0 bytes
-rw-r--r--chromium/chrome/browser/resources/hotword_audio_verification/images/intro-2x.pngbin9665 -> 0 bytes
-rw-r--r--chromium/chrome/browser/resources/hotword_audio_verification/images/placeholder-loader-1x.pngbin289 -> 0 bytes
-rw-r--r--chromium/chrome/browser/resources/hotword_audio_verification/images/placeholder-loader-2x.pngbin534 -> 0 bytes
-rw-r--r--chromium/chrome/browser/resources/hotword_audio_verification/main.html25
-rw-r--r--chromium/chrome/browser/resources/hotword_audio_verification/main.js50
-rw-r--r--chromium/chrome/browser/resources/hotword_audio_verification/manifest.json27
-rw-r--r--chromium/chrome/browser/resources/hotword_audio_verification/steps/audio_history_step.html38
-rw-r--r--chromium/chrome/browser/resources/hotword_audio_verification/steps/finished_step.html30
-rw-r--r--chromium/chrome/browser/resources/hotword_audio_verification/steps/speech_training_step.html56
-rw-r--r--chromium/chrome/browser/resources/hotword_audio_verification/steps/start_step.html17
-rw-r--r--chromium/chrome/browser/resources/hotword_audio_verification/style.css361
-rw-r--r--chromium/chrome/browser/resources/inspect/inspect.css13
-rw-r--r--chromium/chrome/browser/resources/instant/instant.css15
-rw-r--r--chromium/chrome/browser/resources/instant/instant.html24
-rw-r--r--chromium/chrome/browser/resources/instant/instant.js163
-rw-r--r--chromium/chrome/browser/resources/interventions_internals/OWNERS3
-rw-r--r--chromium/chrome/browser/resources/interventions_internals/index.css251
-rw-r--r--chromium/chrome/browser/resources/interventions_internals/index.html98
-rw-r--r--chromium/chrome/browser/resources/interventions_internals/index.js381
-rw-r--r--chromium/chrome/browser/resources/local_ntp/local_ntp.css84
-rw-r--r--chromium/chrome/browser/resources/local_ntp/local_ntp.html17
-rw-r--r--chromium/chrome/browser/resources/local_ntp/local_ntp.js170
-rw-r--r--chromium/chrome/browser/resources/local_ntp/most_visited_single.css120
-rw-r--r--chromium/chrome/browser/resources/local_ntp/most_visited_single.html1
-rw-r--r--chromium/chrome/browser/resources/local_ntp/most_visited_single.js51
-rw-r--r--chromium/chrome/browser/resources/local_ntp/voice.css12
-rw-r--r--chromium/chrome/browser/resources/md_bookmarks/OWNERS1
-rw-r--r--chromium/chrome/browser/resources/md_bookmarks/dnd_manager.js5
-rw-r--r--chromium/chrome/browser/resources/md_bookmarks/list.html2
-rw-r--r--chromium/chrome/browser/resources/md_downloads/downloads.html2
-rw-r--r--chromium/chrome/browser/resources/md_downloads/item.js6
-rw-r--r--chromium/chrome/browser/resources/md_downloads/toolbar.html1
-rw-r--r--chromium/chrome/browser/resources/md_extensions/compiled_resources2.gyp30
-rw-r--r--chromium/chrome/browser/resources/md_extensions/detail_view.html254
-rw-r--r--chromium/chrome/browser/resources/md_extensions/detail_view.js89
-rw-r--r--chromium/chrome/browser/resources/md_extensions/drag_and_drop_handler.js78
-rw-r--r--chromium/chrome/browser/resources/md_extensions/drop_overlay.html15
-rw-r--r--chromium/chrome/browser/resources/md_extensions/drop_overlay.js7
-rw-r--r--chromium/chrome/browser/resources/md_extensions/error_page.html76
-rw-r--r--chromium/chrome/browser/resources/md_extensions/error_page.js113
-rw-r--r--chromium/chrome/browser/resources/md_extensions/error_severity_fatal.pngbin218 -> 0 bytes
-rw-r--r--chromium/chrome/browser/resources/md_extensions/error_severity_info.pngbin304 -> 0 bytes
-rw-r--r--chromium/chrome/browser/resources/md_extensions/error_severity_warning.pngbin242 -> 0 bytes
-rw-r--r--chromium/chrome/browser/resources/md_extensions/extensions.html23
-rw-r--r--chromium/chrome/browser/resources/md_extensions/extensions.js12
-rw-r--r--chromium/chrome/browser/resources/md_extensions/extensions_resources.grd21
-rw-r--r--chromium/chrome/browser/resources/md_extensions/install_warnings_dialog.html40
-rw-r--r--chromium/chrome/browser/resources/md_extensions/install_warnings_dialog.js28
-rw-r--r--chromium/chrome/browser/resources/md_extensions/item.html249
-rw-r--r--chromium/chrome/browser/resources/md_extensions/item.js72
-rw-r--r--chromium/chrome/browser/resources/md_extensions/item_behavior.html1
-rw-r--r--chromium/chrome/browser/resources/md_extensions/item_behavior.js30
-rw-r--r--chromium/chrome/browser/resources/md_extensions/item_list.html53
-rw-r--r--chromium/chrome/browser/resources/md_extensions/item_list.js92
-rw-r--r--chromium/chrome/browser/resources/md_extensions/item_util.js46
-rw-r--r--chromium/chrome/browser/resources/md_extensions/keyboard_shortcuts.html39
-rw-r--r--chromium/chrome/browser/resources/md_extensions/keyboard_shortcuts.js11
-rw-r--r--chromium/chrome/browser/resources/md_extensions/kiosk_dialog.html7
-rw-r--r--chromium/chrome/browser/resources/md_extensions/kiosk_dialog.js2
-rw-r--r--chromium/chrome/browser/resources/md_extensions/load_error.html5
-rw-r--r--chromium/chrome/browser/resources/md_extensions/load_error.js18
-rw-r--r--chromium/chrome/browser/resources/md_extensions/manager.html78
-rw-r--r--chromium/chrome/browser/resources/md_extensions/manager.js398
-rw-r--r--chromium/chrome/browser/resources/md_extensions/navigation_helper.js89
-rw-r--r--chromium/chrome/browser/resources/md_extensions/options_dialog.html23
-rw-r--r--chromium/chrome/browser/resources/md_extensions/options_dialog.js32
-rw-r--r--chromium/chrome/browser/resources/md_extensions/pack_dialog.html2
-rw-r--r--chromium/chrome/browser/resources/md_extensions/pack_dialog.js34
-rw-r--r--chromium/chrome/browser/resources/md_extensions/pack_dialog_alert.html13
-rw-r--r--chromium/chrome/browser/resources/md_extensions/pack_dialog_alert.js28
-rw-r--r--chromium/chrome/browser/resources/md_extensions/service.js196
-rw-r--r--chromium/chrome/browser/resources/md_extensions/shortcut_input.html11
-rw-r--r--chromium/chrome/browser/resources/md_extensions/shortcut_input.js78
-rw-r--r--chromium/chrome/browser/resources/md_extensions/sidebar.html102
-rw-r--r--chromium/chrome/browser/resources/md_extensions/sidebar.js47
-rw-r--r--chromium/chrome/browser/resources/md_extensions/toggle_row.html49
-rw-r--r--chromium/chrome/browser/resources/md_extensions/toggle_row.js85
-rw-r--r--chromium/chrome/browser/resources/md_extensions/toolbar.html54
-rw-r--r--chromium/chrome/browser/resources/md_extensions/toolbar.js46
-rw-r--r--chromium/chrome/browser/resources/md_extensions/view_manager.js32
-rw-r--r--chromium/chrome/browser/resources/md_history/OWNERS1
-rw-r--r--chromium/chrome/browser/resources/md_history/app.html1
-rw-r--r--chromium/chrome/browser/resources/md_history/browser_service.js2
-rw-r--r--chromium/chrome/browser/resources/md_history/history_item.html10
-rw-r--r--chromium/chrome/browser/resources/md_history/history_list.html2
-rw-r--r--chromium/chrome/browser/resources/md_history/history_list.js16
-rw-r--r--chromium/chrome/browser/resources/md_history/history_toolbar.html2
-rw-r--r--chromium/chrome/browser/resources/md_history/history_toolbar.js9
-rw-r--r--chromium/chrome/browser/resources/md_history/shared_style.html10
-rw-r--r--chromium/chrome/browser/resources/md_history/shared_vars.html2
-rw-r--r--chromium/chrome/browser/resources/md_history/side_bar.html1
-rw-r--r--chromium/chrome/browser/resources/md_history/synced_device_card.html8
-rw-r--r--chromium/chrome/browser/resources/md_user_manager/create_profile.html6
-rw-r--r--chromium/chrome/browser/resources/md_user_manager/icons.html14
-rw-r--r--chromium/chrome/browser/resources/md_user_manager/supervised_user_create_confirm.html11
-rw-r--r--chromium/chrome/browser/resources/md_user_manager/supervised_user_learn_more.html11
-rw-r--r--chromium/chrome/browser/resources/md_user_manager/user_manager.html15
-rw-r--r--chromium/chrome/browser/resources/md_user_manager/user_manager_pages.html8
-rw-r--r--chromium/chrome/browser/resources/md_user_manager/user_manager_pages.js14
-rw-r--r--chromium/chrome/browser/resources/media/media_engagement.html43
-rw-r--r--chromium/chrome/browser/resources/media/media_engagement.js50
-rw-r--r--chromium/chrome/browser/resources/media_router/elements/issue_banner/issue_banner.html4
-rw-r--r--chromium/chrome/browser/resources/media_router/elements/route_controls/route_controls.css29
-rw-r--r--chromium/chrome/browser/resources/media_router/elements/route_controls/route_controls.html28
-rw-r--r--chromium/chrome/browser/resources/media_router/elements/route_controls/route_controls.js57
-rw-r--r--chromium/chrome/browser/resources/media_router/elements/route_details/route_details.css4
-rw-r--r--chromium/chrome/browser/resources/media_router/elements/route_details/route_details.html6
-rw-r--r--chromium/chrome/browser/resources/media_router/elements/route_details/route_details.js17
-rw-r--r--chromium/chrome/browser/resources/media_router/icons/media_router_icons.html1
-rw-r--r--chromium/chrome/browser/resources/media_router/media_router.css1
-rw-r--r--chromium/chrome/browser/resources/media_router/media_router_browser_api.js12
-rw-r--r--chromium/chrome/browser/resources/media_router/media_router_common.css14
-rw-r--r--chromium/chrome/browser/resources/media_router/media_router_data.js7
-rw-r--r--chromium/chrome/browser/resources/net_internals/browser_bridge.js9
-rw-r--r--chromium/chrome/browser/resources/net_internals/domain_security_policy_view.html13
-rw-r--r--chromium/chrome/browser/resources/net_internals/domain_security_policy_view.js34
-rw-r--r--chromium/chrome/browser/resources/net_internals/events_view.js7
-rw-r--r--chromium/chrome/browser/resources/net_internals/log_util.js20
-rw-r--r--chromium/chrome/browser/resources/net_internals/log_view_painter.js144
-rw-r--r--chromium/chrome/browser/resources/net_internals/main.js11
-rw-r--r--chromium/chrome/browser/resources/net_internals/source_entry.js2
-rw-r--r--chromium/chrome/browser/resources/net_internals/source_tracker.js29
-rw-r--r--chromium/chrome/browser/resources/ntp4/app_launcher_promo.pngbin6939 -> 0 bytes
-rw-r--r--chromium/chrome/browser/resources/ntp4/apps_page.css61
-rw-r--r--chromium/chrome/browser/resources/ntp4/incognito_tab.css288
-rw-r--r--chromium/chrome/browser/resources/ntp4/incognito_tab.html42
-rw-r--r--chromium/chrome/browser/resources/ntp4/incognito_tab.js (renamed from chromium/chrome/browser/resources/ntp4/md_incognito_tab.js)0
-rw-r--r--chromium/chrome/browser/resources/ntp4/md_incognito_tab.css300
-rw-r--r--chromium/chrome/browser/resources/ntp4/md_incognito_tab.html40
-rw-r--r--chromium/chrome/browser/resources/ntp4/new_tab.html12
-rw-r--r--chromium/chrome/browser/resources/ntp4/new_tab.js9
-rw-r--r--chromium/chrome/browser/resources/ntp4/page_list_view.js21
-rw-r--r--chromium/chrome/browser/resources/offline_pages/offline_internals.css11
-rw-r--r--chromium/chrome/browser/resources/offline_pages/offline_internals.html9
-rw-r--r--chromium/chrome/browser/resources/offline_pages/offline_internals.js71
-rw-r--r--chromium/chrome/browser/resources/offline_pages/offline_internals_browser_proxy.js2
-rw-r--r--chromium/chrome/browser/resources/password_manager_internals/OWNERS4
-rw-r--r--chromium/chrome/browser/resources/password_manager_internals/password_manager_internals.css31
-rw-r--r--chromium/chrome/browser/resources/password_manager_internals/password_manager_internals.html25
-rw-r--r--chromium/chrome/browser/resources/password_manager_internals/password_manager_internals.js17
-rw-r--r--chromium/chrome/browser/resources/password_manager_internals_resources.grd16
-rw-r--r--chromium/chrome/browser/resources/pdf/compiled_resources2.gyp7
-rw-r--r--chromium/chrome/browser/resources/pdf/elements/viewer-page-selector/viewer-page-selector.html5
-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-toolbar-dropdown/viewer-toolbar-dropdown.html2
-rw-r--r--chromium/chrome/browser/resources/pdf/elements/viewer-zoom-toolbar/viewer-zoom-toolbar.js44
-rw-r--r--chromium/chrome/browser/resources/pdf/gesture_detector.js89
-rw-r--r--chromium/chrome/browser/resources/pdf/index.html1
-rw-r--r--chromium/chrome/browser/resources/pdf/open_pdf_params_parser.js100
-rw-r--r--chromium/chrome/browser/resources/pdf/pdf.js87
-rw-r--r--chromium/chrome/browser/resources/pdf/pdf_fitting_type.js16
-rw-r--r--chromium/chrome/browser/resources/pdf/viewport.js208
-rw-r--r--chromium/chrome/browser/resources/plugin_metadata/plugins_linux.json6
-rw-r--r--chromium/chrome/browser/resources/plugin_metadata/plugins_mac.json6
-rw-r--r--chromium/chrome/browser/resources/plugin_metadata/plugins_win.json6
-rw-r--r--chromium/chrome/browser/resources/policy_tool.css4
-rw-r--r--chromium/chrome/browser/resources/policy_tool.html3
-rw-r--r--chromium/chrome/browser/resources/policy_tool.js20
-rw-r--r--chromium/chrome/browser/resources/print_preview/.eslintrc.js13
-rw-r--r--chromium/chrome/browser/resources/print_preview/cloud_print_interface.js547
-rw-r--r--chromium/chrome/browser/resources/print_preview/common/overlay.js2
-rw-r--r--chromium/chrome/browser/resources/print_preview/common/search_box.js6
-rw-r--r--chromium/chrome/browser/resources/print_preview/common/search_bubble.js14
-rw-r--r--chromium/chrome/browser/resources/print_preview/compiled_resources2.gyp11
-rw-r--r--chromium/chrome/browser/resources/print_preview/component.js6
-rw-r--r--chromium/chrome/browser/resources/print_preview/data/app_state.js29
-rw-r--r--chromium/chrome/browser/resources/print_preview/data/cloud_parsers.js151
-rw-r--r--chromium/chrome/browser/resources/print_preview/data/compiled_resources2.gyp58
-rw-r--r--chromium/chrome/browser/resources/print_preview/data/coordinate2d.html3
-rw-r--r--chromium/chrome/browser/resources/print_preview/data/destination.html4
-rw-r--r--chromium/chrome/browser/resources/print_preview/data/destination.js75
-rw-r--r--chromium/chrome/browser/resources/print_preview/data/destination_match.js2
-rw-r--r--chromium/chrome/browser/resources/print_preview/data/destination_store.js174
-rw-r--r--chromium/chrome/browser/resources/print_preview/data/document_info.html7
-rw-r--r--chromium/chrome/browser/resources/print_preview/data/document_info.js217
-rw-r--r--chromium/chrome/browser/resources/print_preview/data/invitation_store.js148
-rw-r--r--chromium/chrome/browser/resources/print_preview/data/local_parsers.js22
-rw-r--r--chromium/chrome/browser/resources/print_preview/data/margins.js20
-rw-r--r--chromium/chrome/browser/resources/print_preview/data/measurement_system.js168
-rw-r--r--chromium/chrome/browser/resources/print_preview/data/print_ticket_store.js43
-rw-r--r--chromium/chrome/browser/resources/print_preview/data/printable_area.html5
-rw-r--r--chromium/chrome/browser/resources/print_preview/data/size.html3
-rw-r--r--chromium/chrome/browser/resources/print_preview/data/ticket_items/collate.js4
-rw-r--r--chromium/chrome/browser/resources/print_preview/data/ticket_items/color.js26
-rw-r--r--chromium/chrome/browser/resources/print_preview/data/ticket_items/copies.js6
-rw-r--r--chromium/chrome/browser/resources/print_preview/data/ticket_items/custom_margins.js42
-rw-r--r--chromium/chrome/browser/resources/print_preview/data/ticket_items/dpi.js6
-rw-r--r--chromium/chrome/browser/resources/print_preview/data/ticket_items/duplex.js12
-rw-r--r--chromium/chrome/browser/resources/print_preview/data/ticket_items/header_footer.js6
-rw-r--r--chromium/chrome/browser/resources/print_preview/data/ticket_items/landscape.js18
-rw-r--r--chromium/chrome/browser/resources/print_preview/data/ticket_items/media_size.js10
-rw-r--r--chromium/chrome/browser/resources/print_preview/data/ticket_items/page_range.js10
-rw-r--r--chromium/chrome/browser/resources/print_preview/data/ticket_items/scaling.js4
-rw-r--r--chromium/chrome/browser/resources/print_preview/data/ticket_items/ticket_item.js2
-rw-r--r--chromium/chrome/browser/resources/print_preview/data/ticket_items/vendor_items.js6
-rw-r--r--chromium/chrome/browser/resources/print_preview/data/user_info.js80
-rw-r--r--chromium/chrome/browser/resources/print_preview/native_layer.js50
-rw-r--r--chromium/chrome/browser/resources/print_preview/new/advanced_options_settings.html23
-rw-r--r--chromium/chrome/browser/resources/print_preview/new/advanced_options_settings.js7
-rw-r--r--chromium/chrome/browser/resources/print_preview/new/app.html95
-rw-r--r--chromium/chrome/browser/resources/print_preview/new/app.js37
-rw-r--r--chromium/chrome/browser/resources/print_preview/new/button_css.html26
-rw-r--r--chromium/chrome/browser/resources/print_preview/new/checkbox_radio_css.html123
-rw-r--r--chromium/chrome/browser/resources/print_preview/new/color_settings.html22
-rw-r--r--chromium/chrome/browser/resources/print_preview/new/color_settings.js7
-rw-r--r--chromium/chrome/browser/resources/print_preview/new/compiled_resources2.gyp135
-rw-r--r--chromium/chrome/browser/resources/print_preview/new/copies_settings.html28
-rw-r--r--chromium/chrome/browser/resources/print_preview/new/copies_settings.js56
-rw-r--r--chromium/chrome/browser/resources/print_preview/new/destination_settings.html81
-rw-r--r--chromium/chrome/browser/resources/print_preview/new/destination_settings.js27
-rw-r--r--chromium/chrome/browser/resources/print_preview/new/dpi_settings.html20
-rw-r--r--chromium/chrome/browser/resources/print_preview/new/dpi_settings.js7
-rw-r--r--chromium/chrome/browser/resources/print_preview/new/header.html85
-rw-r--r--chromium/chrome/browser/resources/print_preview/new/header.js190
-rw-r--r--chromium/chrome/browser/resources/print_preview/new/input_css.html33
-rw-r--r--chromium/chrome/browser/resources/print_preview/new/layout_settings.html21
-rw-r--r--chromium/chrome/browser/resources/print_preview/new/layout_settings.js7
-rw-r--r--chromium/chrome/browser/resources/print_preview/new/margins_settings.html27
-rw-r--r--chromium/chrome/browser/resources/print_preview/new/margins_settings.js7
-rw-r--r--chromium/chrome/browser/resources/print_preview/new/media_size_settings.html20
-rw-r--r--chromium/chrome/browser/resources/print_preview/new/media_size_settings.js7
-rw-r--r--chromium/chrome/browser/resources/print_preview/new/model.html6
-rw-r--r--chromium/chrome/browser/resources/print_preview/new/model.js338
-rw-r--r--chromium/chrome/browser/resources/print_preview/new/number_settings_section.html48
-rw-r--r--chromium/chrome/browser/resources/print_preview/new/number_settings_section.js70
-rw-r--r--chromium/chrome/browser/resources/print_preview/new/other_options_settings.html48
-rw-r--r--chromium/chrome/browser/resources/print_preview/new/other_options_settings.js32
-rw-r--r--chromium/chrome/browser/resources/print_preview/new/pages_settings.html58
-rw-r--r--chromium/chrome/browser/resources/print_preview/new/pages_settings.js215
-rw-r--r--chromium/chrome/browser/resources/print_preview/new/print_preview_shared_css.html136
-rw-r--r--chromium/chrome/browser/resources/print_preview/new/scaling_settings.html28
-rw-r--r--chromium/chrome/browser/resources/print_preview/new/scaling_settings.js80
-rw-r--r--chromium/chrome/browser/resources/print_preview/new/select_css.html40
-rw-r--r--chromium/chrome/browser/resources/print_preview/new/settings_behavior.html3
-rw-r--r--chromium/chrome/browser/resources/print_preview/new/settings_behavior.js48
-rw-r--r--chromium/chrome/browser/resources/print_preview/new/settings_section.html34
-rw-r--r--chromium/chrome/browser/resources/print_preview/new/settings_section.js7
-rw-r--r--chromium/chrome/browser/resources/print_preview/new/strings.html2
-rw-r--r--chromium/chrome/browser/resources/print_preview/new/throbber_css.html15
-rw-r--r--chromium/chrome/browser/resources/print_preview/preview_generator.js371
-rw-r--r--chromium/chrome/browser/resources/print_preview/previewarea/margin_control.js20
-rw-r--r--chromium/chrome/browser/resources/print_preview/previewarea/margin_control_container.js48
-rw-r--r--chromium/chrome/browser/resources/print_preview/previewarea/preview_area.js34
-rw-r--r--chromium/chrome/browser/resources/print_preview/print_header.js24
-rw-r--r--chromium/chrome/browser/resources/print_preview/print_preview.js82
-rw-r--r--chromium/chrome/browser/resources/print_preview/print_preview_animations.js39
-rw-r--r--chromium/chrome/browser/resources/print_preview/print_preview_focus_manager.js4
-rw-r--r--chromium/chrome/browser/resources/print_preview/print_preview_new.html21
-rw-r--r--chromium/chrome/browser/resources/print_preview/print_preview_resources.grd185
-rw-r--r--chromium/chrome/browser/resources/print_preview/print_preview_utils.html3
-rw-r--r--chromium/chrome/browser/resources/print_preview/print_preview_utils.js50
-rw-r--r--chromium/chrome/browser/resources/print_preview/search/cloud_destination_list.js39
-rw-r--r--chromium/chrome/browser/resources/print_preview/search/destination_list.js33
-rw-r--r--chromium/chrome/browser/resources/print_preview/search/destination_list_item.js32
-rw-r--r--chromium/chrome/browser/resources/print_preview/search/destination_search.html3
-rw-r--r--chromium/chrome/browser/resources/print_preview/search/destination_search.js188
-rw-r--r--chromium/chrome/browser/resources/print_preview/search/provisional_destination_resolver.js4
-rw-r--r--chromium/chrome/browser/resources/print_preview/settings/advanced_settings/advanced_settings.js24
-rw-r--r--chromium/chrome/browser/resources/print_preview/settings/advanced_settings/advanced_settings_item.js30
-rw-r--r--chromium/chrome/browser/resources/print_preview/settings/color_settings.js10
-rw-r--r--chromium/chrome/browser/resources/print_preview/settings/copies_settings.js2
-rw-r--r--chromium/chrome/browser/resources/print_preview/settings/destination_settings.js26
-rw-r--r--chromium/chrome/browser/resources/print_preview/settings/dpi_settings.js4
-rw-r--r--chromium/chrome/browser/resources/print_preview/settings/layout_settings.js10
-rw-r--r--chromium/chrome/browser/resources/print_preview/settings/margin_settings.js10
-rw-r--r--chromium/chrome/browser/resources/print_preview/settings/more_settings.js8
-rw-r--r--chromium/chrome/browser/resources/print_preview/settings/other_options_settings.js8
-rw-r--r--chromium/chrome/browser/resources/print_preview/settings/page_settings.js6
-rw-r--r--chromium/chrome/browser/resources/print_preview/settings/scaling_settings.js2
-rw-r--r--chromium/chrome/browser/resources/print_preview/settings/settings_section.js5
-rw-r--r--chromium/chrome/browser/resources/print_preview/settings/settings_section_select.js16
-rw-r--r--chromium/chrome/browser/resources/safe_browsing/download_file_types.asciipb216
-rw-r--r--chromium/chrome/browser/resources/settings/about_page/about_page.html9
-rw-r--r--chromium/chrome/browser/resources/settings/about_page/about_page.js8
-rw-r--r--chromium/chrome/browser/resources/settings/android_apps_page/android_apps_page.html3
-rw-r--r--chromium/chrome/browser/resources/settings/android_apps_page/android_apps_subpage.js2
-rw-r--r--chromium/chrome/browser/resources/settings/basic_page/basic_page.html4
-rw-r--r--chromium/chrome/browser/resources/settings/basic_page/basic_page.js8
-rw-r--r--chromium/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.js8
-rw-r--r--chromium/chrome/browser/resources/settings/bluetooth_page/bluetooth_subpage.html18
-rw-r--r--chromium/chrome/browser/resources/settings/bluetooth_page/bluetooth_subpage.js152
-rw-r--r--chromium/chrome/browser/resources/settings/chrome_cleanup_page/chrome_cleanup_page.html7
-rw-r--r--chromium/chrome/browser/resources/settings/clear_browsing_data_dialog/clear_browsing_data_dialog_tabs.html1
-rw-r--r--chromium/chrome/browser/resources/settings/controls/compiled_resources2.gyp1
-rw-r--r--chromium/chrome/browser/resources/settings/controls/settings_toggle_button.html13
-rw-r--r--chromium/chrome/browser/resources/settings/controls/settings_toggle_button.js31
-rw-r--r--chromium/chrome/browser/resources/settings/date_time_page/compiled_resources2.gyp35
-rw-r--r--chromium/chrome/browser/resources/settings/date_time_page/date_time_page.html168
-rw-r--r--chromium/chrome/browser/resources/settings/date_time_page/date_time_page.js242
-rw-r--r--chromium/chrome/browser/resources/settings/date_time_page/date_time_types.html2
-rw-r--r--chromium/chrome/browser/resources/settings/date_time_page/date_time_types.js48
-rw-r--r--chromium/chrome/browser/resources/settings/date_time_page/timezone_selector.html52
-rw-r--r--chromium/chrome/browser/resources/settings/date_time_page/timezone_selector.js153
-rw-r--r--chromium/chrome/browser/resources/settings/date_time_page/timezone_subpage.html54
-rw-r--r--chromium/chrome/browser/resources/settings/date_time_page/timezone_subpage.js43
-rw-r--r--chromium/chrome/browser/resources/settings/device_page/display.html45
-rw-r--r--chromium/chrome/browser/resources/settings/device_page/display.js38
-rw-r--r--chromium/chrome/browser/resources/settings/device_page/display_layout.html14
-rw-r--r--chromium/chrome/browser/resources/settings/device_page/display_layout.js33
-rw-r--r--chromium/chrome/browser/resources/settings/device_page/stylus.html9
-rw-r--r--chromium/chrome/browser/resources/settings/icons.html7
-rw-r--r--chromium/chrome/browser/resources/settings/internet_page/compiled_resources2.gyp24
-rw-r--r--chromium/chrome/browser/resources/settings/internet_page/internet_config.html57
-rw-r--r--chromium/chrome/browser/resources/settings/internet_page/internet_config.js124
-rw-r--r--chromium/chrome/browser/resources/settings/internet_page/internet_detail_page.html22
-rw-r--r--chromium/chrome/browser/resources/settings/internet_page/internet_detail_page.js117
-rw-r--r--chromium/chrome/browser/resources/settings/internet_page/internet_known_networks_page.js31
-rw-r--r--chromium/chrome/browser/resources/settings/internet_page/internet_page.html30
-rw-r--r--chromium/chrome/browser/resources/settings/internet_page/internet_page.js153
-rw-r--r--chromium/chrome/browser/resources/settings/internet_page/internet_page_browser_proxy.html2
-rw-r--r--chromium/chrome/browser/resources/settings/internet_page/internet_page_browser_proxy.js78
-rw-r--r--chromium/chrome/browser/resources/settings/internet_page/internet_shared_css.html1
-rw-r--r--chromium/chrome/browser/resources/settings/internet_page/internet_subpage.html22
-rw-r--r--chromium/chrome/browser/resources/settings/internet_page/internet_subpage.js104
-rw-r--r--chromium/chrome/browser/resources/settings/internet_page/network_siminfo.html199
-rw-r--r--chromium/chrome/browser/resources/settings/internet_page/network_siminfo.js402
-rw-r--r--chromium/chrome/browser/resources/settings/internet_page/network_summary.js45
-rw-r--r--chromium/chrome/browser/resources/settings/internet_page/network_summary_item.html2
-rw-r--r--chromium/chrome/browser/resources/settings/internet_page/network_summary_item.js38
-rw-r--r--chromium/chrome/browser/resources/settings/internet_page/tether_connection_dialog.html1
-rw-r--r--chromium/chrome/browser/resources/settings/languages_page/languages.js46
-rw-r--r--chromium/chrome/browser/resources/settings/languages_page/languages_page.html6
-rw-r--r--chromium/chrome/browser/resources/settings/languages_page/languages_page.js6
-rw-r--r--chromium/chrome/browser/resources/settings/languages_page/languages_types.js4
-rw-r--r--chromium/chrome/browser/resources/settings/on_startup_page/startup_urls_page.html20
-rw-r--r--chromium/chrome/browser/resources/settings/passwords_and_forms_page/autofill_section.html95
-rw-r--r--chromium/chrome/browser/resources/settings/passwords_and_forms_page/autofill_section.js11
-rw-r--r--chromium/chrome/browser/resources/settings/passwords_and_forms_page/password_edit_dialog.html18
-rw-r--r--chromium/chrome/browser/resources/settings/passwords_and_forms_page/password_list_item.html24
-rw-r--r--chromium/chrome/browser/resources/settings/passwords_and_forms_page/password_list_item.js2
-rw-r--r--chromium/chrome/browser/resources/settings/passwords_and_forms_page/passwords_export_dialog.html37
-rw-r--r--chromium/chrome/browser/resources/settings/passwords_and_forms_page/passwords_export_dialog.js52
-rw-r--r--chromium/chrome/browser/resources/settings/passwords_and_forms_page/passwords_section.html38
-rw-r--r--chromium/chrome/browser/resources/settings/passwords_and_forms_page/passwords_section.js85
-rw-r--r--chromium/chrome/browser/resources/settings/passwords_and_forms_page/show_password_behavior.js33
-rw-r--r--chromium/chrome/browser/resources/settings/people_page/change_picture.html9
-rw-r--r--chromium/chrome/browser/resources/settings/people_page/change_picture.js11
-rw-r--r--chromium/chrome/browser/resources/settings/people_page/manage_profile.html6
-rw-r--r--chromium/chrome/browser/resources/settings/people_page/password_prompt_dialog.js6
-rw-r--r--chromium/chrome/browser/resources/settings/people_page/people_page.html6
-rw-r--r--chromium/chrome/browser/resources/settings/people_page/setup_pin_dialog.html4
-rw-r--r--chromium/chrome/browser/resources/settings/people_page/sync_page.html46
-rw-r--r--chromium/chrome/browser/resources/settings/people_page/users_page.html12
-rw-r--r--chromium/chrome/browser/resources/settings/people_page/users_page.js9
-rw-r--r--chromium/chrome/browser/resources/settings/printing_page/compiled_resources2.gyp8
-rw-r--r--chromium/chrome/browser/resources/settings/printing_page/cups_add_printer_dialog.html2
-rw-r--r--chromium/chrome/browser/resources/settings/printing_page/cups_add_printer_dialog.js9
-rw-r--r--chromium/chrome/browser/resources/settings/printing_page/cups_printers.js2
-rw-r--r--chromium/chrome/browser/resources/settings/printing_page/cups_printers_browser_proxy.js2
-rw-r--r--chromium/chrome/browser/resources/settings/printing_page/printing_browser_proxy.html2
-rw-r--r--chromium/chrome/browser/resources/settings/printing_page/printing_browser_proxy.js35
-rw-r--r--chromium/chrome/browser/resources/settings/printing_page/printing_page.html11
-rw-r--r--chromium/chrome/browser/resources/settings/printing_page/printing_page.js6
-rw-r--r--chromium/chrome/browser/resources/settings/privacy_page/privacy_page.html24
-rw-r--r--chromium/chrome/browser/resources/settings/privacy_page/privacy_page.js8
-rw-r--r--chromium/chrome/browser/resources/settings/reset_page/compiled_resources2.gyp19
-rw-r--r--chromium/chrome/browser/resources/settings/reset_page/reset_browser_proxy.js1
-rw-r--r--chromium/chrome/browser/resources/settings/reset_page/reset_page.html102
-rw-r--r--chromium/chrome/browser/resources/settings/reset_page/reset_page.js24
-rw-r--r--chromium/chrome/browser/resources/settings/reset_page/reset_profile_dialog.js8
-rw-r--r--chromium/chrome/browser/resources/settings/route.js21
-rw-r--r--chromium/chrome/browser/resources/settings/search_engines_page/search_engines_browser_proxy.js28
-rw-r--r--chromium/chrome/browser/resources/settings/search_page/search_page.html56
-rw-r--r--chromium/chrome/browser/resources/settings/search_page/search_page.js79
-rw-r--r--chromium/chrome/browser/resources/settings/search_settings.js2
-rw-r--r--chromium/chrome/browser/resources/settings/settings_page/settings_section.html4
-rw-r--r--chromium/chrome/browser/resources/settings/settings_resources.grd47
-rw-r--r--chromium/chrome/browser/resources/settings/settings_ui/settings_ui.html1
-rw-r--r--chromium/chrome/browser/resources/settings/site_settings/category_default_setting.js1
-rw-r--r--chromium/chrome/browser/resources/settings/site_settings/compiled_resources2.gyp1
-rw-r--r--chromium/chrome/browser/resources/settings/site_settings/constants.js3
-rw-r--r--chromium/chrome/browser/resources/settings/site_settings/cookie_info.js2
-rw-r--r--chromium/chrome/browser/resources/settings/site_settings/local_data_browser_proxy.js12
-rw-r--r--chromium/chrome/browser/resources/settings/site_settings/protocol_handlers.html22
-rw-r--r--chromium/chrome/browser/resources/settings/site_settings/protocol_handlers.js43
-rw-r--r--chromium/chrome/browser/resources/settings/site_settings/site_data.html15
-rw-r--r--chromium/chrome/browser/resources/settings/site_settings/site_data.js15
-rw-r--r--chromium/chrome/browser/resources/settings/site_settings/site_data_details_subpage.js1
-rw-r--r--chromium/chrome/browser/resources/settings/site_settings/site_details.html12
-rw-r--r--chromium/chrome/browser/resources/settings/site_settings/site_details.js19
-rw-r--r--chromium/chrome/browser/resources/settings/site_settings/site_details_permission.html18
-rw-r--r--chromium/chrome/browser/resources/settings/site_settings/site_details_permission.js91
-rw-r--r--chromium/chrome/browser/resources/settings/site_settings/site_settings_prefs_browser_proxy.js15
-rw-r--r--chromium/chrome/browser/resources/settings/site_settings/usb_devices.html2
-rw-r--r--chromium/chrome/browser/resources/settings/site_settings_page/site_settings_page.html24
-rw-r--r--chromium/chrome/browser/resources/settings/site_settings_page/site_settings_page.js9
-rw-r--r--chromium/chrome/browser/resources/signin/dice_sync_confirmation/sync_confirmation.css322
-rw-r--r--chromium/chrome/browser/resources/signin/dice_sync_confirmation/sync_confirmation.html102
-rw-r--r--chromium/chrome/browser/resources/signin/dice_sync_confirmation/sync_confirmation.js72
-rw-r--r--chromium/chrome/browser/resources/snippets_internals.html9
-rw-r--r--chromium/chrome/browser/resources/snippets_internals.js3
-rw-r--r--chromium/chrome/browser/resources/task_scheduler_internals/resources.grd9
-rwxr-xr-xchromium/chrome/browser/resources/unpack_pak.py2
-rw-r--r--chromium/chrome/browser/resources/welcome/default.webpbin0 -> 28802 bytes
-rw-r--r--chromium/chrome/browser/resources/welcome/dice_welcome/compiled_resources2.gyp24
-rw-r--r--chromium/chrome/browser/resources/welcome/dice_welcome/welcome.css33
-rw-r--r--chromium/chrome/browser/resources/welcome/dice_welcome/welcome.html18
-rw-r--r--chromium/chrome/browser/resources/welcome/dice_welcome/welcome_app.html205
-rw-r--r--chromium/chrome/browser/resources/welcome/dice_welcome/welcome_app.js36
-rw-r--r--chromium/chrome/browser/resources/welcome/dice_welcome/welcome_browser_proxy.html2
-rw-r--r--chromium/chrome/browser/resources/welcome/dice_welcome/welcome_browser_proxy.js37
-rw-r--r--chromium/chrome/browser/resources/welcome/pin.webp (renamed from chromium/chrome/browser/resources/welcome/win10/pin-small.webp)bin4584 -> 4584 bytes
-rw-r--r--chromium/chrome/browser/resources/welcome/welcome.css2
-rw-r--r--chromium/chrome/browser/resources/welcome/welcome_win10.css (renamed from chromium/chrome/browser/resources/welcome/win10/inline.css)0
-rw-r--r--chromium/chrome/browser/resources/welcome/welcome_win10.html (renamed from chromium/chrome/browser/resources/welcome/win10/inline.html)77
-rw-r--r--chromium/chrome/browser/resources/welcome/welcome_win10.js (renamed from chromium/chrome/browser/resources/welcome/win10/inline.js)37
-rw-r--r--chromium/chrome/browser/resources/welcome/win10/README.md7
-rw-r--r--chromium/chrome/browser/resources/welcome/win10/default-large.webpbin6210 -> 0 bytes
-rw-r--r--chromium/chrome/browser/resources/welcome/win10/default-small.webpbin3334 -> 0 bytes
-rw-r--r--chromium/chrome/browser/resources/welcome/win10/pin-large.webpbin15036 -> 0 bytes
-rw-r--r--chromium/chrome/browser/resources/welcome/win10/sectioned.css323
-rw-r--r--chromium/chrome/browser/resources/welcome/win10/sectioned.html90
-rw-r--r--chromium/chrome/browser/resources/welcome/win10/sectioned.js74
472 files changed, 12567 insertions, 10706 deletions
diff --git a/chromium/chrome/browser/resources/BUILD.gn b/chromium/chrome/browser/resources/BUILD.gn
index b2d10f2a0ba..f0559f28e62 100644
--- a/chromium/chrome/browser/resources/BUILD.gn
+++ b/chromium/chrome/browser/resources/BUILD.gn
@@ -27,16 +27,6 @@ grit("net_internals_resources") {
output_dir = "$root_gen_dir/chrome"
}
-grit("password_manager_internals_resources") {
- source = "password_manager_internals_resources.grd"
- defines = chrome_grit_defines
- outputs = [
- "grit/password_manager_internals_resources.h",
- "password_manager_internals_resources.pak",
- ]
- output_dir = "$root_gen_dir/chrome"
-}
-
grit("quota_internals_resources") {
source = "quota_internals_resources.grd"
defines = chrome_grit_defines
@@ -163,6 +153,20 @@ if (enable_extensions) {
}
}
+if (enable_print_preview) {
+ grit("print_preview_resources") {
+ source = "print_preview/print_preview_resources.grd"
+ defines = chrome_grit_defines
+ outputs = [
+ "grit/print_preview_resources.h",
+ "grit/print_preview_resources_map.cc",
+ "grit/print_preview_resources_map.h",
+ "print_preview_resources.pak",
+ ]
+ output_dir = "$root_gen_dir/chrome"
+ }
+}
+
if (enable_vr) {
grit("vr_shell_resources") {
source = "vr_shell_resources.grd"
diff --git a/chromium/chrome/browser/resources/bluetooth_internals/bluetooth_internals.css b/chromium/chrome/browser/resources/bluetooth_internals/bluetooth_internals.css
index c0f225af31f..55b21cbfd64 100644
--- a/chromium/chrome/browser/resources/bluetooth_internals/bluetooth_internals.css
+++ b/chromium/chrome/browser/resources/bluetooth_internals/bluetooth_internals.css
@@ -26,6 +26,10 @@ h1 {
color: rgb(92, 97, 102);
}
+.info-container h4 button.show-all-properties {
+ margin: 10px;
+}
+
.toggle-status {
background-image: url(../../../../ui/webui/resources/images/cancel_red.svg);
background-repeat: no-repeat;
diff --git a/chromium/chrome/browser/resources/bluetooth_internals/characteristic_list.js b/chromium/chrome/browser/resources/bluetooth_internals/characteristic_list.js
index ecee19eb0fe..c2372998a34 100644
--- a/chromium/chrome/browser/resources/bluetooth_internals/characteristic_list.js
+++ b/chromium/chrome/browser/resources/bluetooth_internals/characteristic_list.js
@@ -88,6 +88,7 @@ cr.define('characteristic_list', function() {
this.propertiesFieldSet_.setPropertyDisplayNames(
PROPERTIES_PROPERTY_NAMES);
var Property = bluetooth.mojom.Property;
+ this.propertiesFieldSet_.showAll = false;
this.propertiesFieldSet_.setObject({
broadcast: (this.info.properties & Property.BROADCAST) > 0,
read: (this.info.properties & Property.READ) > 0,
@@ -148,6 +149,17 @@ cr.define('characteristic_list', function() {
var propertiesHeader = document.createElement('h4');
propertiesHeader.textContent = 'Properties';
+ var propertiesBtn = document.createElement('button');
+ propertiesBtn.textContent = 'Show All';
+ propertiesBtn.classList.add('show-all-properties');
+ propertiesBtn.addEventListener('click', () => {
+ this.propertiesFieldSet_.showAll = !this.propertiesFieldSet_.showAll;
+ propertiesBtn.textContent =
+ this.propertiesFieldSet_.showAll ? 'Hide' : 'Show all';
+ this.propertiesFieldSet_.redraw();
+ });
+ propertiesHeader.appendChild(propertiesBtn);
+
var propertiesDiv = document.createElement('div');
propertiesDiv.classList.add('flex');
propertiesDiv.appendChild(this.propertiesFieldSet_);
diff --git a/chromium/chrome/browser/resources/bluetooth_internals/object_fieldset.js b/chromium/chrome/browser/resources/bluetooth_internals/object_fieldset.js
index f433c6f2629..c28fb097ad1 100644
--- a/chromium/chrome/browser/resources/bluetooth_internals/object_fieldset.js
+++ b/chromium/chrome/browser/resources/bluetooth_internals/object_fieldset.js
@@ -26,6 +26,14 @@ cr.define('object_fieldset', function() {
ObjectFieldSet.prototype = {
__proto__: HTMLFieldSetElement.prototype,
+ set showAll(showAll) {
+ this.showAll_ = showAll;
+ },
+
+ get showAll() {
+ return this.showAll_;
+ },
+
/**
* Decorates the element as an ObjectFieldset.
*/
@@ -36,6 +44,7 @@ cr.define('object_fieldset', function() {
this.value = null;
/** @private {?Object<string, string>} */
this.nameMap_ = null;
+ this.showAll_ = true;
},
/**
@@ -63,8 +72,11 @@ cr.define('object_fieldset', function() {
this.innerHTML = '';
Object.keys(this.value).forEach(function(propName) {
- var name = this.nameMap_[propName] || propName;
var value = this.value[propName];
+ if (value === false && !this.showAll_)
+ return;
+
+ var name = this.nameMap_[propName] || propName;
var newField = document.createElement('div');
newField.classList.add('status');
diff --git a/chromium/chrome/browser/resources/bluetooth_internals/value_control.js b/chromium/chrome/browser/resources/bluetooth_internals/value_control.js
index 69dfc188cf8..9a8ea9133f2 100644
--- a/chromium/chrome/browser/resources/bluetooth_internals/value_control.js
+++ b/chromium/chrome/browser/resources/bluetooth_internals/value_control.js
@@ -295,7 +295,9 @@ cr.define('value_control', function() {
this.readBtn_.hidden =
(this.properties_ & bluetooth.mojom.Property.READ) === 0;
this.writeBtn_.hidden =
- (this.properties_ & bluetooth.mojom.Property.WRITE) === 0;
+ (this.properties_ & bluetooth.mojom.Property.WRITE) === 0 &&
+ (this.properties_ &
+ bluetooth.mojom.Property.WRITE_WITHOUT_RESPONSE) === 0;
var isAvailable = !this.readBtn_.hidden || !this.writeBtn_.hidden;
this.unavailableMessage_.hidden = isAvailable;
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 dbbb3c6f00a..ed7b45e0e20 100644
--- a/chromium/chrome/browser/resources/chromeos/chromevox/strings/chromevox_strings.grd
+++ b/chromium/chrome/browser/resources/chromeos/chromevox/strings/chromevox_strings.grd
@@ -979,7 +979,7 @@
<message desc="Spoken in PowerKey if there are no jumps to display." name="IDS_CHROMEVOX_POWERKEY_NO_JUMPS">
No jumps.
</message>
- <message desc="Describes the list position of a list item." name="IDS_CHROMEVOX_LIST_POSITION">
+ <message desc="Describes the list position of a list item in spoken feedback." name="IDS_CHROMEVOX_LIST_POSITION">
<ph name="index">$1</ph> of <ph name="total">$2</ph>
</message>
<message desc="Describes the list position of a list item in braille." name="IDS_CHROMEVOX_LIST_POSITION_BRL">
diff --git a/chromium/chrome/browser/resources/chromeos/compiled_resources2.gyp b/chromium/chrome/browser/resources/chromeos/compiled_resources2.gyp
index 20fea0a35fc..2aff6fece17 100644
--- a/chromium/chrome/browser/resources/chromeos/compiled_resources2.gyp
+++ b/chromium/chrome/browser/resources/chromeos/compiled_resources2.gyp
@@ -4,7 +4,7 @@
{
'targets': [
{
- 'target_name': 'bluetooth_dialog_host',
+ 'target_name': 'bluetooth_pairing_dialog',
'dependencies': [
'<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
'<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:i18n_behavior',
@@ -20,6 +20,7 @@
'dependencies': [
'<(DEPTH)/ui/webui/resources/cr_components/chromeos/network/compiled_resources2.gyp:network_config',
'<(DEPTH)/ui/webui/resources/cr_elements/chromeos/network/compiled_resources2.gyp:cr_onc_types',
+ '<(DEPTH)/ui/webui/resources/cr_elements/cr_dialog/compiled_resources2.gyp:cr_dialog',
'<(DEPTH)/ui/webui/resources/cr_elements/policy/compiled_resources2.gyp:cr_policy_network_behavior',
'<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:assert',
'<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:i18n_behavior',
diff --git a/chromium/chrome/browser/resources/chromeos/input_method/google_xkb_manifest.json b/chromium/chrome/browser/resources/chromeos/input_method/google_xkb_manifest.json
index ed509c9735b..a18e51cd59f 100644
--- a/chromium/chrome/browser/resources/chromeos/input_method/google_xkb_manifest.json
+++ b/chromium/chrome/browser/resources/chromeos/input_method/google_xkb_manifest.json
@@ -410,7 +410,9 @@
"description": "",
"language": [
"de",
- "de-DE"
+ "de-AT",
+ "de-DE",
+ "de-LI"
],
"layouts": [
"de"
@@ -426,7 +428,9 @@
"description": "",
"language": [
"de",
- "de-DE"
+ "de-AT",
+ "de-DE",
+ "de-LI"
],
"layouts": [
"de(neo)"
diff --git a/chromium/chrome/browser/resources/chromeos/login/BUILD.gn b/chromium/chrome/browser/resources/chromeos/login/BUILD.gn
new file mode 100644
index 00000000000..8ad38cb8443
--- /dev/null
+++ b/chromium/chrome/browser/resources/chromeos/login/BUILD.gn
@@ -0,0 +1,30 @@
+# Copyright 2017 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//third_party/closure_compiler/compile_js.gni")
+
+group("closure_compile") {
+ deps = [
+ ":offline_ad_login",
+ ":oobe_change_picture",
+ ]
+}
+
+js_binary("offline_ad_login") {
+ deps = [
+ "//ui/webui/resources/js:load_time_data",
+ ]
+}
+
+js_binary("oobe_change_picture") {
+ deps = [
+ "//ui/webui/resources/cr_elements/chromeos/cr_picture:cr_picture_list",
+ "//ui/webui/resources/cr_elements/chromeos/cr_picture:cr_picture_pane",
+ "//ui/webui/resources/cr_elements/chromeos/cr_picture:cr_picture_types",
+ "//ui/webui/resources/js:assert",
+ "//ui/webui/resources/js:i18n_behavior",
+ "//ui/webui/resources/js:load_time_data",
+ "//ui/webui/resources/js:util",
+ ]
+}
diff --git a/chromium/chrome/browser/resources/chromeos/select_to_speak/BUILD.gn b/chromium/chrome/browser/resources/chromeos/select_to_speak/BUILD.gn
index 9be56005408..a30ce42d14c 100644
--- a/chromium/chrome/browser/resources/chromeos/select_to_speak/BUILD.gn
+++ b/chromium/chrome/browser/resources/chromeos/select_to_speak/BUILD.gn
@@ -29,6 +29,7 @@ run_jsbundler("select_to_speak_copied_files") {
"checked.png",
"options.css",
"options.html",
+ "paragraph_utils.js",
"select_to_speak.js",
"select_to_speak_gdocs_script.js",
"select_to_speak_main.js",
diff --git a/chromium/chrome/browser/resources/chromeos/select_to_speak/compiled_resources2.gyp b/chromium/chrome/browser/resources/chromeos/select_to_speak/compiled_resources2.gyp
index 7920ad89a63..a5811052311 100644
--- a/chromium/chrome/browser/resources/chromeos/select_to_speak/compiled_resources2.gyp
+++ b/chromium/chrome/browser/resources/chromeos/select_to_speak/compiled_resources2.gyp
@@ -7,9 +7,11 @@
'target_name': 'select_to_speak',
'dependencies': [
'externs',
+ 'paragraph_utils',
'<(EXTERNS_GYP):accessibility_private',
'<(EXTERNS_GYP):automation',
'<(EXTERNS_GYP):chrome_extensions',
+ '<(EXTERNS_GYP):metrics_private',
],
'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
},
@@ -20,6 +22,7 @@
'<(EXTERNS_GYP):accessibility_private',
'<(EXTERNS_GYP):automation',
'<(EXTERNS_GYP):chrome_extensions',
+ '<(EXTERNS_GYP):metrics_private',
],
'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
},
@@ -27,5 +30,15 @@
'target_name': 'externs',
'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
},
+ {
+ 'target_name': 'paragraph_utils',
+ 'dependencies': [
+ 'externs',
+ '<(EXTERNS_GYP):accessibility_private',
+ '<(EXTERNS_GYP):automation',
+ '<(EXTERNS_GYP):chrome_extensions',
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
],
}
diff --git a/chromium/chrome/browser/resources/chromeos/select_to_speak/strings/select_to_speak_strings.grd b/chromium/chrome/browser/resources/chromeos/select_to_speak/strings/select_to_speak_strings.grd
index 5518b2f7ba1..c78c65c209e 100644
--- a/chromium/chrome/browser/resources/chromeos/select_to_speak/strings/select_to_speak_strings.grd
+++ b/chromium/chrome/browser/resources/chromeos/select_to_speak/strings/select_to_speak_strings.grd
@@ -153,6 +153,36 @@
<message desc="Label for the fastest synthesized speech rate in the Select-to-speak options dialog." name="IDS_SELECT_TO_SPEAK_OPTIONS_RATE_FASTEST">
Fastest
</message>
+ <message desc="Group of options controlling highlighting." name="IDS_SELECT_TO_SPEAK_OPTIONS_HIGHLIGHT">
+ Highlighting
+ </message>
+ <message desc="Label for option to highlight spoken words rather than spoken nodes." name="IDS_SELECT_TO_SPEAK_OPTIONS_HIGHLIGHT_DESCRIPTION">
+ Highlight each word as it is spoken
+ </message>
+ <message desc="Label for option to pick word highlight color." name="IDS_SELECT_TO_SPEAK_OPTIONS_HIGHLIGHT_COLOR_DESCRIPTION">
+ Color for word highlights:
+ </message>
+ <message desc="Label for a blue highlight color in the Select-to-speak options dialog." name="IDS_SELECT_TO_SPEAK_OPTIONS_HIGHLIGHT_COLOR_BLUE">
+ Blue
+ </message>
+ <message desc="Label for a orange highlight color in the Select-to-speak options dialog." name="IDS_SELECT_TO_SPEAK_OPTIONS_HIGHLIGHT_COLOR_ORANGE">
+ Orange
+ </message>
+ <message desc="Label for a yellow highlight color in the Select-to-speak options dialog." name="IDS_SELECT_TO_SPEAK_OPTIONS_HIGHLIGHT_COLOR_YELLOW">
+ Yellow
+ </message>
+ <message desc="Label for a green highlight color in the Select-to-speak options dialog." name="IDS_SELECT_TO_SPEAK_OPTIONS_HIGHLIGHT_COLOR_GREEN">
+ Green
+ </message>
+ <message desc="Label for a pink highlight color in the Select-to-speak options dialog." name="IDS_SELECT_TO_SPEAK_OPTIONS_HIGHLIGHT_COLOR_PINK">
+ Pink
+ </message>
+ <message desc="Example of a word highlight on a dark background in the Select-to-speak options dialog." name="IDS_SELECT_TO_SPEAK_OPTIONS_HIGHLIGHT_DARK">
+ Dark background
+ </message>
+ <message desc="Example of a word highlight on a light background in the Select-to-speak options dialog." name="IDS_SELECT_TO_SPEAK_OPTIONS_HIGHLIGHT_LIGHT">
+ Light background
+ </message>
</messages>
</release>
</grit>
diff --git a/chromium/chrome/browser/resources/component_extension_resources.grd b/chromium/chrome/browser/resources/component_extension_resources.grd
index 6ec5019a7ff..1a7f9514b0c 100644
--- a/chromium/chrome/browser/resources/component_extension_resources.grd
+++ b/chromium/chrome/browser/resources/component_extension_resources.grd
@@ -13,7 +13,6 @@
<release seq="1">
<structures>
<structure name="IDR_BOOKMARK_MANAGER_MAIN" file="bookmark_manager/main.html" flattenhtml="true" allowexternalscript="true" type="chrome_html" />
- <structure name="IDR_HOTWORD_AUDIO_VERIFICATION_MAIN" file="hotword_audio_verification/main.html" flattenhtml="true" allowexternalscript="true" type="chrome_html" />
<if expr="chromeos">
<structure name="IDR_WALLPAPER_MANAGER_MAIN" file="chromeos/wallpaper_manager/main.html" flattenhtml="true" allowexternalscript="true" type="chrome_html" />
<if expr="not _google_chrome">
@@ -48,49 +47,6 @@
<include name="IDR_HANGOUT_SERVICES_BACKGROUND_HTML" file="hangout_services/background.html" type="BINDATA" />
<include name="IDR_HANGOUT_SERVICES_THUNK_JS" file="hangout_services/thunk.js" type="BINDATA" />
</if>
- <if expr="enable_extensions">
- <!-- Hotword Audio Verification app -->
- <include name="IDR_HOTWORD_AUDIO_VERIFICATION_BACKGROUND_JS" file="hotword_audio_verification/event_page.js" type="BINDATA" />
- <include name="IDR_HOTWORD_AUDIO_VERIFICATION_MAIN_JS" file="hotword_audio_verification/main.js" type="BINDATA" />
- <include name="IDR_HOTWORD_AUDIO_VERIFICATION_FLOW_JS" file="hotword_audio_verification/flow.js" type="BINDATA" />
- <include name="IDR_START_STEP_HTML" file="hotword_audio_verification/steps/start_step.html" flattenhtml="true" type="BINDATA" />
- <include name="IDR_AUDIO_HISTORY_STEP_HTML" file="hotword_audio_verification/steps/audio_history_step.html" flattenhtml="true" type="BINDATA" />
- <include name="IDR_SPEECH_TRAINING_STEP_HTML" file="hotword_audio_verification/steps/speech_training_step.html" flattenhtml="true" type="BINDATA" />
- <include name="IDR_FINISHED_STEP_HTML" file="hotword_audio_verification/steps/finished_step.html" flattenhtml="true" type="BINDATA" />
- <include name="IDR_HOTWORD_AUDIO_VERIFICATION_STYLE_CSS" file="hotword_audio_verification/style.css" type="BINDATA" />
- <include name="IDR_HOTWORD_AUDIO_VERIFICATION_IMAGE_CLOSE_1X" file="hotword_audio_verification/images/ic-x-white-1x.png" type="BINDATA" />
- <include name="IDR_HOTWORD_AUDIO_VERIFICATION_IMAGE_CLOSE_2X" file="hotword_audio_verification/images/ic-x-white-2x.png" type="BINDATA" />
- <include name="IDR_HOTWORD_AUDIO_VERIFICATION_IMAGE_INTRO_1X" file="hotword_audio_verification/images/intro-1x.png" type="BINDATA" />
- <include name="IDR_HOTWORD_AUDIO_VERIFICATION_IMAGE_INTRO_2X" file="hotword_audio_verification/images/intro-2x.png" type="BINDATA" />
- <include name="IDR_HOTWORD_AUDIO_VERIFICATION_IMAGE_HEADER_1X" file="hotword_audio_verification/images/gradient-1x.png" type="BINDATA" />
- <include name="IDR_HOTWORD_AUDIO_VERIFICATION_IMAGE_HEADER_2X" file="hotword_audio_verification/images/gradient-2x.png" type="BINDATA" />
- <include name="IDR_HOTWORD_AUDIO_VERIFICATION_IMAGE_CHECK_BLUE_1X" file="hotword_audio_verification/images/ic-check-blue-1x.png" type="BINDATA" />
- <include name="IDR_HOTWORD_AUDIO_VERIFICATION_IMAGE_CHECK_BLUE_2X" file="hotword_audio_verification/images/ic-check-blue-2x.png" type="BINDATA" />
- <include name="IDR_HOTWORD_AUDIO_VERIFICATION_IMAGE_CHECK_GRAY_1X" file="hotword_audio_verification/images/ic-check-gray-1x.png" type="BINDATA" />
- <include name="IDR_HOTWORD_AUDIO_VERIFICATION_IMAGE_CHECK_GRAY_2X" file="hotword_audio_verification/images/ic-check-gray-2x.png" type="BINDATA" />
- <include name="IDR_HOTWORD_AUDIO_VERIFICATION_IMAGE_LOADER_1X" file="hotword_audio_verification/images/placeholder-loader-1x.png" type="BINDATA" />
- <include name="IDR_HOTWORD_AUDIO_VERIFICATION_IMAGE_LOADER_2X" file="hotword_audio_verification/images/placeholder-loader-2x.png" type="BINDATA" />
- <include name="IDR_HOTWORD_AUDIO_VERIFICATION_IMAGE_ERROR_1X" file="hotword_audio_verification/images/ic-error-1x.png" type="BINDATA" />
- <include name="IDR_HOTWORD_AUDIO_VERIFICATION_IMAGE_ERROR_2X" file="hotword_audio_verification/images/ic-error-2x.png" type="BINDATA" />
- <include name="IDR_HOTWORD_AUDIO_VERIFICATION_IMAGE_ICON_16" file="hotword_audio_verification/images/icon-16.png" type="BINDATA" />
- <include name="IDR_HOTWORD_AUDIO_VERIFICATION_IMAGE_ICON_48" file="hotword_audio_verification/images/icon-48.png" type="BINDATA" />
- <include name="IDR_HOTWORD_AUDIO_VERIFICATION_IMAGE_ICON_128" file="hotword_audio_verification/images/icon-128.png" type="BINDATA" />
-
- <!-- Hotword extension -->
- <include name="IDR_HOTWORD_ALWAYS_ON_MANAGER_JS" file="hotword/always_on_manager.js" type="BINDATA" />
- <include name="IDR_HOTWORD_AUDIO_CLIENT_JS" file="hotword/audio_client.js" type="BINDATA" />
- <include name="IDR_HOTWORD_BASE_SESSION_MANAGER_JS" file="hotword/base_session_manager.js" type="BINDATA" />
- <include name="IDR_HOTWORD_CONSTANTS_JS" file="hotword/constants.js" type="BINDATA" />
- <include name="IDR_HOTWORD_KEEP_ALIVE_JS" file="hotword/keep_alive.js" type="BINDATA" />
- <include name="IDR_HOTWORD_LAUNCHER_MANAGER_JS" file="hotword/launcher_manager.js" type="BINDATA" />
- <include name="IDR_HOTWORD_LOGGING_JS" file="hotword/logging.js" type="BINDATA" />
- <include name="IDR_HOTWORD_MANAGER_JS" file="hotword/manager.js" type="BINDATA" />
- <include name="IDR_HOTWORD_METRICS_JS" file="hotword/metrics.js" type="BINDATA" />
- <include name="IDR_HOTWORD_NACL_MANAGER_JS" file="hotword/nacl_manager.js" type="BINDATA" />
- <include name="IDR_HOTWORD_PAGE_AUDIO_MANAGER_JS" file="hotword/page_audio_manager.js" type="BINDATA" />
- <include name="IDR_HOTWORD_STATE_MANAGER_JS" file="hotword/state_manager.js" type="BINDATA" />
- <include name="IDR_HOTWORD_TRAINING_MANAGER_JS" file="hotword/training_manager.js" type="BINDATA" />
- </if>
<if expr="not is_android">
<include name="IDR_FEEDBACK_DEFAULT_HTML" file="feedback/html/default.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" />
<include name="IDR_FEEDBACK_SYSINFO_HTML" file="feedback/html/sys_info.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" />
@@ -137,6 +93,7 @@
<include name="IDR_ARC_SUPPORT_PLAYSTORE_LOGO" file="chromeos/arc_support/icon/playstore.svg" type="BINDATA" />
<include name="IDR_ARC_SUPPORT_PROGRESSBAR_CSS" file="chromeos/arc_support/progressbar.css" type="BINDATA" />
<include name="IDR_ARC_SUPPORT_PROGRESSBAR_JS" file="chromeos/arc_support/progressbar.js" type="BINDATA" />
+ <include name="IDR_ARC_SUPPORT_FOCUS_MANAGER_JS" file="chromeos/arc_support/arc_optin_focus_manager.js" type="BINDATA" />
<include name="IDR_ARC_SUPPORT_MAIN" file="chromeos/arc_support/main.html" allowexternalscript="true" type="BINDATA" />
<include name="IDR_ARC_SUPPORT_ICON_48" file="chromeos/arc_support/icon/48.png" type="BINDATA" />
<include name="IDR_ARC_SUPPORT_ICON_96" file="chromeos/arc_support/icon/96.png" type="BINDATA" />
@@ -149,6 +106,7 @@
<include name="IDR_PDF_MAIN_JS" file="pdf/main.js" type="BINDATA" />
<include name="IDR_PDF_PDF_JS" file="pdf/pdf.js" type="BINDATA" />
<include name="IDR_PDF_UI_MANAGER_JS" file="pdf/toolbar_manager.js" type="BINDATA" />
+ <include name="IDR_PDF_PDF_FITTING_TYPE_JS" file="pdf/pdf_fitting_type.js" type="BINDATA" />
<include name="IDR_PDF_VIEWPORT_JS" file="pdf/viewport.js" type="BINDATA" />
<include name="IDR_PDF_OPEN_PDF_PARAMS_PARSER_JS" file="pdf/open_pdf_params_parser.js" type="BINDATA" />
<include name="IDR_PDF_NAVIGATOR_JS" file="pdf/navigator.js" type="BINDATA" />
diff --git a/chromium/chrome/browser/resources/discards/.eslintrc.js b/chromium/chrome/browser/resources/discards/.eslintrc.js
new file mode 100644
index 00000000000..847d6e99509
--- /dev/null
+++ b/chromium/chrome/browser/resources/discards/.eslintrc.js
@@ -0,0 +1,13 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module.exports = {
+ 'env': {
+ 'browser': true,
+ 'es6': true,
+ },
+ 'rules': {
+ 'no-var': 'error',
+ },
+};
diff --git a/chromium/chrome/browser/resources/discards/OWNERS b/chromium/chrome/browser/resources/discards/OWNERS
new file mode 100644
index 00000000000..dcd54320481
--- /dev/null
+++ b/chromium/chrome/browser/resources/discards/OWNERS
@@ -0,0 +1 @@
+file://services/resource_coordinator/OWNERS
diff --git a/chromium/chrome/browser/resources/discards/discards.css b/chromium/chrome/browser/resources/discards/discards.css
new file mode 100644
index 00000000000..b5a965016cc
--- /dev/null
+++ b/chromium/chrome/browser/resources/discards/discards.css
@@ -0,0 +1,84 @@
+/* Copyright 2017 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file. */
+
+table {
+ border-collapse: collapse;
+}
+
+table td,
+table th {
+ border: 1px solid #777;
+ padding-left: 4px;
+ padding-right: 4px;
+}
+
+table th {
+ -webkit-padding-end: 16px;
+ background: rgb(224, 236, 255);
+ cursor: pointer;
+ padding-bottom: 4px;
+ padding-top: 4px;
+ white-space: nowrap;
+}
+
+table td.title-cell {
+ max-width: 200px;
+ overflow: hidden;
+ white-space: nowrap;
+}
+
+table td div.title-cell-container {
+ align-items: center;
+ display: flex;
+ justify-content: flex-start;
+}
+
+table td div.favicon-div {
+ height: 16px;
+ margin: 3px;
+ padding: 0;
+ width: 16px;
+}
+
+table td div.favicon-div img {
+ height: 16px;
+ width: 16px;
+}
+
+table td div.title-div {
+ margin: 0;
+ overflow: hidden;
+ padding: 0;
+ white-space: nowrap;
+}
+
+table td.tab-url-cell {
+ max-width: 200px;
+ overflow: hidden;
+ white-space: nowrap;
+}
+
+table td.boolean-cell,
+table td.discard-count-cell {
+ text-align: center;
+}
+
+table td div.is-auto-discardable-link,
+table td.discard-links-cell {
+ font-size: 0.6rem;
+}
+
+table tr:hover {
+ background: rgb(255, 255, 187);
+}
+
+th.sort-column::after {
+ content: 'â–²';
+ position: absolute;
+}
+
+th[data-sort-reverse].sort-column::after {
+ content: 'â–¼';
+ position: absolute;
+}
diff --git a/chromium/chrome/browser/resources/discards/discards.html b/chromium/chrome/browser/resources/discards/discards.html
new file mode 100644
index 00000000000..aaa2930665a
--- /dev/null
+++ b/chromium/chrome/browser/resources/discards/discards.html
@@ -0,0 +1,84 @@
+<!--
+Copyright 2017 The Chromium 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 is an internal only page meant for debugging. It is not intended for
+general use and is not localized.
+-->
+<!doctype html>
+<html lang="en">
+ <head>
+ <title>Discards</title>
+ <meta charset="utf-8">
+ <link rel="stylesheet" href="chrome://resources/css/action_link.css">
+ <link rel="stylesheet" href="chrome://resources/css/text_defaults.css">
+ <script src="chrome://resources/js/cr.js"></script>
+ <script src="chrome://resources/js/mojo_bindings.js"></script>
+ <script src="chrome://resources/js/util.js"></script>
+ <script src="chrome/browser/ui/webui/discards/discards.mojom.js"></script>
+ <script src="discards.js"></script>
+ <link rel="stylesheet" type="text/css" href="discards.css">
+ </head>
+ <body>
+ <h1>Discards</h1>
+ <div is="action-link" id="discard-now-link">
+ [Discard a tab now]
+ </div>
+ <div is="action-link" id="discard-now-urgent-link">
+ [Urgent discard a tab now]
+ </div>
+ <table id="tab-discard-info-table">
+ <thead>
+ <tr id="tab-discards-info-table-header">
+ <th data-sort-key="utilityRank" class="sort-column">Utility Rank</th>
+ <th data-sort-key="title">Tab Title</th>
+ <th data-sort-key="tabUrl">Tab URL</th>
+ <th data-sort-key="isApp">App</th>
+ <th data-sort-key="isInternal">Internal</th>
+ <th data-sort-key="isMedia">Media</th>
+ <th data-sort-key="isPinned">Pinned</th>
+ <th data-sort-key="isDiscarded">Discarded</th>
+ <th data-sort-key="discardCount">Discard Count</th>
+ <th data-sort-key="isAutoDiscardable">Auto Discardable</th>
+ <th data-sort-key="lastActiveSeconds">Last Active</th>
+ </tr>
+ </thead>
+ <tbody id="tab-discards-info-table-body">
+ </tbody>
+ </table>
+ <template id="tab-discard-info-row">
+ <tr>
+ <td class="utility-rank-cell"></td>
+ <td class="title-cell">
+ <div class="title-cell-container">
+ <div class="favicon-div">
+ <img class="favicon" alt="FavIcon">
+ </div>
+ <div class="title-div"></div>
+ </div>
+ </td>
+ <td class="tab-url-cell"></td>
+ <td class="is-app-cell boolean-cell"></td>
+ <td class="is-internal-cell boolean-cell"></td>
+ <td class="is-media-cell boolean-cell"></td>
+ <td class="is-pinned-cell boolean-cell"></td>
+ <td class="is-discarded-cell boolean-cell"></td>
+ <td class="discard-count-cell"></td>
+ <td class="is-auto-discardable-cell boolean-cell">
+ <div class="is-auto-discardable-div"></div>
+ <div is="action-link" class="is-auto-discardable-link">
+ Toggle
+ </div>
+ </td>
+ <td class="last-active-cell"></td>
+ <td class="discard-links-cell">
+ <div is="action-link" class="discard-link">[Discard]</div>
+ <div is="action-link" class="discard-urgent-link">
+ [Urgent Discard]
+ </div>
+ </td>
+ </tr>
+ </template>
+ </body>
+</html>
diff --git a/chromium/chrome/browser/resources/discards/discards.js b/chromium/chrome/browser/resources/discards/discards.js
new file mode 100644
index 00000000000..210abe907a5
--- /dev/null
+++ b/chromium/chrome/browser/resources/discards/discards.js
@@ -0,0 +1,433 @@
+// Copyright 2017 The Chromium 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('discards', function() {
+ 'use strict';
+
+ // The following variables are initialized by 'initialize'.
+ // Points to the Mojo WebUI handler.
+ let uiHandler;
+ // After initialization this points to the discard info table body.
+ let tabDiscardsInfoTableBody;
+ // This holds the sorted tab discard infos as retrieved from the uiHandler.
+ let infos;
+ // Holds information about the current sorting of the table.
+ let sortKey;
+ let sortReverse;
+ // Points to the timer that refreshes the table content.
+ let updateTimer;
+
+ // Specifies the update interval of the page, in ms.
+ const UPDATE_INTERVAL_MS = 1000;
+
+ /**
+ * Ensures the discards info table has the appropriate length. Decorates
+ * newly created rows with a 'row-index' attribute to enable event listeners
+ * to quickly determine the index of the row.
+ */
+ function ensureTabDiscardsInfoTableLength() {
+ let rows = tabDiscardsInfoTableBody.querySelectorAll('tr');
+ if (rows.length < infos.length) {
+ for (let i = rows.length; i < infos.length; ++i) {
+ let row = createEmptyTabDiscardsInfoTableRow();
+ row.setAttribute('data-row-index', i.toString());
+ tabDiscardsInfoTableBody.appendChild(row);
+ }
+ } else if (rows.length > infos.length) {
+ for (let i = infos.length; i < rows.length; ++i) {
+ tabDiscardsInfoTableBody.removeChild(rows[i]);
+ }
+ }
+ }
+
+ /**
+ * Compares two TabDiscardsInfos based on the data in the provided sort-key.
+ * @param {string} sortKey The key of the sort. See the "data-sort-key"
+ * attribute of the table headers for valid sort-keys.
+ * @param {boolean|number|string} a The first value being compared.
+ * @param {boolean|number|string} b The second value being compared.
+ * @return {number} A negative number if a < b, 0 if a == b, and a positive
+ * number if a > b.
+ */
+ function compareTabDiscardsInfos(sortKey, a, b) {
+ let val1 = a[sortKey];
+ let val2 = b[sortKey];
+
+ // Compares strings.
+ if (sortKey == 'title' || sortKey == 'tabUrl') {
+ val1 = val1.toLowerCase();
+ val2 = val2.toLowerCase();
+ if (val1 == val2)
+ return 0;
+ return val1 > val2 ? 1 : -1;
+ }
+
+ // Compares boolean fields.
+ if ([
+ 'isApp', 'isInternal', 'isMedia', 'isPinned', 'isDiscarded',
+ 'isAutoDiscardable'
+ ].includes(sortKey)) {
+ if (val1 == val2)
+ return 0;
+ return val1 ? 1 : -1;
+ }
+
+ // Compares numeric fields.
+ if (['discardCount', 'utilityRank', 'lastActiveSeconds'].includes(
+ sortKey)) {
+ return val1 - val2;
+ }
+
+ assertNotReached('Unsupported sort key: ' + sortKey);
+ return 0;
+ }
+
+ /**
+ * Sorts the tab discards info data in |infos| according to the current
+ * |sortKey|.
+ */
+ function sortTabDiscardsInfoTable() {
+ infos = infos.sort((a, b) => {
+ return (sortReverse ? -1 : 1) * compareTabDiscardsInfos(sortKey, a, b);
+ });
+ }
+
+ /**
+ * Pluralizes a string according to the given count. Assumes that appending an
+ * 's' is sufficient to make a string plural.
+ * @param {string} s The string to be made plural if necessary.
+ * @param {number} n The count of the number of ojects.
+ * @return {string} The plural version of |s| if n != 1, otherwise |s|.
+ */
+ function maybeMakePlural(s, n) {
+ return n == 1 ? s : s + 's';
+ }
+
+ /**
+ * Converts a |secondsAgo| last-active time to a user friendly string.
+ * @param {number} secondsAgo The amount of time since the tab was active.
+ * @return {string} An English string representing the last active time.
+ */
+ function lastActiveToString(secondsAgo) {
+ // These constants aren't perfect, but close enough.
+ const SECONDS_PER_MINUTE = 60;
+ const MINUTES_PER_HOUR = 60;
+ const SECONDS_PER_HOUR = SECONDS_PER_MINUTE * MINUTES_PER_HOUR;
+ const HOURS_PER_DAY = 24;
+ const SECONDS_PER_DAY = SECONDS_PER_HOUR * HOURS_PER_DAY;
+ const DAYS_PER_WEEK = 7;
+ const SECONDS_PER_WEEK = SECONDS_PER_DAY * DAYS_PER_WEEK;
+ const SECONDS_PER_MONTH = SECONDS_PER_DAY * 30.5;
+ const SECONDS_PER_YEAR = SECONDS_PER_DAY * 365;
+
+ // Seconds ago.
+ if (secondsAgo < SECONDS_PER_MINUTE)
+ return 'just now';
+
+ // Minutes ago.
+ let minutesAgo = Math.floor(secondsAgo / SECONDS_PER_MINUTE);
+ if (minutesAgo < MINUTES_PER_HOUR) {
+ return minutesAgo.toString() + maybeMakePlural(' minute', minutesAgo) +
+ ' ago';
+ }
+
+ // Hours and minutes and ago.
+ let hoursAgo = Math.floor(secondsAgo / SECONDS_PER_HOUR);
+ minutesAgo = minutesAgo % MINUTES_PER_HOUR;
+ if (hoursAgo < HOURS_PER_DAY) {
+ let s = hoursAgo.toString() + maybeMakePlural(' hour', hoursAgo);
+ if (minutesAgo > 0) {
+ s += ' and ' + minutesAgo.toString() +
+ maybeMakePlural(' minute', minutesAgo);
+ }
+ s += ' ago';
+ return s;
+ }
+
+ // Days ago.
+ let daysAgo = Math.floor(secondsAgo / SECONDS_PER_DAY);
+ if (daysAgo < DAYS_PER_WEEK) {
+ return daysAgo.toString() + maybeMakePlural(' day', daysAgo) + ' ago';
+ }
+
+ // Weeks ago. There's an awkward gap to bridge where 4 weeks can have
+ // elapsed but not quite 1 month. Be sure to use weeks to report that.
+ let weeksAgo = Math.floor(secondsAgo / SECONDS_PER_WEEK);
+ let monthsAgo = Math.floor(secondsAgo / SECONDS_PER_MONTH);
+ if (monthsAgo < 1) {
+ return 'over ' + weeksAgo.toString() +
+ maybeMakePlural(' week', weeksAgo) + ' ago';
+ }
+
+ // Months ago.
+ let yearsAgo = Math.floor(secondsAgo / SECONDS_PER_YEAR);
+ if (yearsAgo < 1) {
+ return 'over ' + monthsAgo.toString() +
+ maybeMakePlural(' month', monthsAgo) + ' ago';
+ }
+
+ // Years ago.
+ return 'over ' + yearsAgo.toString() + maybeMakePlural(' year', yearsAgo) +
+ ' ago';
+ }
+
+ /**
+ * Returns a string representation of a boolean value for display in a table.
+ * @param {boolean} bool A boolean value.
+ * @return {string} A string representing the bool.
+ */
+ function boolToString(bool) {
+ return bool ? '✔' : '\xa0';
+ }
+
+ /**
+ * Returns the index of the row in the table that houses the given |element|.
+ * @param {HTMLElement} element Any element in the DOM.
+ */
+ function getRowIndex(element) {
+ let row = element.closest('tr');
+ return parseInt(row.getAttribute('data-row-index'), 10);
+ }
+
+ /**
+ * Creates an empty tab discards table row with action-link listeners, etc.
+ * By default the links are inactive.
+ */
+ function createEmptyTabDiscardsInfoTableRow() {
+ let template = $('tab-discard-info-row');
+ let content = document.importNode(template.content, true);
+ let row = content.querySelector('tr');
+
+ // Set up the listener for the auto-discardable toggle action.
+ let isAutoDiscardable = row.querySelector('.is-auto-discardable-link');
+ isAutoDiscardable.setAttribute('disabled', '');
+ isAutoDiscardable.addEventListener('click', (e) => {
+ // Get the info backing this row.
+ let info = infos[getRowIndex(e.target)];
+ // Disable the action. The update function is responsible for
+ // re-enabling actions if necessary.
+ e.target.setAttribute('disabled', '');
+ // Perform the action.
+ uiHandler.setAutoDiscardable(info.id, !info.isAutoDiscardable)
+ .then(stableUpdateTabDiscardsInfoTable());
+ });
+
+ // Set up the listeners for discard links.
+ let discardListener = function(e) {
+ // Get the info backing this row.
+ let info = infos[getRowIndex(e.target)];
+ // Determine whether this is urgent or not.
+ let urgent = e.target.classList.contains('discard-urgent-link');
+ // Disable the action. The update function is responsible for
+ // re-enabling actions if necessary.
+ e.target.setAttribute('disabled', '');
+ // Perform the action.
+ uiHandler.discardById(info.id, urgent).then((response) => {
+ stableUpdateTabDiscardsInfoTable();
+ });
+ };
+ let discardLink = row.querySelector('.discard-link');
+ let discardUrgentLink = row.querySelector('.discard-urgent-link');
+ discardLink.addEventListener('click', discardListener);
+ discardUrgentLink.addEventListener('click', discardListener);
+
+ return row;
+ }
+
+ /**
+ * Updates a tab discards info table row in place. Sets/unsets 'disabled'
+ * attributes on action-links as necessary, and populates all contents.
+ */
+ function updateTabDiscardsInfoTableRow(row, info) {
+ // Update the content.
+ row.querySelector('.utility-rank-cell').textContent =
+ info.utilityRank.toString();
+ row.querySelector('.favicon').src =
+ info.faviconUrl ? info.faviconUrl : 'chrome://favicon';
+ row.querySelector('.title-div').textContent = info.title;
+ row.querySelector('.tab-url-cell').textContent = info.tabUrl;
+ row.querySelector('.is-app-cell').textContent = boolToString(info.isApp);
+ row.querySelector('.is-internal-cell').textContent =
+ boolToString(info.isInternal);
+ row.querySelector('.is-media-cell').textContent =
+ boolToString(info.isMedia);
+ row.querySelector('.is-pinned-cell').textContent =
+ boolToString(info.isPinned);
+ row.querySelector('.is-discarded-cell').textContent =
+ boolToString(info.isDiscarded);
+ row.querySelector('.discard-count-cell').textContent =
+ info.discardCount.toString();
+ row.querySelector('.is-auto-discardable-div').textContent =
+ boolToString(info.isAutoDiscardable);
+ row.querySelector('.last-active-cell').textContent =
+ lastActiveToString(info.lastActiveSeconds);
+
+ // Enable/disable action links as appropriate.
+ row.querySelector('.is-auto-discardable-link').removeAttribute('disabled');
+ let discardLink = row.querySelector('.discard-link');
+ let discardUrgentLink = row.querySelector('.discard-urgent-link');
+ if (info.isDiscarded) {
+ discardLink.setAttribute('disabled', '');
+ discardUrgentLink.setAttribute('disabled', '');
+ } else {
+ discardLink.removeAttribute('disabled');
+ discardUrgentLink.removeAttribute('disabled');
+ }
+ }
+
+ /**
+ * Causes the discards info table to be rendered. Reuses existing table rows
+ * in place to minimize disruption to the page.
+ */
+ function renderTabDiscardsInfoTable() {
+ ensureTabDiscardsInfoTableLength();
+ let rows = tabDiscardsInfoTableBody.querySelectorAll('tr');
+ for (let i = 0; i < infos.length; ++i)
+ updateTabDiscardsInfoTableRow(rows[i], infos[i]);
+ }
+
+ /**
+ * Causes the discard info table to be updated in as stable a manner as
+ * possible. That is, rows will stay in their relative positions, even if the
+ * current sort order is violated. Only the addition or removal of rows (tabs)
+ * can cause the layout to change.
+ */
+ function stableUpdateTabDiscardsInfoTableImpl() {
+ uiHandler.getTabDiscardsInfo().then((response) => {
+ let newInfos = response.infos;
+ let stableInfos = [];
+
+ // Update existing infos in place, remove old ones, and append new ones.
+ // This tries to keep the existing ordering stable so that clicking links
+ // is minimally disruptive.
+ for (let i = 0; i < infos.length; ++i) {
+ let oldInfo = infos[i];
+ let newInfo = null;
+ for (let j = 0; j < newInfos.length; ++j) {
+ if (newInfos[j].id == oldInfo.id) {
+ newInfo = newInfos[j];
+ break;
+ }
+ }
+
+ // Old infos that have corresponding new infos are pushed first, in the
+ // current order of the old infos.
+ if (newInfo != null)
+ stableInfos.push(newInfo);
+ }
+
+ // Make sure info about new tabs is appended to the end, in the order they
+ // were originally returned.
+ for (let i = 0; i < newInfos.length; ++i) {
+ let newInfo = newInfos[i];
+ let oldInfo = null;
+ for (let j = 0; j < infos.length; ++j) {
+ if (infos[j].id == newInfo.id) {
+ oldInfo = infos[j];
+ break;
+ }
+ }
+
+ // Entirely new information (has no corresponding old info) is appended
+ // to the end.
+ if (oldInfo == null)
+ stableInfos.push(newInfo);
+ }
+
+ // Swap out the current info with the new stably sorted information.
+ infos = stableInfos;
+
+ // Render the content in place.
+ renderTabDiscardsInfoTable();
+ });
+ }
+
+ /**
+ * A wrapper to stableUpdateTabDiscardsInfoTableImpl that is called due to
+ * user action and not due to the automatic timer. Cancels the existing timer
+ * and reschedules it after rendering instantaneously.
+ */
+ function stableUpdateTabDiscardsInfoTable() {
+ if (updateTimer)
+ clearInterval(updateTimer);
+ stableUpdateTabDiscardsInfoTableImpl();
+ updateTimer =
+ setInterval(stableUpdateTabDiscardsInfoTableImpl, UPDATE_INTERVAL_MS);
+ }
+
+ /**
+ * Initializes this page. Invoked by the DOMContentLoaded event.
+ */
+ function initialize() {
+ uiHandler = new mojom.DiscardsDetailsProviderPtr;
+ Mojo.bindInterface(
+ mojom.DiscardsDetailsProvider.name, mojo.makeRequest(uiHandler).handle);
+
+ tabDiscardsInfoTableBody = $('tab-discards-info-table-body');
+ infos = [];
+ sortKey = 'utilityRank';
+ sortReverse = false;
+ updateTimer = null;
+
+ // Set the column sort handlers.
+ let tabDiscardsInfoTableHeader = $('tab-discards-info-table-header');
+ let headers = tabDiscardsInfoTableHeader.children;
+ for (let header of headers) {
+ header.addEventListener('click', (e) => {
+ let newSortKey = e.target.dataset.sortKey;
+
+ // Skip columns that aren't explicitly labeled with a sort-key
+ // attribute.
+ if (newSortKey == null)
+ return;
+
+ // Reverse the sort key if the key itself hasn't changed.
+ if (sortKey == newSortKey) {
+ sortReverse = !sortReverse;
+ } else {
+ sortKey = newSortKey;
+ sortReverse = false;
+ }
+
+ // Undecorate the old sort column, and decorate the new one.
+ let oldSortColumn = document.querySelector('.sort-column');
+ oldSortColumn.classList.remove('sort-column');
+ e.target.classList.add('sort-column');
+ if (sortReverse)
+ e.target.setAttribute('data-sort-reverse', '');
+ else
+ e.target.removeAttribute('data-sort-reverse');
+
+ sortTabDiscardsInfoTable();
+ renderTabDiscardsInfoTable();
+ });
+ }
+
+ // Setup the "Discard a tab now" links.
+ let discardNow = $('discard-now-link');
+ let discardNowUrgent = $('discard-now-urgent-link');
+ let discardListener = function(e) {
+ e.target.setAttribute('disabled', '');
+ let urgent = e.target.id.includes('urgent');
+ uiHandler.discard(urgent).then(() => {
+ stableUpdateTabDiscardsInfoTable();
+ e.target.removeAttribute('disabled');
+ });
+ };
+ discardNow.addEventListener('click', discardListener);
+ discardNowUrgent.addEventListener('click', discardListener);
+
+ stableUpdateTabDiscardsInfoTable();
+ }
+
+ document.addEventListener('DOMContentLoaded', initialize);
+
+ // These functions are exposed on the 'discards' object created by
+ // cr.define. This allows unittesting of these functions.
+ return {
+ compareTabDiscardsInfos: compareTabDiscardsInfos,
+ lastActiveToString: lastActiveToString,
+ maybeMakePlural: maybeMakePlural
+ };
+});
diff --git a/chromium/chrome/browser/resources/download_internals/download_internals.css b/chromium/chrome/browser/resources/download_internals/download_internals.css
index 63dab4dbfc0..bc909013457 100644
--- a/chromium/chrome/browser/resources/download_internals/download_internals.css
+++ b/chromium/chrome/browser/resources/download_internals/download_internals.css
@@ -12,6 +12,10 @@ h1 {
font-size: 15px;
}
+.sub-text {
+ font-size: 10px;
+}
+
.service-entry-new {
background-color: rgb(242, 242, 242)
}
diff --git a/chromium/chrome/browser/resources/download_internals/download_internals.html b/chromium/chrome/browser/resources/download_internals/download_internals.html
index 259ed42fc33..49e67cdce47 100644
--- a/chromium/chrome/browser/resources/download_internals/download_internals.html
+++ b/chromium/chrome/browser/resources/download_internals/download_internals.html
@@ -29,6 +29,10 @@
File Monitor: <span id="service-status-file" class="status"></span>
</div>
<h4>Entry Requests</h4>
+ <div class="sub-text">
+ The entry URLs have been modified to strip query params so that possibly
+ private information is hidden from view.
+ </div>
<div id="download-service-request-info">
<table class="styled-table">
<thead>
diff --git a/chromium/chrome/browser/resources/extensions/extensions.js b/chromium/chrome/browser/resources/extensions/extensions.js
index d46ea50ad19..663f8382b3d 100644
--- a/chromium/chrome/browser/resources/extensions/extensions.js
+++ b/chromium/chrome/browser/resources/extensions/extensions.js
@@ -108,7 +108,7 @@ cr.define('extensions', function() {
var dragTarget = document.documentElement;
/** @private {extensions.DragAndDropHandler} */
this.dragWrapperHandler_ =
- new extensions.DragAndDropHandler(true, dragTarget);
+ new extensions.DragAndDropHandler(true, false, dragTarget);
dragTarget.addEventListener('extension-drag-started', function() {
ExtensionSettings.showOverlay($('drop-target-overlay'));
});
diff --git a/chromium/chrome/browser/resources/feedback/js/feedback.js b/chromium/chrome/browser/resources/feedback/js/feedback.js
index 62712dab768..6089c1b9c55 100644
--- a/chromium/chrome/browser/resources/feedback/js/feedback.js
+++ b/chromium/chrome/browser/resources/feedback/js/feedback.js
@@ -215,21 +215,6 @@ function cancel(e) {
scheduleWindowClose();
}
-/**
- * Converts a blob data URL to a blob object.
- * @param {string} url The data URL to convert.
- * @return {Blob} Blob object containing the data.
- */
-function dataUrlToBlob(url) {
- var mimeString = url.split(',')[0].split(':')[1].split(';')[0];
- var data = atob(url.split(',')[1]);
- var dataArray = [];
- for (var i = 0; i < data.length; ++i)
- dataArray.push(data.charCodeAt(i));
-
- return new Blob([new Uint8Array(dataArray)], {type: mimeString});
-}
-
// <if expr="chromeos">
/**
* Update the page when performance feedback state is changed.
@@ -347,17 +332,17 @@ function initialize() {
});
chrome.app.window.current().show();
- var screenshotDataUrl = screenshotCanvas.toDataURL('image/png');
-
- // Only set the alt text when the src url is available, otherwise we'd
- // get a broken image picture instead. crbug.com/773985.
- $('screenshot-image').src = screenshotDataUrl;
- $('screenshot-image').alt = 'screenshot';
- $('screenshot-image')
- .classList.toggle(
- 'wide-screen',
- $('screenshot-image').width > MAX_SCREENSHOT_WIDTH);
- feedbackInfo.screenshot = dataUrlToBlob(screenshotDataUrl);
+ screenshotCanvas.toBlob(function(blob) {
+ $('screenshot-image').src = URL.createObjectURL(blob);
+ // Only set the alt text when the src url is available, otherwise we'd
+ // get a broken image picture instead. crbug.com/773985.
+ $('screenshot-image').alt = 'screenshot';
+ $('screenshot-image')
+ .classList.toggle(
+ 'wide-screen',
+ $('screenshot-image').width > MAX_SCREENSHOT_WIDTH);
+ feedbackInfo.screenshot = blob;
+ });
});
chrome.feedbackPrivate.getUserEmail(function(email) {
diff --git a/chromium/chrome/browser/resources/gaia_auth_host/authenticator.js b/chromium/chrome/browser/resources/gaia_auth_host/authenticator.js
index fa1e41103f4..f55f6593447 100644
--- a/chromium/chrome/browser/resources/gaia_auth_host/authenticator.js
+++ b/chromium/chrome/browser/resources/gaia_auth_host/authenticator.js
@@ -3,6 +3,7 @@
// found in the LICENSE file.
// <include src="saml_handler.js">
+// Note: webview_event_manager.js is already included by saml_handler.js.
/**
* @fileoverview An UI component to authenciate to Chrome. The component hosts
@@ -122,9 +123,6 @@ cr.define('cr.login', function() {
* @constructor
*/
function Authenticator(webview) {
- this.webview_ = typeof webview == 'string' ? $(webview) : webview;
- assert(this.webview_);
-
this.isLoaded_ = false;
this.email_ = null;
this.password_ = null;
@@ -145,38 +143,19 @@ cr.define('cr.login', function() {
this.gapsCookieSent_ = false;
this.newGapsCookie_ = null;
this.readyFired_ = false;
+ this.webviewEventManager_ = WebviewEventManager.create();
this.clientId_ = null;
- this.samlHandler_ = new cr.login.SamlHandler(this.webview_);
this.confirmPasswordCallback = null;
this.noPasswordCallback = null;
this.insecureContentBlockedCallback = null;
this.samlApiUsedCallback = null;
this.missingGaiaInfoCallback = null;
this.needPassword = true;
- this.samlHandler_.addEventListener(
- 'insecureContentBlocked', this.onInsecureContentBlocked_.bind(this));
- this.samlHandler_.addEventListener(
- 'authPageLoaded', this.onAuthPageLoaded_.bind(this));
- this.samlHandler_.addEventListener(
- 'videoEnabled', this.onVideoEnabled_.bind(this));
- this.samlHandler_.addEventListener(
- 'apiPasswordAdded', this.onSamlApiPasswordAdded_.bind(this));
-
- this.webview_.addEventListener('droplink', this.onDropLink_.bind(this));
- this.webview_.addEventListener('newwindow', this.onNewWindow_.bind(this));
- this.webview_.addEventListener(
- 'contentload', this.onContentLoad_.bind(this));
- this.webview_.addEventListener('loadabort', this.onLoadAbort_.bind(this));
- this.webview_.addEventListener('loadcommit', this.onLoadCommit_.bind(this));
- this.webview_.request.onCompleted.addListener(
- this.onRequestCompleted_.bind(this),
- {urls: ['<all_urls>'], types: ['main_frame']}, ['responseHeaders']);
- this.webview_.request.onHeadersReceived.addListener(
- this.onHeadersReceived_.bind(this),
- {urls: ['<all_urls>'], types: ['main_frame', 'xmlhttprequest']},
- ['responseHeaders']);
+
+ this.bindToWebview_(webview);
+
window.addEventListener(
'message', this.onMessageFromWebview_.bind(this), false);
window.addEventListener('focus', this.onFocus_.bind(this), false);
@@ -217,6 +196,74 @@ cr.define('cr.login', function() {
};
/**
+ * Binds this authenticator to the passed webview.
+ * @param {!Object} webview the new webview to be used by this Authenticator.
+ * @private
+ */
+ Authenticator.prototype.bindToWebview_ = function(webview) {
+ assert(!this.webview_);
+ assert(!this.samlHandler_);
+
+ this.webview_ = typeof webview == 'string' ? $(webview) : webview;
+
+ this.samlHandler_ = new cr.login.SamlHandler(this.webview_);
+ this.webviewEventManager_.addEventListener(
+ this.samlHandler_, 'insecureContentBlocked',
+ this.onInsecureContentBlocked_.bind(this));
+ this.webviewEventManager_.addEventListener(
+ this.samlHandler_, 'authPageLoaded', this.onAuthPageLoaded_.bind(this));
+ this.webviewEventManager_.addEventListener(
+ this.samlHandler_, 'videoEnabled', this.onVideoEnabled_.bind(this));
+ this.webviewEventManager_.addEventListener(
+ this.samlHandler_, 'apiPasswordAdded',
+ this.onSamlApiPasswordAdded_.bind(this));
+
+ this.webviewEventManager_.addEventListener(
+ this.webview_, 'droplink', this.onDropLink_.bind(this));
+ this.webviewEventManager_.addEventListener(
+ this.webview_, 'newwindow', this.onNewWindow_.bind(this));
+ this.webviewEventManager_.addEventListener(
+ this.webview_, 'contentload', this.onContentLoad_.bind(this));
+ this.webviewEventManager_.addEventListener(
+ this.webview_, 'loadabort', this.onLoadAbort_.bind(this));
+ this.webviewEventManager_.addEventListener(
+ this.webview_, 'loadcommit', this.onLoadCommit_.bind(this));
+
+ this.webviewEventManager_.addWebRequestEventListener(
+ this.webview_.request.onCompleted, this.onRequestCompleted_.bind(this),
+ {urls: ['<all_urls>'], types: ['main_frame']}, ['responseHeaders']);
+ this.webviewEventManager_.addWebRequestEventListener(
+ this.webview_.request.onHeadersReceived,
+ this.onHeadersReceived_.bind(this),
+ {urls: ['<all_urls>'], types: ['main_frame', 'xmlhttprequest']},
+ ['responseHeaders']);
+ };
+
+ /**
+ * Unbinds this Authenticator from the currently bound webview.
+ * @private
+ */
+ Authenticator.prototype.unbindFromWebview_ = function() {
+ assert(this.webview_);
+ assert(this.samlHandler_);
+
+ this.webviewEventManager_.removeAllListeners();
+
+ this.webview_ = undefined;
+ this.samlHandler_.unbindFromWebview();
+ this.samlHandler_ = undefined;
+ };
+
+ /**
+ * Re-binds to another webview.
+ * @param {Object} webview the new webview to be used by this Authenticator.
+ */
+ Authenticator.prototype.rebindWebview = function(webview) {
+ this.unbindFromWebview_();
+ this.bindToWebview_(webview);
+ };
+
+ /**
* Loads the authenticator component with the given parameters.
* @param {AuthMode} authMode Authorization mode.
* @param {Object} data Parameters for the authorization flow.
diff --git a/chromium/chrome/browser/resources/gaia_auth_host/saml_handler.js b/chromium/chrome/browser/resources/gaia_auth_host/saml_handler.js
index 89907937681..670bf7f90af 100644
--- a/chromium/chrome/browser/resources/gaia_auth_host/saml_handler.js
+++ b/chromium/chrome/browser/resources/gaia_auth_host/saml_handler.js
@@ -3,6 +3,7 @@
// found in the LICENSE file.
// <include src="post_message_channel.js">
+// <include src="webview_event_manager.js">
/**
* @fileoverview Saml support for webview based auth.
@@ -34,6 +35,9 @@ cr.define('cr.login', function() {
/** @const */
var SAML_HEADER = 'google-accounts-saml';
+ /** @const */
+ var injectedScriptName = 'samlInjected';
+
/**
* The script to inject into webview and its sub frames.
* @type {string}
@@ -141,23 +145,30 @@ cr.define('cr.login', function() {
*/
this.blockInsecureContent = false;
- this.webview_.addEventListener(
- 'contentload', this.onContentLoad_.bind(this));
- this.webview_.addEventListener('loadabort', this.onLoadAbort_.bind(this));
- this.webview_.addEventListener('loadcommit', this.onLoadCommit_.bind(this));
- this.webview_.addEventListener(
- 'permissionrequest', this.onPermissionRequest_.bind(this));
+ this.webviewEventManager_ = WebviewEventManager.create();
- this.webview_.request.onBeforeRequest.addListener(
+ this.webviewEventManager_.addEventListener(
+ this.webview_, 'contentload', this.onContentLoad_.bind(this));
+ this.webviewEventManager_.addEventListener(
+ this.webview_, 'loadabort', this.onLoadAbort_.bind(this));
+ this.webviewEventManager_.addEventListener(
+ this.webview_, 'loadcommit', this.onLoadCommit_.bind(this));
+ this.webviewEventManager_.addEventListener(
+ this.webview_, 'permissionrequest',
+ this.onPermissionRequest_.bind(this));
+
+ this.webviewEventManager_.addWebRequestEventListener(
+ this.webview_.request.onBeforeRequest,
this.onInsecureRequest.bind(this),
{urls: ['http://*/*', 'file://*/*', 'ftp://*/*']}, ['blocking']);
- this.webview_.request.onHeadersReceived.addListener(
+ this.webviewEventManager_.addWebRequestEventListener(
+ this.webview_.request.onHeadersReceived,
this.onHeadersReceived_.bind(this),
{urls: ['<all_urls>'], types: ['main_frame', 'xmlhttprequest']},
['blocking', 'responseHeaders']);
this.webview_.addContentScripts([{
- name: 'samlInjected',
+ name: injectedScriptName,
matches: ['http://*/*', 'https://*/*'],
js: {code: injectedJs},
all_frames: true,
@@ -217,6 +228,16 @@ cr.define('cr.login', function() {
},
/**
+ * Removes the injected content script and unbinds all listeners from the
+ * webview passed to the constructor. This SAMLHandler will be unusable
+ * after this function returns.
+ */
+ unbindFromWebview: function() {
+ this.webview_.removeContentScripts([injectedScriptName]);
+ this.webviewEventManager_.removeAllListeners();
+ },
+
+ /**
* Resets all auth states
*/
reset: function() {
diff --git a/chromium/chrome/browser/resources/gaia_auth_host/webview_event_manager.js b/chromium/chrome/browser/resources/gaia_auth_host/webview_event_manager.js
new file mode 100644
index 00000000000..527ed101de2
--- /dev/null
+++ b/chromium/chrome/browser/resources/gaia_auth_host/webview_event_manager.js
@@ -0,0 +1,66 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/**
+ * @fileoverview
+ * Provides WebviewEventManager which can register and keep track of listeners
+ * on EventTargets and WebRequests, and unregister all listeners later.
+ */
+'use strict';
+
+/**
+ * Creates a new WebviewEventManager.
+ */
+function WebviewEventManager() {
+ this.unbindWebviewCleanupFunctions_ = [];
+}
+
+WebviewEventManager.prototype = {
+ /**
+ * Adds a EventListener to |eventTarget| and adds a clean-up function so we
+ * can remove the listener in unbindFromWebview.
+ * @param {Object} webview the object to add the listener to
+ * @param {string} type the event type
+ * @param {Function} listener the event listener
+ * @private
+ */
+ addEventListener: function(eventTarget, type, listener) {
+ eventTarget.addEventListener(type, listener);
+ this.unbindWebviewCleanupFunctions_.push(
+ eventTarget.removeEventListener.bind(eventTarget, type, listener));
+ },
+
+ /**
+ * Adds a listener to |webRequestEvent| and adds a clean-up function so we can
+ * remove the listener in unbindFromWebview.
+ * @param {Object} webRequestEvent the object to add the listener to
+ * @param {string} type the event type
+ * @param {Function} listener the event listener
+ * @private
+ */
+ addWebRequestEventListener: function(
+ webRequestEvent, listener, filter, extraInfoSpec) {
+ webRequestEvent.addListener(listener, filter, extraInfoSpec);
+ this.unbindWebviewCleanupFunctions_.push(
+ webRequestEvent.removeListener.bind(webRequestEvent, listener));
+ },
+
+ /**
+ * Unbinds this Authenticator from the currently bound webview.
+ * @private
+ */
+ removeAllListeners: function() {
+ for (var i = 0; i < this.unbindWebviewCleanupFunctions_.length; i++)
+ this.unbindWebviewCleanupFunctions_[i]();
+ this.unbindWebviewCleanupFunctions_ = [];
+ }
+};
+
+/**
+ * Class factory.
+ * @return {WebviewEventManager}
+ */
+WebviewEventManager.create = function() {
+ return new WebviewEventManager();
+};
diff --git a/chromium/chrome/browser/resources/hangout_services/manifest.json b/chromium/chrome/browser/resources/hangout_services/manifest.json
index af76f3d202c..0c062af714f 100644
--- a/chromium/chrome/browser/resources/hangout_services/manifest.json
+++ b/chromium/chrome/browser/resources/hangout_services/manifest.json
@@ -5,7 +5,7 @@
"name": "Google Hangouts",
// Note: Always update the version number when this file is updated. Chrome
// triggers extension preferences update on the version increase.
- "version": "1.3.5",
+ "version": "1.3.6",
"manifest_version": 2,
"externally_connectable": {
"matches": [
diff --git a/chromium/chrome/browser/resources/hangout_services/thunk.js b/chromium/chrome/browser/resources/hangout_services/thunk.js
index 85a7e688a8c..4e9fe41578c 100644
--- a/chromium/chrome/browser/resources/hangout_services/thunk.js
+++ b/chromium/chrome/browser/resources/hangout_services/thunk.js
@@ -191,9 +191,8 @@ chrome.runtime.onMessageExternal.addListener(function(
} else if (method == 'setAudioExperiments') {
var experiments = message['experiments'];
chrome.webrtcAudioPrivate.setAudioExperiments(
- requestInfo, origin, experiments);
- doSendResponse();
- return false;
+ requestInfo, origin, experiments, doSendResponse);
+ return true;
}
throw new Error('Unknown method: ' + method);
diff --git a/chromium/chrome/browser/resources/hotword/OWNERS b/chromium/chrome/browser/resources/hotword/OWNERS
deleted file mode 100644
index 2ae98b3a1f1..00000000000
--- a/chromium/chrome/browser/resources/hotword/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-kcarattini@chromium.org
-mgiuca@chromium.org
diff --git a/chromium/chrome/browser/resources/hotword/always_on_manager.js b/chromium/chrome/browser/resources/hotword/always_on_manager.js
deleted file mode 100644
index f34bc6da370..00000000000
--- a/chromium/chrome/browser/resources/hotword/always_on_manager.js
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-cr.define('hotword', function() {
- 'use strict';
-
- /**
- * Class used to manage always-on hotwording. Automatically starts hotwording
- * on startup, if always-on is enabled, and starts/stops hotwording at
- * appropriate times.
- * @param {!hotword.StateManager} stateManager
- * @constructor
- * @extends {hotword.BaseSessionManager}
- */
- function AlwaysOnManager(stateManager) {
- hotword.BaseSessionManager.call(
- this, stateManager, hotword.constants.SessionSource.ALWAYS);
- }
-
- AlwaysOnManager.prototype = {
- __proto__: hotword.BaseSessionManager.prototype,
-
- /** @override */
- enabled: function() {
- return this.stateManager.isAlwaysOnEnabled();
- },
-
- /** @override */
- updateListeners: function() {
- hotword.BaseSessionManager.prototype.updateListeners.call(this);
- if (this.enabled())
- this.startSession();
- }
- };
-
- return {AlwaysOnManager: AlwaysOnManager};
-});
diff --git a/chromium/chrome/browser/resources/hotword/audio_client.js b/chromium/chrome/browser/resources/hotword/audio_client.js
deleted file mode 100644
index 552dd49cdaf..00000000000
--- a/chromium/chrome/browser/resources/hotword/audio_client.js
+++ /dev/null
@@ -1,375 +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.
-
-'use strict';
-
-/* eslint-disable no-restricted-properties */
-
-/**
- * @fileoverview This is the audio client content script injected into eligible
- * Google.com and New tab pages for interaction between the Webpage and the
- * Hotword extension.
- */
-
-(function() {
-/**
- * @constructor
- */
-var AudioClient = function() {
- /** @private {Element} */
- this.speechOverlay_ = null;
-
- /** @private {number} */
- this.checkSpeechUiRetries_ = 0;
-
- /**
- * Port used to communicate with the audio manager.
- * @private {?Port}
- */
- this.port_ = null;
-
- /**
- * Keeps track of the effects of different commands. Used to verify that
- * proper UIs are shown to the user.
- * @private {Object<AudioClient.CommandToPage, Object>}
- */
- this.uiStatus_ = null;
-
- /**
- * Bound function used to handle commands sent from the page to this script.
- * @private {Function}
- */
- this.handleCommandFromPageFunc_ = null;
-};
-
-/**
- * Messages sent to the page to control the voice search UI.
- * @enum {string}
- */
-AudioClient.CommandToPage = {
- HOTWORD_VOICE_TRIGGER: 'vt',
- HOTWORD_STARTED: 'hs',
- HOTWORD_ENDED: 'hd',
- HOTWORD_TIMEOUT: 'ht',
- HOTWORD_ERROR: 'he'
-};
-
-/**
- * Messages received from the page used to indicate voice search state.
- * @enum {string}
- */
-AudioClient.CommandFromPage = {
- SPEECH_START: 'ss',
- SPEECH_END: 'se',
- SPEECH_RESET: 'sr',
- SHOWING_HOTWORD_START: 'shs',
- SHOWING_ERROR_MESSAGE: 'sem',
- SHOWING_TIMEOUT_MESSAGE: 'stm',
- CLICKED_RESUME: 'hcc',
- CLICKED_RESTART: 'hcr',
- CLICKED_DEBUG: 'hcd'
-};
-
-/**
- * Errors that are sent to the hotword extension.
- * @enum {string}
- */
-AudioClient.Error = {
- NO_SPEECH_UI: 'ac1',
- NO_HOTWORD_STARTED_UI: 'ac2',
- NO_HOTWORD_TIMEOUT_UI: 'ac3',
- NO_HOTWORD_ERROR_UI: 'ac4'
-};
-
-/**
- * @const {string}
- * @private
- */
-AudioClient.HOTWORD_EXTENSION_ID_ = 'nbpagnldghgfoolbancepceaanlmhfmd';
-
-/**
- * Number of times to retry checking a transient error.
- * @const {number}
- * @private
- */
-AudioClient.MAX_RETRIES = 3;
-
-/**
- * Delay to wait in milliseconds before rechecking for any transient errors.
- * @const {number}
- * @private
- */
-AudioClient.RETRY_TIME_MS_ = 2000;
-
-/**
- * DOM ID for the speech UI overlay.
- * @const {string}
- * @private
- */
-AudioClient.SPEECH_UI_OVERLAY_ID_ = 'spch';
-
-/**
- * @const {string}
- * @private
- */
-AudioClient.HELP_CENTER_URL_ =
- 'https://support.google.com/chrome/?p=ui_hotword_search';
-
-/**
- * @const {string}
- * @private
- */
-AudioClient.CLIENT_PORT_NAME_ = 'chwcpn';
-
-/**
- * Existence of the Audio Client.
- * @const {string}
- * @private
- */
-AudioClient.EXISTS_ = 'chwace';
-
-/**
- * Checks for the presence of speech overlay UI DOM elements.
- * @private
- */
-AudioClient.prototype.checkSpeechOverlayUi_ = function() {
- if (!this.speechOverlay_) {
- window.setTimeout(
- this.delayedCheckSpeechOverlayUi_.bind(this),
- AudioClient.RETRY_TIME_MS_);
- } else {
- this.checkSpeechUiRetries_ = 0;
- }
-};
-
-/**
- * Function called to check for the speech UI overlay after some time has
- * passed since an initial check. Will either retry triggering the speech
- * or sends an error message depending on the number of retries.
- * @private
- */
-AudioClient.prototype.delayedCheckSpeechOverlayUi_ = function() {
- this.speechOverlay_ =
- document.getElementById(AudioClient.SPEECH_UI_OVERLAY_ID_);
- if (!this.speechOverlay_) {
- if (this.checkSpeechUiRetries_++ < AudioClient.MAX_RETRIES) {
- this.sendCommandToPage_(AudioClient.CommandToPage.VOICE_TRIGGER);
- this.checkSpeechOverlayUi_();
- } else {
- this.sendCommandToExtension_(AudioClient.Error.NO_SPEECH_UI);
- }
- } else {
- this.checkSpeechUiRetries_ = 0;
- }
-};
-
-/**
- * Checks that the triggered UI is actually displayed.
- * @param {AudioClient.CommandToPage} command Command that was send.
- * @private
- */
-AudioClient.prototype.checkUi_ = function(command) {
- this.uiStatus_[command].timeoutId = window.setTimeout(
- this.failedCheckUi_.bind(this, command), AudioClient.RETRY_TIME_MS_);
-};
-
-/**
- * Function called when the UI verification is not called in time. Will either
- * retry the command or sends an error message, depending on the number of
- * retries for the command.
- * @param {AudioClient.CommandToPage} command Command that was sent.
- * @private
- */
-AudioClient.prototype.failedCheckUi_ = function(command) {
- if (this.uiStatus_[command].tries++ < AudioClient.MAX_RETRIES) {
- this.sendCommandToPage_(command);
- this.checkUi_(command);
- } else {
- this.sendCommandToExtension_(this.uiStatus_[command].error);
- }
-};
-
-/**
- * Confirm that an UI element has been shown.
- * @param {AudioClient.CommandToPage} command UI to confirm.
- * @private
- */
-AudioClient.prototype.verifyUi_ = function(command) {
- if (this.uiStatus_[command].timeoutId) {
- window.clearTimeout(this.uiStatus_[command].timeoutId);
- this.uiStatus_[command].timeoutId = null;
- this.uiStatus_[command].tries = 0;
- }
-};
-
-/**
- * Sends a command to the audio manager.
- * @param {string} commandStr command to send to plugin.
- * @private
- */
-AudioClient.prototype.sendCommandToExtension_ = function(commandStr) {
- if (this.port_)
- this.port_.postMessage({'cmd': commandStr});
-};
-
-/**
- * Handles a message from the audio manager.
- * @param {{cmd: string}} commandObj Command from the audio manager.
- * @private
- */
-AudioClient.prototype.handleCommandFromExtension_ = function(commandObj) {
- var command = commandObj['cmd'];
- if (command) {
- switch (command) {
- case AudioClient.CommandToPage.HOTWORD_VOICE_TRIGGER:
- this.sendCommandToPage_(command);
- this.checkSpeechOverlayUi_();
- break;
- case AudioClient.CommandToPage.HOTWORD_STARTED:
- this.sendCommandToPage_(command);
- this.checkUi_(command);
- break;
- case AudioClient.CommandToPage.HOTWORD_ENDED:
- this.sendCommandToPage_(command);
- break;
- case AudioClient.CommandToPage.HOTWORD_TIMEOUT:
- this.sendCommandToPage_(command);
- this.checkUi_(command);
- break;
- case AudioClient.CommandToPage.HOTWORD_ERROR:
- this.sendCommandToPage_(command);
- this.checkUi_(command);
- break;
- }
- }
-};
-
-/**
- * @param {AudioClient.CommandToPage} commandStr Command to send.
- * @private
- */
-AudioClient.prototype.sendCommandToPage_ = function(commandStr) {
- window.postMessage({'type': commandStr}, '*');
-};
-
-/**
- * Handles a message from the html window.
- * @param {!MessageEvent} messageEvent Message event from the window.
- * @private
- */
-AudioClient.prototype.handleCommandFromPage_ = function(messageEvent) {
- if (messageEvent.source == window && messageEvent.data.type) {
- var command = messageEvent.data.type;
- switch (command) {
- case AudioClient.CommandFromPage.SPEECH_START:
- this.speechActive_ = true;
- this.sendCommandToExtension_(command);
- break;
- case AudioClient.CommandFromPage.SPEECH_END:
- this.speechActive_ = false;
- this.sendCommandToExtension_(command);
- break;
- case AudioClient.CommandFromPage.SPEECH_RESET:
- this.speechActive_ = false;
- this.sendCommandToExtension_(command);
- break;
- case 'SPEECH_RESET': // Legacy, for embedded NTP.
- this.speechActive_ = false;
- this.sendCommandToExtension_(AudioClient.CommandFromPage.SPEECH_END);
- break;
- case AudioClient.CommandFromPage.CLICKED_RESUME:
- this.sendCommandToExtension_(command);
- break;
- case AudioClient.CommandFromPage.CLICKED_RESTART:
- this.sendCommandToExtension_(command);
- break;
- case AudioClient.CommandFromPage.CLICKED_DEBUG:
- window.open(AudioClient.HELP_CENTER_URL_, '_blank');
- break;
- case AudioClient.CommandFromPage.SHOWING_HOTWORD_START:
- this.verifyUi_(AudioClient.CommandToPage.HOTWORD_STARTED);
- break;
- case AudioClient.CommandFromPage.SHOWING_ERROR_MESSAGE:
- this.verifyUi_(AudioClient.CommandToPage.HOTWORD_ERROR);
- break;
- case AudioClient.CommandFromPage.SHOWING_TIMEOUT_MESSAGE:
- this.verifyUi_(AudioClient.CommandToPage.HOTWORD_TIMEOUT);
- break;
- }
- }
-};
-
-/**
- * Initialize the content script.
- */
-AudioClient.prototype.initialize = function() {
- if (AudioClient.EXISTS_ in window)
- return;
- window[AudioClient.EXISTS_] = true;
-
- // UI verification object.
- this.uiStatus_ = {};
- this.uiStatus_[AudioClient.CommandToPage.HOTWORD_STARTED] = {
- timeoutId: null,
- tries: 0,
- error: AudioClient.Error.NO_HOTWORD_STARTED_UI
- };
- this.uiStatus_[AudioClient.CommandToPage.HOTWORD_TIMEOUT] = {
- timeoutId: null,
- tries: 0,
- error: AudioClient.Error.NO_HOTWORD_TIMEOUT_UI
- };
- this.uiStatus_[AudioClient.CommandToPage.HOTWORD_ERROR] = {
- timeoutId: null,
- tries: 0,
- error: AudioClient.Error.NO_HOTWORD_ERROR_UI
- };
-
- this.handleCommandFromPageFunc_ = this.handleCommandFromPage_.bind(this);
- window.addEventListener('message', this.handleCommandFromPageFunc_, false);
- this.initPort_();
-};
-
-/**
- * Initialize the communications port with the audio manager. This
- * function will be also be called again if the audio-manager
- * disconnects for some reason (such as the extension
- * background.html page being reloaded).
- * @private
- */
-AudioClient.prototype.initPort_ = function() {
- this.port_ = chrome.runtime.connect(
- AudioClient.HOTWORD_EXTENSION_ID_,
- {'name': AudioClient.CLIENT_PORT_NAME_});
- // Note that this listen may have to be destroyed manually if AudioClient
- // is ever destroyed on this tab.
- this.port_.onDisconnect.addListener(
- (function(e) {
- if (this.handleCommandFromPageFunc_) {
- window.removeEventListener(
- 'message', this.handleCommandFromPageFunc_, false);
- }
- delete window[AudioClient.EXISTS_];
- }).bind(this));
-
- // See note above.
- this.port_.onMessage.addListener(this.handleCommandFromExtension_.bind(this));
-
- if (this.speechActive_) {
- this.sendCommandToExtension_(AudioClient.CommandFromPage.SPEECH_START);
- } else {
- // It's possible for this script to be injected into the page after it has
- // completed loaded (i.e. when prerendering). In this case, this script
- // won't receive a SPEECH_RESET from the page to forward onto the
- // extension. To make up for this, always send a SPEECH_RESET. This means
- // in most cases, the extension will receive SPEECH_RESET twice, one from
- // this sendCommandToExtension_ and the one forwarded from the page. But
- // that's OK and the extension can handle it.
- this.sendCommandToExtension_(AudioClient.CommandFromPage.SPEECH_RESET);
- }
-};
-
-// Initializes as soon as the code is ready, do not wait for the page.
-new AudioClient().initialize();
-})();
diff --git a/chromium/chrome/browser/resources/hotword/base_session_manager.js b/chromium/chrome/browser/resources/hotword/base_session_manager.js
deleted file mode 100644
index 6891199d9a5..00000000000
--- a/chromium/chrome/browser/resources/hotword/base_session_manager.js
+++ /dev/null
@@ -1,152 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-cr.define('hotword', function() {
- 'use strict';
-
- /**
- * Base class for managing hotwording sessions.
- * @param {!hotword.StateManager} stateManager Manager of global hotwording
- * state.
- * @param {!hotword.constants.SessionSource} sessionSource Source of the
- * hotword session request.
- * @constructor
- */
- function BaseSessionManager(stateManager, sessionSource) {
- /**
- * Manager of global hotwording state.
- * @protected {!hotword.StateManager}
- */
- this.stateManager = stateManager;
-
- /**
- * Source of the hotword session request.
- * @private {!hotword.constants.SessionSource}
- */
- this.sessionSource_ = sessionSource;
-
- /**
- * Chrome event listeners. Saved so that they can be de-registered when
- * hotwording is disabled.
- * @private
- */
- this.sessionRequestedListener_ = this.handleSessionRequested_.bind(this);
- this.sessionStoppedListener_ = this.handleSessionStopped_.bind(this);
-
- // Need to setup listeners on startup, otherwise events that caused the
- // event page to start up, will be lost.
- this.setupListeners_();
-
- this.stateManager.onStatusChanged.addListener(function() {
- hotword.debug('onStatusChanged');
- this.updateListeners();
- }.bind(this));
- }
-
- BaseSessionManager.prototype = {
- /**
- * Return whether or not this session type is enabled.
- * @protected
- * @return {boolean}
- */
- enabled: assertNotReached,
-
- /**
- * Called when the hotwording session is stopped.
- * @protected
- */
- onSessionStop: function() {},
-
- /**
- * Starts a launcher hotwording session.
- * @param {hotword.constants.TrainingMode=} opt_mode The mode to start the
- * recognizer in.
- */
- startSession: function(opt_mode) {
- this.stateManager.startSession(this.sessionSource_, function() {
- chrome.hotwordPrivate.setHotwordSessionState(true, function() {});
- }, this.handleHotwordTrigger.bind(this), opt_mode);
- },
-
- /**
- * Stops a launcher hotwording session.
- * @private
- */
- stopSession_: function() {
- this.stateManager.stopSession(this.sessionSource_);
- this.onSessionStop();
- },
-
- /**
- * Handles a hotword triggered event.
- * @param {?Object} log Audio log data, if audio logging is enabled.
- * @protected
- */
- handleHotwordTrigger: function(log) {
- hotword.debug('Hotword triggered: ' + this.sessionSource_, log);
- chrome.hotwordPrivate.notifyHotwordRecognition(
- 'search', log, function() {});
- },
-
- /**
- * Handles a hotwordPrivate.onHotwordSessionRequested event.
- * @private
- */
- handleSessionRequested_: function() {
- hotword.debug('handleSessionRequested_: ' + this.sessionSource_);
- this.startSession();
- },
-
- /**
- * Handles a hotwordPrivate.onHotwordSessionStopped event.
- * @private
- */
- handleSessionStopped_: function() {
- hotword.debug('handleSessionStopped_: ' + this.sessionSource_);
- this.stopSession_();
- },
-
- /**
- * Set up event listeners.
- * @private
- */
- setupListeners_: function() {
- if (chrome.hotwordPrivate.onHotwordSessionRequested.hasListener(
- this.sessionRequestedListener_)) {
- return;
- }
-
- chrome.hotwordPrivate.onHotwordSessionRequested.addListener(
- this.sessionRequestedListener_);
- chrome.hotwordPrivate.onHotwordSessionStopped.addListener(
- this.sessionStoppedListener_);
- },
-
- /**
- * Remove event listeners.
- * @private
- */
- removeListeners_: function() {
- chrome.hotwordPrivate.onHotwordSessionRequested.removeListener(
- this.sessionRequestedListener_);
- chrome.hotwordPrivate.onHotwordSessionStopped.removeListener(
- this.sessionStoppedListener_);
- },
-
- /**
- * Update event listeners based on the current hotwording state.
- * @protected
- */
- updateListeners: function() {
- if (this.enabled()) {
- this.setupListeners_();
- } else {
- this.removeListeners_();
- this.stopSession_();
- }
- }
- };
-
- return {BaseSessionManager: BaseSessionManager};
-});
diff --git a/chromium/chrome/browser/resources/hotword/constants.js b/chromium/chrome/browser/resources/hotword/constants.js
deleted file mode 100644
index 0fbfa0e8a45..00000000000
--- a/chromium/chrome/browser/resources/hotword/constants.js
+++ /dev/null
@@ -1,299 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-cr.define('hotword.constants', function() {
- 'use strict';
-
- /**
- * Number of seconds of audio to record when logging is enabled.
- * @const {number}
- */
- var AUDIO_LOG_SECONDS = 2;
-
- /**
- * Timeout in seconds, for detecting false positives with a hotword stream.
- * @const {number}
- */
- var HOTWORD_STREAM_TIMEOUT_SECONDS = 2;
-
- /**
- * Hotword data shared module extension's ID.
- * @const {string}
- */
- var SHARED_MODULE_ID = 'lccekmodgklaepjeofjdjpbminllajkg';
-
- /**
- * Path to shared module data.
- * @const {string}
- */
- var SHARED_MODULE_ROOT = '_modules/' + SHARED_MODULE_ID;
-
- /**
- * Name used by the content scripts to create communications Ports.
- * @const {string}
- */
- var CLIENT_PORT_NAME = 'chwcpn';
-
- /**
- * The field name to specify the command among pages.
- * @const {string}
- */
- var COMMAND_FIELD_NAME = 'cmd';
-
- /**
- * The speaker model file name.
- * @const {string}
- */
- var SPEAKER_MODEL_FILE_NAME = 'speaker_model.data';
-
- /**
- * The training utterance file name prefix.
- * @const {string}
- */
- var UTTERANCE_FILE_PREFIX = 'utterance-';
-
- /**
- * The training utterance file extension.
- * @const {string}
- */
- var UTTERANCE_FILE_EXTENSION = '.raw';
-
- /**
- * The number of training utterances required to train the speaker model.
- * @const {number}
- */
- var NUM_TRAINING_UTTERANCES = 3;
-
- /**
- * The size of the file system requested for reading the speaker model and
- * utterances. This number should always be larger than the combined file
- * size,
- * currently 576338 bytes as of February 2015.
- * @const {number}
- */
- var FILE_SYSTEM_SIZE_BYTES = 1048576;
-
- /**
- * Time to wait for expected messages, in milliseconds.
- * @enum {number}
- */
- var TimeoutMs = {SHORT: 200, NORMAL: 500, LONG: 2000};
-
- /**
- * The URL of the files used by the plugin.
- * @enum {string}
- */
- var File = {
- RECOGNIZER_CONFIG: 'hotword.data',
- };
-
- /**
- * Errors emitted by the NaClManager.
- * @enum {string}
- */
- var Error = {
- NACL_CRASH: 'nacl_crash',
- TIMEOUT: 'timeout',
- };
-
- /**
- * Event types supported by NaClManager.
- * @enum {string}
- */
- var Event = {
- READY: 'ready',
- TRIGGER: 'trigger',
- SPEAKER_MODEL_SAVED: 'speaker model saved',
- ERROR: 'error',
- TIMEOUT: 'timeout',
- };
-
- /**
- * Messages for communicating with the NaCl recognizer plugin. These must
- * match
- * constants in <google3>/hotword_plugin.c
- * @enum {string}
- */
- var NaClPlugin = {
- RESTART: 'r',
- SAMPLE_RATE_PREFIX: 'h',
- MODEL_PREFIX: 'm',
- STOP: 's',
- LOG: 'l',
- DSP: 'd',
- BEGIN_SPEAKER_MODEL: 'b',
- ADAPT_SPEAKER_MODEL: 'a',
- FINISH_SPEAKER_MODEL: 'f',
- SPEAKER_MODEL_SAVED: 'sm_saved',
- REQUEST_MODEL: 'model',
- MODEL_LOADED: 'model_loaded',
- READY_FOR_AUDIO: 'audio',
- STOPPED: 'stopped',
- HOTWORD_DETECTED: 'hotword',
- MS_CONFIGURED: 'ms_configured',
- TIMEOUT: 'timeout'
- };
-
- /**
- * Messages sent from the injected scripts to the Google page.
- * @enum {string}
- */
- var CommandToPage = {
- HOTWORD_VOICE_TRIGGER: 'vt',
- HOTWORD_STARTED: 'hs',
- HOTWORD_ENDED: 'hd',
- HOTWORD_TIMEOUT: 'ht',
- HOTWORD_ERROR: 'he'
- };
-
- /**
- * Messages sent from the Google page to the extension or to the
- * injected script and then passed to the extension.
- * @enum {string}
- */
- var CommandFromPage = {
- SPEECH_START: 'ss',
- SPEECH_END: 'se',
- SPEECH_RESET: 'sr',
- SHOWING_HOTWORD_START: 'shs',
- SHOWING_ERROR_MESSAGE: 'sem',
- SHOWING_TIMEOUT_MESSAGE: 'stm',
- CLICKED_RESUME: 'hcc',
- CLICKED_RESTART: 'hcr',
- CLICKED_DEBUG: 'hcd',
- WAKE_UP_HELPER: 'wuh',
- // Command specifically for the opt-in promo below this line.
- // User has explicitly clicked 'no'.
- CLICKED_NO_OPTIN: 'hcno',
- // User has opted in.
- CLICKED_OPTIN: 'hco',
- // User clicked on the microphone.
- PAGE_WAKEUP: 'wu'
- };
-
- /**
- * Source of a hotwording session request.
- * @enum {string}
- */
- var SessionSource = {
- LAUNCHER: 'launcher',
- NTP: 'ntp',
- ALWAYS: 'always',
- TRAINING: 'training'
- };
-
- /**
- * The mode to start the hotword recognizer in.
- * @enum {string}
- */
- var RecognizerStartMode = {
- NORMAL: 'normal',
- NEW_MODEL: 'new model',
- ADAPT_MODEL: 'adapt model'
- };
-
- /**
- * MediaStream open success/errors to be reported via UMA.
- * DO NOT remove or renumber values in this enum. Only add new ones.
- * @enum {number}
- */
- var UmaMediaStreamOpenResult = {
- SUCCESS: 0,
- UNKNOWN: 1,
- NOT_SUPPORTED: 2,
- PERMISSION_DENIED: 3,
- CONSTRAINT_NOT_SATISFIED: 4,
- OVERCONSTRAINED: 5,
- NOT_FOUND: 6,
- ABORT: 7,
- SOURCE_UNAVAILABLE: 8,
- PERMISSION_DISMISSED: 9,
- INVALID_STATE: 10,
- DEVICES_NOT_FOUND: 11,
- INVALID_SECURITY_ORIGIN: 12,
- MAX: 12
- };
-
- /**
- * UMA metrics.
- * DO NOT change these enum values.
- * @enum {string}
- */
- var UmaMetrics = {
- TRIGGER: 'Hotword.HotwordTrigger',
- MEDIA_STREAM_RESULT: 'Hotword.HotwordMediaStreamResult',
- NACL_PLUGIN_LOAD_RESULT: 'Hotword.HotwordNaClPluginLoadResult',
- NACL_MESSAGE_TIMEOUT: 'Hotword.HotwordNaClMessageTimeout',
- TRIGGER_SOURCE: 'Hotword.HotwordTriggerSource'
- };
-
- /**
- * Message waited for by NaCl plugin, to be reported via UMA.
- * DO NOT remove or renumber values in this enum. Only add new ones.
- * @enum {number}
- */
- var UmaNaClMessageTimeout = {
- REQUEST_MODEL: 0,
- MODEL_LOADED: 1,
- READY_FOR_AUDIO: 2,
- STOPPED: 3,
- HOTWORD_DETECTED: 4,
- MS_CONFIGURED: 5,
- MAX: 5
- };
-
- /**
- * NaCl plugin load success/errors to be reported via UMA.
- * DO NOT remove or renumber values in this enum. Only add new ones.
- * @enum {number}
- */
- var UmaNaClPluginLoadResult =
- {SUCCESS: 0, UNKNOWN: 1, CRASH: 2, NO_MODULE_FOUND: 3, MAX: 3};
-
- /**
- * Source of hotword triggering, to be reported via UMA.
- * DO NOT remove or renumber values in this enum. Only add new ones.
- * @enum {number}
- */
- var UmaTriggerSource =
- {LAUNCHER: 0, NTP_GOOGLE_COM: 1, ALWAYS_ON: 2, TRAINING: 3, MAX: 3};
-
- /**
- * The browser UI language.
- * @const {string}
- */
- var UI_LANGUAGE = (chrome.i18n && chrome.i18n.getUILanguage) ?
- chrome.i18n.getUILanguage() :
- '';
-
- return {
- AUDIO_LOG_SECONDS: AUDIO_LOG_SECONDS,
- CLIENT_PORT_NAME: CLIENT_PORT_NAME,
- COMMAND_FIELD_NAME: COMMAND_FIELD_NAME,
- FILE_SYSTEM_SIZE_BYTES: FILE_SYSTEM_SIZE_BYTES,
- HOTWORD_STREAM_TIMEOUT_SECONDS: HOTWORD_STREAM_TIMEOUT_SECONDS,
- NUM_TRAINING_UTTERANCES: NUM_TRAINING_UTTERANCES,
- SHARED_MODULE_ID: SHARED_MODULE_ID,
- SHARED_MODULE_ROOT: SHARED_MODULE_ROOT,
- SPEAKER_MODEL_FILE_NAME: SPEAKER_MODEL_FILE_NAME,
- UI_LANGUAGE: UI_LANGUAGE,
- UTTERANCE_FILE_EXTENSION: UTTERANCE_FILE_EXTENSION,
- UTTERANCE_FILE_PREFIX: UTTERANCE_FILE_PREFIX,
- CommandToPage: CommandToPage,
- CommandFromPage: CommandFromPage,
- Error: Error,
- Event: Event,
- File: File,
- NaClPlugin: NaClPlugin,
- RecognizerStartMode: RecognizerStartMode,
- SessionSource: SessionSource,
- TimeoutMs: TimeoutMs,
- UmaMediaStreamOpenResult: UmaMediaStreamOpenResult,
- UmaMetrics: UmaMetrics,
- UmaNaClMessageTimeout: UmaNaClMessageTimeout,
- UmaNaClPluginLoadResult: UmaNaClPluginLoadResult,
- UmaTriggerSource: UmaTriggerSource
- };
-
-});
diff --git a/chromium/chrome/browser/resources/hotword/keep_alive.js b/chromium/chrome/browser/resources/hotword/keep_alive.js
deleted file mode 100644
index 20ff2eabb9d..00000000000
--- a/chromium/chrome/browser/resources/hotword/keep_alive.js
+++ /dev/null
@@ -1,52 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-cr.define('hotword', function() {
- 'use strict';
-
- /**
- * Class used to keep this extension alive. When started, this calls an
- * extension API on a regular basis which resets the event page keep-alive
- * timer.
- * @constructor
- */
- function KeepAlive() {
- this.timeoutId_ = null;
- }
-
- KeepAlive.prototype = {
- /**
- * Start the keep alive process. Safe to call multiple times.
- */
- start: function() {
- if (this.timeoutId_ == null)
- this.timeoutId_ = setTimeout(this.handleTimeout_.bind(this), 1000);
- },
-
- /**
- * Stops the keep alive process. Safe to call multiple times.
- */
- stop: function() {
- if (this.timeoutId_ != null) {
- clearTimeout(this.timeoutId_);
- this.timeoutId_ = null;
- }
- },
-
- /**
- * Handle the timer timeout. Calls an extension API and schedules the next
- * timeout.
- * @private
- */
- handleTimeout_: function() {
- // Dummy extensions API call used to keep this event page alive by
- // resetting the shutdown timer.
- chrome.runtime.getPlatformInfo(function(info) {});
-
- this.timeoutId_ = setTimeout(this.handleTimeout_.bind(this), 1000);
- }
- };
-
- return {KeepAlive: KeepAlive};
-});
diff --git a/chromium/chrome/browser/resources/hotword/launcher_manager.js b/chromium/chrome/browser/resources/hotword/launcher_manager.js
deleted file mode 100644
index 144c247eec4..00000000000
--- a/chromium/chrome/browser/resources/hotword/launcher_manager.js
+++ /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.
-
-cr.define('hotword', function() {
- 'use strict';
-
- /**
- * Class used to manage the interaction between hotwording and the launcher
- * (app list).
- * @param {!hotword.StateManager} stateManager
- * @constructor
- * @extends {hotword.BaseSessionManager}
- */
- function LauncherManager(stateManager) {
- hotword.BaseSessionManager.call(
- this, stateManager, hotword.constants.SessionSource.LAUNCHER);
- }
-
- LauncherManager.prototype = {
- __proto__: hotword.BaseSessionManager.prototype,
-
- /** @override */
- enabled: function() {
- return this.stateManager.isSometimesOnEnabled();
- },
-
- /** @override */
- onSessionStop: function() {
- chrome.hotwordPrivate.setHotwordSessionState(false, function() {});
- }
- };
-
- return {LauncherManager: LauncherManager};
-});
diff --git a/chromium/chrome/browser/resources/hotword/logging.js b/chromium/chrome/browser/resources/hotword/logging.js
deleted file mode 100644
index e0744e07a42..00000000000
--- a/chromium/chrome/browser/resources/hotword/logging.js
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-cr.define('hotword', function() {
- 'use strict';
-
- /**
- * Wrapper around console.log allowing debug log message to be enabled during
- * development.
- * @param {...*} varArgs
- */
- function debug(varArgs) {
- if (hotword.DEBUG || window.localStorage['hotword.DEBUG'])
- console.log.apply(console, arguments);
- }
-
- return {DEBUG: false, debug: debug};
-});
diff --git a/chromium/chrome/browser/resources/hotword/manager.js b/chromium/chrome/browser/resources/hotword/manager.js
deleted file mode 100644
index f4ac1473c9a..00000000000
--- a/chromium/chrome/browser/resources/hotword/manager.js
+++ /dev/null
@@ -1,50 +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() {
-'use strict';
-
-/**
- * @fileoverview This extension provides hotword triggering capabilites to
- * Chrome.
- *
- * This extension contains all the JavaScript for loading and managing the
- * hotword detector. The hotword detector and language model data will be
- * provided by a shared module loaded from the web store.
- *
- * IMPORTANT! Whenever adding new events, the extension version number MUST be
- * incremented.
- */
-
-// Hotwording state.
-var stateManager = new hotword.StateManager();
-var pageAudioManager = new hotword.PageAudioManager(stateManager);
-var alwaysOnManager = new hotword.AlwaysOnManager(stateManager);
-var launcherManager = new hotword.LauncherManager(stateManager);
-var trainingManager = new hotword.TrainingManager(stateManager);
-
-// Detect when hotword settings have changed.
-chrome.hotwordPrivate.onEnabledChanged.addListener(function() {
- stateManager.updateStatus();
-});
-
-// Detect a request to delete the speaker model.
-chrome.hotwordPrivate.onDeleteSpeakerModel.addListener(function() {
- hotword.TrainingManager.handleDeleteSpeakerModel();
-});
-
-// Detect a request for the speaker model existence.
-chrome.hotwordPrivate.onSpeakerModelExists.addListener(function() {
- hotword.TrainingManager.handleSpeakerModelExists();
-});
-
-// Detect when the shared module containing the NaCL module and language model
-// is installed.
-chrome.management.onInstalled.addListener(function(info) {
- if (info.id == hotword.constants.SHARED_MODULE_ID) {
- hotword.debug('Shared module installed, reloading extension.');
- chrome.runtime.reload();
- }
-});
-}());
diff --git a/chromium/chrome/browser/resources/hotword/manifest.json b/chromium/chrome/browser/resources/hotword/manifest.json
deleted file mode 100644
index e22ff936ddb..00000000000
--- a/chromium/chrome/browser/resources/hotword/manifest.json
+++ /dev/null
@@ -1,88 +0,0 @@
-{
- // Extension ID: nbpagnldghgfoolbancepceaanlmhfmd
- "key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDbHXRPiq2De9EJ+4pvNN6uE/D2avxrqyLSpA/Hq3II+btkPl1gboY3oUPTfevpVOFa90Y1c1b3/W682dXqybT0klIvFLKhdQx0LiVqSUQyIaDrwOCSo/ZcukbEwDRojegWymCjHvX6WZk4kKZzTJYzY1vrp0TWKLhttEMN9KFmowIDAQAB",
-
- "name": "Hotword triggering",
- "version": "0.0.1.4",
- "manifest_version": 2,
-
- "background": {
- "scripts": [
- "chrome://resources/js/cr.js",
- "chrome://resources/js/util.js",
- "chrome://resources/js/cr/event_target.js",
- "constants.js",
- "keep_alive.js",
- "logging.js",
- "metrics.js",
- "nacl_manager.js",
- "state_manager.js",
- "base_session_manager.js",
- "always_on_manager.js",
- "launcher_manager.js",
- "page_audio_manager.js",
- "training_manager.js",
- "manager.js"
- ],
- "persistent": false
- },
-
- "permissions": [
- "*://*.google.at/*",
- "*://*.google.ca/*",
- "*://*.google.com/*",
- "*://*.google.com.au/*",
- "*://*.google.com.mx/*",
- "*://*.google.com.br/*",
- "*://*.google.co.jp/*",
- "*://*.google.co.kr/*",
- "*://*.google.co.nz/*",
- "*://*.google.co.uk/*",
- "*://*.google.co.za/*",
- "*://*.google.de/*",
- "*://*.google.es/*",
- "*://*.google.fr/*",
- "*://*.google.it/*",
- "*://*.google.ru/*",
- "chrome://newtab/",
- "chrome://resources/",
- "audioCapture",
- "hotwordPrivate",
- "idle",
- "management",
- "metricsPrivate",
- "tabs",
- "unlimitedStorage"
- ],
-
- "externally_connectable": {
- "matches": [
- "*://*.google.at/*",
- "*://*.google.ca/*",
- "*://*.google.com/*",
- "*://*.google.com.au/*",
- "*://*.google.com.mx/*",
- "*://*.google.com.br/*",
- "*://*.google.co.jp/*",
- "*://*.google.co.kr/*",
- "*://*.google.co.nz/*",
- "*://*.google.co.uk/*",
- "*://*.google.co.za/*",
- "*://*.google.de/*",
- "*://*.google.es/*",
- "*://*.google.fr/*",
- "*://*.google.it/*",
- "*://*.google.ru/*",
- "chrome://newtab/"
- ]
- },
-
- "import": [
- {
- "id": "lccekmodgklaepjeofjdjpbminllajkg"
- }
- ],
-
- "content_security_policy": "object-src 'none'; script-src chrome://resources 'self' blob: filesystem:",
- "minimum_chrome_version": "38"
-}
diff --git a/chromium/chrome/browser/resources/hotword/metrics.js b/chromium/chrome/browser/resources/hotword/metrics.js
deleted file mode 100644
index 7d4001bf3ec..00000000000
--- a/chromium/chrome/browser/resources/hotword/metrics.js
+++ /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.
-
-cr.define('hotword.metrics', function() {
- 'use strict';
-
- /**
- * Helper function to record enum values in UMA.
- * @param {!string} name
- * @param {!number} value
- * @param {!number} maxValue
- */
- function recordEnum(name, value, maxValue) {
- var metricDesc = {
- 'metricName': name,
- 'type': chrome.metricsPrivate.MetricTypeType.HISTOGRAM_LINEAR,
- 'min': 1,
- 'max': maxValue,
- 'buckets': maxValue + 1
- };
- chrome.metricsPrivate.recordValue(metricDesc, value);
- }
-
- return {recordEnum: recordEnum};
-});
diff --git a/chromium/chrome/browser/resources/hotword/nacl_manager.js b/chromium/chrome/browser/resources/hotword/nacl_manager.js
deleted file mode 100644
index 015399f346c..00000000000
--- a/chromium/chrome/browser/resources/hotword/nacl_manager.js
+++ /dev/null
@@ -1,612 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-cr.define('hotword', function() {
- 'use strict';
-
- /**
- * Class used to manage the state of the NaCl recognizer plugin. Handles all
- * control of the NaCl plugin, including creation, start, stop, trigger, and
- * shutdown.
- *
- * @param {boolean} loggingEnabled Whether audio logging is enabled.
- * @param {boolean} hotwordStream Whether the audio input stream is from a
- * hotword stream.
- * @constructor
- * @extends {cr.EventTarget}
- */
- function NaClManager(loggingEnabled, hotwordStream) {
- /**
- * Current state of this manager.
- * @private {hotword.NaClManager.ManagerState_}
- */
- this.recognizerState_ = ManagerState_.UNINITIALIZED;
-
- /**
- * The window.timeout ID associated with a pending message.
- * @private {?number}
- */
- this.naclTimeoutId_ = null;
-
- /**
- * The expected message that will cancel the current timeout.
- * @private {?string}
- */
- this.expectingMessage_ = null;
-
- /**
- * Whether the plugin will be started as soon as it stops.
- * @private {boolean}
- */
- this.restartOnStop_ = false;
-
- /**
- * NaCl plugin element on extension background page.
- * @private {?HTMLEmbedElement}
- */
- this.plugin_ = null;
-
- /**
- * URL containing hotword-model data file.
- * @private {string}
- */
- this.modelUrl_ = '';
-
- /**
- * Media stream containing an audio input track.
- * @private {?MediaStream}
- */
- this.stream_ = null;
-
- /**
- * The mode to start the recognizer in.
- * @private {?chrome.hotwordPrivate.RecognizerStartMode}
- */
- this.startMode_ = hotword.constants.RecognizerStartMode.NORMAL;
-
- /**
- * Whether audio logging is enabled.
- * @private {boolean}
- */
- this.loggingEnabled_ = loggingEnabled;
-
- /**
- * Whether the audio input stream is from a hotword stream.
- * @private {boolean}
- */
- this.hotwordStream_ = hotwordStream;
-
- /**
- * Audio log of X seconds before hotword triggered.
- * @private {?Object}
- */
- this.preambleLog_ = null;
- }
-
- /**
- * States this manager can be in. Since messages to/from the plugin are
- * asynchronous (and potentially queued), it's not possible to know what state
- * the plugin is in. However, track a state machine for NaClManager based on
- * what messages are sent/received.
- * @enum {number}
- * @private
- */
- NaClManager.ManagerState_ = {
- UNINITIALIZED: 0,
- LOADING: 1,
- STOPPING: 2,
- STOPPED: 3,
- STARTING: 4,
- RUNNING: 5,
- ERROR: 6,
- SHUTDOWN: 7,
- };
- var ManagerState_ = NaClManager.ManagerState_;
- var Error_ = hotword.constants.Error;
- var UmaNaClMessageTimeout_ = hotword.constants.UmaNaClMessageTimeout;
- var UmaNaClPluginLoadResult_ = hotword.constants.UmaNaClPluginLoadResult;
-
- NaClManager.prototype.__proto__ = cr.EventTarget.prototype;
-
- /**
- * Called when an error occurs. Dispatches an event.
- * @param {!hotword.constants.Error} error
- * @private
- */
- NaClManager.prototype.handleError_ = function(error) {
- var event = new Event(hotword.constants.Event.ERROR);
- event.data = error;
- this.dispatchEvent(event);
- };
-
- /**
- * Record the result of loading the NaCl plugin to UMA.
- * @param {!hotword.constants.UmaNaClPluginLoadResult} error
- * @private
- */
- NaClManager.prototype.logPluginLoadResult_ = function(error) {
- hotword.metrics.recordEnum(
- hotword.constants.UmaMetrics.NACL_PLUGIN_LOAD_RESULT, error,
- UmaNaClPluginLoadResult_.MAX);
- };
-
- /**
- * Set a timeout. Only allow one timeout to exist at any given time.
- * @param {!function()} func
- * @param {number} timeout
- * @private
- */
- NaClManager.prototype.setTimeout_ = function(func, timeout) {
- assert(!this.naclTimeoutId_, 'Timeout already exists');
- this.naclTimeoutId_ = window.setTimeout(function() {
- this.naclTimeoutId_ = null;
- func();
- }.bind(this), timeout);
- };
-
- /**
- * Clears the current timeout.
- * @private
- */
- NaClManager.prototype.clearTimeout_ = function() {
- window.clearTimeout(this.naclTimeoutId_);
- this.naclTimeoutId_ = null;
- };
-
- /**
- * Starts a stopped or stopping hotword recognizer (NaCl plugin).
- * @param {hotword.constants.RecognizerStartMode} mode The mode to start the
- * recognizer in.
- */
- NaClManager.prototype.startRecognizer = function(mode) {
- this.startMode_ = mode;
- if (this.recognizerState_ == ManagerState_.STOPPED) {
- this.preambleLog_ = null;
- this.recognizerState_ = ManagerState_.STARTING;
- if (mode == hotword.constants.RecognizerStartMode.NEW_MODEL) {
- hotword.debug('Starting Recognizer in START training mode');
- this.sendDataToPlugin_(
- hotword.constants.NaClPlugin.BEGIN_SPEAKER_MODEL);
- } else if (mode == hotword.constants.RecognizerStartMode.ADAPT_MODEL) {
- hotword.debug('Starting Recognizer in ADAPT training mode');
- this.sendDataToPlugin_(
- hotword.constants.NaClPlugin.ADAPT_SPEAKER_MODEL);
- } else {
- hotword.debug('Starting Recognizer in NORMAL mode');
- this.sendDataToPlugin_(hotword.constants.NaClPlugin.RESTART);
- }
- // Normally, there would be a waitForMessage_(READY_FOR_AUDIO) here.
- // However, this message is sent the first time audio data is read and in
- // some cases (ie. using the hotword stream), this won't happen until a
- // potential hotword trigger is seen. Having a waitForMessage_() would
- // time
- // out in this case, so just leave it out. This ends up sacrificing a bit
- // of
- // error detection in the non-hotword-stream case, but I think we can live
- // with that.
- } else if (this.recognizerState_ == ManagerState_.STOPPING) {
- // Wait until the plugin is stopped before trying to start it.
- this.restartOnStop_ = true;
- } else {
- throw 'Attempting to start NaCl recogniser not in STOPPED or STOPPING ' +
- 'state';
- }
- };
-
- /**
- * Stops the hotword recognizer.
- */
- NaClManager.prototype.stopRecognizer = function() {
- if (this.recognizerState_ == ManagerState_.STARTING) {
- // If the recognizer is stopped before it finishes starting, it causes an
- // assertion to be raised in waitForMessage_() since we're waiting for the
- // READY_FOR_AUDIO message. Clear the current timeout and expecting
- // message
- // since we no longer expect it and may never receive it.
- this.clearTimeout_();
- this.expectingMessage_ = null;
- }
- this.sendDataToPlugin_(hotword.constants.NaClPlugin.STOP);
- this.recognizerState_ = ManagerState_.STOPPING;
- this.waitForMessage_(
- hotword.constants.TimeoutMs.NORMAL,
- hotword.constants.NaClPlugin.STOPPED);
- };
-
- /**
- * Saves the speaker model.
- */
- NaClManager.prototype.finalizeSpeakerModel = function() {
- if (this.recognizerState_ == ManagerState_.UNINITIALIZED ||
- this.recognizerState_ == ManagerState_.ERROR ||
- this.recognizerState_ == ManagerState_.SHUTDOWN ||
- this.recognizerState_ == ManagerState_.LOADING) {
- return;
- }
- this.sendDataToPlugin_(hotword.constants.NaClPlugin.FINISH_SPEAKER_MODEL);
- };
-
- /**
- * Checks whether the file at the given path exists.
- * @param {!string} path Path to a file. Can be any valid URL.
- * @return {boolean} True if the patch exists.
- * @private
- */
- NaClManager.prototype.fileExists_ = function(path) {
- var xhr = new XMLHttpRequest();
- xhr.open('HEAD', path, false);
- try {
- xhr.send();
- } catch (err) {
- return false;
- }
- if (xhr.readyState != xhr.DONE || xhr.status != 200) {
- return false;
- }
- return true;
- };
-
- /**
- * Creates and returns a list of possible languages to check for hotword
- * support.
- * @return {!Array<string>} Array of languages.
- * @private
- */
- NaClManager.prototype.getPossibleLanguages_ = function() {
- // Create array used to search first for language-country, if not found then
- // search for language, if not found then no language (empty string).
- // For example, search for 'en-us', then 'en', then ''.
- var langs = new Array();
- if (hotword.constants.UI_LANGUAGE) {
- // Chrome webstore doesn't support uppercase path: crbug.com/353407
- var language = hotword.constants.UI_LANGUAGE.toLowerCase();
- langs.push(language); // Example: 'en-us'.
- // Remove country to add just the language to array.
- var hyphen = language.lastIndexOf('-');
- if (hyphen >= 0) {
- langs.push(language.substr(0, hyphen)); // Example: 'en'.
- }
- }
- langs.push('');
- return langs;
- };
-
- /**
- * Creates a NaCl plugin object and attaches it to the page.
- * @param {!string} src Location of the plugin.
- * @return {!HTMLEmbedElement} NaCl plugin DOM object.
- * @private
- */
- NaClManager.prototype.createPlugin_ = function(src) {
- var plugin =
- /** @type {HTMLEmbedElement} */ (document.createElement('embed'));
- plugin.src = src;
- plugin.type = 'application/x-nacl';
- document.body.appendChild(plugin);
- return plugin;
- };
-
- /**
- * Initializes the NaCl manager.
- * @param {!string} naclArch Either 'arm', 'x86-32' or 'x86-64'.
- * @param {!MediaStream} stream A stream containing an audio source track.
- * @return {boolean} True if the successful.
- */
- NaClManager.prototype.initialize = function(naclArch, stream) {
- assert(
- this.recognizerState_ == ManagerState_.UNINITIALIZED,
- 'Recognizer not in uninitialized state. State: ' +
- this.recognizerState_);
- assert(this.plugin_ == null);
- var langs = this.getPossibleLanguages_();
- var i, j;
- // For country-lang variations. For example, when combined with path it will
- // attempt to find: '/x86-32_en-gb/', else '/x86-32_en/', else '/x86-32_/'.
- for (i = 0; i < langs.length; i++) {
- var folder = hotword.constants.SHARED_MODULE_ROOT +
- '/_platform_specific/' + naclArch + '_' + langs[i] + '/';
- var dataSrc = folder + hotword.constants.File.RECOGNIZER_CONFIG;
- var pluginSrc = hotword.constants.SHARED_MODULE_ROOT + '/hotword_' +
- langs[i] + '.nmf';
- var dataExists = this.fileExists_(dataSrc) && this.fileExists_(pluginSrc);
- if (!dataExists) {
- continue;
- }
-
- var plugin = this.createPlugin_(pluginSrc);
- if (!plugin || !plugin.postMessage) {
- document.body.removeChild(plugin);
- this.recognizerState_ = ManagerState_.ERROR;
- return false;
- }
- this.plugin_ = plugin;
- this.modelUrl_ = chrome.extension.getURL(dataSrc);
- this.stream_ = stream;
- this.recognizerState_ = ManagerState_.LOADING;
-
- plugin.addEventListener(
- 'message', this.handlePluginMessage_.bind(this), false);
-
- plugin.addEventListener('crash', function() {
- this.handleError_(Error_.NACL_CRASH);
- this.logPluginLoadResult_(UmaNaClPluginLoadResult_.CRASH);
- }.bind(this), false);
- return true;
- }
- this.recognizerState_ = ManagerState_.ERROR;
- this.logPluginLoadResult_(UmaNaClPluginLoadResult_.NO_MODULE_FOUND);
- return false;
- };
-
- /**
- * Shuts down the NaCl plugin and frees all resources.
- */
- NaClManager.prototype.shutdown = function() {
- if (this.plugin_ != null) {
- document.body.removeChild(this.plugin_);
- this.plugin_ = null;
- }
- this.clearTimeout_();
- this.recognizerState_ = ManagerState_.SHUTDOWN;
- if (this.stream_)
- this.stream_.getAudioTracks()[0].stop();
- this.stream_ = null;
- };
-
- /**
- * Sends data to the NaCl plugin.
- * @param {!string|!MediaStreamTrack} data Command to be sent to NaCl plugin.
- * @private
- */
- NaClManager.prototype.sendDataToPlugin_ = function(data) {
- assert(
- this.recognizerState_ != ManagerState_.UNINITIALIZED,
- 'Recognizer in uninitialized state');
- this.plugin_.postMessage(data);
- };
-
- /**
- * Waits, with a timeout, for a message to be received from the plugin. If the
- * message is not seen within the timeout, dispatch an 'error' event and go
- * into
- * the ERROR state.
- * @param {number} timeout Timeout, in milliseconds, to wait for the message.
- * @param {!string} message Message to wait for.
- * @private
- */
- NaClManager.prototype.waitForMessage_ = function(timeout, message) {
- assert(
- this.expectingMessage_ == null,
- 'Cannot wait for message: ' + message +
- ', already waiting for message ' + this.expectingMessage_);
- this.setTimeout_(function() {
- this.recognizerState_ = ManagerState_.ERROR;
- this.handleError_(Error_.TIMEOUT);
- switch (this.expectingMessage_) {
- case hotword.constants.NaClPlugin.REQUEST_MODEL:
- var metricValue = UmaNaClMessageTimeout_.REQUEST_MODEL;
- break;
- case hotword.constants.NaClPlugin.MODEL_LOADED:
- var metricValue = UmaNaClMessageTimeout_.MODEL_LOADED;
- break;
- case hotword.constants.NaClPlugin.READY_FOR_AUDIO:
- var metricValue = UmaNaClMessageTimeout_.READY_FOR_AUDIO;
- break;
- case hotword.constants.NaClPlugin.STOPPED:
- var metricValue = UmaNaClMessageTimeout_.STOPPED;
- break;
- case hotword.constants.NaClPlugin.HOTWORD_DETECTED:
- var metricValue = UmaNaClMessageTimeout_.HOTWORD_DETECTED;
- break;
- case hotword.constants.NaClPlugin.MS_CONFIGURED:
- var metricValue = UmaNaClMessageTimeout_.MS_CONFIGURED;
- break;
- }
- hotword.metrics.recordEnum(
- hotword.constants.UmaMetrics.NACL_MESSAGE_TIMEOUT, metricValue,
- UmaNaClMessageTimeout_.MAX);
- }.bind(this), timeout);
- this.expectingMessage_ = message;
- };
-
- /**
- * Called when a message is received from the plugin. If we're waiting for
- * that
- * message, cancel the pending timeout.
- * @param {string} message Message received.
- * @private
- */
- NaClManager.prototype.receivedMessage_ = function(message) {
- if (message == this.expectingMessage_) {
- this.clearTimeout_();
- this.expectingMessage_ = null;
- }
- };
-
- /**
- * Handle a REQUEST_MODEL message from the plugin.
- * The plugin sends this message immediately after starting.
- * @private
- */
- NaClManager.prototype.handleRequestModel_ = function() {
- if (this.recognizerState_ != ManagerState_.LOADING) {
- return;
- }
- this.logPluginLoadResult_(UmaNaClPluginLoadResult_.SUCCESS);
- this.sendDataToPlugin_(
- hotword.constants.NaClPlugin.MODEL_PREFIX + this.modelUrl_);
- this.waitForMessage_(
- hotword.constants.TimeoutMs.LONG,
- hotword.constants.NaClPlugin.MODEL_LOADED);
-
- // Configure logging in the plugin. This can be configured any time before
- // starting the recognizer, and now is as good a time as any.
- if (this.loggingEnabled_) {
- this.sendDataToPlugin_(
- hotword.constants.NaClPlugin.LOG + ':' +
- hotword.constants.AUDIO_LOG_SECONDS);
- }
-
- // If the audio stream is from a hotword stream, tell the plugin.
- if (this.hotwordStream_) {
- this.sendDataToPlugin_(
- hotword.constants.NaClPlugin.DSP + ':' +
- hotword.constants.HOTWORD_STREAM_TIMEOUT_SECONDS);
- }
- };
-
- /**
- * Handle a MODEL_LOADED message from the plugin.
- * The plugin sends this message after successfully loading the language
- * model.
- * @private
- */
- NaClManager.prototype.handleModelLoaded_ = function() {
- if (this.recognizerState_ != ManagerState_.LOADING) {
- return;
- }
- this.sendDataToPlugin_(this.stream_.getAudioTracks()[0]);
- // The plugin will send a MS_CONFIGURED, but don't set a timeout waiting for
- // it. MediaStreamAudioTrack::Configure() will remain pending until the
- // first
- // audio buffer is received. When the audio source is a DSP for always-on
- // detection, no audio sample is sent until the DSP detects a potential
- // hotword trigger. Thus, Configure would remain pending indefinitely if we
- // were to wait here. See https://crbug.com/616203
- };
-
- /**
- * Handle a MS_CONFIGURED message from the plugin.
- * The plugin sends this message after successfully configuring the audio
- * input
- * stream.
- * @private
- */
- NaClManager.prototype.handleMsConfigured_ = function() {
- if (this.recognizerState_ != ManagerState_.LOADING) {
- return;
- }
- this.recognizerState_ = ManagerState_.STOPPED;
- this.dispatchEvent(new Event(hotword.constants.Event.READY));
- };
-
- /**
- * Handle a READY_FOR_AUDIO message from the plugin.
- * The plugin sends this message after the recognizer is started and
- * successfully receives and processes audio data.
- * @private
- */
- NaClManager.prototype.handleReadyForAudio_ = function() {
- if (this.recognizerState_ != ManagerState_.STARTING) {
- return;
- }
- this.recognizerState_ = ManagerState_.RUNNING;
- };
-
- /**
- * Handle a HOTWORD_DETECTED message from the plugin.
- * The plugin sends this message after detecting the hotword.
- * @private
- */
- NaClManager.prototype.handleHotwordDetected_ = function() {
- if (this.recognizerState_ != ManagerState_.RUNNING) {
- return;
- }
- // We'll receive a STOPPED message very soon.
- this.recognizerState_ = ManagerState_.STOPPING;
- this.waitForMessage_(
- hotword.constants.TimeoutMs.NORMAL,
- hotword.constants.NaClPlugin.STOPPED);
- var event = new Event(hotword.constants.Event.TRIGGER);
- event.log = this.preambleLog_;
- this.dispatchEvent(event);
- };
-
- /**
- * Handle a STOPPED message from the plugin.
- * This plugin sends this message after stopping the recognizer. This can
- * happen
- * either in response to a stop request, or after the hotword is detected.
- * @private
- */
- NaClManager.prototype.handleStopped_ = function() {
- this.recognizerState_ = ManagerState_.STOPPED;
- if (this.restartOnStop_) {
- this.restartOnStop_ = false;
- this.startRecognizer(this.startMode_);
- }
- };
-
- /**
- * Handle a TIMEOUT message from the plugin.
- * The plugin sends this message when it thinks the stream is from a DSP and
- * a hotword wasn't detected within a timeout period after arrival of the
- * first
- * audio samples.
- * @private
- */
- NaClManager.prototype.handleTimeout_ = function() {
- if (this.recognizerState_ != ManagerState_.RUNNING) {
- return;
- }
- this.recognizerState_ = ManagerState_.STOPPED;
- this.dispatchEvent(new Event(hotword.constants.Event.TIMEOUT));
- };
-
- /**
- * Handle a SPEAKER_MODEL_SAVED message from the plugin.
- * The plugin sends this message after writing the model to a file.
- * @private
- */
- NaClManager.prototype.handleSpeakerModelSaved_ = function() {
- this.dispatchEvent(new Event(hotword.constants.Event.SPEAKER_MODEL_SAVED));
- };
-
- /**
- * Handles a message from the NaCl plugin.
- * @param {!Event} msg Message from NaCl plugin.
- * @private
- */
- NaClManager.prototype.handlePluginMessage_ = function(msg) {
- if (msg['data']) {
- if (typeof(msg['data']) == 'object') {
- // Save the preamble for delivery to the trigger handler when the
- // trigger
- // message arrives.
- this.preambleLog_ = msg['data'];
- return;
- }
- this.receivedMessage_(msg['data']);
- switch (msg['data']) {
- case hotword.constants.NaClPlugin.REQUEST_MODEL:
- this.handleRequestModel_();
- break;
- case hotword.constants.NaClPlugin.MODEL_LOADED:
- this.handleModelLoaded_();
- break;
- case hotword.constants.NaClPlugin.MS_CONFIGURED:
- this.handleMsConfigured_();
- break;
- case hotword.constants.NaClPlugin.READY_FOR_AUDIO:
- this.handleReadyForAudio_();
- break;
- case hotword.constants.NaClPlugin.HOTWORD_DETECTED:
- this.handleHotwordDetected_();
- break;
- case hotword.constants.NaClPlugin.STOPPED:
- this.handleStopped_();
- break;
- case hotword.constants.NaClPlugin.TIMEOUT:
- this.handleTimeout_();
- break;
- case hotword.constants.NaClPlugin.SPEAKER_MODEL_SAVED:
- this.handleSpeakerModelSaved_();
- break;
- }
- }
- };
-
- return {NaClManager: NaClManager};
-
-});
diff --git a/chromium/chrome/browser/resources/hotword/page_audio_manager.js b/chromium/chrome/browser/resources/hotword/page_audio_manager.js
deleted file mode 100644
index 8c8c928cf08..00000000000
--- a/chromium/chrome/browser/resources/hotword/page_audio_manager.js
+++ /dev/null
@@ -1,541 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-cr.define('hotword', function() {
- 'use strict';
-
- /**
- * Class used to manage the interaction between hotwording and the
- * NTP/google.com. Injects a content script to interact with NTP/google.com
- * and updates the global hotwording state based on interaction with those
- * pages.
- * @param {!hotword.StateManager} stateManager
- * @constructor
- */
- function PageAudioManager(stateManager) {
- /**
- * Manager of global hotwording state.
- * @private {!hotword.StateManager}
- */
- this.stateManager_ = stateManager;
-
- /**
- * Mapping between tab ID and port that is connected from the injected
- * content script.
- * @private {!Object<number, Port>}
- */
- this.portMap_ = {};
-
- /**
- * Chrome event listeners. Saved so that they can be de-registered when
- * hotwording is disabled.
- */
- this.connectListener_ = this.handleConnect_.bind(this);
- this.tabCreatedListener_ = this.handleCreatedTab_.bind(this);
- this.tabUpdatedListener_ = this.handleUpdatedTab_.bind(this);
- this.tabActivatedListener_ = this.handleActivatedTab_.bind(this);
- this.microphoneStateChangedListener_ =
- this.handleMicrophoneStateChanged_.bind(this);
- this.windowFocusChangedListener_ = this.handleChangedWindow_.bind(this);
- this.messageListener_ = this.handleMessageFromPage_.bind(this);
-
- // Need to setup listeners on startup, otherwise events that caused the
- // event page to start up, will be lost.
- this.setupListeners_();
-
- this.stateManager_.onStatusChanged.addListener(function() {
- this.updateListeners_();
- this.updateTabState_();
- }.bind(this));
- }
-
- var CommandToPage = hotword.constants.CommandToPage;
- var CommandFromPage = hotword.constants.CommandFromPage;
-
- PageAudioManager.prototype = {
- /**
- * Helper function to test if a URL path is eligible for hotwording.
- * @param {!string} url URL to check.
- * @param {!string} base Base URL to compare against..
- * @return {boolean} True if url is an eligible hotword URL.
- * @private
- */
- checkUrlPathIsEligible_: function(url, base) {
- if (url == base || url == base + '/' ||
- url.startsWith(base + '/_/chrome/newtab?') || // Appcache NTP.
- url.startsWith(base + '/?') || url.startsWith(base + '/#') ||
- url.startsWith(base + '/webhp') || url.startsWith(base + '/search') ||
- url.startsWith(base + '/imghp')) {
- return true;
- }
- return false;
- },
-
- /**
- * Determines if a URL is eligible for hotwording. For now, the valid pages
- * are the Google HP and SERP (this will include the NTP).
- * @param {!string} url URL to check.
- * @return {boolean} True if url is an eligible hotword URL.
- * @private
- */
- isEligibleUrl_: function(url) {
- if (!url)
- return false;
-
- var baseGoogleUrls = [
- 'https://encrypted.google.', 'https://images.google.',
- 'https://www.google.'
- ];
- // TODO(amistry): Get this list from a file in the shared module instead.
- var tlds = [
- 'at', 'ca', 'com', 'com.au', 'com.mx', 'com.br', 'co.jp', 'co.kr',
- 'co.nz', 'co.uk', 'co.za', 'de', 'es', 'fr', 'it', 'ru'
- ];
-
- // Check for the new tab page first.
- if (this.checkUrlPathIsEligible_(url, 'chrome://newtab'))
- return true;
-
- // Check URLs with each type of local-based TLD.
- for (var i = 0; i < baseGoogleUrls.length; i++) {
- for (var j = 0; j < tlds.length; j++) {
- var base = baseGoogleUrls[i] + tlds[j];
- if (this.checkUrlPathIsEligible_(url, base))
- return true;
- }
- }
- return false;
- },
-
- /**
- * Locates the current active tab in the current focused window and
- * performs a callback with the tab as the parameter.
- * @param {function(?Tab)} callback Function to call with the
- * active tab or null if not found. The function's |this| will be set to
- * this object.
- * @private
- */
- findCurrentTab_: function(callback) {
- chrome.windows.getAll({'populate': true}, function(windows) {
- for (var i = 0; i < windows.length; ++i) {
- if (!windows[i].focused)
- continue;
-
- for (var j = 0; j < windows[i].tabs.length; ++j) {
- var tab = windows[i].tabs[j];
- if (tab.active) {
- callback.call(this, tab);
- return;
- }
- }
- }
- callback.call(this, null);
- }.bind(this));
- },
-
- /**
- * This function is called when a tab is activated (comes into focus).
- * @param {Tab} tab Current active tab.
- * @private
- */
- activateTab_: function(tab) {
- if (!tab) {
- this.stopHotwording_();
- return;
- }
- if (tab.id in this.portMap_) {
- this.startHotwordingIfEligible_();
- return;
- }
- this.stopHotwording_();
- this.prepareTab_(tab);
- },
-
- /**
- * Prepare a new or updated tab by injecting the content script.
- * @param {!Tab} tab Newly updated or created tab.
- * @private
- */
- prepareTab_: function(tab) {
- if (!this.isEligibleUrl_(tab.url))
- return;
-
- chrome.tabs.executeScript(
- tab.id, {'file': 'audio_client.js'}, function(results) {
- if (chrome.runtime.lastError) {
- // Ignore this error. For new tab pages, even though the URL is
- // reported to be chrome://newtab/, the actual URL is a
- // country-specific google domain. Since we don't have permission
- // to inject on every page, an error will happen when the user is
- // in an unsupported country.
- //
- // The property still needs to be accessed so that the error
- // condition is cleared. If it isn't, exectureScript will log an
- // error the next time it is called.
- }
- });
- },
-
- /**
- * Updates hotwording state based on the state of current tabs/windows.
- * @private
- */
- updateTabState_: function() {
- this.findCurrentTab_(this.activateTab_);
- },
-
- /**
- * Handles a newly created tab.
- * @param {!Tab} tab Newly created tab.
- * @private
- */
- handleCreatedTab_: function(tab) {
- this.prepareTab_(tab);
- },
-
- /**
- * Handles an updated tab.
- * @param {number} tabId Id of the updated tab.
- * @param {{status: string}} info Change info of the tab.
- * @param {!Tab} tab Updated tab.
- * @private
- */
- handleUpdatedTab_: function(tabId, info, tab) {
- // Chrome fires multiple update events: undefined, loading and completed.
- // We perform content injection on loading state.
- if (info['status'] != 'loading')
- return;
-
- this.prepareTab_(tab);
- },
-
- /**
- * Handles a tab that has just become active.
- * @param {{tabId: number}} info Information about the activated tab.
- * @private
- */
- handleActivatedTab_: function(info) {
- this.updateTabState_();
- },
-
- /**
- * Handles the microphone state changing.
- * @param {boolean} enabled Whether the microphone is now enabled.
- * @private
- */
- handleMicrophoneStateChanged_: function(enabled) {
- if (enabled) {
- this.updateTabState_();
- return;
- }
-
- this.stopHotwording_();
- },
-
- /**
- * Handles a change in Chrome windows.
- * Note: this does not always trigger in Linux.
- * @param {number} windowId Id of newly focused window.
- * @private
- */
- handleChangedWindow_: function(windowId) {
- this.updateTabState_();
- },
-
- /**
- * Handles a content script attempting to connect.
- * @param {!Port} port Communications port from the client.
- * @private
- */
- handleConnect_: function(port) {
- if (port.name != hotword.constants.CLIENT_PORT_NAME)
- return;
-
- var tab = /** @type {!Tab} */ (port.sender.tab);
- // An existing port from the same tab might already exist. But that port
- // may be from the previous page, so just overwrite the port.
- this.portMap_[tab.id] = port;
- port.onDisconnect.addListener(function() {
- this.handleClientDisconnect_(port);
- }.bind(this));
- port.onMessage.addListener(function(msg) {
- this.handleMessage_(msg, port.sender, port.postMessage);
- }.bind(this));
- },
-
- /**
- * Handles a client content script disconnect.
- * @param {Port} port Disconnected port.
- * @private
- */
- handleClientDisconnect_: function(port) {
- var tabId = port.sender.tab.id;
- if (tabId in this.portMap_ && this.portMap_[tabId] == port) {
- // Due to a race between port disconnection and tabs.onUpdated messages,
- // the port could have changed.
- delete this.portMap_[port.sender.tab.id];
- }
- this.stopHotwordingIfIneligibleTab_();
- },
-
- /**
- * Disconnect all connected clients.
- * @private
- */
- disconnectAllClients_: function() {
- for (var id in this.portMap_) {
- var port = this.portMap_[id];
- port.disconnect();
- delete this.portMap_[id];
- }
- },
-
- /**
- * Sends a command to the client content script on an eligible tab.
- * @param {hotword.constants.CommandToPage} command Command to send.
- * @param {number} tabId Id of the target tab.
- * @private
- */
- sendClient_: function(command, tabId) {
- if (tabId in this.portMap_) {
- var message = {};
- message[hotword.constants.COMMAND_FIELD_NAME] = command;
- this.portMap_[tabId].postMessage(message);
- }
- },
-
- /**
- * Sends a command to all connected clients.
- * @param {hotword.constants.CommandToPage} command Command to send.
- * @private
- */
- sendAllClients_: function(command) {
- for (var idStr in this.portMap_) {
- var id = parseInt(idStr, 10);
- assert(!isNaN(id), 'Tab ID is not a number: ' + idStr);
- this.sendClient_(command, id);
- }
- },
-
- /**
- * Handles a hotword trigger. Sends a trigger message to the currently
- * active tab.
- * @private
- */
- hotwordTriggered_: function() {
- this.findCurrentTab_(function(tab) {
- if (tab)
- this.sendClient_(CommandToPage.HOTWORD_VOICE_TRIGGER, tab.id);
- });
- },
-
- /**
- * Starts hotwording.
- * @private
- */
- startHotwording_: function() {
- this.stateManager_.startSession(
- hotword.constants.SessionSource.NTP, function() {
- this.sendAllClients_(CommandToPage.HOTWORD_STARTED);
- }.bind(this), this.hotwordTriggered_.bind(this));
- },
-
- /**
- * Starts hotwording if the currently active tab is eligible for hotwording
- * (e.g. google.com).
- * @private
- */
- startHotwordingIfEligible_: function() {
- this.findCurrentTab_(function(tab) {
- if (!tab) {
- this.stopHotwording_();
- return;
- }
- if (this.isEligibleUrl_(tab.url))
- this.startHotwording_();
- });
- },
-
- /**
- * Stops hotwording.
- * @private
- */
- stopHotwording_: function() {
- this.stateManager_.stopSession(hotword.constants.SessionSource.NTP);
- this.sendAllClients_(CommandToPage.HOTWORD_ENDED);
- },
-
- /**
- * Stops hotwording if the currently active tab is not eligible for
- * hotwording (i.e. google.com).
- * @private
- */
- stopHotwordingIfIneligibleTab_: function() {
- this.findCurrentTab_(function(tab) {
- if (!tab) {
- this.stopHotwording_();
- return;
- }
- if (!this.isEligibleUrl_(tab.url))
- this.stopHotwording_();
- });
- },
-
- /**
- * Handles a message from the content script injected into the page.
- * @param {!Object} request Request from the content script.
- * @param {!MessageSender} sender Message sender.
- * @param {!function(Object)} sendResponse Function for sending a response.
- * @private
- */
- handleMessage_: function(request, sender, sendResponse) {
- switch (request[hotword.constants.COMMAND_FIELD_NAME]) {
- // TODO(amistry): Handle other messages such as CLICKED_RESUME and
- // CLICKED_RESTART, if necessary.
- case CommandFromPage.SPEECH_START:
- this.stopHotwording_();
- break;
- case CommandFromPage.SPEECH_END:
- case CommandFromPage.SPEECH_RESET:
- this.startHotwording_();
- break;
- }
- },
-
-
- /**
- * Handles a message directly from the NTP/HP/SERP.
- * @param {!Object} request Message from the sender.
- * @param {!MessageSender} sender Information about the sender.
- * @param {!function(HotwordStatus)} sendResponse Callback to respond
- * to sender.
- * @return {boolean} Whether to maintain the port open to call sendResponse.
- * @private
- */
- handleMessageFromPage_: function(request, sender, sendResponse) {
- switch (request.type) {
- case CommandFromPage.PAGE_WAKEUP:
- if (sender.tab && this.isEligibleUrl_(sender.tab.url)) {
- chrome.hotwordPrivate.getStatus(
- true /* getOptionalFields */,
- this.statusDone_.bind(
- this, request.tab || sender.tab || {incognito: true},
- sendResponse));
- return true;
- }
-
- // Do not show the opt-in promo for ineligible urls.
- this.sendResponse_({'doNotShowOptinMessage': true}, sendResponse);
- break;
- case CommandFromPage.CLICKED_OPTIN:
- chrome.hotwordPrivate.setEnabled(true);
- break;
- // User has explicitly clicked 'no thanks'.
- case CommandFromPage.CLICKED_NO_OPTIN:
- chrome.hotwordPrivate.setEnabled(false);
- break;
- }
- return false;
- },
-
- /**
- * Sends a message directly to the sending page.
- * @param {!HotwordStatus} response The response to send to the sender.
- * @param {!function(HotwordStatus)} sendResponse Callback to respond
- * to sender.
- * @private
- */
- sendResponse_: function(response, sendResponse) {
- try {
- sendResponse(response);
- } catch (err) {
- // Suppress the exception thrown by sendResponse() when the page doesn't
- // specify a response callback in the call to
- // chrome.runtime.sendMessage().
- // Unfortunately, there doesn't appear to be a way to detect one-way
- // messages without explicitly saying in the message itself. This
- // message is defined as a constant in
- // extensions/renderer/messaging_bindings.cc
- if (err.message == 'Attempting to use a disconnected port object')
- return;
- throw err;
- }
- },
-
- /**
- * Sends the response to the tab.
- * @param {Tab} tab The tab that the request was sent from.
- * @param {function(HotwordStatus)} sendResponse Callback function to
- * respond to sender.
- * @param {HotwordStatus} hotwordStatus Status of the hotword extension.
- * @private
- */
- statusDone_: function(tab, sendResponse, hotwordStatus) {
- var response = {'doNotShowOptinMessage': true};
-
- // If always-on is available, then we do not show the promo, as the promo
- // only works with the sometimes-on pref.
- if (!tab.incognito && hotwordStatus.available &&
- !hotwordStatus.enabledSet && !hotwordStatus.alwaysOnAvailable) {
- response = hotwordStatus;
- }
-
- this.sendResponse_(response, sendResponse);
- },
-
- /**
- * Set up event listeners.
- * @private
- */
- setupListeners_: function() {
- if (chrome.runtime.onConnect.hasListener(this.connectListener_))
- return;
-
- chrome.runtime.onConnect.addListener(this.connectListener_);
- chrome.tabs.onCreated.addListener(this.tabCreatedListener_);
- chrome.tabs.onUpdated.addListener(this.tabUpdatedListener_);
- chrome.tabs.onActivated.addListener(this.tabActivatedListener_);
- chrome.windows.onFocusChanged.addListener(
- this.windowFocusChangedListener_);
- chrome.hotwordPrivate.onMicrophoneStateChanged.addListener(
- this.microphoneStateChangedListener_);
- if (chrome.runtime.onMessage.hasListener(this.messageListener_))
- return;
- chrome.runtime.onMessageExternal.addListener(this.messageListener_);
- },
-
- /**
- * Remove event listeners.
- * @private
- */
- removeListeners_: function() {
- chrome.runtime.onConnect.removeListener(this.connectListener_);
- chrome.tabs.onCreated.removeListener(this.tabCreatedListener_);
- chrome.tabs.onUpdated.removeListener(this.tabUpdatedListener_);
- chrome.tabs.onActivated.removeListener(this.tabActivatedListener_);
- chrome.windows.onFocusChanged.removeListener(
- this.windowFocusChangedListener_);
- chrome.hotwordPrivate.onMicrophoneStateChanged.removeListener(
- this.microphoneStateChangedListener_);
- // Don't remove the Message listener, as we want them listening all
- // the time,
- },
-
- /**
- * Update event listeners based on the current hotwording state.
- * @private
- */
- updateListeners_: function() {
- if (this.stateManager_.isSometimesOnEnabled()) {
- this.setupListeners_();
- } else {
- this.removeListeners_();
- this.stopHotwording_();
- this.disconnectAllClients_();
- }
- }
- };
-
- return {PageAudioManager: PageAudioManager};
-});
diff --git a/chromium/chrome/browser/resources/hotword/state_manager.js b/chromium/chrome/browser/resources/hotword/state_manager.js
deleted file mode 100644
index 98e0a5cbd17..00000000000
--- a/chromium/chrome/browser/resources/hotword/state_manager.js
+++ /dev/null
@@ -1,641 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-cr.define('hotword', function() {
- 'use strict';
-
- /**
- * Trivial container class for session information.
- * @param {!hotword.constants.SessionSource} source Source of the hotword
- * session.
- * @param {!function()} triggerCb Callback invoked when the hotword has
- * triggered.
- * @param {!function()} startedCb Callback invoked when the session has
- * been started successfully.
- * @param {function()=} opt_modelSavedCb Callback invoked when the speaker
- * model has been saved successfully.
- * @constructor
- * @struct
- * @private
- */
- function Session_(source, triggerCb, startedCb, opt_modelSavedCb) {
- /**
- * Source of the hotword session request.
- * @private {!hotword.constants.SessionSource}
- */
- this.source_ = source;
-
- /**
- * Callback invoked when the hotword has triggered.
- * @private {!function()}
- */
- this.triggerCb_ = triggerCb;
-
- /**
- * Callback invoked when the session has been started successfully.
- * @private {?function()}
- */
- this.startedCb_ = startedCb;
-
- /**
- * Callback invoked when the session has been started successfully.
- * @private {?function()}
- */
- this.speakerModelSavedCb_ = opt_modelSavedCb;
- }
-
- /**
- * Class to manage hotwording state. Starts/stops the hotword detector based
- * on user settings, session requests, and any other factors that play into
- * whether or not hotwording should be running.
- * @constructor
- */
- function StateManager() {
- /**
- * Current state.
- * @private {hotword.StateManager.State_}
- */
- this.state_ = State_.STOPPED;
-
- /**
- * Current hotwording status.
- * @private {?chrome.hotwordPrivate.StatusDetails}
- */
- this.hotwordStatus_ = null;
-
- /**
- * NaCl plugin manager.
- * @private {?hotword.NaClManager}
- */
- this.pluginManager_ = null;
-
- /**
- * Currently active hotwording sessions.
- * @private {!Array<Session_>}
- */
- this.sessions_ = [];
-
- /**
- * The mode to start the recognizer in.
- * @private {!hotword.constants.RecognizerStartMode}
- */
- this.startMode_ = hotword.constants.RecognizerStartMode.NORMAL;
-
- /**
- * Event that fires when the hotwording status has changed.
- * @type {!ChromeEvent}
- */
- this.onStatusChanged = new chrome.Event();
-
- /**
- * Hotword trigger audio notification... a.k.a The Chime (tm).
- * @private {!HTMLAudioElement}
- */
- this.chime_ =
- /** @type {!HTMLAudioElement} */ (document.createElement('audio'));
-
- /**
- * Chrome event listeners. Saved so that they can be de-registered when
- * hotwording is disabled.
- * @private
- */
- this.idleStateChangedListener_ = this.handleIdleStateChanged_.bind(this);
- this.startupListener_ = this.handleStartup_.bind(this);
-
- /**
- * Whether this user is locked.
- * @private {boolean}
- */
- this.isLocked_ = false;
-
- /**
- * Current state of audio logging.
- * This is tracked separately from hotwordStatus_ because we need to restart
- * the hotword detector when this value changes.
- * @private {boolean}
- */
- this.loggingEnabled_ = false;
-
- /**
- * Current state of training.
- * This is tracked separately from |hotwordStatus_| because we need to
- * restart the hotword detector when this value changes.
- * @private {!boolean}
- */
- this.trainingEnabled_ = false;
-
- /**
- * Helper class to keep this extension alive while the hotword detector is
- * running in always-on mode.
- * @private {!hotword.KeepAlive}
- */
- this.keepAlive_ = new hotword.KeepAlive();
-
- // Get the initial status.
- chrome.hotwordPrivate.getStatus(this.handleStatus_.bind(this));
-
- // Setup the chime and insert into the page.
- // Set preload=none to prevent an audio output stream from being created
- // when the extension loads.
- this.chime_.preload = 'none';
- this.chime_.src = chrome.extension.getURL(
- hotword.constants.SHARED_MODULE_ROOT + '/audio/chime.wav');
- document.body.appendChild(this.chime_);
-
- // In order to remove this listener, it must first be added. This handles
- // the case on first Chrome startup where this event is never registered,
- // so can't be removed when it's determined that hotwording is disabled.
- // Why not only remove the listener if it exists? Extension API events have
- // two parts to them, the Javascript listeners, and a browser-side component
- // that wakes up the extension if it's an event page. The browser-side
- // wake-up event is only removed when the number of javascript listeners
- // becomes 0. To clear the browser wake-up event, a listener first needs to
- // be added, then removed in order to drop the count to 0 and remove the
- // event.
- chrome.runtime.onStartup.addListener(this.startupListener_);
- }
-
- /**
- * @enum {number}
- * @private
- */
- StateManager.State_ = {
- STOPPED: 0,
- STARTING: 1,
- RUNNING: 2,
- ERROR: 3,
- };
- var State_ = StateManager.State_;
-
- var UmaMediaStreamOpenResults_ = {
- // These first error are defined by the MediaStream spec:
- // http://w3c.github.io/mediacapture-main/getusermedia.html#idl-def-MediaStreamError
- 'NotSupportedError':
- hotword.constants.UmaMediaStreamOpenResult.NOT_SUPPORTED,
- 'PermissionDeniedError':
- hotword.constants.UmaMediaStreamOpenResult.PERMISSION_DENIED,
- 'ConstraintNotSatisfiedError':
- hotword.constants.UmaMediaStreamOpenResult.CONSTRAINT_NOT_SATISFIED,
- 'OverconstrainedError':
- hotword.constants.UmaMediaStreamOpenResult.OVERCONSTRAINED,
- 'NotFoundError': hotword.constants.UmaMediaStreamOpenResult.NOT_FOUND,
- 'AbortError': hotword.constants.UmaMediaStreamOpenResult.ABORT,
- 'SourceUnavailableError':
- hotword.constants.UmaMediaStreamOpenResult.SOURCE_UNAVAILABLE,
- // The next few errors are chrome-specific. See:
- // content/renderer/media/user_media_client_impl.cc
- // (UserMediaClientImpl::GetUserMediaRequestFailed)
- 'PermissionDismissedError':
- hotword.constants.UmaMediaStreamOpenResult.PERMISSION_DISMISSED,
- 'InvalidStateError':
- hotword.constants.UmaMediaStreamOpenResult.INVALID_STATE,
- 'DevicesNotFoundError':
- hotword.constants.UmaMediaStreamOpenResult.DEVICES_NOT_FOUND,
- 'InvalidSecurityOriginError':
- hotword.constants.UmaMediaStreamOpenResult.INVALID_SECURITY_ORIGIN
- };
-
- var UmaTriggerSources_ = {
- 'launcher': hotword.constants.UmaTriggerSource.LAUNCHER,
- 'ntp': hotword.constants.UmaTriggerSource.NTP_GOOGLE_COM,
- 'always': hotword.constants.UmaTriggerSource.ALWAYS_ON,
- 'training': hotword.constants.UmaTriggerSource.TRAINING
- };
-
- StateManager.prototype = {
- /**
- * Request status details update. Intended to be called from the
- * hotwordPrivate.onEnabledChanged() event.
- */
- updateStatus: function() {
- chrome.hotwordPrivate.getStatus(this.handleStatus_.bind(this));
- },
-
- /**
- * @return {boolean} True if google.com/NTP/launcher hotwording is enabled.
- */
- isSometimesOnEnabled: function() {
- assert(
- this.hotwordStatus_, 'No hotwording status (isSometimesOnEnabled)');
- // Although the two settings are supposed to be mutually exclusive, it's
- // possible for both to be set. In that case, always-on takes precedence.
- return this.hotwordStatus_.enabled &&
- !this.hotwordStatus_.alwaysOnEnabled;
- },
-
- /**
- * @return {boolean} True if always-on hotwording is enabled.
- */
- isAlwaysOnEnabled: function() {
- assert(this.hotwordStatus_, 'No hotword status (isAlwaysOnEnabled)');
- return this.hotwordStatus_.alwaysOnEnabled &&
- !this.hotwordStatus_.trainingEnabled;
- },
-
- /**
- * @return {boolean} True if training is enabled.
- */
- isTrainingEnabled: function() {
- assert(this.hotwordStatus_, 'No hotword status (isTrainingEnabled)');
- return this.hotwordStatus_.trainingEnabled;
- },
-
- /**
- * Callback for hotwordPrivate.getStatus() function.
- * @param {chrome.hotwordPrivate.StatusDetails} status Current hotword
- * status.
- * @private
- */
- handleStatus_: function(status) {
- hotword.debug('New hotword status', status);
- this.hotwordStatus_ = status;
- this.updateStateFromStatus_();
-
- this.onStatusChanged.dispatch();
- },
-
- /**
- * Updates state based on the current status.
- * @private
- */
- updateStateFromStatus_: function() {
- if (!this.hotwordStatus_)
- return;
-
- if (this.hotwordStatus_.enabled || this.hotwordStatus_.alwaysOnEnabled ||
- this.hotwordStatus_.trainingEnabled) {
- // Detect changes to audio logging and kill the detector if that setting
- // has changed.
- if (this.hotwordStatus_.audioLoggingEnabled != this.loggingEnabled_)
- this.shutdownDetector_();
- this.loggingEnabled_ = this.hotwordStatus_.audioLoggingEnabled;
-
- // If the training state has changed, we need to first shut down the
- // detector so that we can restart in a different mode.
- if (this.hotwordStatus_.trainingEnabled != this.trainingEnabled_)
- this.shutdownDetector_();
- this.trainingEnabled_ = this.hotwordStatus_.trainingEnabled;
-
- // Start the detector if there's a session and the user is unlocked, and
- // stops it otherwise.
- if (this.sessions_.length && !this.isLocked_ &&
- this.hotwordStatus_.userIsActive) {
- this.startDetector_();
- } else {
- this.shutdownDetector_();
- }
-
- if (!chrome.idle.onStateChanged.hasListener(
- this.idleStateChangedListener_)) {
- chrome.idle.onStateChanged.addListener(
- this.idleStateChangedListener_);
- }
- if (!chrome.runtime.onStartup.hasListener(this.startupListener_))
- chrome.runtime.onStartup.addListener(this.startupListener_);
- } else {
- // Not enabled. Shut down if running.
- this.shutdownDetector_();
-
- chrome.idle.onStateChanged.removeListener(
- this.idleStateChangedListener_);
- // If hotwording isn't enabled, don't start this component extension on
- // Chrome startup. If a user enables hotwording, the status change
- // event will be fired and the onStartup event will be registered.
- chrome.runtime.onStartup.removeListener(this.startupListener_);
- }
- },
-
- /**
- * Starts the hotword detector.
- * @private
- */
- startDetector_: function() {
- // Last attempt to start detector resulted in an error.
- if (this.state_ == State_.ERROR) {
- // TODO(amistry): Do some error rate tracking here and disable the
- // extension if we error too often.
- }
-
- if (!this.pluginManager_) {
- this.state_ = State_.STARTING;
- var isHotwordStream = this.isAlwaysOnEnabled() &&
- this.hotwordStatus_.hotwordHardwareAvailable;
- this.pluginManager_ =
- new hotword.NaClManager(this.loggingEnabled_, isHotwordStream);
- this.pluginManager_.addEventListener(
- hotword.constants.Event.READY, this.onReady_.bind(this));
- this.pluginManager_.addEventListener(
- hotword.constants.Event.ERROR, this.onError_.bind(this));
- this.pluginManager_.addEventListener(
- hotword.constants.Event.TRIGGER, this.onTrigger_.bind(this));
- this.pluginManager_.addEventListener(
- hotword.constants.Event.TIMEOUT, this.onTimeout_.bind(this));
- this.pluginManager_.addEventListener(
- hotword.constants.Event.SPEAKER_MODEL_SAVED,
- this.onSpeakerModelSaved_.bind(this));
- chrome.runtime.getPlatformInfo(function(platform) {
- var naclArch = platform.nacl_arch;
-
- // googDucking set to false so that audio output level from other tabs
- // is not affected when hotword is enabled. https://crbug.com/357773
- // content/common/media/media_stream_options.cc
- // When always-on is enabled, request the hotword stream.
- // Optional because we allow power users to bypass the hardware
- // detection via a flag, and hence the hotword stream may not be
- // available.
- var constraints = /** @type {googMediaStreamConstraints} */
- ({
- audio: {
- optional: [
- {googDucking: false},
- {googHotword: this.isAlwaysOnEnabled()}
- ]
- }
- });
- navigator.webkitGetUserMedia(
- /** @type {MediaStreamConstraints} */ (constraints),
- function(stream) {
- hotword.metrics.recordEnum(
- hotword.constants.UmaMetrics.MEDIA_STREAM_RESULT,
- hotword.constants.UmaMediaStreamOpenResult.SUCCESS,
- hotword.constants.UmaMediaStreamOpenResult.MAX);
- // The detector could have been shut down before the stream
- // finishes opening.
- if (this.pluginManager_ == null) {
- stream.getAudioTracks()[0].stop();
- return;
- }
-
- if (this.isAlwaysOnEnabled())
- this.keepAlive_.start();
- if (!this.pluginManager_.initialize(naclArch, stream)) {
- this.state_ = State_.ERROR;
- this.shutdownPluginManager_();
- }
- }.bind(this),
- function(error) {
- if (error.name in UmaMediaStreamOpenResults_) {
- var metricValue = UmaMediaStreamOpenResults_[error.name];
- } else {
- var metricValue =
- hotword.constants.UmaMediaStreamOpenResult.UNKNOWN;
- }
- hotword.metrics.recordEnum(
- hotword.constants.UmaMetrics.MEDIA_STREAM_RESULT,
- metricValue,
- hotword.constants.UmaMediaStreamOpenResult.MAX);
- this.state_ = State_.ERROR;
- this.pluginManager_ = null;
- }.bind(this));
- }.bind(this));
- } else if (this.state_ != State_.STARTING) {
- // Don't try to start a starting detector.
- this.startRecognizer_();
- }
- },
-
- /**
- * Start the recognizer plugin. Assumes the plugin has been loaded and is
- * ready to start.
- * @private
- */
- startRecognizer_: function() {
- assert(this.pluginManager_, 'No NaCl plugin loaded');
- if (this.state_ != State_.RUNNING) {
- this.state_ = State_.RUNNING;
- if (this.isAlwaysOnEnabled())
- this.keepAlive_.start();
- this.pluginManager_.startRecognizer(this.startMode_);
- }
- for (var i = 0; i < this.sessions_.length; i++) {
- var session = this.sessions_[i];
- if (session.startedCb_) {
- session.startedCb_();
- session.startedCb_ = null;
- }
- }
- },
-
- /**
- * Stops the hotword detector, if it's running.
- * @private
- */
- stopDetector_: function() {
- this.keepAlive_.stop();
- if (this.pluginManager_ && this.state_ == State_.RUNNING) {
- this.state_ = State_.STOPPED;
- this.pluginManager_.stopRecognizer();
- }
- },
-
- /**
- * Shuts down and removes the plugin manager, if it exists.
- * @private
- */
- shutdownPluginManager_: function() {
- this.keepAlive_.stop();
- if (this.pluginManager_) {
- this.pluginManager_.shutdown();
- this.pluginManager_ = null;
- }
- },
-
- /**
- * Shuts down the hotword detector.
- * @private
- */
- shutdownDetector_: function() {
- this.state_ = State_.STOPPED;
- this.shutdownPluginManager_();
- },
-
- /**
- * Finalizes the speaker model. Assumes the plugin has been loaded and
- * started.
- */
- finalizeSpeakerModel: function() {
- assert(
- this.pluginManager_,
- 'Cannot finalize speaker model: No NaCl plugin loaded');
- if (this.state_ != State_.RUNNING) {
- hotword.debug('Cannot finalize speaker model: NaCl plugin not started');
- return;
- }
- this.pluginManager_.finalizeSpeakerModel();
- },
-
- /**
- * Handle the hotword plugin being ready to start.
- * @private
- */
- onReady_: function() {
- if (this.state_ != State_.STARTING) {
- // At this point, we should not be in the RUNNING state. Doing so would
- // imply the hotword detector was started without being ready.
- assert(this.state_ != State_.RUNNING, 'Unexpected RUNNING state');
- this.shutdownPluginManager_();
- return;
- }
- this.startRecognizer_();
- },
-
- /**
- * Handle an error from the hotword plugin.
- * @private
- */
- onError_: function() {
- this.state_ = State_.ERROR;
- this.shutdownPluginManager_();
- },
-
- /**
- * Handle hotword triggering.
- * @param {!Event} event Event containing audio log data.
- * @private
- */
- onTrigger_: function(event) {
- this.keepAlive_.stop();
- hotword.debug('Hotword triggered!');
- chrome.metricsPrivate.recordUserAction(
- hotword.constants.UmaMetrics.TRIGGER);
- assert(this.pluginManager_, 'No NaCl plugin loaded on trigger');
- // Detector implicitly stops when the hotword is detected.
- this.state_ = State_.STOPPED;
-
- // Play the chime.
- this.chime_.play();
-
- // Implicitly clear the top session. A session needs to be started in
- // order to restart the detector.
- if (this.sessions_.length) {
- var session = this.sessions_.pop();
- session.triggerCb_(event.log);
-
- hotword.metrics.recordEnum(
- hotword.constants.UmaMetrics.TRIGGER_SOURCE,
- UmaTriggerSources_[session.source_],
- hotword.constants.UmaTriggerSource.MAX);
- }
-
- // If we're in always-on mode, shut down the hotword detector. The hotword
- // stream requires that we close and re-open it after a trigger, and the
- // only way to accomplish this is to shut everything down.
- if (this.isAlwaysOnEnabled())
- this.shutdownDetector_();
- },
-
- /**
- * Handle hotword timeout.
- * @private
- */
- onTimeout_: function() {
- hotword.debug('Hotword timeout!');
-
- // We get this event when the hotword detector thinks there's a false
- // trigger. In this case, we need to shut down and restart the detector to
- // re-arm the DSP.
- this.shutdownDetector_();
- this.updateStateFromStatus_();
- },
-
- /**
- * Handle speaker model saved.
- * @private
- */
- onSpeakerModelSaved_: function() {
- hotword.debug('Speaker model saved!');
-
- if (this.sessions_.length) {
- // Only call the callback of the the top session.
- var session = this.sessions_[this.sessions_.length - 1];
- if (session.speakerModelSavedCb_)
- session.speakerModelSavedCb_();
- }
- },
-
- /**
- * Remove a hotwording session from the given source.
- * @param {!hotword.constants.SessionSource} source Source of the hotword
- * session request.
- * @private
- */
- removeSession_: function(source) {
- for (var i = 0; i < this.sessions_.length; i++) {
- if (this.sessions_[i].source_ == source) {
- this.sessions_.splice(i, 1);
- break;
- }
- }
- },
-
- /**
- * Start a hotwording session.
- * @param {!hotword.constants.SessionSource} source Source of the hotword
- * session request.
- * @param {!function()} startedCb Callback invoked when the session has
- * been started successfully.
- * @param {!function()} triggerCb Callback invoked when the hotword has
- * @param {function()=} modelSavedCb Callback invoked when the speaker model
- * has been saved.
- * @param {hotword.constants.RecognizerStartMode=} opt_mode The mode to
- * start the recognizer in.
- */
- startSession: function(
- source, startedCb, triggerCb, opt_modelSavedCb, opt_mode) {
- if (this.isTrainingEnabled() && opt_mode) {
- this.startMode_ = opt_mode;
- } else {
- this.startMode_ = hotword.constants.RecognizerStartMode.NORMAL;
- }
- hotword.debug('Starting session for source: ' + source);
- this.removeSession_(source);
- this.sessions_.push(
- new Session_(source, triggerCb, startedCb, opt_modelSavedCb));
- this.updateStateFromStatus_();
- },
-
- /**
- * Stops a hotwording session.
- * @param {!hotword.constants.SessionSource} source Source of the hotword
- * session request.
- */
- stopSession: function(source) {
- hotword.debug('Stopping session for source: ' + source);
- this.removeSession_(source);
- // If this is a training session then switch the start mode back to
- // normal.
- if (source == hotword.constants.SessionSource.TRAINING)
- this.startMode_ = hotword.constants.RecognizerStartMode.NORMAL;
- this.updateStateFromStatus_();
- },
-
- /**
- * Handles a chrome.idle.onStateChanged event.
- * @param {!string} state State, one of "active", "idle", or "locked".
- * @private
- */
- handleIdleStateChanged_: function(state) {
- hotword.debug('Idle state changed: ' + state);
- var oldLocked = this.isLocked_;
- if (state == 'locked')
- this.isLocked_ = true;
- else
- this.isLocked_ = false;
-
- if (oldLocked != this.isLocked_)
- this.updateStateFromStatus_();
- },
-
- /**
- * Handles a chrome.runtime.onStartup event.
- * @private
- */
- handleStartup_: function() {
- // Nothing specific needs to be done here. This function exists solely to
- // be registered on the startup event.
- }
- };
-
- return {StateManager: StateManager};
-});
diff --git a/chromium/chrome/browser/resources/hotword/training_manager.js b/chromium/chrome/browser/resources/hotword/training_manager.js
deleted file mode 100644
index f5b68d44885..00000000000
--- a/chromium/chrome/browser/resources/hotword/training_manager.js
+++ /dev/null
@@ -1,201 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-cr.define('hotword', function() {
- 'use strict';
-
- /**
- * Class used to manage speaker training. Starts a hotwording session
- * if training is on, and automatically restarts the detector when a
- * a hotword is triggered.
- * @param {!hotword.StateManager} stateManager
- * @constructor
- * @extends {hotword.BaseSessionManager}
- */
- function TrainingManager(stateManager) {
- /**
- * Chrome event listeners. Saved so that they can be de-registered when
- * hotwording is disabled.
- * @private
- */
- this.finalizedSpeakerModelListener_ =
- this.handleFinalizeSpeakerModel_.bind(this);
-
- hotword.BaseSessionManager.call(
- this, stateManager, hotword.constants.SessionSource.TRAINING);
- }
-
- /**
- * Handles a success event on mounting the file system event and deletes
- * the user data files.
- * @param {FileSystem} fs The FileSystem object.
- * @private
- */
- TrainingManager.deleteFiles_ = function(fs) {
- fs.root.getFile(
- hotword.constants.SPEAKER_MODEL_FILE_NAME, {create: false},
- TrainingManager.deleteFile_, TrainingManager.fileErrorHandler_);
-
- for (var i = 0; i < hotword.constants.NUM_TRAINING_UTTERANCES; ++i) {
- fs.root.getFile(
- hotword.constants.UTTERANCE_FILE_PREFIX + i +
- hotword.constants.UTTERANCE_FILE_EXTENSION,
- {create: false}, TrainingManager.deleteFile_,
- TrainingManager.fileErrorHandler_);
- }
- };
-
- /**
- * Deletes a file.
- * @param {FileEntry} fileEntry The FileEntry object.
- * @private
- */
- TrainingManager.deleteFile_ = function(fileEntry) {
- if (fileEntry.isFile) {
- hotword.debug('File found: ' + fileEntry.fullPath);
- if (hotword.DEBUG || window.localStorage['hotword.DEBUG']) {
- fileEntry.getMetadata(function(md) {
- hotword.debug('File size: ' + md.size);
- });
- }
- fileEntry.remove(function() {
- hotword.debug('File removed: ' + fileEntry.fullPath);
- }, TrainingManager.fileErrorHandler_);
- }
- };
-
- /**
- * Handles a failure event on mounting the file system event.
- * @param {FileError} e The FileError object.
- * @private
- */
- TrainingManager.fileErrorHandler_ = function(e) {
- hotword.debug('File error: ' + e.code);
- };
-
- /**
- * Handles a failure event on checking for the existence of the speaker model.
- * @param {FileError} e The FileError object.
- * @private
- */
- TrainingManager.sendNoSpeakerModelResponse_ = function(e) {
- chrome.hotwordPrivate.speakerModelExistsResult(false);
- };
-
- /**
- * Handles a success event on mounting the file system and checks for the
- * existence of the speaker model.
- * @param {FileSystem} fs The FileSystem object.
- * @private
- */
- TrainingManager.speakerModelExists_ = function(fs) {
- fs.root.getFile(
- hotword.constants.SPEAKER_MODEL_FILE_NAME, {create: false},
- TrainingManager.sendSpeakerModelExistsResponse_,
- TrainingManager.sendNoSpeakerModelResponse_);
- };
-
- /**
- * Sends a response through the HotwordPrivateApi indicating whether
- * the speaker model exists.
- * @param {FileEntry} fileEntry The FileEntry object.
- * @private
- */
- TrainingManager.sendSpeakerModelExistsResponse_ = function(fileEntry) {
- if (fileEntry.isFile) {
- hotword.debug('File found: ' + fileEntry.fullPath);
- if (hotword.DEBUG || window.localStorage['hotword.DEBUG']) {
- fileEntry.getMetadata(function(md) {
- hotword.debug('File size: ' + md.size);
- });
- }
- }
- chrome.hotwordPrivate.speakerModelExistsResult(fileEntry.isFile);
- };
-
- /**
- * Handles a request to delete the speaker model.
- */
- TrainingManager.handleDeleteSpeakerModel = function() {
- window.webkitRequestFileSystem(
- PERSISTENT, hotword.constants.FILE_SYSTEM_SIZE_BYTES,
- TrainingManager.deleteFiles_, TrainingManager.fileErrorHandler_);
- };
-
- /**
- * Handles a request for the speaker model existence.
- */
- TrainingManager.handleSpeakerModelExists = function() {
- window.webkitRequestFileSystem(
- PERSISTENT, hotword.constants.FILE_SYSTEM_SIZE_BYTES,
- TrainingManager.speakerModelExists_, TrainingManager.fileErrorHandler_);
- };
-
- TrainingManager.prototype = {
- __proto__: hotword.BaseSessionManager.prototype,
-
- /** @override */
- enabled: function() {
- return this.stateManager.isTrainingEnabled();
- },
-
- /** @override */
- updateListeners: function() {
- hotword.BaseSessionManager.prototype.updateListeners.call(this);
-
- if (this.enabled()) {
- // Detect when the speaker model needs to be finalized.
- if (!chrome.hotwordPrivate.onFinalizeSpeakerModel.hasListener(
- this.finalizedSpeakerModelListener_)) {
- chrome.hotwordPrivate.onFinalizeSpeakerModel.addListener(
- this.finalizedSpeakerModelListener_);
- }
- this.startSession(hotword.constants.RecognizerStartMode.NEW_MODEL);
- } else {
- chrome.hotwordPrivate.onFinalizeSpeakerModel.removeListener(
- this.finalizedSpeakerModelListener_);
- }
- },
-
- /** @override */
- handleHotwordTrigger: function(log) {
- if (this.enabled()) {
- hotword.BaseSessionManager.prototype.handleHotwordTrigger.call(
- this, log);
- this.startSession(hotword.constants.RecognizerStartMode.ADAPT_MODEL);
- }
- },
-
- /** @override */
- startSession: function(opt_mode) {
- this.stateManager.startSession(
- this.sessionSource_,
- function() {
- chrome.hotwordPrivate.setHotwordSessionState(true, function() {});
- },
- this.handleHotwordTrigger.bind(this),
- this.handleSpeakerModelSaved_.bind(this), opt_mode);
- },
-
- /**
- * Handles a hotwordPrivate.onFinalizeSpeakerModel event.
- * @private
- */
- handleFinalizeSpeakerModel_: function() {
- if (this.enabled())
- this.stateManager.finalizeSpeakerModel();
- },
-
- /**
- * Handles a hotwordPrivate.onFinalizeSpeakerModel event.
- * @private
- */
- handleSpeakerModelSaved_: function() {
- if (this.enabled())
- chrome.hotwordPrivate.notifySpeakerModelSaved();
- },
- };
-
- return {TrainingManager: TrainingManager};
-});
diff --git a/chromium/chrome/browser/resources/hotword_audio_verification/OWNERS b/chromium/chrome/browser/resources/hotword_audio_verification/OWNERS
deleted file mode 100644
index 99e28241baa..00000000000
--- a/chromium/chrome/browser/resources/hotword_audio_verification/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-kcarattini@chromium.org
diff --git a/chromium/chrome/browser/resources/hotword_audio_verification/event_page.js b/chromium/chrome/browser/resources/hotword_audio_verification/event_page.js
deleted file mode 100644
index ea379d33d9b..00000000000
--- a/chromium/chrome/browser/resources/hotword_audio_verification/event_page.js
+++ /dev/null
@@ -1,27 +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.
-
-var appId = 'hotword_audio_verification';
-
-chrome.app.runtime.onLaunched.addListener(function() {
- // We need to focus the window if it already exists, since it
- // is created as 'hidden'.
- //
- // Note: If we ever launch on another platform, make sure that this works
- // with window managers that support hiding (e.g. Cmd+h on an app window on
- // Mac).
- var appWindow = chrome.app.window.get(appId);
- if (appWindow) {
- appWindow.focus();
- return;
- }
-
- chrome.app.window.create('main.html', {
- 'frame': 'none',
- 'resizable': false,
- 'hidden': true,
- 'id': appId,
- 'innerBounds': {'width': 784, 'height': 448}
- });
-});
diff --git a/chromium/chrome/browser/resources/hotword_audio_verification/flow.js b/chromium/chrome/browser/resources/hotword_audio_verification/flow.js
deleted file mode 100644
index c22211492c4..00000000000
--- a/chromium/chrome/browser/resources/hotword_audio_verification/flow.js
+++ /dev/null
@@ -1,566 +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() {
-
-// Correspond to steps in the hotword opt-in flow.
-/** @const */ var START = 'start-container';
-/** @const */ var AUDIO_HISTORY = 'audio-history-container';
-/** @const */ var SPEECH_TRAINING = 'speech-training-container';
-/** @const */ var FINISH = 'finish-container';
-
-/**
- * These flows correspond to the three LaunchModes as defined in
- * chrome/browser/search/hotword_service.h and should be kept in sync
- * with them.
- * @const
- */
-var FLOWS = [
- [START, SPEECH_TRAINING, FINISH],
- [START, AUDIO_HISTORY, SPEECH_TRAINING, FINISH], [SPEECH_TRAINING, FINISH]
-];
-
-/**
- * The launch mode. This enum needs to be kept in sync with that of
- * the same name in hotword_service.h.
- * @enum {number}
- */
-var LaunchMode = {HOTWORD_ONLY: 0, HOTWORD_AND_AUDIO_HISTORY: 1, RETRAIN: 2};
-
-/**
- * The training state.
- * @enum {string}
- */
-var TrainingState = {
- RESET: 'reset',
- TIMEOUT: 'timeout',
- ERROR: 'error',
-};
-
-/**
- * Class to control the page flow of the always-on hotword and
- * Audio History opt-in process.
- * @constructor
- */
-function Flow() {
- this.currentStepIndex_ = -1;
- this.currentFlow_ = [];
-
- /**
- * The mode that this app was launched in.
- * @private {LaunchMode}
- */
- this.launchMode_ = LaunchMode.HOTWORD_AND_AUDIO_HISTORY;
-
- /**
- * Whether this flow is currently in the process of training a voice model.
- * @private {boolean}
- */
- this.training_ = false;
-
- /**
- * The current training state.
- * @private {?TrainingState}
- */
- this.trainingState_ = null;
-
- /**
- * Whether an expected hotword trigger has been received, indexed by
- * training step.
- * @private {boolean[]}
- */
- this.hotwordTriggerReceived_ = [];
-
- /**
- * Prefix of the element ids for the page that is currently training.
- * @private {string}
- */
- this.trainingPagePrefix_ = 'speech-training';
-
- /**
- * Whether the speaker model for this flow has been finalized.
- * @private {boolean}
- */
- this.speakerModelFinalized_ = false;
-
- /**
- * ID of the currently active timeout.
- * @private {?number}
- */
- this.timeoutId_ = null;
-
- /**
- * Listener for the speakerModelSaved event.
- * @private {Function}
- */
- this.speakerModelFinalizedListener_ =
- this.onSpeakerModelFinalized_.bind(this);
-
- /**
- * Listener for the hotword trigger event.
- * @private {Function}
- */
- this.hotwordTriggerListener_ = this.handleHotwordTrigger_.bind(this);
-
- // Listen for the user locking the screen.
- chrome.idle.onStateChanged.addListener(
- this.handleIdleStateChanged_.bind(this));
-
- // Listen for hotword settings changes. This used to detect when the user
- // switches to a different profile.
- if (chrome.hotwordPrivate.onEnabledChanged) {
- chrome.hotwordPrivate.onEnabledChanged.addListener(
- this.handleEnabledChanged_.bind(this));
- }
-}
-
-/**
- * Advances the current step. Begins training if the speech-training
- * page has been reached.
- */
-Flow.prototype.advanceStep = function() {
- this.currentStepIndex_++;
- if (this.currentStepIndex_ < this.currentFlow_.length) {
- if (this.currentFlow_[this.currentStepIndex_] == SPEECH_TRAINING)
- this.startTraining();
- this.showStep_.apply(this);
- }
-};
-
-/**
- * Gets the appropriate flow and displays its first page.
- */
-Flow.prototype.startFlow = function() {
- if (chrome.hotwordPrivate && chrome.hotwordPrivate.getLaunchState)
- chrome.hotwordPrivate.getLaunchState(this.startFlowForMode_.bind(this));
-};
-
-/**
- * Starts the training process.
- */
-Flow.prototype.startTraining = function() {
- // Don't start a training session if one already exists.
- if (this.training_)
- return;
-
- this.training_ = true;
-
- if (chrome.hotwordPrivate.onHotwordTriggered &&
- !chrome.hotwordPrivate.onHotwordTriggered.hasListener(
- this.hotwordTriggerListener_)) {
- chrome.hotwordPrivate.onHotwordTriggered.addListener(
- this.hotwordTriggerListener_);
- }
-
- this.waitForHotwordTrigger_(0);
- if (chrome.hotwordPrivate.startTraining)
- chrome.hotwordPrivate.startTraining();
-};
-
-/**
- * Stops the training process.
- */
-Flow.prototype.stopTraining = function() {
- if (!this.training_)
- return;
-
- this.training_ = false;
- if (chrome.hotwordPrivate.onHotwordTriggered) {
- chrome.hotwordPrivate.onHotwordTriggered.removeListener(
- this.hotwordTriggerListener_);
- }
- if (chrome.hotwordPrivate.stopTraining)
- chrome.hotwordPrivate.stopTraining();
-};
-
-/**
- * Attempts to enable audio history for the signed-in account.
- */
-Flow.prototype.enableAudioHistory = function() {
- // Update UI
- $('audio-history-agree').disabled = true;
- $('audio-history-cancel').disabled = true;
-
- $('audio-history-error').hidden = true;
- $('audio-history-wait').hidden = false;
-
- if (chrome.hotwordPrivate.setAudioHistoryEnabled) {
- chrome.hotwordPrivate.setAudioHistoryEnabled(
- true, this.onAudioHistoryRequestCompleted_.bind(this));
- }
-};
-
-// ---- private methods:
-
-/**
- * Shows an error if the audio history setting was not enabled successfully.
- * @private
- */
-Flow.prototype.handleAudioHistoryError_ = function() {
- $('audio-history-agree').disabled = false;
- $('audio-history-cancel').disabled = false;
-
- $('audio-history-wait').hidden = true;
- $('audio-history-error').hidden = false;
-
- // Set a timeout before focusing the Enable button so that screenreaders
- // have time to announce the error first.
- this.setTimeout_(function() {
- $('audio-history-agree').focus();
- }.bind(this), 50);
-};
-
-/**
- * Callback for when an audio history request completes.
- * @param {chrome.hotwordPrivate.AudioHistoryState} state The audio history
- * request state.
- * @private
- */
-Flow.prototype.onAudioHistoryRequestCompleted_ = function(state) {
- if (!state.success || !state.enabled) {
- this.handleAudioHistoryError_();
- return;
- }
-
- this.advanceStep();
-};
-
-/**
- * Shows an error if the speaker model has not been finalized.
- * @private
- */
-Flow.prototype.handleSpeakerModelFinalizedError_ = function() {
- if (!this.training_)
- return;
-
- if (this.speakerModelFinalized_)
- return;
-
- this.updateTrainingState_(TrainingState.ERROR);
- this.stopTraining();
-};
-
-/**
- * Handles the speaker model finalized event.
- * @private
- */
-Flow.prototype.onSpeakerModelFinalized_ = function() {
- this.speakerModelFinalized_ = true;
- if (chrome.hotwordPrivate.onSpeakerModelSaved) {
- chrome.hotwordPrivate.onSpeakerModelSaved.removeListener(
- this.speakerModelFinalizedListener_);
- }
- this.stopTraining();
- this.setTimeout_(this.finishFlow_.bind(this), 2000);
-};
-
-/**
- * Completes the training process.
- * @private
- */
-Flow.prototype.finishFlow_ = function() {
- if (chrome.hotwordPrivate.setHotwordAlwaysOnSearchEnabled) {
- chrome.hotwordPrivate.setHotwordAlwaysOnSearchEnabled(
- true, this.advanceStep.bind(this));
- }
-};
-
-/**
- * Handles a user clicking on the retry button.
- */
-Flow.prototype.handleRetry = function() {
- if (!(this.trainingState_ == TrainingState.TIMEOUT ||
- this.trainingState_ == TrainingState.ERROR))
- return;
-
- this.startTraining();
- this.updateTrainingState_(TrainingState.RESET);
-};
-
-// ---- private methods:
-
-/**
- * Completes the training process.
- * @private
- */
-Flow.prototype.finalizeSpeakerModel_ = function() {
- if (!this.training_)
- return;
-
- // Listen for the success event from the NaCl module.
- if (chrome.hotwordPrivate.onSpeakerModelSaved &&
- !chrome.hotwordPrivate.onSpeakerModelSaved.hasListener(
- this.speakerModelFinalizedListener_)) {
- chrome.hotwordPrivate.onSpeakerModelSaved.addListener(
- this.speakerModelFinalizedListener_);
- }
-
- this.speakerModelFinalized_ = false;
- this.setTimeout_(this.handleSpeakerModelFinalizedError_.bind(this), 30000);
- if (chrome.hotwordPrivate.finalizeSpeakerModel)
- chrome.hotwordPrivate.finalizeSpeakerModel();
-};
-
-/**
- * Returns the current training step.
- * @param {string} curStepClassName The name of the class of the current
- * training step.
- * @return {Object} The current training step, its index, and an array of
- * all training steps. Any of these can be undefined.
- * @private
- */
-Flow.prototype.getCurrentTrainingStep_ = function(curStepClassName) {
- var steps =
- $(this.trainingPagePrefix_ + '-training').querySelectorAll('.train');
- var curStep =
- $(this.trainingPagePrefix_ + '-training').querySelector('.listening');
-
- return {
- current: curStep,
- index: Array.prototype.indexOf.call(steps, curStep),
- steps: steps
- };
-};
-
-/**
- * Updates the training state.
- * @param {TrainingState} state The training state.
- * @private
- */
-Flow.prototype.updateTrainingState_ = function(state) {
- this.trainingState_ = state;
- this.updateErrorUI_();
-};
-
-/**
- * Waits two minutes and then checks for a training error.
- * @param {number} index The index of the training step.
- * @private
- */
-Flow.prototype.waitForHotwordTrigger_ = function(index) {
- if (!this.training_)
- return;
-
- this.hotwordTriggerReceived_[index] = false;
- this.setTimeout_(this.handleTrainingTimeout_.bind(this, index), 120000);
-};
-
-/**
- * Checks for and handles a training error.
- * @param {number} index The index of the training step.
- * @private
- */
-Flow.prototype.handleTrainingTimeout_ = function(index) {
- if (this.hotwordTriggerReceived_[index])
- return;
-
- this.timeoutTraining_();
-};
-
-/**
- * Times out training and updates the UI to show a "retry" message, if
- * currently training.
- * @private
- */
-Flow.prototype.timeoutTraining_ = function() {
- if (!this.training_)
- return;
-
- this.clearTimeout_();
- this.updateTrainingState_(TrainingState.TIMEOUT);
- this.stopTraining();
-};
-
-/**
- * Sets a timeout. If any timeout is active, clear it.
- * @param {Function} func The function to invoke when the timeout occurs.
- * @param {number} delay Timeout delay in milliseconds.
- * @private
- */
-Flow.prototype.setTimeout_ = function(func, delay) {
- this.clearTimeout_();
- this.timeoutId_ = setTimeout(function() {
- this.timeoutId_ = null;
- func();
- }, delay);
-};
-
-/**
- * Clears any currently active timeout.
- * @private
- */
-Flow.prototype.clearTimeout_ = function() {
- if (this.timeoutId_ != null) {
- clearTimeout(this.timeoutId_);
- this.timeoutId_ = null;
- }
-};
-
-/**
- * Updates the training error UI.
- * @private
- */
-Flow.prototype.updateErrorUI_ = function() {
- if (!this.training_)
- return;
-
- var trainingSteps = this.getCurrentTrainingStep_('listening');
- var steps = trainingSteps.steps;
-
- $(this.trainingPagePrefix_ + '-toast').hidden =
- this.trainingState_ != TrainingState.TIMEOUT;
- if (this.trainingState_ == TrainingState.RESET) {
- // We reset the training to begin at the first step.
- // The first step is reset to 'listening', while the rest
- // are reset to 'not-started'.
- var prompt = loadTimeData.getString('trainingFirstPrompt');
- for (var i = 0; i < steps.length; ++i) {
- steps[i].classList.remove('recorded');
- if (i == 0) {
- steps[i].classList.remove('not-started');
- steps[i].classList.add('listening');
- } else {
- steps[i].classList.add('not-started');
- if (i == steps.length - 1)
- prompt = loadTimeData.getString('trainingLastPrompt');
- else
- prompt = loadTimeData.getString('trainingMiddlePrompt');
- }
- steps[i].querySelector('.text').textContent = prompt;
- }
-
- // Reset the buttonbar.
- $(this.trainingPagePrefix_ + '-processing').hidden = true;
- $(this.trainingPagePrefix_ + '-wait').hidden = false;
- $(this.trainingPagePrefix_ + '-error').hidden = true;
- $(this.trainingPagePrefix_ + '-retry').hidden = true;
- } else if (this.trainingState_ == TrainingState.TIMEOUT) {
- var curStep = trainingSteps.current;
- if (curStep) {
- curStep.classList.remove('listening');
- curStep.classList.add('not-started');
- }
-
- // Set a timeout before focusing the Retry button so that screenreaders
- // have time to announce the timeout first.
- this.setTimeout_(function() {
- $(this.trainingPagePrefix_ + '-toast').children[1].focus();
- }.bind(this), 50);
- } else if (this.trainingState_ == TrainingState.ERROR) {
- // Update the buttonbar.
- $(this.trainingPagePrefix_ + '-wait').hidden = true;
- $(this.trainingPagePrefix_ + '-error').hidden = false;
- $(this.trainingPagePrefix_ + '-retry').hidden = false;
- $(this.trainingPagePrefix_ + '-processing').hidden = false;
-
- // Set a timeout before focusing the Retry button so that screenreaders
- // have time to announce the error first.
- this.setTimeout_(function() {
- $(this.trainingPagePrefix_ + '-retry').children[0].focus();
- }.bind(this), 50);
- }
-};
-
-/**
- * Handles a hotword trigger event and updates the training UI.
- * @private
- */
-Flow.prototype.handleHotwordTrigger_ = function() {
- var trainingSteps = this.getCurrentTrainingStep_('listening');
-
- if (!trainingSteps.current)
- return;
-
- var index = trainingSteps.index;
- this.hotwordTriggerReceived_[index] = true;
-
- trainingSteps.current.querySelector('.text').textContent =
- loadTimeData.getString('trainingRecorded');
- trainingSteps.current.classList.remove('listening');
- trainingSteps.current.classList.add('recorded');
-
- if (trainingSteps.steps[index + 1]) {
- trainingSteps.steps[index + 1].classList.remove('not-started');
- trainingSteps.steps[index + 1].classList.add('listening');
- this.waitForHotwordTrigger_(index + 1);
- return;
- }
-
- // Only the last step makes it here.
- var buttonElem = $(this.trainingPagePrefix_ + '-processing').hidden = false;
- this.finalizeSpeakerModel_();
-};
-
-/**
- * Handles a chrome.idle.onStateChanged event and times out the training if
- * the state is "locked".
- * @param {!string} state State, one of "active", "idle", or "locked".
- * @private
- */
-Flow.prototype.handleIdleStateChanged_ = function(state) {
- if (state == 'locked')
- this.timeoutTraining_();
-};
-
-/**
- * Handles a chrome.hotwordPrivate.onEnabledChanged event and times out
- * training if the user is no longer the active user (user switches profiles).
- * @private
- */
-Flow.prototype.handleEnabledChanged_ = function() {
- if (chrome.hotwordPrivate.getStatus) {
- chrome.hotwordPrivate.getStatus(function(status) {
- if (status.userIsActive)
- return;
-
- this.timeoutTraining_();
- }.bind(this));
- }
-};
-
-/**
- * Gets and starts the appropriate flow for the launch mode.
- * @param {chrome.hotwordPrivate.LaunchState} state Launch state of the
- * Hotword Audio Verification App.
- * @private
- */
-Flow.prototype.startFlowForMode_ = function(state) {
- this.launchMode_ = state.launchMode;
- assert(
- state.launchMode >= 0 && state.launchMode < FLOWS.length,
- 'Invalid Launch Mode.');
- this.currentFlow_ = FLOWS[state.launchMode];
- if (state.launchMode == LaunchMode.HOTWORD_ONLY) {
- $('intro-description-audio-history-enabled').hidden = false;
- } else if (state.launchMode == LaunchMode.HOTWORD_AND_AUDIO_HISTORY) {
- $('intro-description').hidden = false;
- }
-
- this.advanceStep();
-};
-
-/**
- * Displays the current step. If the current step is not the first step,
- * also hides the previous step. Focuses the current step's first button.
- * @private
- */
-Flow.prototype.showStep_ = function() {
- var currentStepId = this.currentFlow_[this.currentStepIndex_];
- var currentStep = document.getElementById(currentStepId);
- currentStep.hidden = false;
-
- cr.ui.setInitialFocus(currentStep);
-
- var previousStep = null;
- if (this.currentStepIndex_ > 0)
- previousStep = this.currentFlow_[this.currentStepIndex_ - 1];
-
- if (previousStep)
- document.getElementById(previousStep).hidden = true;
-
- chrome.app.window.current().show();
-};
-
-window.Flow = Flow;
-})();
diff --git a/chromium/chrome/browser/resources/hotword_audio_verification/images/gradient-1x.png b/chromium/chrome/browser/resources/hotword_audio_verification/images/gradient-1x.png
deleted file mode 100644
index 6ff742000e8..00000000000
--- a/chromium/chrome/browser/resources/hotword_audio_verification/images/gradient-1x.png
+++ /dev/null
Binary files differ
diff --git a/chromium/chrome/browser/resources/hotword_audio_verification/images/gradient-2x.png b/chromium/chrome/browser/resources/hotword_audio_verification/images/gradient-2x.png
deleted file mode 100644
index 3c39792f23c..00000000000
--- a/chromium/chrome/browser/resources/hotword_audio_verification/images/gradient-2x.png
+++ /dev/null
Binary files differ
diff --git a/chromium/chrome/browser/resources/hotword_audio_verification/images/ic-check-blue-1x.png b/chromium/chrome/browser/resources/hotword_audio_verification/images/ic-check-blue-1x.png
deleted file mode 100644
index c04541c591b..00000000000
--- a/chromium/chrome/browser/resources/hotword_audio_verification/images/ic-check-blue-1x.png
+++ /dev/null
Binary files differ
diff --git a/chromium/chrome/browser/resources/hotword_audio_verification/images/ic-check-blue-2x.png b/chromium/chrome/browser/resources/hotword_audio_verification/images/ic-check-blue-2x.png
deleted file mode 100644
index 7fca135f4b6..00000000000
--- a/chromium/chrome/browser/resources/hotword_audio_verification/images/ic-check-blue-2x.png
+++ /dev/null
Binary files differ
diff --git a/chromium/chrome/browser/resources/hotword_audio_verification/images/ic-check-gray-1x.png b/chromium/chrome/browser/resources/hotword_audio_verification/images/ic-check-gray-1x.png
deleted file mode 100644
index 1071613cb1b..00000000000
--- a/chromium/chrome/browser/resources/hotword_audio_verification/images/ic-check-gray-1x.png
+++ /dev/null
Binary files differ
diff --git a/chromium/chrome/browser/resources/hotword_audio_verification/images/ic-check-gray-2x.png b/chromium/chrome/browser/resources/hotword_audio_verification/images/ic-check-gray-2x.png
deleted file mode 100644
index e93d6e18eb9..00000000000
--- a/chromium/chrome/browser/resources/hotword_audio_verification/images/ic-check-gray-2x.png
+++ /dev/null
Binary files differ
diff --git a/chromium/chrome/browser/resources/hotword_audio_verification/images/ic-error-1x.png b/chromium/chrome/browser/resources/hotword_audio_verification/images/ic-error-1x.png
deleted file mode 100644
index f8d75841375..00000000000
--- a/chromium/chrome/browser/resources/hotword_audio_verification/images/ic-error-1x.png
+++ /dev/null
Binary files differ
diff --git a/chromium/chrome/browser/resources/hotword_audio_verification/images/ic-error-2x.png b/chromium/chrome/browser/resources/hotword_audio_verification/images/ic-error-2x.png
deleted file mode 100644
index dc0bf4f1c93..00000000000
--- a/chromium/chrome/browser/resources/hotword_audio_verification/images/ic-error-2x.png
+++ /dev/null
Binary files differ
diff --git a/chromium/chrome/browser/resources/hotword_audio_verification/images/ic-x-white-1x.png b/chromium/chrome/browser/resources/hotword_audio_verification/images/ic-x-white-1x.png
deleted file mode 100644
index 23d17c9c322..00000000000
--- a/chromium/chrome/browser/resources/hotword_audio_verification/images/ic-x-white-1x.png
+++ /dev/null
Binary files differ
diff --git a/chromium/chrome/browser/resources/hotword_audio_verification/images/ic-x-white-2x.png b/chromium/chrome/browser/resources/hotword_audio_verification/images/ic-x-white-2x.png
deleted file mode 100644
index 63cf9729d34..00000000000
--- a/chromium/chrome/browser/resources/hotword_audio_verification/images/ic-x-white-2x.png
+++ /dev/null
Binary files differ
diff --git a/chromium/chrome/browser/resources/hotword_audio_verification/images/icon-128.png b/chromium/chrome/browser/resources/hotword_audio_verification/images/icon-128.png
deleted file mode 100644
index d3a010c5376..00000000000
--- a/chromium/chrome/browser/resources/hotword_audio_verification/images/icon-128.png
+++ /dev/null
Binary files differ
diff --git a/chromium/chrome/browser/resources/hotword_audio_verification/images/icon-16.png b/chromium/chrome/browser/resources/hotword_audio_verification/images/icon-16.png
deleted file mode 100644
index 3a7caeb0c2f..00000000000
--- a/chromium/chrome/browser/resources/hotword_audio_verification/images/icon-16.png
+++ /dev/null
Binary files differ
diff --git a/chromium/chrome/browser/resources/hotword_audio_verification/images/icon-48.png b/chromium/chrome/browser/resources/hotword_audio_verification/images/icon-48.png
deleted file mode 100644
index 1f48e48098e..00000000000
--- a/chromium/chrome/browser/resources/hotword_audio_verification/images/icon-48.png
+++ /dev/null
Binary files differ
diff --git a/chromium/chrome/browser/resources/hotword_audio_verification/images/intro-1x.png b/chromium/chrome/browser/resources/hotword_audio_verification/images/intro-1x.png
deleted file mode 100644
index 3190980fbf9..00000000000
--- a/chromium/chrome/browser/resources/hotword_audio_verification/images/intro-1x.png
+++ /dev/null
Binary files differ
diff --git a/chromium/chrome/browser/resources/hotword_audio_verification/images/intro-2x.png b/chromium/chrome/browser/resources/hotword_audio_verification/images/intro-2x.png
deleted file mode 100644
index 6465825b0ae..00000000000
--- a/chromium/chrome/browser/resources/hotword_audio_verification/images/intro-2x.png
+++ /dev/null
Binary files differ
diff --git a/chromium/chrome/browser/resources/hotword_audio_verification/images/placeholder-loader-1x.png b/chromium/chrome/browser/resources/hotword_audio_verification/images/placeholder-loader-1x.png
deleted file mode 100644
index 0bb41bc244e..00000000000
--- a/chromium/chrome/browser/resources/hotword_audio_verification/images/placeholder-loader-1x.png
+++ /dev/null
Binary files differ
diff --git a/chromium/chrome/browser/resources/hotword_audio_verification/images/placeholder-loader-2x.png b/chromium/chrome/browser/resources/hotword_audio_verification/images/placeholder-loader-2x.png
deleted file mode 100644
index cd1ffa7205b..00000000000
--- a/chromium/chrome/browser/resources/hotword_audio_verification/images/placeholder-loader-2x.png
+++ /dev/null
Binary files differ
diff --git a/chromium/chrome/browser/resources/hotword_audio_verification/main.html b/chromium/chrome/browser/resources/hotword_audio_verification/main.html
deleted file mode 100644
index 2572c9464c9..00000000000
--- a/chromium/chrome/browser/resources/hotword_audio_verification/main.html
+++ /dev/null
@@ -1,25 +0,0 @@
-<!doctype html>
-<html i18n-values="dir:textdirection;lang:language">
- <head>
- <meta charset=utf-8>
- <title i18n-content="introTitle"></title>
- <link rel="stylesheet" href="chrome://resources/css/text_defaults.css">
- <link type="text/css" rel="stylesheet" href="style.css">
- <script src="chrome://resources/js/action_link.js"></script>
- <script src="chrome://resources/js/cr.js"></script>
- <script src="chrome://resources/js/cr/ui/node_utils.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/i18n_template_no_process.js"></script>
- <script src="flow.js"></script>
- <script src="main.js"></script>
- </head>
- <body>
- <div id="steps">
- <include src="steps/start_step.html">
- <include src="steps/audio_history_step.html">
- <include src="steps/speech_training_step.html">
- <include src="steps/finished_step.html">
- </div>
- </body>
-</html>
diff --git a/chromium/chrome/browser/resources/hotword_audio_verification/main.js b/chromium/chrome/browser/resources/hotword_audio_verification/main.js
deleted file mode 100644
index 33fc21a9ec4..00000000000
--- a/chromium/chrome/browser/resources/hotword_audio_verification/main.js
+++ /dev/null
@@ -1,50 +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.
-
-var appWindow = chrome.app.window.current();
-
-document.addEventListener('DOMContentLoaded', function() {
- chrome.hotwordPrivate.getLocalizedStrings(function(strings) {
- loadTimeData.data = strings;
- i18nTemplate.process(document, loadTimeData);
-
- var flow = new Flow();
- flow.startFlow();
-
- var pressFunction = function(e) {
- // Only respond to 'Enter' key presses.
- if (e.type == 'keyup' && e.key != 'Enter')
- return;
-
- var classes = e.target.classList;
- if (classes.contains('close') || classes.contains('finish-button')) {
- flow.stopTraining();
- appWindow.close();
- e.preventDefault();
- }
- if (classes.contains('retry-button')) {
- flow.handleRetry();
- e.preventDefault();
- }
- };
-
- $('steps').addEventListener('click', pressFunction);
- $('steps').addEventListener('keyup', pressFunction);
-
- $('audio-history-agree').addEventListener('click', function(e) {
- flow.enableAudioHistory();
- e.preventDefault();
- });
-
- $('hotword-start').addEventListener('click', function(e) {
- flow.advanceStep();
- e.preventDefault();
- });
-
- $('settings-link').addEventListener('click', function(e) {
- chrome.browser.openTab({'url': 'chrome://settings'}, function() {});
- e.preventDefault();
- });
- });
-});
diff --git a/chromium/chrome/browser/resources/hotword_audio_verification/manifest.json b/chromium/chrome/browser/resources/hotword_audio_verification/manifest.json
deleted file mode 100644
index a6e4091e39c..00000000000
--- a/chromium/chrome/browser/resources/hotword_audio_verification/manifest.json
+++ /dev/null
@@ -1,27 +0,0 @@
-{
- // chrome-extension://abjokfonkihficiokmkfboogholifghn/
- "key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtfVZc80kw93gaZwHGhOLpxGKil8n/x1IQ2L/Oj76YeICJk5w4YKw+0N2IYA0gJnwqJdTu3ijrWqO2oQTWoZ3lHmAv9NHsUXHdrWuoGRuVqo0dakLnS+AB3rLGPSerZZNExpdK0Yd3wR6GMOJAoAQM9H6Zpo7LNYjPebx31QJZ6OgdYZA+Eu4fGIJkWIPY1LMsVO1jzFJ4JSPyNWmhxL4fHfQXVM5p1cgJSVxTXsB1ZGaRc4HF2kwSYMOimIiWqfU0VInTXVU7IS3hJaKzm/LExW/ABTGejf2sGIa725EQTavGFsQ07jFZdVzKGAjHCU/0Jy8PxDIg2B+ixlM2QXP/wIDAQAB",
- "name": "Ok Google",
- "version": "0.1",
- "manifest_version": 2,
- "icons": {
- "16": "images/icon-16.png",
- "48": "images/icon-48.png",
- "128": "images/icon-128.png"
- },
- "app": {
- "background": {
- "scripts": ["event_page.js"],
- "persistent": false
- },
- "content_security_policy": "default-src 'self' blob: filesystem:; script-src 'self' blob: filesystem: chrome://resources chrome://settings; style-src 'self' blob: filesystem: chrome://resources"
- },
- "permissions": [
- "chrome://resources/",
- "chrome://settings/",
- "browser",
- "hotwordPrivate",
- "idle"
- ],
- "display_in_launcher": false
-}
diff --git a/chromium/chrome/browser/resources/hotword_audio_verification/steps/audio_history_step.html b/chromium/chrome/browser/resources/hotword_audio_verification/steps/audio_history_step.html
deleted file mode 100644
index 8c2304ba9ab..00000000000
--- a/chromium/chrome/browser/resources/hotword_audio_verification/steps/audio_history_step.html
+++ /dev/null
@@ -1,38 +0,0 @@
-<div id="audio-history-container" hidden>
- <div class="container">
- <span class="close" tabindex="0" role="button"
- i18n-values="aria-label:close"></span>
- <div class="header">
- <h1 i18n-content="audioHistoryTitle" aria-live="polite"></h1>
- </div>
- <div class="content">
- <div i18n-content="audioHistoryDescription1"></div>
- <div class="v-spacing"></div>
- <div i18n-values=".innerHTML:audioHistoryDescription2"></div>
- <div class="v-spacing"></div>
- <div i18n-values=".innerHTML:audioHistoryDescription3"></div>
- </div>
- <div class="buttonbar">
- <div class="right">
- <div>
- <button id="audio-history-agree" i18n-content="audioHistoryAgree"
- class="primary">
- </button>
- <button id="audio-history-cancel" i18n-content="cancel"
- class="finish-button">
- </button>
- </div>
- </div>
- <div class="left">
- <div id="audio-history-wait" class="message wait" hidden>
- <span class="icon"></span>
- <span i18n-content="audioHistoryWait" class="text"></span>
- </div>
- <div id="audio-history-error" class="message error" role="alert" hidden>
- <span class="icon"></span>
- <span i18n-content="error" class="text"></span>
- </div>
- </div>
- </div>
- </div>
-</div>
diff --git a/chromium/chrome/browser/resources/hotword_audio_verification/steps/finished_step.html b/chromium/chrome/browser/resources/hotword_audio_verification/steps/finished_step.html
deleted file mode 100644
index 71537dd45aa..00000000000
--- a/chromium/chrome/browser/resources/hotword_audio_verification/steps/finished_step.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<div id="finish-container" hidden>
- <div class="container">
- <span class="close" tabindex="0" role="button"
- i18n-values="aria-label:close"></span>
- <div class="header">
- <h1 i18n-content="finishedTitle" aria-live="polite"></h1>
- </div>
- <div class="content">
- <h3 i18n-content="finishedListIntro"></h3>
- <div class="check">
- <span class="icon"></span>
- <span i18n-content="finishedListItem1" class="text">
- </span>
- </div>
- <div class="check">
- <span class="icon"></span>
- <span i18n-content="finishedListItem2" class="text">
- </span>
- </div>
- <div i18n-values=".innerHTML:finishedSettings"></div>
- <div i18n-values=".innerHTML:finishedAudioHistory"></div>
- </div>
- <div class="buttonbar">
- <div class="right">
- <button id="done-button" i18n-content="finish"
- class="primary finish-button"></button>
- </div>
- </div>
- </div>
-</div>
diff --git a/chromium/chrome/browser/resources/hotword_audio_verification/steps/speech_training_step.html b/chromium/chrome/browser/resources/hotword_audio_verification/steps/speech_training_step.html
deleted file mode 100644
index fd37331147a..00000000000
--- a/chromium/chrome/browser/resources/hotword_audio_verification/steps/speech_training_step.html
+++ /dev/null
@@ -1,56 +0,0 @@
-<div id="speech-training-container" hidden>
- <div class="container">
- <span class="close" tabindex="0" role="button"
- i18n-values="aria-label:close"></span>
- <div class="header">
- <h1 i18n-content="trainingTitle" aria-live="polite"></h1>
- </div>
- <div id="speech-training-training" class="content">
- <div class="col-2">
- <div i18n-content="trainingDescription"></div>
- <br>
- <h3 i18n-content="trainingSpeak"></h3>
- </div>
- <div class="col-spacing"></div>
- <div class="col-2">
- <div class="train listening">
- <span class="icon"></span>
- <span i18n-content="trainingFirstPrompt"
- class="text"></span>
- </div>
- <div class="train not-started">
- <span class="icon"></span>
- <span i18n-content="trainingMiddlePrompt"
- class="text"></span>
- </div>
- <div class="train not-started">
- <span class="icon"></span>
- <span i18n-content="trainingLastPrompt"
- class="text"></span>
- </div>
- </div>
- </div>
- <div id="speech-training-toast" class="toast" hidden>
- <span i18n-content="trainingTimeout" class="message" role="alert"></span>
- <button i18n-content="trainingRetry" class="retry-button" tabindex="0">
- </button>
- </div>
- <div id="speech-training-processing" class="buttonbar" hidden>
- <div id="speech-training-retry" class="right" hidden>
- <button i18n-content="trainingRetry" class="primary retry-button">
- </button>
- </div>
- <div class="left">
- <div id="speech-training-wait" class="message wait">
- <span class="icon"></span>
- <span i18n-content="finishedWait" class="text"></span>
- </div>
- <div id="speech-training-error" class="message error"
- role="alert" hidden>
- <span class="icon"></span>
- <span i18n-content="error" class="text"></span>
- </div>
- </div>
- </div>
- </div>
-</div>
diff --git a/chromium/chrome/browser/resources/hotword_audio_verification/steps/start_step.html b/chromium/chrome/browser/resources/hotword_audio_verification/steps/start_step.html
deleted file mode 100644
index 441ae6b86aa..00000000000
--- a/chromium/chrome/browser/resources/hotword_audio_verification/steps/start_step.html
+++ /dev/null
@@ -1,17 +0,0 @@
-<div id="start-container" hidden>
- <div class="container">
- <span class="close" tabindex="0" role="button"
- i18n-values="aria-label:close"></span>
- <div class="intro-image"></div>
- <div class="intro-text">
- <h1 i18n-content="introTitle"></h1>
- <h2 i18n-content="introSubtitle"></h2>
- <h3 id="intro-description" i18n-content="introDescription" hidden></h3>
- <h3 id="intro-description-audio-history-enabled"
- i18n-content="introDescriptionAudioHistoryEnabled" hidden></h3>
- </div>
- <div class="buttonbar">
- <button id="hotword-start" i18n-content="introStart"></button>
- </div>
- </div>
-</div>
diff --git a/chromium/chrome/browser/resources/hotword_audio_verification/style.css b/chromium/chrome/browser/resources/hotword_audio_verification/style.css
deleted file mode 100644
index 233ad3143f7..00000000000
--- a/chromium/chrome/browser/resources/hotword_audio_verification/style.css
+++ /dev/null
@@ -1,361 +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. */
-
-/* TODO(xdai): Remove hard-coded font-family for 'Roboto'. */
-
-* {
- box-sizing: border-box;
- color: rgba(0, 0, 0, .54);
- font-family: Roboto, 'Noto Sans', sans-serif;
- font-size: 13px;
- margin: 0;
- padding: 0;
-}
-
-#start-container * {
- color: #fff;
-}
-
-#start-container h2 {
- font-size: 15px;
- font-weight: normal;
- line-height: 24px;
- margin-top: 16px;
-}
-
-#start-container h3 {
- font-weight: normal;
- margin: 42px 16px 24px 16px;
-}
-
-#start-container div.container {
- background: rgb(66, 133, 244);
-}
-
-div.intro-image {
- background: -webkit-image-set(
- url(../images/intro-1x.png) 1x,
- url(../images/intro-2x.png) 2x)
- no-repeat;
- height: 152px;
- left: 24px;
- position: absolute;
- top: 122px;
- width: 304px;
-}
-
-div.intro-text {
- left: 328px;
- position: absolute;
- text-align: center;
- top: 116px;
- width: 432px;
-}
-
-#start-container div.buttonbar {
- background-color: rgb(51, 103, 214);
- height: 56px;
- padding: 0;
- text-align: center;
-}
-
-#start-container .buttonbar button {
- height: 100%;
- margin: 0;
- padding: 0 8px;
- width: 100%;
-}
-
-a {
- -webkit-app-region: no-drag;
- color: rgb(51, 103, 214);
- text-decoration: none;
-}
-
-button {
- -webkit-app-region: no-drag;
-}
-
-body {
- -webkit-app-region: drag;
- background: #ddd;
-}
-
-h1 {
- font-size: 20px;
- font-weight: normal;
- line-height: 32px;
-}
-
-h3 {
- font-size: 13px;
- line-height: 20px;
-}
-
-div.container {
- background: #fff;
- height: 448px;
- position: relative;
- width: 784px;
-}
-
-div.header {
- background: -webkit-image-set(
- url(../images/gradient-1x.png) 1x,
- url(../images/gradient-2x.png) 2x)
- no-repeat;
- height: 128px;
- padding: 70px 42px 0 42px;
-}
-
-div.header h1 {
- color: #fff;
-}
-
-div.content {
- height: 264px;
- line-height: 20px;
- padding: 32px 42px 0 42px;
-}
-
-div.content h3 {
- color: rgba(0, 0, 0, .87);
- margin-bottom: 16px;
-}
-
-div.col-2 {
- color: rgba(0, 0, 0, .54);
- float: left;
- width: 320px;
-}
-
-div.col-spacing {
- float: left;
- height: 216px;
- width: 60px;
-}
-
-div.v-spacing {
- height: 8px;
-}
-
-a[is='action-link'] {
- display: inline-block;
- font-size: 14px;
- margin-top: 22px;
- text-decoration: none;
- text-transform: uppercase;
-}
-
-.train {
- clear: both;
- line-height: 18px;
- margin-bottom: 24px;
-}
-
-.train .icon {
- display: inline-block;
- height: 18px;
- margin-right: 8px;
- vertical-align: top;
- width: 18px;
-}
-
-.train .text {
- color: rgba(0, 0, 0, .54);
- display: inline-block;
- line-height: 13px;
- padding-top: 3px;
- vertical-align: top;
-}
-
-.train.recorded .text {
- color: rgba(66, 133, 244, 1);
-}
-
-@keyframes rotate {
- from { transform: rotate(0); }
- to { transform: rotate(359deg); }
-}
-
-.train.listening .icon {
- animation: rotate 2s linear infinite;
- background: -webkit-image-set(
- url(../images/placeholder-loader-1x.png) 1x,
- url(../images/placeholder-loader-2x.png) 2x)
- no-repeat;
-}
-
-.train.not-started .icon {
- background: -webkit-image-set(
- url(../images/ic-check-gray-1x.png) 1x,
- url(../images/ic-check-gray-2x.png) 2x)
- no-repeat;
-}
-
-.train.recorded .icon {
- background: -webkit-image-set(
- url(../images/ic-check-blue-1x.png) 1x,
- url(../images/ic-check-blue-2x.png) 2x)
- no-repeat;
-}
-
-.check {
- clear: both;
- height: 18px;
- margin-bottom: 24px;
-}
-
-.check .icon {
- background: -webkit-image-set(
- url(../images/ic-check-blue-1x.png) 1x,
- url(../images/ic-check-blue-2x.png) 2x)
- no-repeat;
- display: inline-block;
- height: 18px;
- margin-right: 8px;
- vertical-align: top;
- width: 18px;
-}
-
-.check .text {
- color: rgba(0, 0, 0, .54);
- display: inline-block;
- height: 18px;
- line-height: 18px;
- padding-top: 2px;
- vertical-align: top;
-}
-
-div.buttonbar {
- background-color: rgba(236,239, 241, 1);
- bottom: 0;
- height: 56px;
- padding: 12px;
- position: absolute;
- width: 100%;
-}
-
-.buttonbar button {
- background: none;
- border: none;
- display: inline-block;
- font-weight: 700;
- height: 32px;
- line-height: 32px;
- margin-left: 8px;
- min-width: 56px;
- padding: 1px 8px 0 8px;
- text-transform: uppercase;
-}
-
-.buttonbar button:disabled {
- opacity: .5;
-}
-
-.buttonbar button.grayed-out {
- color: rgba(0, 0, 0, .28);
- text-transform: none;
-}
-
-.buttonbar button.primary {
- color: rgb(51, 103, 214);
-}
-
-.buttonbar .left {
- float: left;
- text-align: left;
-}
-
-.buttonbar .left button:first-child {
- margin-left: 0;
-}
-
-.buttonbar .right {
- float: right;
- text-align: right;
-}
-
-.buttonbar .message {
- margin: 7px 0 0 2px;
-}
-
-.buttonbar .message .icon {
- display: inline-block;
- height: 18px;
- margin-right: 8px;
- vertical-align: top;
- width: 18px;
-}
-
-.buttonbar .message.wait .icon {
- animation: rotate 2s linear infinite;
- background: -webkit-image-set(
- url(../images/placeholder-loader-1x.png) 1x,
- url(../images/placeholder-loader-2x.png) 2x)
- no-repeat;
-}
-
-.buttonbar .message.error .icon {
- background: -webkit-image-set(
- url(../images/ic-error-1x.png) 1x,
- url(../images/ic-error-2x.png) 2x)
- no-repeat;
-}
-
-.buttonbar .message .text {
- color: rgba(0, 0, 0, .54);
- display: inline-block;
- line-height: 18px;
- padding-top: 2px;
- vertical-align: top;
-}
-
-.buttonbar .message.error .text {
- color: rgb(213, 0, 0);
-}
-
-.close {
- -webkit-app-region: no-drag;
- background: -webkit-image-set(
- url(../images/ic-x-white-1x.png) 1x,
- url(../images/ic-x-white-2x.png) 2x)
- center center no-repeat;
- border: none;
- float: right;
- height: 42px;
- opacity: .54;
- width: 42px;
-}
-
-.close:hover {
- opacity: 1;
-}
-
-.toast {
- background-color: rgb(38, 50, 56);
- bottom: 0;
- height: 52px;
- padding: 10px 12px 0 42px;
- position: absolute;
- width: 100%;
-}
-
-.toast .message {
- color: #fff;
- float: left;
- padding: 9px 0 0 0;
-}
-
-.toast button {
- background: none;
- border: none;
- color: rgb(58, 218, 255);
- float: right;
- height: 32px;
- margin-left: 18px;
- min-width: 56px;
- padding: 0 8px 0 8px;
- text-transform: uppercase;
-}
diff --git a/chromium/chrome/browser/resources/inspect/inspect.css b/chromium/chrome/browser/resources/inspect/inspect.css
index 13875de17a2..5bd5a239edb 100644
--- a/chromium/chrome/browser/resources/inspect/inspect.css
+++ b/chromium/chrome/browser/resources/inspect/inspect.css
@@ -12,6 +12,8 @@ html {
body {
color: rgb(48, 57, 66);
+ display: flex;
+ flex-direction: column;
font-size: 13px;
height: 100%;
margin: 0;
@@ -38,18 +40,13 @@ img {
#infobar {
background: rgb(255, 212, 0);
- height: 20px;
- left: 0;
- line-height: 20px;
- position: fixed;
- right: 0;
+ display: none;
+ padding: 4px 0;
text-align: center;
- visibility: hidden;
- z-index: 1;
}
#infobar.show {
- visibility: visible;
+ display: block;
}
#navigation {
diff --git a/chromium/chrome/browser/resources/instant/instant.css b/chromium/chrome/browser/resources/instant/instant.css
deleted file mode 100644
index 795df5d309d..00000000000
--- a/chromium/chrome/browser/resources/instant/instant.css
+++ /dev/null
@@ -1,15 +0,0 @@
-/* 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. */
-
-body {
- font-size: 12px;
- margin: 10px;
- min-width: 47em;
- padding-bottom: 65px;
-}
-
-.row {
- border-bottom: 1px solid #a0a0a0;
- padding: 5px;
-}
diff --git a/chromium/chrome/browser/resources/instant/instant.html b/chromium/chrome/browser/resources/instant/instant.html
deleted file mode 100644
index 80fdc497c14..00000000000
--- a/chromium/chrome/browser/resources/instant/instant.html
+++ /dev/null
@@ -1,24 +0,0 @@
-<!doctype html>
-<html>
-<!--
-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.
--->
-<head>
-<meta charset="utf-8">
-<title>Instant preferences</title>
-<link rel="stylesheet" href="chrome://resources/css/text_defaults.css">
-<link rel="stylesheet" href="instant.css">
-<script src="instant.js"></script>
-</head>
-<body>
- <h2>Instant preferences</h2>
- <hr>
- <div id="instant-form"></div>
- <div class="buttons-pane">
- <button id="save-button">Save</button>
- </div>
- <hr/>
-</body>
-</html>
diff --git a/chromium/chrome/browser/resources/instant/instant.js b/chromium/chrome/browser/resources/instant/instant.js
deleted file mode 100644
index be590061c23..00000000000
--- a/chromium/chrome/browser/resources/instant/instant.js
+++ /dev/null
@@ -1,163 +0,0 @@
-// 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.
-
-// Redefine '$' here rather than including 'cr.js', since this is
-// the only function needed. This allows this file to be loaded
-// in a browser directly for layout and some testing purposes.
-var $ = function(id) {
- // eslint-disable-next-line no-restricted-properties
- return document.getElementById(id);
-};
-
-/**
- * WebUI for configuring instant.* preference values used by
- * Chrome's instant search system.
- */
-var instantConfig = (function() {
- 'use strict';
-
- /** List of fields used to dynamically build form. **/
- var FIELDS = [
- {
- key: 'instant_ui.zero_suggest_url_prefix',
- label: 'Prefix URL for the experimental Instant ZeroSuggest provider',
- type: 'string',
- size: 40,
- units: '',
- default: ''
- },
- ];
-
- /**
- * Returns a DOM element of the given type and class name.
- */
- function createElementWithClass(elementType, className) {
- var element = document.createElement(elementType);
- element.className = className;
- return element;
- }
-
- /**
- * Dynamically builds web-form based on FIELDS list.
- * @return {string} The form's HTML.
- */
- function buildForm() {
- var buf = [];
-
- for (var i = 0; i < FIELDS.length; i++) {
- var field = FIELDS[i];
-
- var row = createElementWithClass('div', 'row');
- row.id = '';
-
- var label = createElementWithClass('label', 'row-label');
- label.setAttribute('for', field.key);
- label.textContent = field.label;
- row.appendChild(label);
-
- var input = createElementWithClass('input', 'row-input');
- input.type = field.type;
- input.id = field.key;
- input.title = 'Default Value: ' + field.default;
- if (field.size)
- input.size = field.size;
- input.min = field.min || 0;
- if (field.max)
- input.max = field.max;
- if (field.step)
- input.step = field.step;
- row.appendChild(input);
-
- var units = createElementWithClass('div', 'row-units');
- if (field.units)
- units.innerHTML = field.units;
- row.appendChild(units);
-
- $('instant-form').appendChild(row);
- }
- }
-
- /**
- * Initialize the form by adding 'onChange' listeners to all fields.
- */
- function initForm() {
- for (var i = 0; i < FIELDS.length; i++) {
- var field = FIELDS[i];
- $(field.key).onchange = (function(key) {
- setPreferenceValue(key);
- }).bind(null, field.key);
- }
- }
-
- /**
- * Request a preference setting's value.
- * This method is asynchronous; the result is provided by a call to
- * getPreferenceValueResult.
- * @param {string} prefName The name of the preference value being requested.
- */
- function getPreferenceValue(prefName) {
- chrome.send('getPreferenceValue', [prefName]);
- }
-
- /**
- * Handle callback from call to getPreferenceValue.
- * @param {string} prefName The name of the requested preference value.
- * @param {value} value The current value associated with prefName.
- */
- function getPreferenceValueResult(prefName, value) {
- if ($(prefName).type == 'checkbox')
- $(prefName).checked = value;
- else
- $(prefName).value = value;
- }
-
- /**
- * Set a preference setting's value stored in the element with prefName.
- * @param {string} prefName The name of the preference value being set.
- */
- function setPreferenceValue(prefName) {
- var value;
- if ($(prefName).type == 'checkbox')
- value = $(prefName).checked;
- else if ($(prefName).type == 'number')
- value = parseFloat($(prefName).value);
- else
- value = $(prefName).value;
- chrome.send('setPreferenceValue', [prefName, value]);
- }
-
- /**
- * Saves data back into Chrome preferences.
- */
- function onSave() {
- for (var i = 0; i < FIELDS.length; i++) {
- var field = FIELDS[i];
- setPreferenceValue(field.key);
- }
- return false;
- }
-
- function loadForm() {
- for (var i = 0; i < FIELDS.length; i++)
- getPreferenceValue(FIELDS[i].key);
- }
-
- /**
- * Build and initialize the configuration form.
- */
- function initialize() {
- buildForm();
- loadForm();
- initForm();
-
- $('save-button').onclick = onSave.bind(this);
- }
-
- return {
- initialize: initialize,
- getPreferenceValueResult: getPreferenceValueResult
- };
-})();
-
-document.addEventListener('DOMContentLoaded', instantConfig.initialize);
diff --git a/chromium/chrome/browser/resources/interventions_internals/OWNERS b/chromium/chrome/browser/resources/interventions_internals/OWNERS
new file mode 100644
index 00000000000..0957d79411d
--- /dev/null
+++ b/chromium/chrome/browser/resources/interventions_internals/OWNERS
@@ -0,0 +1,3 @@
+file://components/previews/OWNERS
+
+# COMPONENT: UI>Browser>Previews
diff --git a/chromium/chrome/browser/resources/interventions_internals/index.css b/chromium/chrome/browser/resources/interventions_internals/index.css
index 4ee2351451c..bb04a5b0888 100644
--- a/chromium/chrome/browser/resources/interventions_internals/index.css
+++ b/chromium/chrome/browser/resources/interventions_internals/index.css
@@ -4,6 +4,62 @@
* found in the LICENSE file.
*/
+body {
+ font-family: 'DejaVu Sans', Arial, sans-serif;
+ font-size: 75%;
+ user-select: none;
+}
+
+.section-header {
+ color: rgb(43, 96, 222);
+ font-size: 120%;
+ font-weight: bold;
+ margin-top: 20px;
+}
+
+.previews-status-value {
+ margin-top: 5px;
+}
+
+.previews-flag-container {
+ margin-top: 5px;
+}
+
+.previews-flag-value {
+ margin-left: 10px;
+}
+
+button {
+ background: rgb(53, 106, 222);
+ border-radius: 5px;
+ color: white;
+ font-size: 65%;
+ font-weight: bold;
+ margin: 5px 0;
+ padding: 5px;
+ text-align: center;
+ text-decoration: none;
+ text-transform: uppercase;
+}
+
+.copy-to-clipboard-button {
+ background: rgb(53, 106, 222);
+ border-radius: 2px;
+ color: white;
+ float: right;
+ font-size: 60%;
+ font-weight: bold;
+ margin: 2px;
+ padding: 2px;
+ text-align: center;
+ text-decoration: none;
+ text-transform: uppercase;
+}
+
+#clear-log-button {
+ float: right;
+}
+
.hidden-tab {
display: none;
padding: 12px;
@@ -14,40 +70,197 @@
padding: 12px;
}
+.tab-select {
+ left: 0;
+ right: 0;
+}
+
+nav {
+ border-bottom: 1px solid silver;
+}
+
.tab-select input[type=radio] {
- display: none;
+ display: none;
}
.tab-select label {
- background: #ddd;
- border: outset 1px silver;
+ border: 2px solid white;
+ border-bottom: 0;
+ border-top-left-radius: 8px;
+ border-top-right-radius: 8px;
cursor: pointer;
- margin-right: -5px;
- padding: 5px 5px;
+ display: table-cell;
+ padding: 5px;
+ position: relative;
+ text-align: center;
+ vertical-align: middle;
+ width: 25%;
+}
+
+.inactive-tab {
+ background: #ddd;
+ color: black;
}
-.tab-select input:checked + span {
- background: #aaa;
- border: inset 1px silver;
+.active-tab {
+ background: rgb(0, 128, 255);
+ color: white;
+}
+
+.table-name {
+ color: rgb(43, 96, 222);
+ font-size: 100%;
+ font-weight: bold;
+ margin-bottom: 5px;
+ margin-top: 5px;
}
table {
- border: 1px solid black;
- border-collapse: collapse;
+ border-collapse: separate;
+ font-size: 90%;
+ margin-top: 10px;
+ max-height: 100px;
+ table-layout: fixed;
+ width: 100%;
}
-th {
- border: 1px solid black;
- padding: 15px;
- text-align: left;
+.nqe-value-column {
+ text-align: center;
}
td {
- border: 1px solid black;
- padding: 15px;
+ border: 1px solid white;
+ padding: 10px;
text-align: left;
}
+tr:nth-child(odd) td {
+ background: rgb(240, 255, 255);
+}
+
+th {
+ background: rgb(0, 191, 255);
+ border: 0;
+ color: white;
+ padding-bottom: 5px;
+ padding-top: 5px;
+ text-align: center;
+}
+
+td.log-time {
+ font-size: 80%;
+}
+
+td.log-description {
+ font-size: 80%;
+}
+
+td.log-url {
+ border-bottom: 1px transparent;
+ font-size: 80%;
+ position: relative;
+ word-wrap: break-word;
+}
+
+.log-type {
+ text-align: center;
+ width: 20%;
+}
+
+td.log-type {
+ font-size: 80%;
+}
+
+.url-tooltip {
+ background-color: black;
+ border-radius: 6px;
+ color: #fff;
+ left: 0;
+ padding: 5px;
+ position: absolute;
+ top: 100%;
+ visibility: hidden;
+ width: 100%;
+ z-index: 1;
+}
+
+td.log-url:hover .url-tooltip {
+ opacity: 1;
+ visibility: visible;
+}
+
+td.log-url .url-tooltip::after {
+ border-color: transparent transparent black transparent;
+ border-style: solid;
+ border-width: 5px;
+ bottom: 100%;
+ content: ' ';
+ left: 50%;
+ margin-left: -5px;
+ position: absolute;
+}
+
+@media(min-device-width: 600px) {
+ body {
+ font-size: 85%;
+ }
+
+ #nqe-logs-table {
+ width: 60%;
+ }
+
+ #blacklisted-hosts-table {
+ width: 60%;
+ }
+
+ #previews-flags-table {
+ width: 30%;
+ }
+
+ .log-time {
+ width: 15%;
+ }
+
+ td.log-time {
+ font-size: 80%;
+ }
+
+ .log-type {
+ width: 10%;
+ }
+
+ td.log-type {
+ font-siz15e: 100%;
+ }
+}
+
+@media(min-device-width: 1024px) {
+ body {
+ font-size: 100%;
+ }
+
+ .copy-to-clipboard-button {
+ font-size: 80%;
+ }
+
+ .log-time {
+ font-size: 100%;
+ width: 8%;
+ }
+
+ #nqe-logs-table {
+ width: 30%;
+ }
+
+ #previews-flags-table {
+ width: 30%;
+ }
+
+ td.log-description {
+ font-size: 100%;
+ }
+}
+
.error-header {
font-size: 150%;
font-weight: bold;
@@ -56,3 +269,9 @@ td {
.error-message {
font-style: italic;
}
+
+#blacklist-ignored-status {
+ color: red;
+ font-style: italic;
+ font-weight: bold;
+}
diff --git a/chromium/chrome/browser/resources/interventions_internals/index.html b/chromium/chrome/browser/resources/interventions_internals/index.html
index 4de45b78f77..da429f25a78 100644
--- a/chromium/chrome/browser/resources/interventions_internals/index.html
+++ b/chromium/chrome/browser/resources/interventions_internals/index.html
@@ -1,8 +1,8 @@
<!DOCTYPE html>
-<html>
+<html lang="en">
<head>
<meta charset="utf-8">
- <meta name="viewport" content="width=device-width">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Interventions-Internals</title>
<script src="chrome://resources/js/cr.js"></script>
<script src="chrome://resources/js/mojo_bindings.js"></script>
@@ -15,29 +15,101 @@
<body>
<nav class="tab-select">
- <label>
- <input type="radio" id="statuses" name="tabs"
- value="previews-statuses" checked="checked">
- <span>Previews Modes</span>
+ <label class="active-tab">
+ <input type="radio" id="statuses-tab" name="tabs"
+ value="previews-status" checked="checked">
+ <span>Interventions</span>
</label>
- <label>
- <input type="radio" id="logs" name="tabs" value="message-logs">
+ <label class="inactive-tab">
+ <input type="radio" id="logs-tab" name="tabs" value="message-logs">
<span>Logs</span>
</label>
+ <label class="inactive-tab">
+ <input type="radio" id="blacklist-tab" name="tabs"
+ value="blacklist-status">
+ <span>Blacklist Status</span>
+ </label>
+ <label class="inactive-tab">
+ <input type="radio" id="nqe-tab" name="tabs" value="nqe-info">
+ <span>Network Quality</span>
+ </label>
</nav>
- <div class="tab-content" id="previews-statuses">
+ <div class="tab-content" id="previews-status">
+ <div id="previews-enabled-status">
+ <div class="section-header">
+ Intervention Status
+ </div>
+ </div>
+ <div id="previews-flags-status">
+ <div class="section-header">
+ Intervention Flags
+ </div>
+ <table id="previews-flags-table">
+ <tr>
+ <th class="flag-name" id="flag-name-header">Flag</th>
+ <th class="flag-value" id="flag-value-header">Value</th>
+ </tr>
+ </table>
+ </div>
</div>
<div class="tab-content" id="message-logs">
+ <div class="table-name">Interventions Logs</div>
+ <input type="text" id="log-search-bar"
+ placeholder="Search for something ...">
+ <button id="clear-log-button" type="button">Clear logs</button>
<table id="message-logs-table">
<tr>
- <th id="time-table-header">Time</th>
- <th id="type-table-header">Type</th>
- <th id="description-table-header">Description</th>
- <th id="url-table-header">URL</th>
+ <th class="log-time" id="time-table-header">Time</th>
+ <th class="log-type" id="type-table-header">Type</th>
+ <th class="log-description" id="description-table-header">
+ Description
+ </th>
+ <th class="log-url" id="url-table-header">URL</th>
</tr>
</table>
</div>
+
+ <div class="tab-content" id="blacklist-status">
+ <div id="blacklist-ignored-status"></div>
+ <button id="ignore-blacklist-button" type="button">
+ Ignore Blacklist
+ </button>
+ <div id="user-blacklisted-status">
+ User blacklisted status:
+ <span id="user-blacklisted-status-value">N/A</span>
+ </div>
+ <div id="blacklist-cleared-status">
+ Last blacklist cleared:
+ <span id="blacklist-last-cleared-time">N/A</span>
+ </div>
+
+ <div id="blacklisted-hosts">
+ <div class="table-name">Blacklisted hosts</div>
+ <table id="blacklisted-hosts-table">
+ <tr>
+ <th id="blacklisted-host-header">Host</th>
+ <th id="blacklisted-time-header">Time</th>
+ </tr>
+ </table>
+ </div>
+ </div>
+
+ <div class="tab-content" id="nqe-info">
+ <div id="nqe-status">
+ Estimated effective connection type:
+ <span id="nqe-type">N/A</span>
+ </div>
+ <div id="nqe-logs">
+ <div class="table-name">Network Quality Change Log</div>
+ <table id="nqe-logs-table">
+ <tr>
+ <th id="nqe-time-header">Time</th>
+ <th id="nqe-value-header">Connection</th>
+ </tr>
+ </table>
+ </div>
+ </div>
</body>
</html>
diff --git a/chromium/chrome/browser/resources/interventions_internals/index.js b/chromium/chrome/browser/resources/interventions_internals/index.js
index b01f1b2bfe8..39304a937fe 100644
--- a/chromium/chrome/browser/resources/interventions_internals/index.js
+++ b/chromium/chrome/browser/resources/interventions_internals/index.js
@@ -2,15 +2,78 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+/** The columns that are used to find rows that contain the keyword. */
+const KEY_COLUMNS = ['log-type', 'log-description', 'log-url'];
+const ENABLE_BLACKLIST_BUTTON = 'Enable Blacklist';
+const IGNORE_BLACKLIST_BUTTON = 'Ignore Blacklist';
+const IGNORE_BLACKLIST_MESSAGE = 'Blacklist decisions are ignored.';
+const URL_THRESHOLD = 40; // Maximum URL length
+
+/**
+ * Convert milliseconds to human readable date/time format.
+ * The return format will be "MM/dd/YYYY hh:mm:ss.sss"
+ * @param {number} time Time in millisecond since Unix Epoch.
+ * @return The converted string format.
+ */
+function getTimeFormat(time) {
+ let date = new Date(time);
+ let options = {
+ year: 'numeric',
+ month: '2-digit',
+ day: '2-digit',
+ };
+
+ let dateString = date.toLocaleDateString('en-US', options);
+ return dateString + ' ' + date.getHours() + ':' + date.getMinutes() + ':' +
+ date.getSeconds() + '.' + date.getMilliseconds();
+}
+
+/**
+ * Insert a log message row to the top of the log message table.
+ *
+ * @param {number!} time Millisecond since Unix Epoch representation of time.
+ * @param {string!} type The message event type.
+ * @param {string!} description The event message description.
+ * @param {string} url The URL associated with the event.
+ */
+function insertMessageRowToMessageLogTable(time, type, description, url) {
+ let tableRow =
+ $('message-logs-table').insertRow(1); // Index 0 belongs to header row.
+ tableRow.setAttribute('class', 'log-message');
+
+ let timeTd = document.createElement('td');
+ timeTd.textContent = getTimeFormat(time);
+ timeTd.setAttribute('class', 'log-time');
+ tableRow.appendChild(timeTd);
+
+ let typeTd = document.createElement('td');
+ typeTd.setAttribute('class', 'log-type');
+ typeTd.textContent = type;
+ tableRow.appendChild(typeTd);
+
+ let descriptionTd = document.createElement('td');
+ descriptionTd.setAttribute('class', 'log-description');
+ descriptionTd.textContent = description;
+ tableRow.appendChild(descriptionTd);
+
+ if (url.length > 0) {
+ let urlTd = createUrlElement(url);
+ urlTd.setAttribute('class', 'log-url');
+ tableRow.appendChild(urlTd);
+ }
+}
+
/**
* Switch the selected tab to 'selected-tab' class.
*/
function setSelectedTab() {
- let selected =
- document.querySelector('input[type=radio][name=tabs]:checked').value;
- let selectedTab = document.querySelector('#' + selected);
+ let selected = document.querySelector('input[type=radio][name=tabs]:checked');
+ let selectedTab = document.querySelector('#' + selected.value);
+
selectedTab.className =
selectedTab.className.replace('hidden-tab', 'selected-tab');
+ selected.parentElement.className =
+ selected.parentElement.className.replace('inactive-tab', 'active-tab');
}
/**
@@ -19,8 +82,10 @@ function setSelectedTab() {
*/
function changeTab() {
let lastSelected = document.querySelector('.selected-tab');
+ let lastTab = document.querySelector('.active-tab');
lastSelected.className =
lastSelected.className.replace('selected-tab', 'hidden-tab');
+ lastTab.className = lastTab.className.replace('active-tab', 'inactive-tab');
setSelectedTab();
}
@@ -44,6 +109,110 @@ function setupTabControl() {
setSelectedTab();
}
+/**
+ * Initialize the search functionality of the search bar on the log tab.
+ * Searching will hide any rows that don't contain the keyword in the search
+ * bar.
+ */
+function setupLogSearch() {
+ $('log-search-bar').addEventListener('keyup', () => {
+ let keyword = $('log-search-bar').value.toUpperCase();
+ let rows = document.querySelectorAll('.log-message');
+
+ rows.forEach((row) => {
+ let found = KEY_COLUMNS.some((column) => {
+ return (row.querySelector('.' + column)
+ .textContent.toUpperCase()
+ .includes(keyword));
+ });
+ row.style.display = found ? '' : 'none';
+ });
+ });
+}
+
+/**
+ * Create and add a copy to clipboard button to a given node.
+ *
+ * @param {string} text The text that will be copied to the clipboard.
+ * @param {element!} node The node that will have the button appended to.
+ */
+function appendCopyToClipBoardButton(text, node) {
+ if (!document.queryCommandSupported ||
+ !document.queryCommandSupported('copy')) {
+ // Don't add copy to clipboard button if not supported.
+ return;
+ }
+ let copyButton = document.createElement('div');
+ copyButton.setAttribute('class', 'copy-to-clipboard-button');
+ copyButton.textContent = 'Copy';
+
+ copyButton.addEventListener('click', () => {
+ var textarea = document.createElement('textarea');
+ textarea.textContent = text;
+ document.body.appendChild(textarea);
+ textarea.select();
+ try {
+ return document.execCommand('copy'); // Security exception may be thrown.
+ } catch (ex) {
+ console.warn('Copy to clipboard failed.', ex);
+ return false;
+ } finally {
+ document.body.removeChild(textarea);
+ }
+ });
+ node.appendChild(copyButton);
+}
+
+/**
+ * Shorten long URL string so that it can be displayed nicely on mobile devices.
+ * If |url| is longer than URL_THRESHOLD, then it will be shorten, and a tooltip
+ * element will be added so that user can see the original URL.
+ *
+ * Add copy to clipboard button to it.
+ *
+ * @param {string} url The given URL string.
+ * @return An DOM node with the original URL if the length is within THRESHOLD,
+ * or the shorten URL with a tooltip element at the end of the string.
+ */
+function createUrlElement(url) {
+ let urlCell = document.createElement('div');
+ urlCell.setAttribute('class', 'log-url-value');
+ let urlTd = document.createElement('td');
+ urlTd.appendChild(urlCell);
+
+ if (url.length <= URL_THRESHOLD) {
+ urlCell.textContent = url;
+ } else {
+ urlCell.textContent = url.substring(0, URL_THRESHOLD - 3) + '...';
+ let tooltip = document.createElement('span');
+ tooltip.setAttribute('class', 'url-tooltip');
+ tooltip.textContent = url;
+ urlTd.appendChild(tooltip);
+ }
+
+ // Append copy to clipboard button.
+ appendCopyToClipBoardButton(url, urlTd);
+ return urlTd;
+}
+
+/**
+ * Helper function to remove all log message from log-messages-table.
+ */
+function removeAllLogMessagesRows() {
+ let logsTable = $('message-logs-table');
+ for (let row = logsTable.rows.length - 1; row > 0; row--) {
+ logsTable.deleteRow(row);
+ }
+}
+
+/**
+ * Initialize the button to clear out all the log messages. This button only
+ * remove the logs from the UI, and does not effect any decision made.
+ */
+function setupLogClear() {
+ $('clear-log-button').addEventListener('click', removeAllLogMessagesRows);
+}
+
/** @constructor */
let InterventionsInternalPageImpl = function(request) {
this.binding_ =
@@ -59,34 +228,118 @@ InterventionsInternalPageImpl.prototype = {
* PreviewsLogger.
*/
logNewMessage: function(log) {
- let logsTable = $('message-logs-table');
- let tableRow = document.createElement('tr');
- tableRow.setAttribute('class', 'log-message');
+ insertMessageRowToMessageLogTable(
+ log.time, log.type, log.description, log.url.url);
+ },
+
+ /**
+ * Update new blacklisted host to the web page.
+ *
+ * @override
+ * @param {!string} host The blacklisted host.
+ * @param {number} time The time when the host was blacklisted in milliseconds
+ * since Unix epoch.
+ */
+ onBlacklistedHost: function(host, time) {
+ let row = document.createElement('tr');
+ row.setAttribute('class', 'blacklisted-host-row');
+
+ let hostTd = document.createElement('td');
+ hostTd.setAttribute('class', 'host-blacklisted');
+ hostTd.textContent = host;
+ row.appendChild(hostTd);
let timeTd = document.createElement('td');
- let date = new Date(log.time);
- timeTd.textContent = date.toISOString();
- timeTd.setAttribute('class', 'log-time');
- tableRow.appendChild(timeTd);
-
- let typeTd = document.createElement('td');
- typeTd.setAttribute('class', 'log-type');
- typeTd.textContent = log.type;
- tableRow.appendChild(typeTd);
-
- let descriptionTd = document.createElement('td');
- descriptionTd.setAttribute('class', 'log-description');
- descriptionTd.textContent = log.description;
- tableRow.appendChild(descriptionTd);
-
- // TODO(thanhdle): Truncate url and show full url when user clicks on it.
- // crbug.com/773019
- let urlTd = document.createElement('td');
- urlTd.setAttribute('class', 'log-url');
- urlTd.textContent = log.url.url;
- tableRow.appendChild(urlTd);
+ timeTd.setAttribute('class', 'host-blacklisted-time');
+ timeTd.textContent = getTimeFormat(time);
+ row.appendChild(timeTd);
+
+ // TODO(thanhdle): Insert row at correct index. crbug.com/776105.
+ $('blacklisted-hosts-table').appendChild(row);
+ },
+
+ /**
+ * Update to the page that the user blacklisted status has changed.
+ *
+ * @override
+ * @param {boolean} blacklisted The time of the event in milliseconds since
+ * Unix epoch.
+ */
+ onUserBlacklistedStatusChange: function(blacklisted) {
+ let userBlacklistedStatus = $('user-blacklisted-status-value');
+ userBlacklistedStatus.textContent =
+ (blacklisted ? 'Blacklisted' : 'Not blacklisted');
+ },
+
+ /**
+ * Update the blacklist cleared status on the page.
+ *
+ * @override
+ * @param {number} time The time of the event in milliseconds since Unix
+ * epoch.
+ */
+ onBlacklistCleared: function(time) {
+ let blacklistClearedStatus = $('blacklist-last-cleared-time');
+ blacklistClearedStatus.textContent = getTimeFormat(time);
+
+ // Remove hosts from table.
+ let blacklistedHostsTable = $('blacklisted-hosts-table');
+ for (let row = blacklistedHostsTable.rows.length - 1; row > 0; row--) {
+ blacklistedHostsTable.deleteRow(row);
+ }
+
+ // Remove log message from logs table.
+ removeAllLogMessagesRows();
+ },
+
+ /**
+ * Update the page with the new value of ignored blacklist decision status.
+ *
+ * @override
+ * @param {boolean} ignored The new status of whether the previews blacklist
+ * decisions is blacklisted or not.
+ */
+ onIgnoreBlacklistDecisionStatusChanged: function(ignored) {
+ let ignoreButton = $('ignore-blacklist-button');
+ ignoreButton.textContent =
+ ignored ? ENABLE_BLACKLIST_BUTTON : IGNORE_BLACKLIST_BUTTON;
- logsTable.appendChild(tableRow);
+ // Update the status of blacklist ignored on the page.
+ $('blacklist-ignored-status').textContent =
+ ignored ? IGNORE_BLACKLIST_MESSAGE : '';
+ },
+
+ /**
+ * Update the page with the new value of estimated Effective Connection Type
+ * (ECT). Log the ECT to the ECT logs table.
+ *
+ * @override
+ * @param {string} type The string representation of estimated ECT.
+ */
+ onEffectiveConnectionTypeChanged: function(type) {
+ // Change the current ECT.
+ let ectType = $('nqe-type');
+ ectType.textContent = type;
+
+ let now = getTimeFormat(Date.now());
+
+ // Log ECT changed event to ECT change log.
+ let nqeRow =
+ $('nqe-logs-table').insertRow(1); // Index 0 belongs to header row.
+
+ let timeCol = document.createElement('td');
+ timeCol.textContent = now;
+ timeCol.setAttribute('class', 'nqe-time-column');
+ nqeRow.appendChild((timeCol));
+
+ let nqeCol = document.createElement('td');
+ nqeCol.setAttribute('class', 'nqe-value-column');
+ nqeCol.textContent = type;
+ nqeRow.appendChild(nqeCol);
+
+ // Insert ECT changed message to message-logs-table.
+ insertMessageRowToMessageLogTable(
+ now, 'ECT Changed', 'Effective Connection Type changed to ' + type, '');
},
};
@@ -96,6 +349,31 @@ cr.define('interventions_internals', () => {
function init(handler) {
pageHandler = handler;
getPreviewsEnabled();
+ getPreviewsFlagsDetails();
+
+ let ignoreButton = $('ignore-blacklist-button');
+ ignoreButton.addEventListener('click', () => {
+ // Whether the blacklist is currently ignored.
+ let ignored = (ignoreButton.textContent == ENABLE_BLACKLIST_BUTTON);
+ // Try to reverse the ignore status.
+ pageHandler.setIgnorePreviewsBlacklistDecision(!ignored);
+ });
+ }
+
+ /**
+ * Sort keys by the value of each value by its description attribute of a
+ * |mapObject|.
+ *
+ * @param mapObject {!Map<string, Object} A map where all values have a
+ * description attribute.
+ * @return A list of keys sorted by their descriptions.
+ */
+ function getSortedKeysByDescription(mapObject) {
+ let sortedKeys = Array.from(mapObject.keys());
+ sortedKeys.sort((a, b) => {
+ return mapObject.get(a).description > mapObject.get(b).description;
+ });
+ return sortedKeys;
}
/**
@@ -105,17 +383,17 @@ cr.define('interventions_internals', () => {
function getPreviewsEnabled() {
pageHandler.getPreviewsEnabled()
.then((response) => {
- let statuses = $('previews-statuses');
+ let statuses = $('previews-enabled-status');
- // TODO(thanhdle): The statuses are not printed in alphabetic order of
- // the key. crbug.com/772458
- response.statuses.forEach((value, key) => {
+ getSortedKeysByDescription(response.statuses).forEach((key) => {
+ let value = response.statuses.get(key);
let message = value.description + ': ';
message += value.enabled ? 'Enabled' : 'Disabled';
assert(!$(key), 'Component ' + key + ' already existed!');
- let node = document.createElement('p');
+ let node = document.createElement('div');
+ node.setAttribute('class', 'previews-status-value');
node.setAttribute('id', key);
node.textContent = message;
statuses.appendChild(node);
@@ -126,6 +404,41 @@ cr.define('interventions_internals', () => {
});
}
+ function getPreviewsFlagsDetails() {
+ pageHandler.getPreviewsFlagsDetails()
+ .then((response) => {
+ let flags = $('previews-flags-table');
+
+ getSortedKeysByDescription(response.flags).forEach((key) => {
+ let value = response.flags.get(key);
+ assert(!$(key), 'Component ' + key + ' already existed!');
+
+ let flagDescription = document.createElement('a');
+ flagDescription.setAttribute('class', 'previews-flag-description');
+ flagDescription.setAttribute('id', key + 'Description');
+ flagDescription.setAttribute('href', value.link);
+ flagDescription.textContent = value.description;
+
+ let flagNameTd = document.createElement('td');
+ flagNameTd.appendChild(flagDescription);
+
+ let flagValueTd = document.createElement('td');
+ flagValueTd.setAttribute('class', 'previews-flag-value');
+ flagValueTd.setAttribute('id', key + 'Value');
+ flagValueTd.textContent = value.value;
+
+ let node = document.createElement('tr');
+ node.setAttribute('class', 'previews-flag-container');
+ node.appendChild(flagNameTd);
+ node.appendChild(flagValueTd);
+ flags.appendChild(node);
+ });
+ })
+ .catch((error) => {
+ console.error(error.message);
+ });
+ }
+
return {
init: init,
};
@@ -137,6 +450,8 @@ window.setupFn = window.setupFn || function() {
document.addEventListener('DOMContentLoaded', () => {
setupTabControl();
+ setupLogSearch();
+ setupLogClear();
let pageHandler = null;
let pageImpl = null;
diff --git a/chromium/chrome/browser/resources/local_ntp/local_ntp.css b/chromium/chrome/browser/resources/local_ntp/local_ntp.css
index 7c507af4ae1..0df099dc71c 100644
--- a/chromium/chrome/browser/resources/local_ntp/local_ntp.css
+++ b/chromium/chrome/browser/resources/local_ntp/local_ntp.css
@@ -9,8 +9,17 @@ html {
/* We add an extra pixel because rounding errors on different zooms can
* make the width shorter than it should be. */
+ 1px);
+ --tile-height: 128px;
--tile-margin: 16px;
--tile-width: 154px;
+ /* Two rows of tiles, margin between the rows, and 4px/8px of margin on top
+ * and bottom respectively. If you change this, also change the corresponding
+ * values in most_visited_single.css. */
+ --mv-tiles-height: calc(
+ 4px + var(--tile-height) + var(--tile-margin) + var(--tile-height) + 8px);
+ /* Base height 16px, plus 8px each of padding on top and bottom. */
+ --mv-notice-height: calc(8px + 16px + 8px);
+ height: 100%;
}
/* width >= (3 cols * (16px + 154px) - 16px + 200px) */
@@ -34,20 +43,31 @@ body {
cursor: default;
font-family: arial, sans-serif;
font-size: small;
+ height: 100%;
margin: 0;
overflow-x: hidden;
}
+/* Button defaults vary by platform. Reset CSS so that the NTP can use buttons
+ * as a kind of clickable div. */
+button {
+ background: transparent;
+ border: 0;
+ margin: 0;
+ padding: 0;
+}
+
#ntp-contents {
+ display: flex;
+ flex-direction: column;
+ height: 100%;
margin: 0 auto;
text-align: -webkit-center;
width: var(--content-width);
}
.non-google-page #ntp-contents {
- left: calc(50% - var(--content-width)/2);
- position: absolute;
- top: calc(50% - 155px);
+ justify-content: center;
}
body.hide-fakebox-logo #logo,
@@ -79,11 +99,28 @@ body.hide-fakebox-logo #fakebox {
#logo-default,
#logo-doodle {
opacity: 0;
+ visibility: hidden;
+}
+
+#logo-default.show-logo,
+#logo-doodle.show-logo {
+ opacity: 1;
+ visibility: visible;
+}
+
+#logo-doodle-button,
+#logo-doodle-iframe {
+ display: none;
+}
+
+#logo-doodle-button.show-logo,
+#logo-doodle-iframe.show-logo {
+ display: block;
}
#logo-default.fade,
#logo-doodle.fade {
- transition: opacity 130ms;
+ transition: opacity 130ms, visibility 130ms;
}
#logo-default,
@@ -125,23 +162,32 @@ body.alternate-logo #logo-non-white {
top: 44px;
}
-#logo-doodle-link {
- cursor: pointer;
+#logo-doodle-button {
margin: 0 auto;
}
-.non-white-bg #logo-doodle-link {
+.non-white-bg #logo-doodle-button,
+.non-white-bg #logo-doodle-iframe {
display: none;
}
+#logo-doodle-iframe {
+ border: 0;
+ height: 228px;
+ width: 100%;
+}
+
#logo-doodle-notifier {
display: none;
}
.non-white-bg #logo-doodle-notifier {
+ background: transparent;
+ border: 0;
cursor: pointer;
display: inline-block;
height: 24px;
left: 148px;
+ padding: 0;
position: relative;
top: 100px;
width: 24px;
@@ -213,6 +259,7 @@ body.alternate-logo #logo-non-white {
font-size: 18px;
height: 44px;
line-height: 36px;
+ margin-bottom: 8px;
max-width: 672px;
outline: none;
position: relative;
@@ -287,12 +334,13 @@ html[dir=rtl] #fakebox-cursor {
#fakebox-microphone {
background: url(googlemic_clr_24px.svg) no-repeat center;
background-size: 24px 24px;
+ bottom: 0;
cursor: pointer;
- height: 21px;
padding: 22px 12px 0;
position: absolute;
right: 0;
- width: 17px;
+ top: 0;
+ width: 41px;
}
html[dir=rtl] #fakebox-microphone {
@@ -324,7 +372,10 @@ body.fakebox-focused #fakebox-cursor {
}
#most-visited {
- margin-top: 64px;
+ height: 100%;
+ margin-top: 56px;
+ max-height: calc(var(--mv-tiles-height) + var(--mv-notice-height));
+ overflow: hidden;
text-align: -webkit-center;
user-select: none;
}
@@ -335,11 +386,10 @@ body.fakebox-focused #fakebox-cursor {
}
#mv-tiles {
- /* Two rows of tiles of 128px each, 16px of spacing between the rows, and
- * 4px/8px of margin on top and bottom respectively. If you change this, also
- * change the corresponding values in most_visited_single.css. */
- height: calc(2*128px + 16px + 4px + 8px);
+ height: var(--mv-tiles-height);
margin: 0;
+ /* Clamp to the remaining window height minus space for #mv-notice. */
+ max-height: calc(100% - var(--mv-notice-height));
position: relative;
text-align: -webkit-auto;
}
@@ -379,7 +429,7 @@ html[dir=rtl] #mv-notice-x {
font-size: 12px;
font-weight: bold;
opacity: 1;
- padding: 10px 0;
+ padding: 8px 0;
}
#mv-notice span {
@@ -450,7 +500,9 @@ html[dir=rtl] #attribution,
}
#one-google {
- position: fixed;
+ position: absolute;
+ right: 0;
+ top: 0;
transition: opacity 130ms;
z-index: 1;
}
diff --git a/chromium/chrome/browser/resources/local_ntp/local_ntp.html b/chromium/chrome/browser/resources/local_ntp/local_ntp.html
index 82ed2ab45ba..7d1111c55c2 100644
--- a/chromium/chrome/browser/resources/local_ntp/local_ntp.html
+++ b/chromium/chrome/browser/resources/local_ntp/local_ntp.html
@@ -32,16 +32,17 @@
<div id="logo-non-white" title="Google"></div>
<!-- A doodle, if any: its link and image. -->
<div id="logo-doodle">
- <a id="logo-doodle-link">
+ <button id="logo-doodle-button">
<img id="logo-doodle-image"></img>
- </a>
+ </button>
+ <iframe id="logo-doodle-iframe"></iframe>
<!-- A spinner, visible on dark-themed NTPs, prompting the doodle -->
- <div id="logo-doodle-notifier">
+ <button id="logo-doodle-notifier">
<div class="outer ball0"><div class="inner"></div></div>
<div class="outer ball1"><div class="inner"></div></div>
<div class="outer ball2"><div class="inner"></div></div>
<div class="outer ball3"><div class="inner"></div></div>
- </div>
+ </button>
</div>
</div>
<div id="fakebox">
@@ -49,7 +50,7 @@
<input id="fakebox-input" autocomplete="off" tabindex="-1" type="url"
aria-hidden="true">
<div id="fakebox-cursor"></div>
- <div id="fakebox-microphone" tabindex="1" hidden></div>
+ <button id="fakebox-microphone" hidden></button>
</div>
</div>
<div id="most-visited">
@@ -60,9 +61,9 @@
<span id="mv-msg"></span>
<!-- Links in the notification. -->
<span id="mv-notice-links">
- <span id="mv-undo" tabindex="2"></span>
- <span id="mv-restore" tabindex="2"></span>
- <div id="mv-notice-x" tabindex="2"></div>
+ <span id="mv-undo" tabindex="0"></span>
+ <span id="mv-restore" tabindex="0"></span>
+ <div id="mv-notice-x" tabindex="0"></div>
</span>
</div>
</div>
diff --git a/chromium/chrome/browser/resources/local_ntp/local_ntp.js b/chromium/chrome/browser/resources/local_ntp/local_ntp.js
index cabafe39fd5..d74320f6cfd 100644
--- a/chromium/chrome/browser/resources/local_ntp/local_ntp.js
+++ b/chromium/chrome/browser/resources/local_ntp/local_ntp.js
@@ -9,6 +9,15 @@
/**
+ * Whether the most visited tiles have finished loading, i.e. we've received the
+ * 'loaded' postMessage from the iframe. Used by tests to detect that loading
+ * has completed.
+ * @type {boolean}
+ */
+var tilesAreLoaded = false;
+
+
+/**
* Controls rendering the new tab page for InstantExtended.
* @return {Object} A limited interface for testing the local NTP.
*/
@@ -68,7 +77,8 @@ var CLASSES = {
// Vertically centers the most visited section for a non-Google provided page.
NON_GOOGLE_PAGE: 'non-google-page',
NON_WHITE_BG: 'non-white-bg',
- RTL: 'rtl' // Right-to-left language text.
+ RTL: 'rtl', // Right-to-left language text.
+ SHOW_LOGO: 'show-logo', // Marks logo/doodle that should be shown.
};
@@ -89,7 +99,8 @@ var IDS = {
LOGO_DEFAULT: 'logo-default',
LOGO_DOODLE: 'logo-doodle',
LOGO_DOODLE_IMAGE: 'logo-doodle-image',
- LOGO_DOODLE_LINK: 'logo-doodle-link',
+ LOGO_DOODLE_IFRAME: 'logo-doodle-iframe',
+ LOGO_DOODLE_BUTTON: 'logo-doodle-button',
LOGO_DOODLE_NOTIFIER: 'logo-doodle-notifier',
NOTIFICATION: 'mv-notice',
NOTIFICATION_CLOSE_BUTTON: 'mv-notice-x',
@@ -103,6 +114,18 @@ var IDS = {
/**
+ * Counterpart of search_provider_logos::LogoType.
+ * @enum {string}
+ * @const
+ */
+var LOGO_TYPE = {
+ SIMPLE: 'SIMPLE',
+ ANIMATED: 'ANIMATED',
+ INTERACTIVE: 'INTERACTIVE',
+};
+
+
+/**
* The different types of events that are logged from the NTP. This enum is
* used to transfer information from the NTP JavaScript to the renderer and is
* not used as a UMA enum histogram's logged value.
@@ -532,6 +555,7 @@ function handlePostMessage(event) {
var cmd = event.data.cmd;
var args = event.data;
if (cmd == 'loaded') {
+ tilesAreLoaded = true;
if (configData.isGooglePage && !$('one-google-loader')) {
// Load the OneGoogleBar script. It'll create a global variable name "og"
// which is a dict corresponding to the native OneGoogleBarData type.
@@ -656,6 +680,9 @@ function init() {
// Got a (possibly empty) ddl object. Show logo or doodle.
showLogoOrDoodle(
ddl.image || null, ddl.metadata || null, /*fromCache=*/true);
+ // Never hide an interactive doodle if it was already shown.
+ if (ddl.metadata && (ddl.metadata.type === LOGO_TYPE.INTERACTIVE))
+ return;
// If we got a valid ddl object (from cache), load a fresh one.
if (ddl.v !== null) {
loadDoodle(ddl.v, function(ddl) {
@@ -675,6 +702,9 @@ function init() {
state.notheme = true;
window.history.replaceState(state, document.title);
onThemeChange();
+ if (e.detail === 0) { // Activated by keyboard.
+ $(IDS.LOGO_DOODLE_BUTTON).focus();
+ }
});
} else {
document.body.classList.add(CLASSES.NON_GOOGLE_PAGE);
@@ -702,7 +732,8 @@ function init() {
// Create the most visited iframe.
var iframe = document.createElement('iframe');
iframe.id = IDS.TILES_IFRAME;
- iframe.tabIndex = 1;
+ iframe.name = IDS.TILES_IFRAME;
+ iframe.title = configData.translatedStrings.mostVisitedTitle;
iframe.src = 'chrome-search://most-visited/single.html?' + args.join('&');
$(IDS.TILES).appendChild(iframe);
@@ -784,16 +815,6 @@ var loadDoodle = function(v, onload) {
};
-/** Returns true if |element| is fully hidden. Returns false if fully visible,
- * fading in, or fading out.
- * @param {HTMLElement} element
- */
-var isFadedOut = function(element) {
- return (element.style.opacity == 0) &&
- (window.getComputedStyle(element).opacity == 0);
-};
-
-
/** Returns true if the doodle given by |image| and |metadata| is currently
* visible. If |image| is null, returns true when the default logo is visible;
* if non-null, checks that it matches the doodle that is currently visible.
@@ -804,39 +825,54 @@ var isFadedOut = function(element) {
* @returns {boolean}
*/
var isDoodleCurrentlyVisible = function(image, metadata) {
- var haveDoodle = ($(IDS.LOGO_DOODLE).style.opacity != 0);
+ var haveDoodle = ($(IDS.LOGO_DOODLE).classList.contains(CLASSES.SHOW_LOGO));
var wantDoodle = (image !== null) && (metadata !== null);
if (!haveDoodle || !wantDoodle)
return haveDoodle === wantDoodle;
// Have a visible doodle and a query doodle. Test that they match.
- var logoDoodleImage = $(IDS.LOGO_DOODLE_IMAGE);
- return (logoDoodleImage.src === image) ||
- (logoDoodleImage.src === metadata.animatedUrl);
+ if (metadata.type === LOGO_TYPE.INTERACTIVE) {
+ var logoDoodleIframe = $(IDS.LOGO_DOODLE_IFRAME);
+ return logoDoodleIframe.classList.contains(CLASSES.SHOW_LOGO) &&
+ (logoDoodleIframe.src === metadata.fullPageUrl);
+ } else {
+ var logoDoodleImage = $(IDS.LOGO_DOODLE_IMAGE);
+ var logoDoodleButton = $(IDS.LOGO_DOODLE_BUTTON);
+ return logoDoodleButton.classList.contains(CLASSES.SHOW_LOGO) &&
+ ((logoDoodleImage.src === image) ||
+ (logoDoodleImage.src === metadata.animatedUrl));
+ }
};
var showLogoOrDoodle = function(image, metadata, fromCache) {
if (metadata !== null) {
applyDoodleMetadata(metadata);
- $(IDS.LOGO_DOODLE_IMAGE).src = image;
- $(IDS.LOGO_DOODLE).style.opacity = 1;
-
- var isCta = !!metadata.animatedUrl;
- var eventType = isCta ?
- (fromCache ? LOG_TYPE.NTP_CTA_LOGO_SHOWN_FROM_CACHE :
- LOG_TYPE.NTP_CTA_LOGO_SHOWN_FRESH) :
- (fromCache ? LOG_TYPE.NTP_STATIC_LOGO_SHOWN_FROM_CACHE :
- LOG_TYPE.NTP_STATIC_LOGO_SHOWN_FRESH);
- ntpApiHandle.logEvent(eventType);
+ if (metadata.type === LOGO_TYPE.INTERACTIVE) {
+ $(IDS.LOGO_DOODLE_BUTTON).classList.remove(CLASSES.SHOW_LOGO);
+ $(IDS.LOGO_DOODLE_IFRAME).classList.add(CLASSES.SHOW_LOGO);
+ } else {
+ $(IDS.LOGO_DOODLE_IMAGE).src = image;
+ $(IDS.LOGO_DOODLE_BUTTON).classList.add(CLASSES.SHOW_LOGO);
+ $(IDS.LOGO_DOODLE_IFRAME).classList.remove(CLASSES.SHOW_LOGO);
+
+ var isCta = !!metadata.animatedUrl;
+ var eventType = isCta ?
+ (fromCache ? LOG_TYPE.NTP_CTA_LOGO_SHOWN_FROM_CACHE :
+ LOG_TYPE.NTP_CTA_LOGO_SHOWN_FRESH) :
+ (fromCache ? LOG_TYPE.NTP_STATIC_LOGO_SHOWN_FROM_CACHE :
+ LOG_TYPE.NTP_STATIC_LOGO_SHOWN_FRESH);
+ ntpApiHandle.logEvent(eventType);
+ }
+ $(IDS.LOGO_DOODLE).classList.add(CLASSES.SHOW_LOGO);
} else {
- $(IDS.LOGO_DEFAULT).style.opacity = 1;
+ $(IDS.LOGO_DEFAULT).classList.add(CLASSES.SHOW_LOGO);
}
};
/** The image and metadata that should be shown, according to the latest fetch.
- * After a logo fades out, onDoodleTransitionEnd fades in a logo according to
+ * After a logo fades out, onDoodleFadeOutComplete fades in a logo according to
* targetDoodle.
*/
var targetDoodle = {
@@ -852,14 +888,18 @@ var targetDoodle = {
* @param {HTMLElement} element
*/
var startFadeOut = function(element) {
+ if (!element.classList.contains(CLASSES.SHOW_LOGO)) {
+ return;
+ }
+
// Compute style now, to ensure that the transition from 1 -> 0 is properly
// recognized. Otherwise, if a 0 -> 1 -> 0 transition is too fast, the
// element might stay invisible instead of appearing then fading out.
window.getComputedStyle(element).opacity;
element.classList.add(CLASSES.FADE);
- element.addEventListener('transitionend', onDoodleTransitionEnd);
- element.style.opacity = 0;
+ element.classList.remove(CLASSES.SHOW_LOGO);
+ element.addEventListener('transitionend', onDoodleFadeOutComplete);
};
@@ -886,51 +926,55 @@ var fadeToLogoOrDoodle = function(image, metadata) {
targetDoodle.image = image;
targetDoodle.metadata = metadata;
- // Start fading out the current logo or doodle. onDoodleTransitionEnd will
+ // Start fading out the current logo or doodle. onDoodleFadeOutComplete will
// apply the change when the fade-out finishes.
startFadeOut($(IDS.LOGO_DEFAULT));
startFadeOut($(IDS.LOGO_DOODLE));
};
-var onDoodleTransitionEnd = function(e) {
- var logoDoodle = $(IDS.LOGO_DOODLE);
- var logoDoodleImage = $(IDS.LOGO_DOODLE_IMAGE);
- var logoDefault = $(IDS.LOGO_DEFAULT);
-
- if (isFadedOut(logoDoodle) && isFadedOut(logoDefault)) {
- // Fade-out finished. Start fading in the appropriate logo.
- showLogoOrDoodle(
- targetDoodle.image, targetDoodle.metadata, /*fromCache=*/false);
+var onDoodleFadeOutComplete = function(e) {
+ // Fade-out finished. Start fading in the appropriate logo.
+ $(IDS.LOGO_DOODLE).classList.add(CLASSES.FADE);
+ $(IDS.LOGO_DEFAULT).classList.add(CLASSES.FADE);
+ showLogoOrDoodle(
+ targetDoodle.image, targetDoodle.metadata, /*fromCache=*/false);
- logoDefault.removeEventListener('transitionend', onDoodleTransitionEnd);
- logoDoodle.removeEventListener('transitionend', onDoodleTransitionEnd);
- }
+ this.removeEventListener('transitionend', onDoodleFadeOutComplete);
};
var applyDoodleMetadata = function(metadata) {
- var logoDoodleLink = $(IDS.LOGO_DOODLE_LINK);
+ var logoDoodleButton = $(IDS.LOGO_DOODLE_BUTTON);
var logoDoodleImage = $(IDS.LOGO_DOODLE_IMAGE);
-
- logoDoodleImage.title = metadata.altText;
-
- if (metadata.animatedUrl) {
- logoDoodleLink.removeAttribute('href');
- logoDoodleLink.onclick = function(e) {
- ntpApiHandle.logEvent(LOG_TYPE.NTP_CTA_LOGO_CLICKED);
- e.preventDefault();
- logoDoodleImage.src = metadata.animatedUrl;
- logoDoodleLink.href = metadata.onClickUrl;
- logoDoodleLink.onclick = function() {
- ntpApiHandle.logEvent(LOG_TYPE.NTP_ANIMATED_LOGO_CLICKED);
+ var logoDoodleIframe = $(IDS.LOGO_DOODLE_IFRAME);
+
+ switch (metadata.type) {
+ case LOGO_TYPE.SIMPLE:
+ logoDoodleImage.title = metadata.altText;
+ logoDoodleButton.onclick = function() {
+ ntpApiHandle.logEvent(LOG_TYPE.NTP_STATIC_LOGO_CLICKED);
+ window.location = metadata.onClickUrl;
};
- };
- } else {
- logoDoodleLink.href = metadata.onClickUrl;
- logoDoodleLink.onclick = function() {
- ntpApiHandle.logEvent(LOG_TYPE.NTP_STATIC_LOGO_CLICKED);
- };
+ break;
+
+ case LOGO_TYPE.ANIMATED:
+ logoDoodleImage.title = metadata.altText;
+ logoDoodleButton.onclick = function(e) {
+ ntpApiHandle.logEvent(LOG_TYPE.NTP_CTA_LOGO_CLICKED);
+ e.preventDefault();
+ logoDoodleImage.src = metadata.animatedUrl;
+ logoDoodleButton.onclick = function() {
+ ntpApiHandle.logEvent(LOG_TYPE.NTP_ANIMATED_LOGO_CLICKED);
+ window.location = metadata.onClickUrl;
+ };
+ };
+ break;
+
+ case LOGO_TYPE.INTERACTIVE:
+ logoDoodleIframe.title = metadata.altText;
+ logoDoodleIframe.src = metadata.fullPageUrl;
+ break;
}
};
diff --git a/chromium/chrome/browser/resources/local_ntp/most_visited_single.css b/chromium/chrome/browser/resources/local_ntp/most_visited_single.css
index 5035a1789e1..b2128fc4837 100644
--- a/chromium/chrome/browser/resources/local_ntp/most_visited_single.css
+++ b/chromium/chrome/browser/resources/local_ntp/most_visited_single.css
@@ -3,15 +3,19 @@
* found in the LICENSE file. */
html {
+ /* Constants. */
--tile-height: 128px;
--tile-margin: 16px;
--tile-width: 154px;
--title-height: 32px;
+
+ /* May be overridden by themes (on the body element). */
+ --tile-title-color: #323232;
}
body {
background: none transparent;
- color: #323232;
+ color: var(--tile-title-color);
margin: 0;
overflow: hidden;
padding: 0;
@@ -44,7 +48,7 @@ a:visited {
* local_ntp.css. */
height: calc(2*var(--tile-height) + var(--tile-margin));
line-height: calc(var(--tile-height) + var(--tile-margin));
- margin: 4px 0 calc(var(--tile-margin) / 2) 0;
+ margin: 4px 0 8px 0;
opacity: 0;
position: absolute;
/* This align correctly for both LTR and RTL */
@@ -64,22 +68,55 @@ a:visited {
line-height: 100%;
margin: 0 calc(var(--tile-margin) / 2);
opacity: 1;
- overflow: hidden;
position: relative;
vertical-align: top;
white-space: nowrap;
width: var(--tile-width);
}
-/* Minimal layout: 2 columns; only first 4 tiles are visible. */
-.mv-tile:nth-child(-n+4),
-.mv-empty-tile:nth-child(-n+4) {
- display: inline-block;
+/* Min height for showing 1 row: 4px + 128px + 8px
+ Min height for showing 2 rows: 4px + 128px + 16px + 128px + 8px
+ In both cases, give it half a px of tolerance, because otherwise rounding
+ errors at some zoom levels break this and a row sometimes doesn't show up.
+*/
+
+/* Minimal layout: 1 row, 2 columns; only first 2 tiles are visible. */
+@media (min-height: 139.5px) {
+ .mv-tile:nth-child(-n+2),
+ .mv-empty-tile:nth-child(-n+2) {
+ display: inline-block;
+ }
+}
+
+/* width >= (3 cols * (16px + 154px))
+ * 1 row, 3 columns; first 3 tiles are visible. */
+@media (min-height: 139.5px) and (min-width: 510px) {
+ .mv-tile:nth-child(-n+3),
+ .mv-empty-tile:nth-child(-n+3) {
+ display: inline-block;
+ }
+}
+
+/* width >= (4 cols * (16px + 154px))
+ * 1 row, 4 columns; first 4 tiles are visible. */
+@media (min-height: 139.5px) and (min-width: 680px) {
+ .mv-tile:nth-child(-n+4),
+ .mv-empty-tile:nth-child(-n+4) {
+ display: inline-block;
+ }
+}
+
+/* 2 rows, 2 columns; only first 4 tiles are visible. */
+@media (min-height: 283.5px) {
+ .mv-tile:nth-child(-n+4),
+ .mv-empty-tile:nth-child(-n+4) {
+ display: inline-block;
+ }
}
/* width >= (3 cols * (16px + 154px))
- * 3 columns; first 6 tiles are visible. */
-@media (min-width: 510px) {
+ * 2 rows, 3 columns; first 6 tiles are visible. */
+@media (min-height: 283.5px) and (min-width: 510px) {
.mv-tile:nth-child(-n+6),
.mv-empty-tile:nth-child(-n+6) {
display: inline-block;
@@ -87,8 +124,8 @@ a:visited {
}
/* width >= (4 cols * (16px + 154px))
- * 4 columns; first 8 tiles are visible. */
-@media (min-width: 680px) {
+ * 2 rows, 4 columns; first 8 tiles are visible. */
+@media (min-height: 283.5px) and (min-width: 680px) {
.mv-tile:nth-child(-n+8),
.mv-empty-tile:nth-child(-n+8) {
display: inline-block;
@@ -103,6 +140,11 @@ a:visited {
background: rgb(245,245,245);
}
+body.dark-theme .mv-tile,
+body.dark-theme .mv-empty-tile {
+ background: rgb(51,51,51);
+}
+
.mv-tile {
box-shadow: 0 2px 2px 0 rgba(0,0,0,0.16), 0 0 0 1px rgba(0,0,0,0.08);
cursor: pointer;
@@ -111,17 +153,19 @@ a:visited {
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
}
-.mv-tile:hover:not(:active) {
+.mv-tile:hover:not(:active),
+.mv-tile:focus-within:not(:active) {
box-shadow: 0 3px 8px 0 rgba(0,0,0,0.2), 0 0 0 1px rgba(0,0,0,0.08);
}
-.mv-tile:focus {
- -webkit-filter: brightness(92%);
+.mv-tile:focus,
+.mv-tile:focus-within {
+ filter: brightness(92%);
}
.mv-tile:active {
- -webkit-filter: brightness(88%);
box-shadow: 0 3px 8px 0 rgba(0,0,0,0.2), 0 0 0 1px rgba(0,0,0,0.12);
+ filter: brightness(88%);
}
.mv-tile.blacklisted {
@@ -168,6 +212,7 @@ html[dir=rtl] .mv-title[style*='direction: rtl'] {
}
.mv-thumb {
+ border-radius: 0 0 2px 2px;
cursor: pointer;
display: block;
height: calc(var(--tile-height) - var(--title-height));
@@ -187,6 +232,10 @@ html[dir=rtl] .mv-title[style*='direction: rtl'] {
background-color: rgb(245,245,245);
}
+body.dark-theme .mv-thumb.failed-img {
+ background-color: #555;
+}
+
/* We use ::after without content to provide an aditional element on top of the
* thumbnail. */
.mv-thumb.failed-img::after {
@@ -199,42 +248,62 @@ html[dir=rtl] .mv-title[style*='direction: rtl'] {
width: 0;
}
+body.dark-theme .mv-thumb.failed-img::after {
+ border-color: #333;
+}
+
.mv-x {
background: linear-gradient(to left, rgb(250,250,250) 60%, transparent);
border: none;
cursor: pointer;
- height: 30px;
+ height: var(--title-height);
opacity: 0;
+ padding: 0;
position: absolute;
right: 0;
transition: opacity 150ms;
width: 40px;
}
+body.dark-theme .mv-x {
+ background: linear-gradient(to left, rgb(51,51,51) 60%, transparent);
+}
+
/* We use ::after without content to provide the masked X element. The "bottom"
* div is actually just the gradient. */
.mv-x::after {
+ --mask-offset: calc((var(--title-height) - var(--mask-width)) / 2);
+ --mask-width: 10px;
-webkit-mask-image: -webkit-image-set(
url(chrome-search://local-ntp/images/close_3_mask.png) 1x,
url(chrome-search://local-ntp/images/close_3_mask.png@2x) 2x);
- -webkit-mask-position: 12px 10px;
+ -webkit-mask-position: var(--mask-offset) var(--mask-offset);
-webkit-mask-repeat: no-repeat;
- -webkit-mask-size: 10px 10px;
+ -webkit-mask-size: var(--mask-width);
background-color: rgba(90,90,90,0.7);
content: '';
display: block;
height: var(--title-height);
position: absolute;
right: 0;
+ top: 0;
width: var(--title-height);
}
+body.dark-theme .mv-x.mv-x::after {
+ background-color: rgba(255,255,255,0.7);
+}
+
html[dir=rtl] .mv-x {
background: linear-gradient(to right, rgb(250,250,250) 60%, transparent);
left: -1px;
right: auto;
}
+body.dark-theme body.dark-theme .mv-x {
+ background: linear-gradient(to right, rgb(51,51,51) 60%, transparent);
+}
+
html[dir=rtl] .mv-x::after {
left: -1px;
right: auto;
@@ -244,16 +313,27 @@ html[dir=rtl] .mv-x::after {
background-color: rgb(90,90,90);
}
+body.dark-theme .mv-x:hover::after {
+ background-color: #fff;
+}
+
.mv-x:active::after {
background-color: rgb(66,133,244);
}
-.mv-tile:hover .mv-x {
+body.dark-theme .mv-x:active::after {
+ background-color: rgba(255,255,255,0.5);
+}
+
+.mv-tile:hover .mv-x,
+.mv-tile:focus .mv-x {
opacity: 1;
transition-delay: 500ms;
}
-.mv-x:hover {
+.mv-x:hover,
+.mv-x:focus {
+ opacity: 1;
transition: none;
}
diff --git a/chromium/chrome/browser/resources/local_ntp/most_visited_single.html b/chromium/chrome/browser/resources/local_ntp/most_visited_single.html
index 2b1ba59971e..094e8f14537 100644
--- a/chromium/chrome/browser/resources/local_ntp/most_visited_single.html
+++ b/chromium/chrome/browser/resources/local_ntp/most_visited_single.html
@@ -7,7 +7,6 @@
<base target="_top">
<meta charset="utf-8">
<link rel="stylesheet" type="text/css" href="single.css">
- <style type="text/css" id="custom-theme"></style>
<script src="single.js"></script>
</head>
<body>
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 446873a2ce6..ca988627132 100644
--- a/chromium/chrome/browser/resources/local_ntp/most_visited_single.js
+++ b/chromium/chrome/browser/resources/local_ntp/most_visited_single.js
@@ -166,7 +166,8 @@ var countLoad = function() {
swapInNewTiles();
logEvent(LOG_TYPE.NTP_ALL_TILES_LOADED);
window.parent.postMessage({cmd: 'loaded'}, DOMAIN_ORIGIN);
- // TODO(treib): Why do we reset to 1 here?
+ // Reset to 1, so that any further 'show' message will cause us to swap in
+ // fresh tiles.
loadedCounter = 1;
}
};
@@ -222,41 +223,8 @@ var showTiles = function(info) {
* @param {object} info Data received in the message.
*/
var updateTheme = function(info) {
- var themeStyle = [];
-
- if (info.isThemeDark) {
- themeStyle.push(
- '.mv-tile, .mv-empty-tile { ' +
- 'background: rgb(51,51,51); }');
- themeStyle.push(
- '.mv-thumb.failed-img { ' +
- 'background-color: #555; }');
- themeStyle.push(
- '.mv-thumb.failed-img::after { ' +
- 'border-color: #333; }');
- themeStyle.push(
- '.mv-x { ' +
- 'background: linear-gradient(to left, ' +
- 'rgb(51,51,51) 60%, transparent); }');
- themeStyle.push(
- 'html[dir=rtl] .mv-x { ' +
- 'background: linear-gradient(to right, ' +
- 'rgb(51,51,51) 60%, transparent); }');
- themeStyle.push(
- '.mv-x::after { ' +
- 'background-color: rgba(255,255,255,0.7); }');
- themeStyle.push(
- '.mv-x:hover::after { ' +
- 'background-color: #fff; }');
- themeStyle.push(
- '.mv-x:active::after { ' +
- 'background-color: rgba(255,255,255,0.5); }');
- }
- if (info.tileTitleColor) {
- themeStyle.push('body { color: ' + info.tileTitleColor + '; }');
- }
-
- document.querySelector('#custom-theme').textContent = themeStyle.join('\n');
+ document.body.style.setProperty('--tile-title-color', info.tileTitleColor);
+ document.body.classList.toggle('dark-theme', info.isThemeDark);
};
@@ -399,7 +367,7 @@ var renderTile = function(data) {
var html = [];
html.push('<div class="mv-favicon"></div>');
html.push('<div class="mv-title"></div><div class="mv-thumb"></div>');
- html.push('<div class="mv-x" role="button"></div>');
+ html.push('<button class="mv-x"></button>');
tile.innerHTML = html.join('');
tile.lastElementChild.title = queryArgs['removeTooltip'] || '';
@@ -496,8 +464,9 @@ var renderTile = function(data) {
var favicon = tile.querySelector('.mv-favicon');
var fi = document.createElement('img');
fi.src = data.faviconUrl;
- // Set the title to empty so screen readers won't say the image name.
+ // Set title and alt to empty so screen readers won't say the image name.
fi.title = '';
+ fi.alt = '';
loadedCounter += 1;
fi.addEventListener('load', countLoad);
fi.addEventListener('error', countLoad);
@@ -514,6 +483,12 @@ var renderTile = function(data) {
ev.stopPropagation();
});
+ // Don't allow the event to bubble out to the containing tile, as that would
+ // trigger navigation to the tile URL.
+ mvx.addEventListener('keydown', function(event) {
+ event.stopPropagation();
+ });
+
return tile;
};
diff --git a/chromium/chrome/browser/resources/local_ntp/voice.css b/chromium/chrome/browser/resources/local_ntp/voice.css
index bcd24e9fa0e..891d91f7c96 100644
--- a/chromium/chrome/browser/resources/local_ntp/voice.css
+++ b/chromium/chrome/browser/resources/local_ntp/voice.css
@@ -24,7 +24,6 @@
/* Color constants. */
:root {
- --dark_grey: #dbdbdb;
--dark_red: rgb(205, 0, 0);
--grey: #777;
--light_grey: #eee;
@@ -33,6 +32,7 @@
--active_icon_color: white;
--button_shadow: rgba(0, 0, 0, .1);
--inactive_icon_color: #999;
+ --level_animation_color: #dbdbdb;
--listening_icon_color: var(--light_red);
--text_link_color: rgb(17, 85, 204);
}
@@ -64,13 +64,13 @@
/* The close 'x' button. */
.close-button {
- color: var(--grey);
+ color: black;
cursor: pointer;
font-size: 26px;
height: 11px;
line-height: 15px;
margin: 15px;
- opacity: .6;
+ opacity: .54;
padding: 0;
position: absolute;
right: 0;
@@ -84,11 +84,11 @@ html[dir=rtl] .close-button {
}
.close-button:hover {
- opacity: .8;
+ opacity: .66;
}
.close-button:active {
- opacity: 1;
+ opacity: .78;
}
/* The vertical positioning container. */
@@ -172,7 +172,7 @@ html[dir=rtl] .close-button {
/* Vibrating input volume level. */
.level {
- background-color: var(--dark_grey);
+ background-color: var(--level_animation_color);
border-radius: 100%;
display: inline-block;
height: 301px;
diff --git a/chromium/chrome/browser/resources/md_bookmarks/OWNERS b/chromium/chrome/browser/resources/md_bookmarks/OWNERS
index b02ce2c777a..267acc634e7 100644
--- a/chromium/chrome/browser/resources/md_bookmarks/OWNERS
+++ b/chromium/chrome/browser/resources/md_bookmarks/OWNERS
@@ -1,4 +1,3 @@
calamity@chromium.org
-tsergeant@chromium.org
# COMPONENT: UI>Browser>Bookmarks
diff --git a/chromium/chrome/browser/resources/md_bookmarks/dnd_manager.js b/chromium/chrome/browser/resources/md_bookmarks/dnd_manager.js
index f4da5779d79..330905b542c 100644
--- a/chromium/chrome/browser/resources/md_bookmarks/dnd_manager.js
+++ b/chromium/chrome/browser/resources/md_bookmarks/dnd_manager.js
@@ -330,6 +330,7 @@ cr.define('bookmarks', function() {
*/
update: function(dropDest) {
this.timerProxy.clearTimeout(this.removeDropIndicatorTimeoutId_);
+ this.removeDropIndicatorTimeoutId_ = null;
const indicatorElement = dropDest.element.getDropTarget();
const position = dropDest.position;
@@ -342,9 +343,11 @@ cr.define('bookmarks', function() {
* Stop displaying the drop indicator.
*/
finish: function() {
+ if (this.removeDropIndicatorTimeoutId_)
+ return;
+
// The use of a timeout is in order to reduce flickering as we move
// between valid drop targets.
- this.timerProxy.clearTimeout(this.removeDropIndicatorTimeoutId_);
this.removeDropIndicatorTimeoutId_ = this.timerProxy.setTimeout(() => {
this.removeDropIndicatorStyle();
}, 100);
diff --git a/chromium/chrome/browser/resources/md_bookmarks/list.html b/chromium/chrome/browser/resources/md_bookmarks/list.html
index 2f5ed7aa577..4c3ec439e4d 100644
--- a/chromium/chrome/browser/resources/md_bookmarks/list.html
+++ b/chromium/chrome/browser/resources/md_bookmarks/list.html
@@ -15,7 +15,7 @@
<style include="shared-style">
:host {
overflow-y: auto;
- padding: 20px var(--card-padding-side) 20px
+ padding: 24px var(--card-padding-side) 24px
calc(var(--card-padding-side) - var(--splitter-width));
}
diff --git a/chromium/chrome/browser/resources/md_downloads/downloads.html b/chromium/chrome/browser/resources/md_downloads/downloads.html
index 789c1d5fdcf..bc126bb68c6 100644
--- a/chromium/chrome/browser/resources/md_downloads/downloads.html
+++ b/chromium/chrome/browser/resources/md_downloads/downloads.html
@@ -7,7 +7,7 @@
<style>
html {
--downloads-card-margin: 24px;
- --downloads-card-width: 640px;
+ --downloads-card-width: 680px;
background: #f1f1f1;
}
diff --git a/chromium/chrome/browser/resources/md_downloads/item.js b/chromium/chrome/browser/resources/md_downloads/item.js
index d589ab8cadd..da53e333d3f 100644
--- a/chromium/chrome/browser/resources/md_downloads/item.js
+++ b/chromium/chrome/browser/resources/md_downloads/item.js
@@ -119,7 +119,7 @@ cr.define('downloads', function() {
if (!this.data.by_ext_id || !this.data.by_ext_name)
return '';
- const url = 'chrome://extensions#' + this.data.by_ext_id;
+ const url = `chrome://extensions#${this.data.by_ext_id}`;
const name = this.data.by_ext_name;
return loadTimeData.getStringF('controlledByUrl', url, HTMLEscape(name));
},
@@ -260,8 +260,8 @@ cr.define('downloads', function() {
} else {
this.$.url.href = assert(this.data.url);
const filePath = encodeURIComponent(this.data.file_path);
- const scaleFactor = '?scale=' + window.devicePixelRatio + 'x';
- this.$['file-icon'].src = 'chrome://fileicon/' + filePath + scaleFactor;
+ const scaleFactor = `?scale=${window.devicePixelRatio}x`;
+ this.$['file-icon'].src = `chrome://fileicon/${filePath}${scaleFactor}`;
}
},
diff --git a/chromium/chrome/browser/resources/md_downloads/toolbar.html b/chromium/chrome/browser/resources/md_downloads/toolbar.html
index 2985c1d09ed..ce6dee4341d 100644
--- a/chromium/chrome/browser/resources/md_downloads/toolbar.html
+++ b/chromium/chrome/browser/resources/md_downloads/toolbar.html
@@ -25,7 +25,6 @@
}
#toolbar {
- --cr-toolbar-field-width: var(--downloads-card-width);
flex: 1;
}
diff --git a/chromium/chrome/browser/resources/md_extensions/compiled_resources2.gyp b/chromium/chrome/browser/resources/md_extensions/compiled_resources2.gyp
index 7689bd4eb76..6c34d5b18fc 100644
--- a/chromium/chrome/browser/resources/md_extensions/compiled_resources2.gyp
+++ b/chromium/chrome/browser/resources/md_extensions/compiled_resources2.gyp
@@ -21,6 +21,7 @@
'<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:load_time_data',
'<(EXTERNS_GYP):developer_private',
'item',
+ 'item_behavior',
'item_util',
'navigation_helper',
],
@@ -32,6 +33,7 @@
'<(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:drag_wrapper',
+ '<(EXTERNS_GYP):developer_private',
],
'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
},
@@ -48,9 +50,10 @@
{
'target_name': 'error_page',
'dependencies': [
+ '<(DEPTH)/third_party/polymer/v1_0/components-chromium/paper-menu/compiled_resources2.gyp:paper-menu-extracted',
'<(DEPTH)/ui/webui/resources/cr_elements/compiled_resources2.gyp:cr_container_shadow_behavior',
'<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
- '<(DEPTH)/third_party/polymer/v1_0/components-chromium/paper-menu/compiled_resources2.gyp:paper-menu-extracted',
+ '<(DEPTH)/ui/webui/resources/js/cr/ui/compiled_resources2.gyp:focus_outline_manager',
'<(EXTERNS_GYP):developer_private',
'code_section',
'item_util',
@@ -59,11 +62,9 @@
'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
},
{
- 'target_name': 'extensions',
+ 'target_name': 'install_warnings_dialog',
'dependencies': [
'<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
- 'manager',
- 'service',
],
'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
},
@@ -75,19 +76,30 @@
'<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:i18n_behavior',
'<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:load_time_data',
'<(EXTERNS_GYP):developer_private',
+ 'item_behavior',
'item_util',
'navigation_helper',
],
'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
},
{
+ 'target_name': 'item_behavior',
+ 'dependencies': [
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
+ '<(EXTERNS_GYP):developer_private',
+ ],
+ 'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
'target_name': 'item_list',
'dependencies': [
+ '<(DEPTH)/third_party/polymer/v1_0/components-chromium/iron-a11y-announcer/compiled_resources2.gyp:iron-a11y-announcer-extracted',
'<(DEPTH)/ui/webui/resources/cr_elements/compiled_resources2.gyp:cr_container_shadow_behavior',
'<(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):developer_private',
+ '<(EXTERNS_GYP):metrics_private',
'item',
],
'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
@@ -110,6 +122,8 @@
'<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:assert',
'<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
'<(EXTERNS_GYP):developer_private',
+ '<(EXTERNS_GYP):metrics_private',
+ 'item_behavior',
],
'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
},
@@ -117,6 +131,7 @@
'target_name': 'kiosk_browser_proxy',
'dependencies': [
'<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
+ 'item_behavior',
],
'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
},
@@ -144,7 +159,6 @@
'<(DEPTH)/ui/webui/resources/cr_elements/cr_drawer/compiled_resources2.gyp:cr_drawer',
'<(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):developer_private',
'detail_view',
'item',
@@ -154,6 +168,7 @@
'keyboard_shortcuts',
'kiosk_browser_proxy',
'navigation_helper',
+ 'service',
'sidebar',
'toolbar',
'view_manager',
@@ -175,6 +190,7 @@
'<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:assert',
'<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
'<(EXTERNS_GYP):developer_private',
+ 'item_behavior',
'navigation_helper',
],
'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
@@ -195,10 +211,10 @@
'<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:load_time_data',
'<(EXTERNS_GYP):developer_private',
'<(EXTERNS_GYP):management',
+ '<(EXTERNS_GYP):metrics_private',
'error_page',
'item',
'load_error',
- 'manager',
'navigation_helper',
'pack_dialog',
'toolbar',
@@ -229,6 +245,7 @@
'dependencies': [
'<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:assert',
'<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
+ '<(EXTERNS_GYP):metrics_private',
'navigation_helper',
],
'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
@@ -238,6 +255,7 @@
'dependencies': [
'<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
'<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:i18n_behavior',
+ '<(EXTERNS_GYP):metrics_private',
],
'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
},
diff --git a/chromium/chrome/browser/resources/md_extensions/detail_view.html b/chromium/chrome/browser/resources/md_extensions/detail_view.html
index c66a6a5eb6d..3be69b952af 100644
--- a/chromium/chrome/browser/resources/md_extensions/detail_view.html
+++ b/chromium/chrome/browser/resources/md_extensions/detail_view.html
@@ -12,17 +12,21 @@
<link rel="import" href="chrome://resources/html/cr.html">
<link rel="import" href="chrome://resources/html/i18n_behavior.html">
<link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/iron-flex-layout-classes.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html">
<link rel="import" href="chrome://resources/polymer/v1_0/iron-icons/iron-icons.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button-light.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-spinner/paper-spinner-lite.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-styles/color.html">
-<link rel="import" href="strings.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-styles/shadow.html">
+<link rel="import" href="item_behavior.html">
<link rel="import" href="item_util.html">
<link rel="import" href="navigation_helper.html">
+<link rel="import" href="strings.html">
+<link rel="import" href="toggle_row.html">
<dom-module id="extensions-detail-view">
<template>
- <style include="iron-flex cr-shared-style cr-icons action-link
- paper-button-style">
+ <style include="iron-flex cr-shared-style cr-icons action-link paper-button-style">
:host {
--iron-icon-fill-color: var(--paper-grey-600);
display: block;
@@ -37,16 +41,26 @@
-webkit-margin-end: 20px;
}
+ #enable-section span {
+ color: var(--paper-grey-600);
+ font-weight: 500;
+ }
+
+ #enable-section .enabled-text {
+ color: var(--google-blue-500);
+ }
+
#container {
height: 100%;
overflow: overlay;
}
#main {
+ @apply(--shadow-elevation-2dp);
background-color: white;
margin: auto;
min-height: 100%;
- width: 640px;
+ width: 680px;
}
#top-bar {
@@ -58,8 +72,8 @@
}
#icon {
- -webkit-margin-end: 8px;
- -webkit-margin-start: 20px;
+ -webkit-margin-end: 12px;
+ -webkit-margin-start: 16px;
height: 24px;
width: 24px;
}
@@ -69,15 +83,13 @@
@apply(--cr-title-text);
}
- .control-line {
- align-items: center;
- display: flex;
- justify-content: space-between;
- width: 100%;
+ #learn-more-link {
+ color: var(--google-blue-700);
+ text-decoration: none;
}
- .control-line span {
- color: var(--paper-grey-900);
+ .three-line {
+ min-height: var(--cr-section-three-line-min-height);
}
.section {
@@ -94,6 +106,10 @@
border-top: none;
}
+ .section.control-line {
+ justify-content: space-between;
+ }
+
.section.continuation.warning {
padding-left: 21px;
padding-right: 8px;
@@ -104,7 +120,6 @@
}
.section-title {
- color: var(--paper-grey-900);
margin-bottom: 12px;
}
@@ -150,34 +165,64 @@
margin: 0;
}
- #remove-extension {
+ button[is='cr-link-row'] {
width: 100%;
}
+
+ #options-section .control-line:first-child {
+ border-top: var(--cr-separator-line);
+ }
+
+ #load-path {
+ word-break: break-all;
+ }
+
+ #load-path > a[is='action-link'] {
+ display: inline;
+ }
+
+ #size {
+ display: flex;
+ align-items: center;
+ }
+
+ paper-spinner-lite {
+ @apply(--cr-icon-height-width);
+ }
</style>
<div id="container">
<div id="main">
<div id="top-bar">
<button id="close-button" is="paper-icon-button-light"
- class="icon-arrow-back no-overlap"
+ aria-label="$i18n{back}" class="icon-arrow-back no-overlap"
on-tap="onCloseButtonTap_"></button>
- <img alt="" id="icon" src="[[data.iconUrl]]">
+ <img id="icon" src="[[data.iconUrl]]"
+ alt$="[[appOrExtension(
+ data.type,
+ '$i18nPolymer{appIcon}',
+ '$i18nPolymer{extensionIcon}')]]">
<span id="name">[[data.name]]</span>
</div>
- <div class="section continuation" id="enable-section">
- <div class="control-line">
- <span>[[computeEnabledText_(data.*)]]</span>
- <div class="layout horizontal">
- <cr-tooltip-icon hidden$="[[!data.controlledInfo]]"
- tooltip-text="[[data.controlledInfo.text]]"
- icon-class="[[getIndicatorIcon_(data.controlledInfo.type)]]"
- icon-aria-label="[[data.controlledInfo.type]]">
- </cr-tooltip-icon>
- <cr-toggle id="enable-toggle"
- checked="[[isEnabled_(data.state)]]"
- on-change="onEnableChange_"
- disabled="[[!isEnableToggleEnabled_(data.*)]]">
- </cr-toggle>
- </div>
+ <div class="section continuation control-line" id="enable-section">
+ <span class$="{{computeEnabledStyle_(data.state)}}">
+ [[computeEnabledText_(data.state)]]
+ </span>
+ <div class="layout horizontal">
+ <cr-tooltip-icon hidden$="[[!data.controlledInfo]]"
+ tooltip-text="[[data.controlledInfo.text]]"
+ icon-class="[[getIndicatorIcon_(data.controlledInfo.type)]]"
+ icon-aria-label="[[data.controlledInfo.type]]">
+ </cr-tooltip-icon>
+ <cr-toggle id="enable-toggle"
+ aria-label$="[[appOrExtension(
+ data.type,
+ '$i18nPolymer{appEnabled}',
+ '$i18nPolymer{extensionEnabled}')]]"
+ aria-describedby="name"
+ checked="[[isEnabled_(data.state)]]"
+ on-change="onEnableChange_"
+ disabled="[[!isEnableToggleEnabled_(data.*)]]">
+ </cr-toggle>
</div>
</div>
<div id="warnings" hidden$="[[!hasWarnings_(data.*)]]">
@@ -185,7 +230,13 @@
hidden$="[[!data.disableReasons.suspiciousInstall]]">
<div>
<iron-icon class="warning-icon" icon="cr:warning"></iron-icon>
- <span>$i18n{itemSuspiciousInstall}</span>
+ <span>
+ $i18n{itemSuspiciousInstall}
+ <a target="_blank" id="learn-more-link"
+ href="$i18n{suspiciousInstallHelpUrl}">
+ $i18n{learnMore}
+ </a>
+ </span>
</div>
</div>
<div class="section continuation warning" id="corrupted-warning"
@@ -216,42 +267,60 @@
</div>
<div class="section continuation block">
<div class="section-title">$i18n{itemDescriptionLabel}</div>
- <div class="section-content">[[data.description]]</div>
+ <div class="section-content">
+ [[getDescription_(data.description, '$i18nPolymer{noDescription}')]]
+ </div>
</div>
<div class="section block">
<div class="section-title">$i18n{itemVersion}</div>
<div class="section-content">[[data.version]]</div>
</div>
+ <div class="section block">
+ <div class="section-title">$i18n{itemSize}</div>
+ <div class="section-content" id="size">
+ <span>[[size_]]</span>
+ <paper-spinner-lite active="[[!size_]]" hidden="[[size_]]">
+ </paper-spinner-lite>
+ </div>
+ </div>
<div class="section block" id="id-section" hidden$="[[!inDevMode]]">
<div class="section-title">$i18n{itemIdHeading}</div>
<div class="section-content">[[data.id]]</div>
</div>
- <div class="section" id="inspectable-views" hidden$="[[!inDevMode]]">
- <div class="section-title">$i18n{itemInspectViews}</div>
- <div class="section-content">
- <ul id="inspect-views">
- <template is="dom-repeat" items="[[data.views]]">
- <li>
- <a is="action-link" class="inspectable-view"
- on-tap="onInspectTap_">
- [[computeInspectLabel_(item)]]
- </a>
- </li>
- </template>
- </ul>
+ <template is="dom-if" if="[[inDevMode]]">
+ <div class="section block" id="inspectable-views"
+ hidden="[[!data.views.length]]">
+ <div class="section-title">$i18n{itemInspectViews}</div>
+ <div class="section-content">
+ <ul id="inspect-views">
+ <template is="dom-repeat" items="[[data.views]]">
+ <li>
+ <a is="action-link" class="inspectable-view"
+ on-tap="onInspectTap_">
+ [[computeInspectLabel_(item)]]
+ </a>
+ </li>
+ </template>
+ </ul>
+ </div>
</div>
- </div>
+ </template>
<div class="section block">
<div class="section-title">$i18n{itemPermissions}</div>
<div class="section-content">
- <span id="no-permissions"
- hidden$="[[hasPermissions_(data.permissions.splices)]]">
+ <span id="no-permissions" hidden="[[data.permissions.length]]">
$i18n{itemPermissionsEmpty}
</span>
- <ul id="permissions-list"
- hidden$="[[!hasPermissions_(data.permissions.splices)]]">
+ <ul id="permissions-list" hidden="[[!data.permissions.length]]">
<template is="dom-repeat" items="[[data.permissions]]">
- <li>[[item]]</li>
+ <li>
+ [[item.message]]
+ <ul hidden="[[!item.submessages.length]]">
+ <template is="dom-repeat" items="[[item.submessages]]">
+ <li>[[item]]</li>
+ </template>
+ </ul>
+ </li>
</template>
</ul>
</div>
@@ -270,60 +339,73 @@
</div>
</template>
<template is="dom-if" if="[[shouldShowOptionsSection_(data.*)]]">
- <div class="section">
+ <div id="options-section">
<template is="dom-if" if="[[data.incognitoAccess.isEnabled]]">
- <div class="control-line">
- <span>$i18n{itemAllowIncognito}</span>
- <cr-toggle id="allow-incognito"
- checked="[[data.incognitoAccess.isActive]]"
- on-change="onAllowIncognitoChange_"></cr-toggle>
- </div>
+ <extensions-toggle-row id="allow-incognito" class="three-line"
+ checked="[[data.incognitoAccess.isActive]]"
+ on-change="onAllowIncognitoChange_">
+ <div>
+ <div>$i18n{itemAllowIncognito}</div>
+ <div class="section-content">$i18n{incognitoInfoWarning}</div>
+ </div>
+ </extensions-toggle-row>
</template>
<template is="dom-if" if="[[data.fileAccess.isEnabled]]">
- <div class="control-line">
+ <extensions-toggle-row id="allow-on-file-urls"
+ checked="[[data.fileAccess.isActive]]"
+ on-change="onAllowOnFileUrlsChange_">
<span>$i18n{itemAllowOnFileUrls}</span>
- <cr-toggle id="allow-on-file-urls"
- checked="[[data.fileAccess.isActive]]"
- on-change="onAllowOnFileUrlsChange_"></cr-toggle>
- </div>
+ </extensions-toggle-row>
</template>
<template is="dom-if" if="[[data.runOnAllUrls.isEnabled]]">
- <div class="control-line">
+ <extensions-toggle-row id="allow-on-all-sites"
+ checked="[[data.runOnAllUrls.isActive]]"
+ on-change="onAllowOnAllSitesChange_">
<span>$i18n{itemAllowOnAllSites}</span>
- <cr-toggle id="allow-on-all-sites"
- checked="[[data.runOnAllUrls.isActive]]"
- on-change="onAllowOnAllSitesChange_"></cr-toggle>
- </div>
+ </extensions-toggle-row>
</template>
<template is="dom-if" if="[[data.errorCollection.isEnabled]]">
- <div class="control-line">
+ <extensions-toggle-row id="collect-errors"
+ checked="[[data.errorCollection.isActive]]"
+ on-change="onCollectErrorsChange_">
<span>$i18n{itemCollectErrors}</span>
- <cr-toggle id="collect-errors"
- checked="[[data.errorCollection.isActive]]"
- on-change="onCollectErrorsChange_"></cr-toggle>
- </div>
+ </extensions-toggle-row>
</template>
</div>
</template>
- <div class="section"
+ <div class="section control-line actionable" id="extensions-options"
+ on-tap="onOptionsTap_"
hidden$="[[!shouldShowOptionsLink_(data.*)]]">
- <div class="control-line actionable" id="extensions-options"
- on-tap="onOptionsTap_">
- <span>$i18n{itemOptions}</span>
- <button class="icon-external" is="paper-icon-button-light"></button>
- </div>
+ <span id="optionLabel">$i18n{itemOptions}</span>
+ <button class="icon-external" is="paper-icon-button-light"
+ aria-labelledby="optionLabel" actionable></button>
</div>
- <button class="hr" is="cr-link-row"
- hidden="[[isControlled_(data.controlledInfo)]]"
- icon-class="subpage-arrow" id="remove-extension"
- label="$i18n{itemRemoveExtension}" on-tap="onRemoveTap_">
+ <button class="hr" hidden="[[!data.manifestHomePageUrl.length]]"
+ is="cr-link-row" icon-class="icon-external" id="developerWebsite"
+ label="$i18n{developerWebsite}" on-tap="onDeveloperWebSiteTap_">
+ </button>
+ <button class="hr" hidden="[[!data.webStoreUrl.length]]"
+ is="cr-link-row" icon-class="icon-external" id="viewInStore"
+ label="$i18n{viewInStore}" on-tap="onViewInStoreTap_">
</button>
<div class="section block">
<div class="section-title">$i18n{itemSource}</div>
- <div class="section-content">
+ <div id="source" class="section-content">
[[computeSourceString_(data.*)]]
</div>
+ <div id="load-path" class="section-content"
+ hidden$="[[!data.prettifiedPath]]">
+ <span>$i18n{itemExtensionPath}</span>
+ <a is="action-link" on-tap="onLoadPathTap_">
+ [[data.prettifiedPath]]
+ </a>
+ </div>
</div>
+ <button class="hr" is="cr-link-row"
+ hidden="[[isControlled_(data.controlledInfo)]]"
+ icon-class="subpage-arrow" id="remove-extension"
+ label="$i18n{itemRemoveExtension}" on-tap="onRemoveTap_">
+ </button>
</div>
</div>
</template>
diff --git a/chromium/chrome/browser/resources/md_extensions/detail_view.js b/chromium/chrome/browser/resources/md_extensions/detail_view.js
index 9f7ab51e2db..0eb723e9679 100644
--- a/chromium/chrome/browser/resources/md_extensions/detail_view.js
+++ b/chromium/chrome/browser/resources/md_extensions/detail_view.js
@@ -8,7 +8,11 @@ cr.define('extensions', function() {
const DetailView = Polymer({
is: 'extensions-detail-view',
- behaviors: [I18nBehavior, CrContainerShadowBehavior],
+ behaviors: [
+ I18nBehavior,
+ CrContainerShadowBehavior,
+ extensions.ItemBehavior,
+ ],
properties: {
/**
@@ -17,6 +21,9 @@ cr.define('extensions', function() {
*/
data: Object,
+ /** @private */
+ size_: String,
+
/** @type {!extensions.ItemDelegate} */
delegate: Object,
@@ -24,10 +31,33 @@ cr.define('extensions', function() {
inDevMode: Boolean,
},
+ observers: [
+ 'onItemIdChanged_(data.id, delegate)',
+ ],
+
+ /** @private */
+ onItemIdChanged_: function() {
+ // Clear the size, since this view is reused, such that no obsolete size
+ // is displayed.:
+ this.size_ = '';
+ this.delegate.getExtensionSize(this.data.id).then(size => {
+ this.size_ = size;
+ });
+ },
+
+ /**
+ * @param {string} description
+ * @param {string} fallback
+ * @return {string}
+ * @private
+ */
+ getDescription_: function(description, fallback) {
+ return description || fallback;
+ },
+
/** @private */
onCloseButtonTap_: function() {
- extensions.navigation.navigateTo(
- {page: Page.LIST, type: extensions.getItemListType(this.data)});
+ extensions.navigation.navigateTo({page: Page.LIST});
},
/**
@@ -66,18 +96,18 @@ cr.define('extensions', function() {
* @return {boolean}
* @private
*/
- hasPermissions_: function() {
- return this.data.permissions.length > 0;
+ hasWarnings_: function() {
+ return this.data.disableReasons.corruptInstall ||
+ this.data.disableReasons.suspiciousInstall ||
+ this.data.disableReasons.updateRequired || !!this.data.blacklistText;
},
/**
- * @return {boolean}
+ * @return {string}
* @private
*/
- hasWarnings_: function() {
- return this.data.disableReasons.corruptInstall ||
- this.data.disableReasons.suspiciousInstall ||
- this.data.disableReasons.updateRequired || !!this.data.blacklistText;
+ computeEnabledStyle_: function() {
+ return this.isEnabled_() ? 'enabled-text' : '';
},
/**
@@ -102,18 +132,6 @@ cr.define('extensions', function() {
* @return {boolean}
* @private
*/
- shouldShowHomepageButton_: function() {
- // Note: we ignore |data.homePage.specified| - we use an extension's
- // webstore entry as a homepage if the extension didn't explicitly specify
- // a homepage. (|url| can still be unset in the case of unpacked
- // extensions.)
- return this.data.homePage.url.length > 0;
- },
-
- /**
- * @return {boolean}
- * @private
- */
shouldShowOptionsLink_: function() {
return !!this.data.optionsPage;
},
@@ -144,7 +162,7 @@ cr.define('extensions', function() {
/** @private */
onOptionsTap_: function() {
- this.delegate.showItemOptionsPage(this.data.id);
+ this.delegate.showItemOptionsPage(this.data);
},
/** @private */
@@ -158,6 +176,11 @@ cr.define('extensions', function() {
},
/** @private */
+ onLoadPathTap_: function() {
+ this.delegate.showInFolder(this.data.id);
+ },
+
+ /** @private */
onAllowIncognitoChange_: function() {
this.delegate.setItemAllowedIncognito(
this.data.id, this.$$('#allow-incognito').checked);
@@ -181,18 +204,32 @@ cr.define('extensions', function() {
this.data.id, this.$$('#collect-errors').checked);
},
+ /** @private */
+ onDeveloperWebSiteTap_: function() {
+ this.delegate.openUrl(this.data.manifestHomePageUrl);
+ },
+
+ /** @private */
+ onViewInStoreTap_: function() {
+ this.delegate.openUrl(this.data.webStoreUrl);
+ },
+
/**
* @param {!chrome.developerPrivate.DependentExtension} item
+ * @return {string}
* @private
*/
computeDependentEntry_: function(item) {
return loadTimeData.getStringF('itemDependentEntry', item.name, item.id);
},
- /** @private */
+ /**
+ * @return {string}
+ * @private
+ */
computeSourceString_: function() {
- return extensions.getItemSourceString(
- extensions.getItemSource(this.data));
+ return this.data.locationText ||
+ extensions.getItemSourceString(extensions.getItemSource(this.data));
},
/**
diff --git a/chromium/chrome/browser/resources/md_extensions/drag_and_drop_handler.js b/chromium/chrome/browser/resources/md_extensions/drag_and_drop_handler.js
index f79bb43cde1..862c3a436b5 100644
--- a/chromium/chrome/browser/resources/md_extensions/drag_and_drop_handler.js
+++ b/chromium/chrome/browser/resources/md_extensions/drag_and_drop_handler.js
@@ -7,21 +7,27 @@ cr.define('extensions', function() {
/**
* @param {boolean} dragEnabled
+ * @param {boolean} isMdExtensions
* @param {!EventTarget} target
* @constructor
* @implements cr.ui.DragWrapperDelegate
*/
- function DragAndDropHandler(dragEnabled, target) {
+ function DragAndDropHandler(dragEnabled, isMdExtensions, target) {
this.dragEnabled = dragEnabled;
+
+ // Behavior is different for dropped directories between MD and non-MD
+ // extensions pages.
+ // TODO(devlin): Delete the non-MD codepath and remove this variable when
+ // MD extensions launches.
+ /** @private {boolean} */
+ this.isMdExtensions_ = isMdExtensions;
+
/** @private {!EventTarget} */
this.eventTarget_ = target;
}
- // TODO(devlin): Un-chrome.send-ify this implementation.
+ // TODO(devlin): Finish un-chrome.send-ifying this implementation.
DragAndDropHandler.prototype = {
- /** @type {boolean} */
- dragEnabled: false,
-
/** @override */
shouldAcceptDrag: function(e) {
// External Extension installation can be disabled globally, e.g. while a
@@ -40,6 +46,9 @@ cr.define('extensions', function() {
/** @override */
doDragEnter: function() {
chrome.send('startDrag');
+ if (this.isMdExtensions_)
+ chrome.developerPrivate.notifyDragInstallInProgress();
+
this.eventTarget_.dispatchEvent(
new CustomEvent('extension-drag-started'));
},
@@ -61,27 +70,56 @@ cr.define('extensions', function() {
if (e.dataTransfer.files.length != 1)
return;
- let toSend = '';
+ let handled = false;
+
// Files lack a check if they're a directory, but we can find out through
// its item entry.
- for (let i = 0; i < e.dataTransfer.items.length; ++i) {
- if (e.dataTransfer.items[i].kind == 'file' &&
- e.dataTransfer.items[i].webkitGetAsEntry().isDirectory) {
- toSend = 'installDroppedDirectory';
- break;
- }
- }
- // Only process files that look like extensions. Other files should
- // navigate the browser normally.
- if (!toSend &&
- /\.(crx|user\.js|zip)$/i.test(e.dataTransfer.files[0].name)) {
- toSend = 'installDroppedFile';
+ let item = e.dataTransfer.items[0];
+ if (item.kind === 'file' && item.webkitGetAsEntry().isDirectory) {
+ handled = true;
+ this.handleDirectoryDrop_();
+ } else if (/\.(crx|user\.js|zip)$/i.test(e.dataTransfer.files[0].name)) {
+ // Only process files that look like extensions. Other files should
+ // navigate the browser normally.
+ handled = true;
+ this.handleFileDrop_();
}
- if (toSend) {
+ if (handled)
e.preventDefault();
- chrome.send(toSend);
+ },
+
+ /**
+ * Handles a dropped file.
+ * @private
+ */
+ handleFileDrop_: function() {
+ // Packaged files always go through chrome.send (for now).
+ chrome.send('installDroppedFile');
+ },
+
+ /**
+ * Handles a dropped directory.
+ * @private
+ */
+ handleDirectoryDrop_: function() {
+ // Dropped directories either go through developerPrivate or chrome.send
+ // depending on if this is the MD page.
+ if (!this.isMdExtensions_) {
+ chrome.send('installDroppedDirectory');
+ return;
}
+
+ // TODO(devlin): Update this to use extensions.Service when it's not
+ // shared between the MD and non-MD pages.
+ chrome.developerPrivate.loadUnpacked(
+ {failQuietly: true, populateError: true, useDraggedPath: true},
+ (loadError) => {
+ if (loadError) {
+ this.eventTarget_.dispatchEvent(new CustomEvent(
+ 'drag-and-drop-load-error', {detail: loadError}));
+ }
+ });
},
/** @private */
diff --git a/chromium/chrome/browser/resources/md_extensions/drop_overlay.html b/chromium/chrome/browser/resources/md_extensions/drop_overlay.html
index 7c6c510578f..168ffe7a9df 100644
--- a/chromium/chrome/browser/resources/md_extensions/drop_overlay.html
+++ b/chromium/chrome/browser/resources/md_extensions/drop_overlay.html
@@ -12,11 +12,11 @@
<style include="cr-hidden-style">
:host {
align-items: center;
- background-color: white;
+ background-color: #f1f1f1;
display: flex;
height: 100%;
justify-content: center;
- opacity: 0.5;
+ opacity: 0.9;
position: absolute;
width: 100%;
z-index: 10;
@@ -29,14 +29,21 @@
}
iron-icon {
- color: var(--paper-teal-a400);
+ color: var(--paper-grey-600);
height: 64px;
+ margin-bottom: 16px;
width: 64px;
}
+
+ #text {
+ color: #6e6e6e;
+ font-size: 123.1%;
+ font-weight: 500;
+ }
</style>
<div id="container">
<iron-icon icon="extension"></iron-icon>
- <div>$i18n{dropToInstall}</div>
+ <div id="text">$i18n{dropToInstall}</div>
</div>
</template>
<script src="drop_overlay.js"></script>
diff --git a/chromium/chrome/browser/resources/md_extensions/drop_overlay.js b/chromium/chrome/browser/resources/md_extensions/drop_overlay.js
index feeddba5520..a1071ef6ca5 100644
--- a/chromium/chrome/browser/resources/md_extensions/drop_overlay.js
+++ b/chromium/chrome/browser/resources/md_extensions/drop_overlay.js
@@ -7,17 +7,22 @@
Polymer({
is: 'extensions-drop-overlay',
+
+ /** @override */
created: function() {
this.hidden = true;
const dragTarget = document.documentElement;
this.dragWrapperHandler_ =
- new extensions.DragAndDropHandler(true, dragTarget);
+ new extensions.DragAndDropHandler(true, true, dragTarget);
dragTarget.addEventListener('extension-drag-started', () => {
this.hidden = false;
});
dragTarget.addEventListener('extension-drag-ended', () => {
this.hidden = true;
});
+ dragTarget.addEventListener('drag-and-drop-load-error', (e) => {
+ this.fire('load-error', e.detail);
+ });
this.dragWrapper_ =
new cr.ui.DragWrapper(dragTarget, this.dragWrapperHandler_);
},
diff --git a/chromium/chrome/browser/resources/md_extensions/error_page.html b/chromium/chrome/browser/resources/md_extensions/error_page.html
index 0ddb9486ee4..d3fbc22f893 100644
--- a/chromium/chrome/browser/resources/md_extensions/error_page.html
+++ b/chromium/chrome/browser/resources/md_extensions/error_page.html
@@ -1,17 +1,17 @@
<link rel="import" href="chrome://resources/html/polymer.html">
<link rel="import" href="chrome://resources/cr_elements/cr_container_shadow_behavior.html">
-<link rel="import" href="chrome://resources/cr_elements/cr_expand_button/cr_expand_button.html">
<link rel="import" href="chrome://resources/cr_elements/cr_icons_css.html">
<link rel="import" href="chrome://resources/cr_elements/shared_style_css.html">
<link rel="import" href="chrome://resources/cr_elements/paper_button_style_css.html">
<link rel="import" href="chrome://resources/html/cr.html">
+<link rel="import" href="chrome://resources/html/cr/ui/focus_outline_manager.html">
<link rel="import" href="chrome://resources/polymer/v1_0/iron-collapse/iron-collapse.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-light.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-styles/color.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-styles/shadow.html">
<link rel="import" href="code_section.html">
<link rel="import" href="item_util.html">
<link rel="import" href="navigation_helper.html">
@@ -29,7 +29,24 @@
overflow: overlay;
}
+ iron-icon {
+ --iron-icon-fill-color: var(--paper-grey-500);
+ @apply(--cr-icon-height-width);
+ }
+
+ iron-icon[icon=warning] {
+ --iron-icon-fill-color: var(--paper-orange-500);
+ }
+
+ iron-icon[icon=error] {
+ --iron-icon-fill-color: var(--paper-red-700);
+ }
+
+ /* TODO(dpapad): There is a lot of duplicated styling between
+ * detail_view.html and error_page.html. Refactor such that no duplication
+ * happens.*/
#main {
+ @apply(--shadow-elevation-2dp);
background-color: white;
margin: auto;
min-height: 100%;
@@ -77,19 +94,6 @@
flex-grow: 1;
}
- .icon-severity-info {
- /* TODO(devlin): 1x/2x versions? */
- content: url(error_severity_info.png);
- }
-
- .icon-severity-warning {
- content: url(error_severity_warning.png);
- }
-
- .icon-severity-fatal {
- content: url(error_severity_fatal.png);
- }
-
#devtools-controls {
padding: 0 var(--cr-section-padding);
}
@@ -130,26 +134,33 @@
/* TODO(scottchen): extract to shared location from settings. */
.separator {
+ --separator-gaps: 9px;
-webkit-border-start: var(--cr-separator-line);
-webkit-margin-end: var(--cr-section-padding);
- -webkit-margin-start: var(--cr-section-padding);
- flex-shrink: 0;
- --separator-gaps: 9px;
- height: calc(var(--cr-section-min-height) -
- var(--separator-gaps));
-
/**
* Makes the tappable area fill its parent.
* TODO(scottchen): This is an explicit reminder to override once
* .separator styling is extracted from settings.
*/
-webkit-margin-start: 0;
+ flex-shrink: 0;
+ height: calc(var(--cr-section-min-height) -
+ var(--separator-gaps));
+
}
/* TODO(scottchen): extract to shared location from settings. */
.separator + button[is='paper-icon-button-light'] {
-webkit-margin-start: var(--cr-icon-ripple-margin);
}
+
+ :host-context(.focus-outline-visible) .start:focus {
+ outline: -webkit-focus-ring-color auto 5px;
+ }
+
+ .start:focus {
+ outline: none;
+ }
</style>
<div id="container">
<div id="main">
@@ -164,17 +175,17 @@
could-not-display-code="$i18n{noErrorsToShow}">
</extensions-code-section>
<div id="errors-list">
- <template is="dom-repeat" items="[[calculateShownItems_(data.*)]]">
+ <template is="dom-repeat" items="[[entries_]]">
<div class="item-container">
- <div class$="error-item [[computeErrorClass_(selectedError_, item)]]">
- <div class="start" on-tap="onErrorItemAction_"
+ <div class$="error-item
+ [[computeErrorClass_(item, selectedEntry_)]]">
+ <div actionable class=" start" on-tap="onErrorItemAction_"
on-keydown="onErrorItemAction_" tabindex="0">
- <img class$="[[computeErrorIconClass_(item)]]">
+ <iron-icon icon$="[[computeErrorIcon_(item)]]"></iron-icon>
<div class="error-message">[[item.message]]</div>
- <cr-expand-button hidden="[[!computeIsRuntimeError_(item)]]"
- expanded="[[isEqual_(selectedError_, item)]]"
- tab-index="-1">
- </cr-expand-button>
+ <div class$="cr-icon [[iconName_(index, selectedEntry_)]]"
+ hidden="[[!computeIsRuntimeError_(item)]]">
+ </div>
</div>
<div class="separator"></div>
<button is="paper-icon-button-light" class="icon-delete-gray"
@@ -183,7 +194,7 @@
</button>
</div>
<template is="dom-if" if="[[computeIsRuntimeError_(item)]]">
- <iron-collapse opened="[[isEqual_(selectedError_, item)]]">
+ <iron-collapse opened="[[isOpened_(index, selectedEntry_)]]">
<div id="devtools-controls">
<div id="stack-trace-heading">
$i18n{stackTrace}
@@ -192,7 +203,8 @@
<template is="dom-repeat" items="[[item.stackTrace]]">
<li on-tap="onStackFrameTap_"
hidden="[[!shouldDisplayFrame_(item.url)]]"
- class$="[[getStackFrameClass_(item, selectedStackFrame_)]]">
+ class$="[[getStackFrameClass_(item,
+ selectedStackFrame_)]]">
[[getStackTraceLabel_(item)]]
</li>
</template>
@@ -207,7 +219,7 @@
</template>
</div>
</template>
- </iron-list>
+ </div>
</div>
</div>
</div>
diff --git a/chromium/chrome/browser/resources/md_extensions/error_page.js b/chromium/chrome/browser/resources/md_extensions/error_page.js
index 113561d6018..b3dc9ca06ea 100644
--- a/chromium/chrome/browser/resources/md_extensions/error_page.js
+++ b/chromium/chrome/browser/resources/md_extensions/error_page.js
@@ -55,8 +55,14 @@ cr.define('extensions', function() {
/** @type {!extensions.ErrorPageDelegate|undefined} */
delegate: Object,
- /** @private {?(ManifestError|RuntimeError)} */
- selectedError_: Object,
+ /** @private {!Array<!(ManifestError|RuntimeError)>} */
+ entries_: Array,
+
+ /**
+ * Index into |entries_|.
+ * @private
+ */
+ selectedEntry_: Number,
/** @private {?chrome.developerPrivate.StackFrame}*/
selectedStackFrame_: {
@@ -68,36 +74,34 @@ cr.define('extensions', function() {
},
observers: [
- 'observeDataChanges_(data)',
- 'onSelectedErrorChanged_(selectedError_)',
+ 'observeDataChanges_(data.*)',
+ 'onSelectedErrorChanged_(selectedEntry_)',
],
+ /** @override */
+ ready: function() {
+ cr.ui.FocusOutlineManager.forDocument(document);
+ },
+
+ /** @return {!ManifestError|!RuntimeError} */
+ getSelectedError: function() {
+ return this.entries_[this.selectedEntry_];
+ },
+
/**
* Watches for changes to |data| in order to fetch the corresponding
* file source.
* @private
*/
observeDataChanges_: function() {
- assert(this.data);
- this.selectedError_ =
- this.data.manifestErrors[0] || this.data.runtimeErrors[0] || null;
- },
-
- /**
- * @return {!Array<!(ManifestError|RuntimeError)>}
- * @private
- */
- calculateShownItems_: function() {
- return this.data.manifestErrors.concat(this.data.runtimeErrors);
+ const errors = this.data.manifestErrors.concat(this.data.runtimeErrors);
+ this.entries_ = errors;
+ this.selectedEntry_ = this.entries_.length ? 0 : -1;
},
/** @private */
onCloseButtonTap_: function() {
- extensions.navigation.navigateTo({
- page: Page.LIST,
- type: extensions.getItemListType(
- /** @type {!chrome.developerPrivate.ExtensionInfo} */ (this.data))
- });
+ extensions.navigation.navigateTo({page: Page.LIST});
},
/**
@@ -105,20 +109,20 @@ cr.define('extensions', function() {
* @return {string}
* @private
*/
- computeErrorIconClass_: function(error) {
+ computeErrorIcon_: function(error) {
if (error.type == chrome.developerPrivate.ErrorType.RUNTIME) {
switch (error.severity) {
case chrome.developerPrivate.ErrorLevel.LOG:
- return 'icon-severity-info';
+ return 'info';
case chrome.developerPrivate.ErrorLevel.WARN:
- return 'icon-severity-warning';
+ return 'warning';
case chrome.developerPrivate.ErrorLevel.ERROR:
- return 'icon-severity-fatal';
+ return 'error';
}
assertNotReached();
}
assert(error.type == chrome.developerPrivate.ErrorType.MANIFEST);
- return 'icon-severity-warning';
+ return 'warning';
},
/**
@@ -139,12 +143,12 @@ cr.define('extensions', function() {
* @private
*/
onSelectedErrorChanged_: function() {
- if (!this.selectedError_) {
+ if (this.selectedEntry_ < 0) {
this.$['code-section'].code = null;
return;
}
- const error = this.selectedError_;
+ const error = this.getSelectedError();
const args = {
extensionId: error.extensionId,
message: error.message,
@@ -188,8 +192,8 @@ cr.define('extensions', function() {
* @private
*/
getStackTraceLabel_: function(frame) {
- let description = getRelativeUrl(frame.url, this.selectedError_) + ':' +
- frame.lineNumber;
+ let description = getRelativeUrl(frame.url, this.getSelectedError()) +
+ ':' + frame.lineNumber;
if (frame.functionName) {
const functionName = frame.functionName == '(anonymous function)' ?
@@ -232,15 +236,16 @@ cr.define('extensions', function() {
* @private
*/
onStackFrameTap_: function(e) {
- const frame = (/** @type {!{model:Object}} */ (e)).model.item;
+ const frame = /** @type {!{model:Object}} */ (e).model.item;
this.selectedStackFrame_ = frame;
+ const selectedError = this.getSelectedError();
this.delegate
.requestFileSource({
- extensionId: this.selectedError_.extensionId,
- message: this.selectedError_.message,
- pathSuffix: getRelativeUrl(frame.url, this.selectedError_),
+ extensionId: selectedError.extensionId,
+ message: selectedError.message,
+ pathSuffix: getRelativeUrl(frame.url, selectedError),
lineNumber: frame.lineNumber,
})
.then(code => {
@@ -250,15 +255,14 @@ cr.define('extensions', function() {
/** @private */
onDevToolButtonTap_: function() {
+ const selectedError = this.getSelectedError();
// This guarantees renderProcessId and renderViewId.
- assert(
- this.selectedError_.type ==
- chrome.developerPrivate.ErrorType.RUNTIME);
+ assert(selectedError.type == chrome.developerPrivate.ErrorType.RUNTIME);
assert(this.selectedStackFrame_);
this.delegate.openDevTools({
- renderProcessId: this.selectedError_.renderProcessId,
- renderViewId: this.selectedError_.renderViewId,
+ renderProcessId: selectedError.renderProcessId,
+ renderViewId: selectedError.renderViewId,
url: this.selectedStackFrame_.url,
lineNumber: this.selectedStackFrame_.lineNumber || 0,
columnNumber: this.selectedStackFrame_.columnNumber || 0,
@@ -268,43 +272,40 @@ cr.define('extensions', function() {
/**
* Computes the class name for the error item depending on whether its
* the currently selected error.
- * @param {!RuntimeError|!ManifestError} selectedError
- * @param {!RuntimeError|!ManifestError} error
+ * @param {number} index
* @return {string}
* @private
*/
- computeErrorClass_: function(selectedError, error) {
- return selectedError == error ? 'selected' : '';
+ computeErrorClass_: function(index) {
+ return index == this.selectedEntry_ ? 'selected' : '';
},
- /**
- * @param {!RuntimeError|!ManifestError} selected
- * @param {!RuntimeError|!ManifestError} current
- * @return {boolean}
- * @private
- */
- isEqual_: function(selected, current) {
- return selected == current;
+ /** @private */
+ iconName_: function(index) {
+ return index == this.selectedEntry_ ? 'icon-expand-less' :
+ 'icon-expand-more';
},
/**
- * Causes the given error to become the currently-selected error.
- * @param {!RuntimeError|!ManifestError} error
+ * Determine if the iron-collapse should be opened (expanded).
+ * @param {number} index
+ * @return {boolean}
* @private
*/
- selectError_: function(error) {
- this.selectedError_ = error;
+ isOpened_: function(index) {
+ return index == this.selectedEntry_;
},
/**
- * @param {!{model: !{item: (!RuntimeError|!ManifestError)}}} e
+ * @param {!{model: !{index: number}}} e
* @private
*/
onErrorItemAction_: function(e) {
if (e.type == 'keydown' && !((e.code == 'Space' || e.code == 'Enter')))
return;
- this.selectError_(e.model.item);
+ this.selectedEntry_ =
+ this.selectedEntry_ == e.model.index ? -1 : e.model.index;
},
});
diff --git a/chromium/chrome/browser/resources/md_extensions/error_severity_fatal.png b/chromium/chrome/browser/resources/md_extensions/error_severity_fatal.png
deleted file mode 100644
index b53dc2cf74b..00000000000
--- a/chromium/chrome/browser/resources/md_extensions/error_severity_fatal.png
+++ /dev/null
Binary files differ
diff --git a/chromium/chrome/browser/resources/md_extensions/error_severity_info.png b/chromium/chrome/browser/resources/md_extensions/error_severity_info.png
deleted file mode 100644
index 1c32c6eb83f..00000000000
--- a/chromium/chrome/browser/resources/md_extensions/error_severity_info.png
+++ /dev/null
Binary files differ
diff --git a/chromium/chrome/browser/resources/md_extensions/error_severity_warning.png b/chromium/chrome/browser/resources/md_extensions/error_severity_warning.png
deleted file mode 100644
index d2e3434a595..00000000000
--- a/chromium/chrome/browser/resources/md_extensions/error_severity_warning.png
+++ /dev/null
Binary files differ
diff --git a/chromium/chrome/browser/resources/md_extensions/extensions.html b/chromium/chrome/browser/resources/md_extensions/extensions.html
index 1428eb4e94f..97ddab4934b 100644
--- a/chromium/chrome/browser/resources/md_extensions/extensions.html
+++ b/chromium/chrome/browser/resources/md_extensions/extensions.html
@@ -1,17 +1,27 @@
<!doctype html>
-<html dir="$i18n{textdirection}" lang="$i18n{language}">
+<html dir="$i18n{textdirection}" lang="$i18n{language}"
+ class="loading $i18n{loadTimeClasses}">
<head>
<meta charset="utf8">
<title>$i18n{title}</title>
<if expr="not optimize_webui">
<base href="chrome://extensions">
</if>
- <link rel="import" href="chrome://resources/html/polymer.html">
- <link rel="import" href="manager.html">
- <link rel="stylesheet" href="chrome://resources/css/md_colors.css">
<style>
html {
- background: var(--md-background-color);
+ /* --md-background-color in disguise. Not using the var for increased
+ * performance. */
+ background-color: #f1f1f1;
+ }
+
+ .loading {
+ /* --google-blue-700 in disguise. Replaced when manager.html loads. */
+ border-top: 56px solid rgb(51, 103, 214);
+ }
+
+ /* Note: .in-dev-mode is applied by i18n{loadTimeClasses}. */
+ .loading.in-dev-mode {
+ border-top-width: 96px;
}
html,
@@ -27,7 +37,6 @@
<body>
<extensions-manager></extensions-manager>
<link rel="stylesheet" href="chrome://resources/css/text_defaults_md.css">
- <link rel="import" href="service.html">
- <script src="extensions.js"></script>
+ <link rel="import" href="manager.html">
</body>
</html>
diff --git a/chromium/chrome/browser/resources/md_extensions/extensions.js b/chromium/chrome/browser/resources/md_extensions/extensions.js
deleted file mode 100644
index a9a62659892..00000000000
--- a/chromium/chrome/browser/resources/md_extensions/extensions.js
+++ /dev/null
@@ -1,12 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-(function() {
-'use strict';
-const manager = /** @type {extensions.Manager} */ (
- document.querySelector('extensions-manager'));
-manager.readyPromiseResolver.promise.then(function() {
- extensions.Service.getInstance().managerReady(manager);
-});
-})();
diff --git a/chromium/chrome/browser/resources/md_extensions/extensions_resources.grd b/chromium/chrome/browser/resources/md_extensions/extensions_resources.grd
index c8d179899b3..7ae0088239c 100644
--- a/chromium/chrome/browser/resources/md_extensions/extensions_resources.grd
+++ b/chromium/chrome/browser/resources/md_extensions/extensions_resources.grd
@@ -12,14 +12,17 @@
</outputs>
<release seq="1">
<structures>
+ <structure name="IDR_MD_EXTENSIONS_ITEM_BEHAVIOR_HTML"
+ file="item_behavior.html"
+ type="chrome_html" />
+ <structure name="IDR_MD_EXTENSIONS_ITEM_BEHAVIOR_JS"
+ file="item_behavior.js"
+ type="chrome_html" />
<structure name="IDR_MD_EXTENSIONS_EXTENSIONS_HTML"
file="extensions.html"
flattenhtml="true"
allowexternalscript="true"
type="chrome_html" />
- <structure name="IDR_MD_EXTENSIONS_EXTENSIONS_JS"
- file="extensions.js"
- type="chrome_html" />
<structure name="IDR_MD_EXTENSIONS_CODE_SECTION_HTML"
file="code_section.html"
type="chrome_html" />
@@ -84,6 +87,12 @@
<structure name="IDR_MD_EXTENSIONS_ICONS_HTML"
file="icons.html"
type="chrome_html" />
+ <structure name="IDR_MD_EXTENSIONS_INSTALL_WARNINGS_DIALOG_HTML"
+ file="install_warnings_dialog.html"
+ type="chrome_html" />
+ <structure name="IDR_MD_EXTENSIONS_INSTALL_WARNINGS_DIALOG_JS"
+ file="install_warnings_dialog.js"
+ type="chrome_html" />
<structure name="IDR_MD_EXTENSIONS_ITEM_HTML"
file="item.html"
type="chrome_html" />
@@ -156,6 +165,12 @@
<structure name="IDR_MD_EXTENSIONS_SIDEBAR_JS"
file="sidebar.js"
type="chrome_html" />
+ <structure name="IDR_MD_EXTENSIONS_TOGGLE_ROW_HTML"
+ file="toggle_row.html"
+ type="chrome_html" />
+ <structure name="IDR_MD_EXTENSIONS_TOGGLE_ROW_JS"
+ file="toggle_row.js"
+ type="chrome_html" />
<structure name="IDR_MD_EXTENSIONS_TOOLBAR_HTML"
file="toolbar.html"
type="chrome_html"
diff --git a/chromium/chrome/browser/resources/md_extensions/install_warnings_dialog.html b/chromium/chrome/browser/resources/md_extensions/install_warnings_dialog.html
new file mode 100644
index 00000000000..87f807d0616
--- /dev/null
+++ b/chromium/chrome/browser/resources/md_extensions/install_warnings_dialog.html
@@ -0,0 +1,40 @@
+<link rel="import" href="chrome://resources/html/polymer.html">
+
+<link rel="import" href="chrome://resources/cr_elements/cr_dialog/cr_dialog.html">
+<link rel="import" href="chrome://resources/cr_elements/paper_button_style_css.html">
+<link rel="import" href="chrome://resources/cr_elements/shared_style_css.html">
+<link rel="import" href="chrome://resources/html/assert.html">
+<link rel="import" href="chrome://resources/html/cr.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-styles/color.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html">
+<link rel="import" href="code_section.html">
+
+<dom-module id="extensions-install-warnings-dialog">
+ <template>
+ <style include="cr-shared-style paper-button-style">
+ div[slot='body'] ul {
+ -webkit-padding-end: 10px;
+ background-color: var(--paper-pink-50);
+ margin: 0;
+ padding-bottom: 10px;
+ padding-top: 10px;
+ }
+ </style>
+ <dialog is="cr-dialog" id="dialog" close-text="$i18n{close}">
+ <div slot="title">$i18n{installWarnings}</div>
+ <div slot="body">
+ <ul>
+ <template is="dom-repeat" items="[[installWarnings]]">
+ <li>[[item]]</li>
+ </template>
+ </ul>
+ </div>
+ <div slot="button-container">
+ <paper-button class="action-button" on-tap="onOkTap_">
+ $i18n{ok}
+ </paper-button>
+ </div>
+ </dialog>
+ </template>
+ <script src="install_warnings_dialog.js"></script>
+</dom-module>
diff --git a/chromium/chrome/browser/resources/md_extensions/install_warnings_dialog.js b/chromium/chrome/browser/resources/md_extensions/install_warnings_dialog.js
new file mode 100644
index 00000000000..5417428c937
--- /dev/null
+++ b/chromium/chrome/browser/resources/md_extensions/install_warnings_dialog.js
@@ -0,0 +1,28 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+cr.define('extensions', function() {
+ 'use strict';
+
+ const InstallWarningsDialog = Polymer({
+ is: 'extensions-install-warnings-dialog',
+
+ properties: {
+ /** @type {!Array<string>} */
+ installWarnings: Array,
+ },
+
+ /** @override */
+ attached: function() {
+ this.$.dialog.showModal();
+ },
+
+ /** @private */
+ onOkTap_: function() {
+ this.$.dialog.close();
+ },
+ });
+
+ return {InstallWarningsDialog: InstallWarningsDialog};
+});
diff --git a/chromium/chrome/browser/resources/md_extensions/item.html b/chromium/chrome/browser/resources/md_extensions/item.html
index 2f35703d131..c9c013e5b6b 100644
--- a/chromium/chrome/browser/resources/md_extensions/item.html
+++ b/chromium/chrome/browser/resources/md_extensions/item.html
@@ -4,11 +4,13 @@
<link rel="import" href="chrome://resources/cr_elements/cr_toggle/cr_toggle.html">
<link rel="import" href="chrome://resources/cr_elements/hidden_style_css.html">
<link rel="import" href="chrome://resources/cr_elements/paper_button_style_css.html">
+<link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html">
<link rel="import" href="chrome://resources/html/action_link.html">
<link rel="import" href="chrome://resources/html/action_link_css.html">
<link rel="import" href="chrome://resources/html/assert.html">
<link rel="import" href="chrome://resources/html/cr.html">
<link rel="import" href="chrome://resources/html/i18n_behavior.html">
+<link rel="import" href="item_behavior.html">
<link rel="import" href="icons.html">
<link rel="import" href="item_util.html">
<link rel="import" href="strings.html">
@@ -17,16 +19,39 @@
<link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/iron-flex-layout-classes.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button-light.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-styles/shadow.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-tooltip/paper-tooltip.html">
<link rel="import" href="navigation_helper.html">
<dom-module id="extensions-item">
<template>
<style include=
"iron-flex cr-hidden-style cr-icons action-link paper-button-style">
+ .bounded-text,
+ .multiline-clippable-text,
+ .clippable-flex-text {
+ /** Ensure that the text does not overflow its container. */
+ overflow: hidden;
+ text-overflow: ellipsis;
+ }
+
+ .bounded-text,
+ .clippable-flex-text {
+ white-space: nowrap;
+ }
+
+ .clipppable-flex-text {
+ /**
+ * These labels can be arbitrarily long. We want to ensure that these
+ * shrink, rather than the neighboring content.
+ */
+ flex-shrink: 1;
+ }
+
#icon-wrapper {
align-self: flex-start;
display: flex;
padding: 6px;
+ position: relative;
}
#icon {
@@ -37,6 +62,7 @@
#card {
@apply(--shadow-elevation-2dp);
background: white;
+ border-radius: 2px;
display: flex;
flex-direction: column;
height: 160px;
@@ -49,16 +75,16 @@
#main {
display: flex;
- flex-grow: 1;
+ flex: 1;
padding: 16px 20px 17px;
- position: relative;
}
#content {
-webkit-margin-start: 24px;
display: flex;
+ flex: 1;
flex-direction: column;
- width: 100%;
+ overflow: hidden;
}
#name-and-version {
@@ -70,9 +96,13 @@
-webkit-margin-end: 8px;
}
- #description,
+ #description {
+ flex: 1;
+ }
+
#warnings {
- flex-grow: 1;
+ color: var(--google-red-700);
+ flex: 1;
margin-bottom: 8px;
}
@@ -86,23 +116,42 @@
font-weight: 400;
}
+ #extension-id {
+ flex-shrink: 0;
+ }
+
+ #inspect-views {
+ display: flex;
+ white-space: nowrap;
+ }
+
+ #inspect-views > span {
+ -webkit-margin-end: 4px;
+ }
+
#button-strip {
- -webkit-padding-end: 4px;
- -webkit-padding-start: var(--cr-section-padding);
+ /* Avoid ripple from overlapping container. */
+ -webkit-margin-end: 20px;
border-top: var(--cr-separator-line);
box-sizing: border-box;
+ flex-shrink: 0;
height: var(--cr-section-min-height);
padding-bottom: 8px;
padding-top: 8px;
}
#button-strip paper-button {
- margin: 0 4px;
+ -webkit-margin-start: 8px;
+ }
+
+ #learn-more-link {
+ color: var(--google-blue-700);
+ text-decoration: none;
}
#source-indicator {
- -webkit-margin-start: 30px;
- margin-top: 30px;
+ -webkit-margin-start: 24px;
+ margin-top: 24px;
position: absolute;
}
@@ -124,30 +173,11 @@
width: 16px;
}
- #source-indicator-text {
- -webkit-margin-start: 11px; /* To align with the center of the icon. */
- background: black;
- border-radius: 2px;
- color: white;
- display: none;
- margin-top: 8px;
- max-width: 150px;
- opacity: 0.6;
- padding: 8px 12px;
- transform: translateX(-50%); /* Move back 50% of width so that the
- text and icon share an x-center. */
- }
-
- :host-context([dir='rtl']) #source-indicator-text {
- transform: translateX(50%);
- }
-
- #source-indicator:hover #source-indicator-text {
- display: block;
- }
-
- cr-toggle {
- -webkit-margin-end: 8px; /* Avoid ripple from overlapping container. */
+ paper-tooltip {
+ --paper-tooltip: {
+ @apply(--cr-tooltip);
+ min-width: 0;
+ };
}
.action-button {
@@ -162,68 +192,92 @@
-webkit-margin-end: 12px;
}
- #warnings {
- color: var(--google-red-700);
- }
-
#blacklisted-warning:empty {
display: none;
}
</style>
<div id="card" class$="[[computeClasses_(data.state, inDevMode)]]">
<div id="main">
+ <div id="icon-wrapper">
+ <img id="icon" src="[[data.iconUrl]]"
+ alt$="[[appOrExtension(
+ data.type,
+ '$i18nPolymer{appIcon}',
+ '$i18nPolymer{extensionIcon}')]]">
+ <template is="dom-if"
+ if="[[computeSourceIndicatorIcon_(data.*)]]">
+ <div id="source-indicator">
+ <div class="source-icon-wrapper" role="img"
+ aria-label$="[[computeSourceIndicatorText_(data.*)]]">
+ <iron-icon icon="[[computeSourceIndicatorIcon_(data.*)]]">
+ </iron-icon>
+ </div>
+ </div>
+ </template>
+ </div>
+ <!-- This needs to be separate from the source-indicator since it can't
+ be contained inside of a position:relative parent element. -->
<template is="dom-if"
if="[[computeSourceIndicatorIcon_(data.*)]]">
- <div id="source-indicator">
- <div class="source-icon-wrapper">
- <iron-icon icon="[[computeSourceIndicatorIcon_(data.*)]]">
- </iron-icon>
- </div>
- <div id="source-indicator-text">
- [[computeSourceIndicatorText_(data.*)]]
- </div>
- </div>
+ <paper-tooltip id="source-indicator-text" for="source-indicator"
+ position="top" fit-to-visible-bounds>
+ [[computeSourceIndicatorText_(data.*)]]
+ </paper-tooltip>
</template>
- <div id="icon-wrapper">
- <img alt="" id="icon" src="[[data.iconUrl]]">
- </div>
<div id="content">
- <div id="name-and-version" class="layout horizontal center">
- <div id="name">[[data.name]]</div>
- <template is="dom-if" if="[[inDevMode]]">
- <span id="version">[[data.version]]</span>
- </template>
+ <!--Note: We wrap inspect-views in a div so that the outer div
+ doesn't shrink (because it's not display: flex).-->
+ <div>
+ <div id="name-and-version" class="layout horizontal center">
+ <div id="name" class="clippable-flex-text">[[data.name]]</div>
+ <span id="version" hidden$="[[!inDevMode]]">
+ [[data.version]]
+ </span>
+ </div>
</div>
- <div id="description" hidden$="[[hasWarnings_(data.*)]]">
+ <div id="description" class="multiline-clippable-text"
+ hidden$="[[hasWarnings_(data.*)]]">
[[data.description]]
</div>
- <div id="warnings" hidden$="[[!hasWarnings_(data.*)]]">
- <div id="suspicious-warning"
- hidden$="[[!data.disableReasons.suspiciousInstall]]">
- $i18n{itemSuspiciousInstall}
- </div>
- <div id="corrupted-warning"
- hidden$="[[!data.disableReasons.corruptInstall]]">
- $i18n{itemCorruptInstall}
+ <template is="dom-if" if="[[hasWarnings_(data.*)]]">
+ <div id="warnings" >
+ <div id="suspicious-warning"
+ hidden$="[[!data.disableReasons.suspiciousInstall]]">
+ $i18n{itemSuspiciousInstall}
+ <a target="_blank" id="learn-more-link"
+ href="$i18n{suspiciousInstallHelpUrl}">
+ $i18n{learnMore}
+ </a>
+ </div>
+ <div id="corrupted-warning"
+ hidden$="[[!data.disableReasons.corruptInstall]]">
+ $i18n{itemCorruptInstall}
+ </div>
+ <div id="blacklisted-warning"><!-- No whitespace
+ -->[[data.blacklistText]]<!-- so we can use :empty in css.
+ --></div>
</div>
- <div id="blacklisted-warning"><!-- No whitespace
- -->[[data.blacklistText]]<!-- so we can use :empty in css.
- --></div>
- </div>
+ </template>
<template is="dom-if" if="[[inDevMode]]">
- <div id="extension-id">[[data.id]]</div>
+ <div id="extension-id" class="bounded-text">[[data.id]]</div>
<template is="dom-if"
if="[[!computeInspectViewsHidden_(data.views)]]">
- <div id="inspect-views">
- <span>$i18n{itemInspectViews}</span>
- <a is="action-link" on-tap="onInspectTap_">
- [[computeFirstInspectLabel_(data.views)]]
- </a>
- <a is="action-link"
- hidden$="[[computeExtraViewsHidden_(data.views)]]"
- on-tap="onExtraInspectTap_">
- [[computeExtraInspectLabel_(data.views)]]
- </a>
+ <!--Note: We wrap inspect-views in a div so that the outer div
+ doesn't shrink (because it's not display: flex).-->
+ <div>
+ <div id="inspect-views">
+ <span>$i18n{itemInspectViews}</span>
+ <a class="clippable-flex-text" is="action-link"
+ title="[[computeFirstInspectTitle_(data.views)]]"
+ on-tap="onInspectTap_">
+ [[computeFirstInspectLabel_(data.views)]]
+ </a>
+ <a is="action-link"
+ hidden$="[[computeExtraViewsHidden_(data.views)]]"
+ on-tap="onExtraInspectTap_">
+ [[computeExtraInspectLabel_(data.views)]]
+ </a>
+ </div>
</div>
</template>
</template>
@@ -238,27 +292,36 @@
hidden="[[isControlled_(data.controlledInfo)]]">
$i18n{itemRemove}
</paper-button>
- <paper-button id="errors-button" on-tap="onErrorsTap_"
- hidden$="[[computeErrorsHidden_(data.*)]]">
- $i18n{itemErrors}
- </paper-button>
+ <template is="dom-if" if="[[shouldShowErrorsButton_(data.*)]]">
+ <paper-button id="errors-button" on-tap="onErrorsTap_">
+ $i18n{itemErrors}
+ </paper-button>
+ </template>
</div>
<template is="dom-if" if="[[!computeDevReloadButtonHidden_(data.*)]]">
<button id="dev-reload-button" is="paper-icon-button-light"
+ aria-label="$i18n{itemReload}"
class="icon-refresh no-overlap" on-tap="onReloadTap_">
</button>
</template>
- <paper-button id="repair-button" class="action-button"
- on-tap="onRepairTap_"
- hidden$="[[!data.disableReasons.corruptInstall]]">
- $i18n{itemRepair}
- </paper-button>
- <paper-button id="terminated-reload-button" on-tap="onReloadTap_"
- class="action-button"
- hidden$="[[!isTerminated_(data.state)]]">
- $i18n{itemReload}
- </paper-button>
+ <template is="dom-if" if="[[data.disableReasons.corruptInstall]]">
+ <paper-button id="repair-button" class="action-button"
+ on-tap="onRepairTap_">
+ $i18n{itemRepair}
+ </paper-button>
+ </template>
+ <template is="dom-if" if="[[isTerminated_(data.state)]]">
+ <paper-button id="terminated-reload-button" on-tap="onReloadTap_"
+ class="action-button">
+ $i18n{itemReload}
+ </paper-button>
+ </template>
<cr-toggle id="enable-toggle" class="action-button"
+ aria-label$="[[appOrExtension(
+ data.type,
+ '$i18nPolymer{appEnabled}',
+ '$i18nPolymer{extensionEnabled}')]]"
+ aria-describedby="name"
checked="[[isEnabled_(data.state)]]" on-change="onEnableChange_"
disabled="[[!isEnableToggleEnabled_(data.*)]]"
hidden$="[[!showEnableToggle_(data.*)]]">
diff --git a/chromium/chrome/browser/resources/md_extensions/item.js b/chromium/chrome/browser/resources/md_extensions/item.js
index f76a9fc0c95..f2fb9841cf1 100644
--- a/chromium/chrome/browser/resources/md_extensions/item.js
+++ b/chromium/chrome/browser/resources/md_extensions/item.js
@@ -44,20 +44,37 @@ cr.define('extensions', function() {
*/
inspectItemView(id, view) {}
- /** @param {string} id */
+ /**
+ * @param {string} url
+ */
+ openUrl(url) {}
+
+ /**
+ * @param {string} id
+ * @return {!Promise}
+ */
reloadItem(id) {}
/** @param {string} id */
repairItem(id) {}
+ /** @param {!chrome.developerPrivate.ExtensionInfo} extension */
+ showItemOptionsPage(extension) {}
+
/** @param {string} id */
- showItemOptionsPage(id) {}
+ showInFolder(id) {}
+
+ /**
+ * @param {string} id
+ * @return {!Promise<string>}
+ */
+ getExtensionSize(id) {}
}
const Item = Polymer({
is: 'extensions-item',
- behaviors: [I18nBehavior],
+ behaviors: [I18nBehavior, extensions.ItemBehavior],
properties: {
// The item's delegate, or null.
@@ -104,9 +121,17 @@ cr.define('extensions', function() {
* @return {boolean}
* @private
*/
- computeErrorsHidden_: function() {
- return !this.data.manifestErrors.length &&
- !this.data.runtimeErrors.length;
+ shouldShowErrorsButton_: function() {
+ // When the error console is disabled (happens when
+ // --disable-error-console command line flag is used or when in the
+ // Stable/Beta channel), |installWarnings| is populated.
+ if (this.data.installWarnings && this.data.installWarnings.length > 0)
+ return true;
+
+ // When error console is enabled |installedWarnings| is not populated.
+ // Instead |manifestErrors| and |runtimeErrors| are used.
+ return this.data.manifestErrors.length > 0 ||
+ this.data.runtimeErrors.length > 0;
},
/** @private */
@@ -122,6 +147,11 @@ cr.define('extensions', function() {
/** @private */
onErrorsTap_: function() {
+ if (this.data.installWarnings && this.data.installWarnings.length > 0) {
+ this.fire('show-install-warnings', this.data.installWarnings);
+ return;
+ }
+
extensions.navigation.navigateTo(
{page: Page.ERRORS, extensionId: this.data.id});
},
@@ -148,7 +178,9 @@ cr.define('extensions', function() {
/** @private */
onReloadTap_: function() {
- this.delegate.reloadItem(this.data.id);
+ this.delegate.reloadItem(this.data.id).catch(loadError => {
+ this.fire('load-error', loadError);
+ });
},
/** @private */
@@ -220,6 +252,9 @@ cr.define('extensions', function() {
return 'communication:business';
case SourceType.SIDELOADED:
return 'input';
+ case SourceType.UNKNOWN:
+ // TODO(dpapad): Ask UX for a better icon for this case.
+ return 'input';
case SourceType.UNPACKED:
return 'extensions-icons:unpacked';
case SourceType.WEBSTORE:
@@ -233,6 +268,9 @@ cr.define('extensions', function() {
* @private
*/
computeSourceIndicatorText_: function() {
+ if (this.data.locationText)
+ return this.data.locationText;
+
const sourceType = extensions.getItemSource(this.data);
return sourceType == SourceType.WEBSTORE ?
'' :
@@ -251,18 +289,24 @@ cr.define('extensions', function() {
* @return {string}
* @private
*/
- computeFirstInspectLabel_: function() {
+ computeFirstInspectTitle_: function() {
// Note: theoretically, this wouldn't be called without any inspectable
// views (because it's in a dom-if="!computeInspectViewsHidden_()").
// However, due to the recycling behavior of iron list, it seems that
// sometimes it can. Even when it is, the UI behaves properly, but we
// need to handle the case gracefully.
- if (this.data.views.length == 0)
- return '';
- let label = extensions.computeInspectableViewLabel(this.data.views[0]);
- if (this.data.views.length > 1)
- label += ',';
- return label;
+ return this.data.views.length > 0 ?
+ extensions.computeInspectableViewLabel(this.data.views[0]) :
+ '';
+ },
+
+ /**
+ * @return {string}
+ * @private
+ */
+ computeFirstInspectLabel_: function() {
+ let label = this.computeFirstInspectTitle_();
+ return label && this.data.views.length > 1 ? label + ',' : label;
},
/**
diff --git a/chromium/chrome/browser/resources/md_extensions/item_behavior.html b/chromium/chrome/browser/resources/md_extensions/item_behavior.html
new file mode 100644
index 00000000000..b0369e6dc6d
--- /dev/null
+++ b/chromium/chrome/browser/resources/md_extensions/item_behavior.html
@@ -0,0 +1 @@
+<script src="item_behavior.js"></script>
diff --git a/chromium/chrome/browser/resources/md_extensions/item_behavior.js b/chromium/chrome/browser/resources/md_extensions/item_behavior.js
new file mode 100644
index 00000000000..40241f5eb2d
--- /dev/null
+++ b/chromium/chrome/browser/resources/md_extensions/item_behavior.js
@@ -0,0 +1,30 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+cr.define('extensions', function() {
+ /** @polymerBehavior */
+ const ItemBehavior = {
+ /**
+ * @param {chrome.developerPrivate.ExtensionType} type
+ * @param {string} appLabel
+ * @param {string} extensionLabel
+ * @return {string} The app or extension label depending on |type|.
+ */
+ appOrExtension: function(type, appLabel, extensionLabel) {
+ const ExtensionType = chrome.developerPrivate.ExtensionType;
+ switch (type) {
+ case ExtensionType.HOSTED_APP:
+ case ExtensionType.LEGACY_PACKAGED_APP:
+ case ExtensionType.PLATFORM_APP:
+ return appLabel;
+ case ExtensionType.EXTENSION:
+ case ExtensionType.SHARED_MODULE:
+ return extensionLabel;
+ }
+ assertNotReached('Item type is not App or Extension.');
+ },
+ };
+
+ return {ItemBehavior: ItemBehavior};
+});
diff --git a/chromium/chrome/browser/resources/md_extensions/item_list.html b/chromium/chrome/browser/resources/md_extensions/item_list.html
index 13b0c0bc166..2ac11babaa0 100644
--- a/chromium/chrome/browser/resources/md_extensions/item_list.html
+++ b/chromium/chrome/browser/resources/md_extensions/item_list.html
@@ -3,19 +3,23 @@
<link rel="import" href="chrome://resources/cr_elements/cr_container_shadow_behavior.html">
<link rel="import" href="chrome://resources/cr_elements/shared_style_css.html">
<link rel="import" href="chrome://resources/html/cr.html">
+<link rel="import" href="chrome://resources/html/i18n_behavior.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/iron-a11y-announcer/iron-a11y-announcer.html">
<link rel="import" href="item.html">
<dom-module id="extensions-item-list">
<template>
<style include="cr-shared-style">
- #items-container,
+ .items-container,
extensions-item {
--extensions-card-width: 400px;
}
#container {
+ box-sizing: border-box;
height: 100%;
overflow: overlay;
+ padding: 24px 60px 64px;
}
.empty-list-message {
@@ -26,7 +30,7 @@
text-align: center;
}
- #items-container {
+ .items-container {
--grid-gutter: 12px;
--max-columns: 3;
display: grid;
@@ -37,33 +41,62 @@
margin: auto;
max-width: calc(var(--extensions-card-width) * var(--max-columns) +
var(--grid-gutter) * var(--max-columns));
- padding: calc(var(--grid-gutter) / 2);
}
extensions-item {
grid-column-start: auto;
grid-row-start: auto;
}
+
+ #app-title {
+ @apply(--cr-section-text);
+ margin-bottom: 12px;
+ margin-top: 21px;
+ }
</style>
<div id="container">
<div class="empty-list-message" hidden="[[!isGuest]]">
$i18n{guestModeMessage}
</div>
<div id="no-items" class="empty-list-message"
- hidden$="[[!shouldShowEmptyItemsMessage_(items.length)]]">
- <span>$i18nRaw{noExtensionsOrApps}</span>
+ hidden$="[[!shouldShowEmptyItemsMessage_(
+ apps.length, extensions.length)]]">
+ <span on-tap="onNoExtensionsTap_">$i18nRaw{noExtensionsOrApps}</span>
</div>
<div id="no-search-results" class="empty-list-message"
- hidden$="[[!shouldShowEmptySearchMessage_(shownItems_.length)]]">
+ hidden$="[[!shouldShowEmptySearchMessage_(
+ shownAppsCount_, shownExtensionsCount_, apps, extensions)]]">
<span>$i18n{noSearchResults}</span>
</div>
- <div id="items-container">
- <template is="dom-repeat" items="[[shownItems_]]">
- <extensions-item data="[[item]]" delegate="[[delegate]]"
- in-dev-mode="[[inDevMode]]">
+ <div class="items-container" hidden="[[!shownExtensionsCount_]]">
+ <!-- Render only a few items first, to improve initial render time, then
+ render the remaining items on a different frame. Value of 3 was chosen
+ by experimentation, and it is a good trade-off between initial render
+ time and total render time. -->
+ <template is="dom-repeat" items="[[extensions]]" initial-count="3"
+ filter="[[computedFilter_]]"
+ rendered-item-count="{{shownExtensionsCount_::dom-change}}"
+ notify-dom-change>
+ <extensions-item id="[[item.id]]" data="[[item]]"
+ delegate="[[delegate]]" in-dev-mode="[[inDevMode]]">
</extensions-item>
</template>
</div>
+ <div hidden="[[!shownAppsCount_]]">
+ <!-- app-title needs to left-align with the grid content below, and
+ the easiest way to achieve this is to make it a grid as well. -->
+ <h2 id="app-title" class="items-container">$i18n{appsTitle}</h2>
+ <div class="items-container">
+ <template is="dom-repeat" items="[[apps]]" initial-count="3"
+ filter="[[computedFilter_]]"
+ rendered-item-count="{{shownAppsCount_::dom-change}}"
+ notify-dom-change>
+ <extensions-item id="[[item.id]]" data="[[item]]"
+ delegate="[[delegate]]" in-dev-mode="[[inDevMode]]">
+ </extensions-item>
+ </template>
+ </div>
+ </div>
</div>
</template>
<script src="item_list.js"></script>
diff --git a/chromium/chrome/browser/resources/md_extensions/item_list.js b/chromium/chrome/browser/resources/md_extensions/item_list.js
index e6cd997e5ea..834f0cb4f4b 100644
--- a/chromium/chrome/browser/resources/md_extensions/item_list.js
+++ b/chromium/chrome/browser/resources/md_extensions/item_list.js
@@ -6,11 +6,14 @@ cr.define('extensions', function() {
const ItemList = Polymer({
is: 'extensions-item-list',
- behaviors: [CrContainerShadowBehavior],
+ behaviors: [CrContainerShadowBehavior, I18nBehavior],
properties: {
- /** @type {Array<!chrome.developerPrivate.ExtensionInfo>} */
- items: Array,
+ /** @type {!Array<!chrome.developerPrivate.ExtensionInfo>} */
+ apps: Array,
+
+ /** @type {!Array<!chrome.developerPrivate.ExtensionInfo>} */
+ extensions: Array,
/** @type {extensions.ItemDelegate} */
delegate: Object,
@@ -22,37 +25,90 @@ cr.define('extensions', function() {
isGuest: Boolean,
- filter: String,
+ filter: {
+ type: String,
+ },
- /** @private {Array<!chrome.developerPrivate.ExtensionInfo>} */
- shownItems_: {
- type: Array,
- computed: 'computeShownItems_(items.*, filter)',
- }
+ /** @private */
+ computedFilter_: {
+ type: String,
+ computed: 'computeFilter_(filter)',
+ observer: 'announceSearchResults_',
+ },
+
+ /** @private */
+ shownExtensionsCount_: {
+ type: Number,
+ value: 0,
+ },
+
+ /** @private */
+ shownAppsCount_: {
+ type: Number,
+ value: 0,
+ },
+ },
+
+ /**
+ * @param {string} id
+ * @return {?Element}
+ */
+ getDetailsButton: function(id) {
+ return this.$$(`#${id} /deep/ #details-button`);
},
/**
- * Computes the list of items to be shown.
- * @param {Object} changeRecord The changeRecord for |items|.
- * @param {string} filter The updated filter string.
- * @return {Array<!chrome.developerPrivate.ExtensionInfo>}
+ * @param {string} id
+ * @return {?Element}
+ */
+ getErrorsButton: function(id) {
+ return this.$$(`#${id} /deep/ #errors-button`);
+ },
+
+ /**
+ * Computes the filter function to be used for determining which items
+ * should be shown. A |null| value indicates that everything should be
+ * shown.
+ * return {?Function}
* @private
*/
- computeShownItems_: function(changeRecord, filter) {
+ computeFilter_: function() {
const formattedFilter = this.filter.trim().toLowerCase();
- return this.items.filter(
- item => item.name.toLowerCase().includes(formattedFilter));
+ return formattedFilter ?
+ i => i.name.toLowerCase().includes(formattedFilter) :
+ null;
},
/** @private */
shouldShowEmptyItemsMessage_: function() {
- return !this.isGuest && this.items.length === 0;
+ return !this.isGuest && this.apps.length === 0 &&
+ this.extensions.length === 0;
},
/** @private */
shouldShowEmptySearchMessage_: function() {
return !this.isGuest && !this.shouldShowEmptyItemsMessage_() &&
- this.shownItems_.length === 0;
+ this.shownAppsCount_ === 0 && this.shownExtensionsCount_ === 0;
+ },
+
+ /** @private */
+ onNoExtensionsTap_: function(e) {
+ if (e.target.tagName == 'A')
+ chrome.metricsPrivate.recordUserAction('Options_GetMoreExtensions');
+ },
+
+ /** @private */
+ announceSearchResults_: function() {
+ if (this.computedFilter_) {
+ Polymer.IronA11yAnnouncer.requestAvailability();
+ this.async(() => { // Async to allow list to update.
+ this.fire('iron-announce', {
+ text: this.shouldShowEmptySearchMessage_() ?
+ this.i18n('noSearchResults') :
+ this.i18n('searchResults', this.filter),
+ });
+ });
+ }
},
});
diff --git a/chromium/chrome/browser/resources/md_extensions/item_util.js b/chromium/chrome/browser/resources/md_extensions/item_util.js
index 5997a53b00f..aaefd16eb47 100644
--- a/chromium/chrome/browser/resources/md_extensions/item_util.js
+++ b/chromium/chrome/browser/resources/md_extensions/item_util.js
@@ -9,6 +9,7 @@ const SourceType = {
POLICY: 'policy',
SIDELOADED: 'sideloaded',
UNPACKED: 'unpacked',
+ UNKNOWN: 'unknown',
};
cr.define('extensions', function() {
@@ -74,11 +75,19 @@ cr.define('extensions', function() {
chrome.developerPrivate.ControllerType.POLICY) {
return SourceType.POLICY;
}
- if (item.location == chrome.developerPrivate.Location.THIRD_PARTY)
- return SourceType.SIDELOADED;
- if (item.location == chrome.developerPrivate.Location.UNPACKED)
- return SourceType.UNPACKED;
- return SourceType.WEBSTORE;
+
+ switch (item.location) {
+ case chrome.developerPrivate.Location.THIRD_PARTY:
+ return SourceType.SIDELOADED;
+ case chrome.developerPrivate.Location.UNPACKED:
+ return SourceType.UNPACKED;
+ case chrome.developerPrivate.Location.UNKNOWN:
+ return SourceType.UNKNOWN;
+ case chrome.developerPrivate.Location.FROM_STORE:
+ return SourceType.WEBSTORE;
+ }
+
+ assertNotReached(item.location);
}
/**
@@ -95,6 +104,10 @@ cr.define('extensions', function() {
return loadTimeData.getString('itemSourceUnpacked');
case SourceType.WEBSTORE:
return loadTimeData.getString('itemSourceWebstore');
+ case SourceType.UNKNOWN:
+ // Nothing to return. Calling code should use
+ // chrome.developerPrivate.ExtensionInfo's |locationText| instead.
+ return '';
}
assertNotReached();
}
@@ -123,33 +136,10 @@ cr.define('extensions', function() {
return label;
}
- /**
- * Returns the list type that the item belongs to.
- * @param {!chrome.developerPrivate.ExtensionInfo} item
- * @return {extensions.ShowingType}
- */
- function getItemListType(item) {
- const ExtensionType = chrome.developerPrivate.ExtensionType;
- switch (item.type) {
- case ExtensionType.HOSTED_APP:
- case ExtensionType.LEGACY_PACKAGED_APP:
- case ExtensionType.PLATFORM_APP:
- return extensions.ShowingType.APPS;
- case ExtensionType.EXTENSION:
- case ExtensionType.SHARED_MODULE:
- return extensions.ShowingType.EXTENSIONS;
- case ExtensionType.THEME:
- assertNotReached('Don\'t send themes to the chrome://extensions page');
- break;
- }
- assertNotReached();
- }
-
return {
isControlled: isControlled,
isEnabled: isEnabled,
userCanChangeEnablement: userCanChangeEnablement,
- getItemListType: getItemListType,
getItemSource: getItemSource,
getItemSourceString: getItemSourceString,
computeInspectableViewLabel: computeInspectableViewLabel
diff --git a/chromium/chrome/browser/resources/md_extensions/keyboard_shortcuts.html b/chromium/chrome/browser/resources/md_extensions/keyboard_shortcuts.html
index ecde827f4f7..854db3556e8 100644
--- a/chromium/chrome/browser/resources/md_extensions/keyboard_shortcuts.html
+++ b/chromium/chrome/browser/resources/md_extensions/keyboard_shortcuts.html
@@ -7,30 +7,37 @@
<link rel="import" href="chrome://resources/html/md_select_css.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-styles/color.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-styles/shadow.html">
+<link rel="import" href="item_behavior.html">
<link rel="import" href="shortcut_input.html">
<dom-module id="extensions-keyboard-shortcuts">
<template>
<style include="md-select cr-shared-style">
:host {
+ --card-max-width: 928px;
+ --card-min-width: 600px;
height: 100%;
}
- #container {
- height: 100%;
- overflow: overlay;
- padding-top: 24px;
+ .shortcut-card {
+ margin: 0 auto 16px auto;
+ max-width: var(--card-max-width);
+ min-width: var(--card-min-width);
+ width: 90%;
}
.shortcut-card {
- @apply(--cr-primary-text);
- @apply(--shadow-elevation-2dp);
+ @apply --cr-primary-text;
+ @apply --shadow-elevation-2dp;
background-color: white;
- margin: 0 auto 16px auto;
- max-width: 928px;
- min-width: 600px;
padding-bottom: 8px;
- width: 90%;
+ }
+
+ #container {
+ box-sizing: border-box;
+ height: 100%;
+ overflow: overlay;
+ padding-top: 24px;
}
.command-entry {
@@ -64,7 +71,7 @@
display: flex;
margin-bottom: 9px;
padding: 16px var(--cr-section-padding);
- @apply(--cr-title-text);
+ @apply --cr-title-text;
}
.icon {
@@ -84,15 +91,19 @@
<template is="dom-repeat" items="[[calculateShownItems_(items.*)]]">
<div class="shortcut-card">
<div class="card-title">
- <img class="icon" src="[[item.iconUrl]]">
+ <img class="icon" src="[[item.iconUrl]]"
+ alt$="[[appOrExtension(
+ item.type,
+ '$i18nPolymer{appIcon}',
+ '$i18nPolymer{extensionIcon}')]]">
<span>[[item.name]]</span>
</div>
<div class="card-controls">
<template is="dom-repeat" items="[[item.commands]]" as="command">
<div class="command-entry" command="[[command]]">
<span class="command-name">[[command.description]]</span>
- <extensions-shortcut-input item="[[item.id]]"
- shortcut="[[command.keybinding]]"
+ <extensions-shortcut-input delegate="[[delegate]]"
+ item="[[item.id]]" shortcut="[[command.keybinding]]"
command-name="[[command.name]]">
</extensions-shortcut-input>
<div class="md-select-wrapper">
diff --git a/chromium/chrome/browser/resources/md_extensions/keyboard_shortcuts.js b/chromium/chrome/browser/resources/md_extensions/keyboard_shortcuts.js
index e75b5cecdab..1baad321ca1 100644
--- a/chromium/chrome/browser/resources/md_extensions/keyboard_shortcuts.js
+++ b/chromium/chrome/browser/resources/md_extensions/keyboard_shortcuts.js
@@ -9,7 +9,7 @@ cr.define('extensions', function() {
const KeyboardShortcuts = Polymer({
is: 'extensions-keyboard-shortcuts',
- behaviors: [CrContainerShadowBehavior],
+ behaviors: [CrContainerShadowBehavior, extensions.ItemBehavior],
properties: {
/** @type {Array<!chrome.developerPrivate.ExtensionInfo>} */
@@ -25,6 +25,15 @@ cr.define('extensions', function() {
},
},
+ listeners: {
+ 'view-enter-start': 'onViewEnter_',
+ },
+
+ /** @private */
+ onViewEnter_: function() {
+ chrome.metricsPrivate.recordUserAction('Options_ExtensionCommands');
+ },
+
/**
* @return {!Array<!chrome.developerPrivate.ExtensionInfo>}
* @private
diff --git a/chromium/chrome/browser/resources/md_extensions/kiosk_dialog.html b/chromium/chrome/browser/resources/md_extensions/kiosk_dialog.html
index 51100a4ec56..2709a38694b 100644
--- a/chromium/chrome/browser/resources/md_extensions/kiosk_dialog.html
+++ b/chromium/chrome/browser/resources/md_extensions/kiosk_dialog.html
@@ -12,6 +12,7 @@
<link rel="import" href="chrome://resources/polymer/v1_0/paper-checkbox/paper-checkbox.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button-light.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-input/paper-input.html">
+<link rel="import" href="item_behavior.html">
<link rel="import" href="kiosk_browser_proxy.html">
<dom-module id="extensions-kiosk-dialog">
@@ -82,7 +83,11 @@
<template is="dom-repeat" items="[[apps_]]">
<div class="list-item">
<div class="item-name">
- <img class="item-icon" src="[[item.iconURL]]">
+ <img class="item-icon" src="[[item.iconURL]]"
+ alt$="[[appOrExtension(
+ data.type,
+ '$i18nPolymer{appIcon}',
+ '$i18nPolymer{extensionIcon}')]]">
[[item.name]]
<span hidden="[[!item.autoLaunch]]">
$i18n{kioskAutoLaunch}
diff --git a/chromium/chrome/browser/resources/md_extensions/kiosk_dialog.js b/chromium/chrome/browser/resources/md_extensions/kiosk_dialog.js
index 254c2c14d81..66ada3fbebc 100644
--- a/chromium/chrome/browser/resources/md_extensions/kiosk_dialog.js
+++ b/chromium/chrome/browser/resources/md_extensions/kiosk_dialog.js
@@ -7,7 +7,7 @@ cr.define('extensions', function() {
const KioskDialog = Polymer({
is: 'extensions-kiosk-dialog',
- behaviors: [WebUIListenerBehavior],
+ behaviors: [WebUIListenerBehavior, extensions.ItemBehavior],
properties: {
/** @private {?string} */
addAppInput_: {
diff --git a/chromium/chrome/browser/resources/md_extensions/load_error.html b/chromium/chrome/browser/resources/md_extensions/load_error.html
index 0d0f1237a5c..d970402508e 100644
--- a/chromium/chrome/browser/resources/md_extensions/load_error.html
+++ b/chromium/chrome/browser/resources/md_extensions/load_error.html
@@ -6,6 +6,7 @@
<link rel="import" href="chrome://resources/html/assert.html">
<link rel="import" href="chrome://resources/html/cr.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-spinner/paper-spinner.html">
<link rel="import" href="code_section.html">
<dom-module id="extensions-load-error">
@@ -38,10 +39,12 @@
</extensions-code-section>
</div>
<div slot="button-container">
+ <paper-spinner active="[[retrying_]]"></paper-spinner>
<paper-button class="cancel-button" on-tap="close">
$i18n{loadErrorCancel}
</paper-button>
- <paper-button class="action-button" on-tap="onRetryTap_">
+ <paper-button class="action-button" disabled="[[retrying_]]"
+ on-tap="onRetryTap_">
$i18n{loadErrorRetry}
</paper-button>
</div>
diff --git a/chromium/chrome/browser/resources/md_extensions/load_error.js b/chromium/chrome/browser/resources/md_extensions/load_error.js
index 67391a189ff..8c22a6b8d17 100644
--- a/chromium/chrome/browser/resources/md_extensions/load_error.js
+++ b/chromium/chrome/browser/resources/md_extensions/load_error.js
@@ -10,6 +10,7 @@ cr.define('extensions', function() {
/**
* Attempts to load the previously-attempted unpacked extension.
* @param {string} retryId
+ * @return {!Promise}
*/
retryLoadUnpacked(retryId) {}
}
@@ -22,6 +23,9 @@ cr.define('extensions', function() {
/** @type {chrome.developerPrivate.LoadError} */
loadError: Object,
+
+ /** @private */
+ retrying_: Boolean,
},
observers: [
@@ -38,8 +42,18 @@ cr.define('extensions', function() {
/** @private */
onRetryTap_: function() {
- this.delegate.retryLoadUnpacked(this.loadError.retryGuid);
- this.close();
+ this.retrying_ = true;
+ this.delegate.retryLoadUnpacked(this.loadError.retryGuid)
+ .then(
+ () => {
+ this.close();
+ },
+ loadError => {
+ this.loadError =
+ /** @type {chrome.developerPrivate.LoadError} */ (
+ loadError);
+ this.retrying_ = false;
+ });
},
/** @private */
diff --git a/chromium/chrome/browser/resources/md_extensions/manager.html b/chromium/chrome/browser/resources/md_extensions/manager.html
index c38263894b1..c4fcc5b96c5 100644
--- a/chromium/chrome/browser/resources/md_extensions/manager.html
+++ b/chromium/chrome/browser/resources/md_extensions/manager.html
@@ -1,15 +1,15 @@
<link rel="import" href="chrome://resources/html/polymer.html">
<link rel="import" href="chrome://resources/cr_elements/cr_drawer/cr_drawer.html">
+<link rel="import" href="chrome://resources/cr_elements/cr_lazy_render/cr_lazy_render.html">
<link rel="import" href="chrome://resources/cr_elements/cr_toolbar/cr_toolbar.html">
<link rel="import" href="chrome://resources/cr_elements/hidden_style_css.html">
<link rel="import" href="chrome://resources/html/assert.html">
<link rel="import" href="chrome://resources/html/cr.html">
-<link rel="import" href="chrome://resources/html/i18n_behavior.html">
-<link rel="import" href="chrome://resources/html/promise_resolver.html">
<link rel="import" href="detail_view.html">
<link rel="import" href="drop_overlay.html">
<link rel="import" href="error_page.html">
+<link rel="import" href="install_warnings_dialog.html">
<link rel="import" href="item_list.html">
<link rel="import" href="item_util.html">
<link rel="import" href="keyboard_shortcuts.html">
@@ -65,42 +65,64 @@
</if>
>
</extensions-toolbar>
- <dialog id="drawer" is="cr-drawer" heading="$i18n{toolbarTitle}"
- align="$i18n{textdirection}">
- <div class="drawer-content">
- <extensions-sidebar id="sidebar"></extensions-sidebar>
- </div>
- </dialog>
+ <template is="dom-if" if="[[showDrawer_]]" restamp>
+ <dialog id="drawer" is="cr-drawer" heading="$i18n{toolbarTitle}"
+ align="$i18n{textdirection}" on-close="onDrawerClose_">
+ <div class="drawer-content">
+ <extensions-sidebar id="sidebar"></extensions-sidebar>
+ </div>
+ </dialog>
+ </template>
<extensions-view-manager id="viewManager" role="main">
- <extensions-item-list id="items-list" items="[[itemsList_]]"
+ <extensions-item-list id="items-list" is-guest="[[isGuest_]]"
delegate="[[delegate]]" in-dev-mode="[[inDevMode]]"
filter="[[filter]]" hidden$="[[!didInitPage_]]" slot="view"
- is-guest="[[isGuest_]]">
+ apps="[[apps_]]" extensions="[[extensions_]]"
+ on-show-install-warnings="onShowInstallWarnings_">
</extensions-item-list>
- <extensions-detail-view id="details-view" delegate="[[delegate]]"
- in-dev-mode="[[inDevMode]]" data="[[detailViewItem_]]"
- slot="view">
- </extensions-detail-view>
- <extensions-keyboard-shortcuts id="keyboard-shortcuts"
- items="[[extensions]]" slot="view">
- </extensions-keyboard-shortcuts>
- <extensions-error-page id="error-page"
- data="[[errorPageItem_]]" delegate="[[delegate]]" slot="view">
- </extensions-error-page>
+ <template id="details-view" is="cr-lazy-render">
+ <extensions-detail-view delegate="[[delegate]]" slot="view"
+ in-dev-mode="[[inDevMode]]" data="[[detailViewItem_]]">
+ </extensions-detail-view>
+ </template>
+ <template id="keyboard-shortcuts" is="cr-lazy-render">
+ <extensions-keyboard-shortcuts delegate="[[delegate]]" slot="view"
+ items="[[extensions_]]">
+ </extensions-keyboard-shortcuts>
+ </template>
+ <template id="error-page" is="cr-lazy-render">
+ <extensions-error-page data="[[errorPageItem_]]" slot="view"
+ delegate="[[delegate]]" slot="view">
+ </extensions-error-page>
+ </template>
</extensions-view-manager>
- <extensions-options-dialog id="options-dialog">
- </extensions-options-dialog>
- <extensions-pack-dialog id="pack-dialog" delegate="[[delegate]]">
- </extensions-pack-dialog>
- <extensions-load-error id="load-error" delegate="[[delegate]]">
- </extensions-load-error>
+ <template is="dom-if" if="[[showOptionsDialog_]]" restamp>
+ <extensions-options-dialog id="options-dialog"
+ on-close="onOptionsDialogClose_">
+ </extensions-options-dialog>
+ </template>
+ <template is="dom-if" if="[[showPackDialog_]]" restamp>
+ <extensions-pack-dialog id="pack-dialog" delegate="[[delegate]]"
+ on-close="onPackDialogClose_">
+ </extensions-pack-dialog>
+ </template>
+ <template is="dom-if" if="[[showLoadErrorDialog_]]" restamp>
+ <extensions-load-error id="load-error" delegate="[[delegate]]"
+ on-close="onLoadErrorDialogClose_">
+ </extensions-load-error>
+ </template>
<if expr="chromeos">
<template is="dom-if" if="[[showKioskDialog_]]" restamp>
- <extensions-kiosk-dialog id="kiosk-dialog"
- on-close="onKioskDialogClose_">
+ <extensions-kiosk-dialog id="kiosk-dialog" on-close="onKioskDialogClose_">
</extensions-kiosk-dialog>
</template>
</if>
+ <template is="dom-if" if="[[showInstallWarningsDialog_]]" restamp>
+ <extensions-install-warnings-dialog
+ on-close="onInstallWarningsDialogClose_"
+ install-warnings="[[installWarnings_]]">
+ </extensions-install-warnings-dialog>
+ </template>
</template>
<script src="manager.js"></script>
</dom-module>
diff --git a/chromium/chrome/browser/resources/md_extensions/manager.js b/chromium/chrome/browser/resources/md_extensions/manager.js
index eb197cabeb3..8d434ead827 100644
--- a/chromium/chrome/browser/resources/md_extensions/manager.js
+++ b/chromium/chrome/browser/resources/md_extensions/manager.js
@@ -32,15 +32,15 @@ cr.define('extensions', function() {
const Manager = Polymer({
is: 'extensions-manager',
- behaviors: [I18nBehavior],
-
properties: {
- /** @type {extensions.Toolbar} */
- toolbar: Object,
-
// This is not typed because it implements multiple interfaces, and is
// passed to different elements as different types.
- delegate: Object,
+ delegate: {
+ type: Object,
+ value: function() {
+ return extensions.Service.getInstance();
+ },
+ },
isGuest_: {
type: Boolean,
@@ -51,7 +51,7 @@ cr.define('extensions', function() {
inDevMode: {
type: Boolean,
- value: false,
+ value: () => loadTimeData.getBoolean('inDevMode'),
},
filter: {
@@ -76,29 +76,11 @@ cr.define('extensions', function() {
*/
detailViewItem_: Object,
- /** @type {!Array<!chrome.developerPrivate.ExtensionInfo>} */
- extensions: {
- type: Array,
- value: function() {
- return [];
- },
- },
+ /** @private {!Array<!chrome.developerPrivate.ExtensionInfo>} */
+ extensions_: Array,
- /** @type {!Array<!chrome.developerPrivate.ExtensionInfo>} */
- apps: {
- type: Array,
- value: function() {
- return [];
- },
- },
-
- /** @private {extensions.ShowingType} */
- listType_: Number,
-
- itemsList_: {
- type: Array,
- computed: 'computeList_(listType_)',
- },
+ /** @private {!Array<!chrome.developerPrivate.ExtensionInfo>} */
+ apps_: Array,
/**
* Prevents page content from showing before data is first loaded.
@@ -109,6 +91,24 @@ cr.define('extensions', function() {
value: false,
},
+ /** @private */
+ showDrawer_: Boolean,
+
+ /** @private */
+ showLoadErrorDialog_: Boolean,
+
+ /** @private */
+ showInstallWarningsDialog_: Boolean,
+
+ /** @private {?Array<string>} */
+ installWarnings_: Array,
+
+ /** @private */
+ showOptionsDialog_: Boolean,
+
+ /** @private */
+ showPackDialog_: Boolean,
+
// <if expr="chromeos">
/** @private */
kioskEnabled_: {
@@ -124,30 +124,47 @@ cr.define('extensions', function() {
// </if>
},
+ listeners: {
+ 'load-error': 'onLoadError_',
+ 'view-exit-finish': 'onViewExitFinish_',
+ },
+
/**
- * The current page being shown. Default to null, and initPage will figure
+ * The current page being shown. Default to null, and initPage_ will figure
* out the initial page based on url.
* @private {?PageState}
*/
currentPage_: null,
/**
- * The ID of the listner on |extensions.navigation|. Stored so that the
+ * The ID of the listener on |extensions.navigation|. Stored so that the
* listener can be removed when this element is detached (happens in tests).
* @private {?number}
*/
navigationListener_: null,
/** @override */
- created: function() {
- this.readyPromiseResolver = new PromiseResolver();
- },
-
- /** @override */
ready: function() {
- this.toolbar =
- /** @type {extensions.Toolbar} */ (this.$$('extensions-toolbar'));
- this.readyPromiseResolver.resolve();
+ if (loadTimeData.getBoolean('isGuest')) {
+ this.initPage_();
+ return;
+ }
+
+ let service = extensions.Service.getInstance();
+
+ let onProfileStateChanged = profileInfo => {
+ this.inDevMode = profileInfo.inDeveloperMode;
+ };
+ service.getProfileStateChangedTarget().addListener(onProfileStateChanged);
+ service.getProfileConfiguration().then(onProfileStateChanged);
+
+ service.getExtensionsInfo().then(extensionsAndApps => {
+ this.initExtensionsAndApps_(extensionsAndApps);
+ this.initPage_();
+
+ service.getItemStateChangedTarget().addListener(
+ this.onItemStateChanged_.bind(this));
+ });
// <if expr="chromeos">
extensions.KioskBrowserProxyImpl.getInstance()
@@ -160,6 +177,9 @@ cr.define('extensions', function() {
/** @override */
attached: function() {
+ document.documentElement.classList.remove('loading');
+ document.fonts.load('bold 12px Roboto');
+
this.navigationListener_ = extensions.navigation.addListener(newPage => {
this.changePage_(newPage);
});
@@ -171,72 +191,93 @@ cr.define('extensions', function() {
this.navigationListener_ = null;
},
- get keyboardShortcuts() {
- return this.$['keyboard-shortcuts'];
- },
-
- get packDialog() {
- return this.$['pack-dialog'];
- },
-
- get loadError() {
- return this.$['load-error'];
- },
-
- get optionsDialog() {
- return this.$['options-dialog'];
- },
-
- get errorPage() {
- return this.$['error-page'];
- },
-
/**
* Initializes the page to reflect what's specified in the url so that if
* the user visits chrome://extensions/?id=..., we land on the proper page.
+ * @private
*/
- initPage: function() {
+ initPage_: function() {
this.didInitPage_ = true;
this.changePage_(extensions.navigation.getCurrentPage());
},
/**
+ * @param {!chrome.developerPrivate.EventData} eventData
+ * @private
+ */
+ onItemStateChanged_: function(eventData) {
+ const EventType = chrome.developerPrivate.EventType;
+ switch (eventData.event_type) {
+ case EventType.VIEW_REGISTERED:
+ case EventType.VIEW_UNREGISTERED:
+ case EventType.INSTALLED:
+ case EventType.LOADED:
+ case EventType.UNLOADED:
+ case EventType.ERROR_ADDED:
+ case EventType.ERRORS_REMOVED:
+ case EventType.PREFS_CHANGED:
+ // |extensionInfo| can be undefined in the case of an extension
+ // being unloaded right before uninstallation. There's nothing to do
+ // here.
+ if (!eventData.extensionInfo)
+ break;
+
+ const listId = this.getListId_(eventData.extensionInfo);
+ const currentIndex = this[listId].findIndex(
+ item => item.id == eventData.extensionInfo.id);
+
+ if (currentIndex >= 0) {
+ this.updateItem_(listId, currentIndex, eventData.extensionInfo);
+ } else {
+ this.addItem_(listId, eventData.extensionInfo);
+ }
+ break;
+ case EventType.UNINSTALLED:
+ this.removeItem_(eventData.item_id);
+ break;
+ default:
+ assertNotReached();
+ }
+ },
+
+ /**
* @param {!CustomEvent} event
* @private
*/
onFilterChanged_: function(event) {
+ if (this.currentPage_.page !== Page.LIST)
+ extensions.navigation.navigateTo({page: Page.LIST});
this.filter = /** @type {string} */ (event.detail);
},
/** @private */
onMenuButtonTap_: function() {
- this.$.drawer.openDrawer();
-
- // Sidebar needs manager to inform it of what to highlight since it
- // has no access to item-specific page.
- let page = extensions.navigation.getCurrentPage();
- if (page.extensionId) {
- // Find out what type of item we're looking at, and replace page info
- // with that list type.
- const data = assert(this.getData_(page.extensionId));
- page = {page: Page.LIST, type: extensions.getItemListType(data)};
- }
-
- this.$.sidebar.updateSelected(page);
+ this.showDrawer_ = true;
+ this.async(() => {
+ this.$$('#drawer').openDrawer();
+ });
},
/**
- * @param {chrome.developerPrivate.ExtensionInfo} item
+ * @param {!chrome.developerPrivate.ExtensionInfo} item
* @return {string} The ID of the list that the item belongs in.
* @private
*/
getListId_: function(item) {
- const type = extensions.getItemListType(item);
- if (type == extensions.ShowingType.APPS)
- return 'apps';
- else if (type == extensions.ShowingType.EXTENSIONS)
- return 'extensions';
-
+ const ExtensionType = chrome.developerPrivate.ExtensionType;
+ switch (item.type) {
+ case ExtensionType.HOSTED_APP:
+ case ExtensionType.LEGACY_PACKAGED_APP:
+ case ExtensionType.PLATFORM_APP:
+ return 'apps_';
+ case ExtensionType.EXTENSION:
+ case ExtensionType.SHARED_MODULE:
+ return 'extensions_';
+ case ExtensionType.THEME:
+ assertNotReached(
+ 'Don\'t send themes to the chrome://extensions page');
+ break;
+ }
assertNotReached();
},
@@ -257,8 +298,27 @@ cr.define('extensions', function() {
* @private
*/
getData_: function(id) {
- return this.extensions[this.getIndexInList_('extensions', id)] ||
- this.apps[this.getIndexInList_('apps', id)];
+ return this.extensions_[this.getIndexInList_('extensions_', id)] ||
+ this.apps_[this.getIndexInList_('apps_', id)];
+ },
+
+ /**
+ * Categorizes |extensionsAndApps| to apps and extensions and initializes
+ * those lists.
+ * @param {!Array<!chrome.developerPrivate.ExtensionInfo>} extensionsAndApps
+ * @private
+ */
+ initExtensionsAndApps_: function(extensionsAndApps) {
+ extensionsAndApps.sort(compareExtensions);
+ let apps = [];
+ let extensions = [];
+ for (let i of extensionsAndApps) {
+ let list = this.getListId_(i) === 'apps_' ? apps : extensions;
+ list.push(i);
+ }
+
+ this.apps_ = apps;
+ this.extensions_ = extensions;
},
/**
@@ -266,9 +326,9 @@ cr.define('extensions', function() {
* into its sorted position in the relevant section.
* @param {!chrome.developerPrivate.ExtensionInfo} item The extension
* the new element is representing.
+ * @private
*/
- addItem: function(item) {
- const listId = this.getListId_(item);
+ addItem_: function(listId, item) {
// We should never try and add an existing item.
assert(this.getIndexInList_(listId, item.id) == -1);
let insertBeforeChild = this[listId].findIndex(function(listEl) {
@@ -282,10 +342,9 @@ cr.define('extensions', function() {
/**
* @param {!chrome.developerPrivate.ExtensionInfo} item The data for the
* item to update.
+ * @private
*/
- updateItem: function(item) {
- const listId = this.getListId_(item);
- const index = this.getIndexInList_(listId, item.id);
+ updateItem_: function(listId, index, item) {
// We should never try and update a non-existent item.
assert(index >= 0);
this.set([listId, index], item);
@@ -306,36 +365,43 @@ cr.define('extensions', function() {
},
/**
- * @param {!chrome.developerPrivate.ExtensionInfo} item The data for the
- * item to remove.
+ * @param {string} itemId The id of item to remove.
+ * @private
*/
- removeItem: function(item) {
- const listId = this.getListId_(item);
- const index = this.getIndexInList_(listId, item.id);
+ removeItem_: function(itemId) {
+ // Search for the item to be deleted in |extensions_|.
+ let listId = 'extensions_';
+ let index = this.getIndexInList_(listId, itemId);
+ if (index == -1) {
+ // If not in |extensions_| it must be in |apps_|.
+ listId = 'apps_';
+ index = this.getIndexInList_(listId, itemId);
+ }
+
// We should never try and remove a non-existent item.
assert(index >= 0);
this.splice(listId, index, 1);
+ if ((this.currentPage_.page == Page.DETAILS ||
+ this.currentPage_.page == Page.ERRORS) &&
+ this.currentPage_.extensionId == itemId) {
+ // Leave the details page (the 'list' page is a fine choice).
+ extensions.navigation.replaceWith({page: Page.LIST});
+ }
},
/**
- * @param {Page} page
- * @return {!(extensions.KeyboardShortcuts |
- * extensions.DetailView |
- * extensions.ItemList)}
+ * @param {!CustomEvent} e
* @private
*/
- getPage_: function(page) {
- switch (page) {
- case Page.LIST:
- return this.$['items-list'];
- case Page.DETAILS:
- return this.$['details-view'];
- case Page.SHORTCUTS:
- return this.$['keyboard-shortcuts'];
- case Page.ERRORS:
- return this.$['error-page'];
- }
- assertNotReached();
+ onLoadError_: function(e) {
+ const loadError =
+ /** @type {!chrome.developerPrivate.LoadError} */ (e.detail);
+ this.showLoadErrorDialog_ = true;
+ this.async(() => {
+ const dialog = this.$$('#load-error');
+ dialog.loadError = loadError;
+ dialog.show();
+ });
},
/**
@@ -344,18 +410,29 @@ cr.define('extensions', function() {
* @private
*/
changePage_: function(newPage) {
- this.$.drawer.closeDrawer();
- if (this.optionsDialog && this.optionsDialog.open)
- this.optionsDialog.close();
+ const drawer = this.$$('#drawer');
+ if (drawer && drawer.open) {
+ drawer.closeDrawer();
+ this.showDrawer_ = false;
+ }
+
+ const optionsDialog = this.$$('#options-dialog');
+ if (optionsDialog && optionsDialog.open) {
+ optionsDialog.close();
+ this.showOptionsDialog_ = false;
+ }
const fromPage = this.currentPage_ ? this.currentPage_.page : null;
const toPage = newPage.page;
let data;
- if (newPage.extensionId)
- data = assert(this.getData_(newPage.extensionId));
-
- if (newPage.hasOwnProperty('type'))
- this.listType_ = /** @type {extensions.ShowingType} */ (newPage.type);
+ if (newPage.extensionId) {
+ data = this.getData_(newPage.extensionId);
+ if (!data) {
+ // Attempting to view an invalid (removed?) app or extension ID.
+ extensions.navigation.replaceWith({page: Page.LIST});
+ return;
+ }
+ }
if (toPage == Page.DETAILS)
this.detailViewItem_ = assert(data);
@@ -365,23 +442,84 @@ cr.define('extensions', function() {
if (fromPage != toPage) {
/** @type {extensions.ViewManager} */ (this.$.viewManager)
.switchView(toPage);
- } else {
- /** @type {extensions.ViewManager} */ (this.$.viewManager)
- .animateCurrentView('fade-in');
}
if (newPage.subpage) {
assert(newPage.subpage == Dialog.OPTIONS);
assert(newPage.extensionId);
- this.optionsDialog.show(data);
+ this.showOptionsDialog_ = true;
+ this.async(() => {
+ this.$$('#options-dialog').show(data);
+ });
}
this.currentPage_ = newPage;
},
/** @private */
+ onDrawerClose_: function() {
+ this.showDrawer_ = false;
+ },
+
+ /** @private */
+ onLoadErrorDialogClose_: function() {
+ this.showLoadErrorDialog_ = false;
+ },
+
+ /** @private */
+ onOptionsDialogClose_: function() {
+ this.showOptionsDialog_ = false;
+ },
+
+ /** @private */
onPackTap_: function() {
- this.$['pack-dialog'].show();
+ this.showPackDialog_ = true;
+ this.async(() => {
+ this.$$('#pack-dialog').show();
+ });
+ },
+
+ /** @private */
+ onPackDialogClose_: function() {
+ this.showPackDialog_ = false;
+ },
+
+ /** @private */
+ onViewExitFinish_: function(e) {
+ const viewType = e.path[0].tagName;
+ if (viewType == 'EXTENSIONS-ITEM-LIST' ||
+ viewType == 'EXTENSIONS-KEYBOARD-SHORTCUTS') {
+ return;
+ }
+
+ const extensionId = e.path[0].data.id;
+ const list = this.$$('extensions-item-list');
+ const button = viewType == 'EXTENSIONS-DETAIL-VIEW' ?
+ list.getDetailsButton(extensionId) :
+ list.getErrorsButton(extensionId);
+
+ // The button will not exist, when returning from a details page
+ // because the corresponding extension/app was deleted.
+ if (button)
+ button.focus();
+ },
+
+ /**
+ * @param {!CustomEvent} e
+ * @private
+ */
+ onShowInstallWarnings_: function(e) {
+ // Leverage Polymer data bindings instead of just assigning the
+ // installWarnings on the dialog since the dialog hasn't been stamped
+ // in the DOM yet.
+ this.installWarnings_ = /** @type{!Array<string>} */ (e.detail);
+ this.showInstallWarningsDialog_ = true;
+ },
+
+ /** @private */
+ onInstallWarningsDialogClose_: function() {
+ this.installWarnings_ = null;
+ this.showInstallWarningsDialog_ = false;
},
// <if expr="chromeos">
@@ -394,24 +532,6 @@ cr.define('extensions', function() {
this.showKioskDialog_ = false;
},
// </if>
-
- /**
- * @param {!extensions.ShowingType} listType
- * @private
- */
- computeList_: function(listType) {
- // TODO(scottchen): the .slice is required to trigger the binding
- // correctly, otherwise the list won't rerender. Should investigate
- // the performance implication, or find better ways to trigger change.
- switch (listType) {
- case extensions.ShowingType.EXTENSIONS:
- this.linkPaths('itemsList_', 'extensions');
- return this.extensions;
- case extensions.ShowingType.APPS:
- this.linkPaths('itemsList_', 'apps');
- return this.apps;
- }
- }
});
return {Manager: Manager};
diff --git a/chromium/chrome/browser/resources/md_extensions/navigation_helper.js b/chromium/chrome/browser/resources/md_extensions/navigation_helper.js
index 9437730ea02..e4efc690d4b 100644
--- a/chromium/chrome/browser/resources/md_extensions/navigation_helper.js
+++ b/chromium/chrome/browser/resources/md_extensions/navigation_helper.js
@@ -21,22 +21,25 @@ const Dialog = {
OPTIONS: 'options',
};
-/** @enum {number} */
-extensions.ShowingType = {
- EXTENSIONS: 0,
- APPS: 1,
-};
-
/** @typedef {{page: Page,
extensionId: (string|undefined),
- subpage: (!Dialog|undefined),
- type: (!extensions.ShowingType|undefined)}} */
+ subpage: (!Dialog|undefined)}} */
let PageState;
cr.define('extensions', function() {
'use strict';
/**
+ * @param {!PageState} a
+ * @param {!PageState} b
+ * @return {boolean} Whether a and b are equal.
+ */
+ function isPageStateEqual(a, b) {
+ return a.page == b.page && a.subpage == b.subpage &&
+ a.extensionId == b.extensionId;
+ }
+
+ /**
* Regular expression that captures the leading slash, the content and the
* trailing slash in three different groups.
* @const {!RegExp}
@@ -50,14 +53,7 @@ cr.define('extensions', function() {
*/
class NavigationHelper {
constructor() {
- // Redirect if route not supported.
- let validPathnames = ['/'];
- if (!loadTimeData.getBoolean('isGuest')) {
- validPathnames.push('/shortcuts', '/apps');
- }
- if (!validPathnames.includes(this.currentPath_)) {
- window.history.replaceState(undefined, '', '/');
- }
+ this.processRoute_();
/** @private {number} */
this.nextListenerId_ = 1;
@@ -65,6 +61,9 @@ cr.define('extensions', function() {
/** @private {!Map<number, function(!PageState)>} */
this.listeners_ = new Map();
+ /** @private {!PageState} */
+ this.previousPage_;
+
window.addEventListener('popstate', () => {
this.notifyRouteChanged_(this.getCurrentPage());
});
@@ -76,6 +75,24 @@ cr.define('extensions', function() {
}
/**
+ * If you're not a guest, going to /configureCommands and /shortcuts should
+ * land you on /shortcuts. These are the only two supported routes, so all
+ * other cases (guest or not) will redirect you to root path if not already
+ * on it.
+ * @private
+ */
+ processRoute_() {
+ if (!loadTimeData.getBoolean('isGuest') &&
+ (this.currentPath_ == '/configureCommands' ||
+ this.currentPath_ == '/shortcuts')) {
+ window.history.replaceState(
+ undefined /* stateObject */, '', '/shortcuts');
+ } else if (this.currentPath_ !== '/') {
+ window.history.replaceState(undefined /* stateObject */, '', '/');
+ }
+ }
+
+ /**
* @return {!PageState} The page that should be displayed for the current
* URL.
*/
@@ -94,10 +111,7 @@ cr.define('extensions', function() {
if (this.currentPath_ == '/shortcuts')
return {page: Page.SHORTCUTS};
- if (this.currentPath_ == '/apps')
- return {page: Page.LIST, type: extensions.ShowingType.APPS};
-
- return {page: Page.LIST, type: extensions.ShowingType.EXTENSIONS};
+ return {page: Page.LIST};
}
/**
@@ -136,28 +150,36 @@ cr.define('extensions', function() {
*/
navigateTo(newPage) {
let currentPage = this.getCurrentPage();
- if (currentPage && currentPage.page == newPage.page &&
- currentPage.type == newPage.type &&
- currentPage.subpage == newPage.subpage &&
- currentPage.extensionId == newPage.extensionId) {
+ if (currentPage && isPageStateEqual(currentPage, newPage)) {
return;
}
- this.updateHistory(newPage);
+ this.updateHistory(newPage, false /* replaceState */);
+ this.notifyRouteChanged_(newPage);
+ }
+
+ /**
+ * @param {!PageState} newPage the page to replace the current page with.
+ */
+ replaceWith(newPage) {
+ this.updateHistory(newPage, true /* replaceState */);
+ if (this.previousPage_ && isPageStateEqual(this.previousPage_, newPage)) {
+ // Skip the duplicate history entry.
+ history.back();
+ return;
+ }
this.notifyRouteChanged_(newPage);
}
/**
* Called when a page changes, and pushes state to history to reflect it.
* @param {!PageState} entry
+ * @param {boolean} replaceState
*/
- updateHistory(entry) {
+ updateHistory(entry, replaceState) {
let path;
switch (entry.page) {
case Page.LIST:
- if (entry.type == extensions.ShowingType.APPS)
- path = '/apps';
- else
path = '/';
break;
case Page.DETAILS:
@@ -179,16 +201,17 @@ cr.define('extensions', function() {
const state = {url: path};
const currentPage = this.getCurrentPage();
const isDialogNavigation = currentPage.page == entry.page &&
- currentPage.extensionId == entry.extensionId &&
- currentPage.type == entry.type;
+ currentPage.extensionId == entry.extensionId;
// Navigating to a dialog doesn't visually change pages; it just opens
// a dialog. As such, we replace state rather than pushing a new state
// on the stack so that hitting the back button doesn't just toggle the
// dialog.
- if (isDialogNavigation)
+ if (replaceState || isDialogNavigation) {
history.replaceState(state, '', path);
- else
+ } else {
+ this.previousPage_ = currentPage;
history.pushState(state, '', path);
+ }
}
}
diff --git a/chromium/chrome/browser/resources/md_extensions/options_dialog.html b/chromium/chrome/browser/resources/md_extensions/options_dialog.html
index 8dd57e9fd69..3c959b13644 100644
--- a/chromium/chrome/browser/resources/md_extensions/options_dialog.html
+++ b/chromium/chrome/browser/resources/md_extensions/options_dialog.html
@@ -3,6 +3,7 @@
<link rel="import" href="chrome://resources/cr_elements/cr_dialog/cr_dialog.html">
<link rel="import" href="chrome://resources/html/assert.html">
<link rel="import" href="chrome://resources/html/cr.html">
+<link rel="import" href="item_behavior.html">
<link rel="import" href="navigation_helper.html">
<dom-module id="extensions-options-dialog">
@@ -13,18 +14,28 @@
height: 32px;
width: 32px;
}
+
#icon-and-name-wrapper {
align-items: center;
display: flex;
}
- extensionoptions {
+ ExtensionOptions {
display: block;
+ min-width: 300px;
}
dialog {
- /* Initially as wide as possible. This will be adjusted by js-code. */
- width: 100%;
+ width: fit-content;
+ --cr-dialog-body: {
+ overflow: hidden;
+ padding: 0;
+ };
+
+ --cr-dialog-body-container: {
+ border: none;
+ min-height: initial;
+ };
}
</style>
@@ -32,7 +43,11 @@
on-close="onClose_">
<div slot="title">
<div id="icon-and-name-wrapper">
- <img id="icon" src="[[data_.iconUrl]]">
+ <img id="icon" src="[[data_.iconUrl]]"
+ alt$="[[appOrExtension(
+ data.type,
+ '$i18nPolymer{appIcon}',
+ '$i18nPolymer{extensionIcon}')]]">
<span>[[data_.name]]</span>
</div>
</div>
diff --git a/chromium/chrome/browser/resources/md_extensions/options_dialog.js b/chromium/chrome/browser/resources/md_extensions/options_dialog.js
index 591c4b7049e..adffadd9da2 100644
--- a/chromium/chrome/browser/resources/md_extensions/options_dialog.js
+++ b/chromium/chrome/browser/resources/md_extensions/options_dialog.js
@@ -5,15 +5,11 @@
cr.define('extensions', function() {
'use strict';
- const MAX_HEIGHT = 600;
- const MAX_WIDTH = 600;
- const MIN_HEIGHT = 300;
- const MIN_WIDTH = 300;
- const HEADER_EXTRA_SPACING = 50; // 40 from x-button + 10 from img margin.
- const DIALOG_PADDING = 32; // Padding from cr-dialog's .body styling.
-
const OptionsDialog = Polymer({
is: 'extensions-options-dialog',
+
+ behaviors: [extensions.ItemBehavior],
+
properties: {
/** @private {Object} */
extensionOptions_: Object,
@@ -33,32 +29,22 @@ cr.define('extensions', function() {
this.extensionOptions_ = document.createElement('ExtensionOptions');
this.extensionOptions_.extension = this.data_.id;
this.extensionOptions_.onclose = this.close.bind(this);
- const bounded = function(min, max, val) {
- return Math.min(Math.max(min, val), max);
- };
const onSizeChanged = e => {
- const minHeaderWidth =
- this.$$('#icon-and-name-wrapper img').offsetWidth +
- this.$$('#icon-and-name-wrapper span').offsetWidth +
- HEADER_EXTRA_SPACING;
- const minWidth = Math.max(minHeaderWidth, MIN_WIDTH);
- this.extensionOptions_.style.height =
- bounded(MIN_HEIGHT, MAX_HEIGHT, e.height) + 'px';
- this.extensionOptions_.style.width =
- bounded(minWidth, MAX_WIDTH, e.width) + 'px';
- this.$.dialog.style.width =
- (bounded(minWidth, MAX_WIDTH, e.width) + DIALOG_PADDING) + 'px';
+ this.extensionOptions_.style.height = e.height + 'px';
+ this.extensionOptions_.style.width = e.width + 'px';
+
+ if (!this.$$('dialog').open)
+ this.$$('dialog').showModal();
};
this.extensionOptions_.onpreferredsizechanged = onSizeChanged;
this.$.body.appendChild(this.extensionOptions_);
- this.$$('dialog').showModal();
- onSizeChanged({height: 0, width: 0});
},
close: function() {
this.$$('dialog').close();
+ this.extensionOptions_.onpreferredsizechanged = null;
},
/** @private */
diff --git a/chromium/chrome/browser/resources/md_extensions/pack_dialog.html b/chromium/chrome/browser/resources/md_extensions/pack_dialog.html
index 2e11adbdf66..ac6a453d0c5 100644
--- a/chromium/chrome/browser/resources/md_extensions/pack_dialog.html
+++ b/chromium/chrome/browser/resources/md_extensions/pack_dialog.html
@@ -61,7 +61,7 @@
</dialog>
<template is="dom-if" if="[[lastResponse_]]" restamp>
<extensions-pack-dialog-alert model="[[lastResponse_]]"
- on-warning-confirmed="onWarningConfirmed_" on-close="resetResponse_">
+ on-close="onAlertClose_">
</extensions-pack-dialog-alert>
</template>
</template>
diff --git a/chromium/chrome/browser/resources/md_extensions/pack_dialog.js b/chromium/chrome/browser/resources/md_extensions/pack_dialog.js
index de6f9b3b2e7..f746508e512 100644
--- a/chromium/chrome/browser/resources/md_extensions/pack_dialog.js
+++ b/chromium/chrome/browser/resources/md_extensions/pack_dialog.js
@@ -89,25 +89,33 @@ cr.define('extensions', function() {
* @private
*/
onPackResponse_: function(response) {
- if (response.status === chrome.developerPrivate.PackStatus.SUCCESS) {
- this.$.dialog.close();
- } else {
- this.set('lastResponse_', response);
- }
+ this.lastResponse_ = response;
},
/**
- * The handler function when user chooses to 'Proceed Anyway' upon
- * receiving a waring.
+ * In the case that the alert dialog was a success message, the entire
+ * pack-dialog should close. Otherwise, we detach the alert by setting
+ * lastResponse_ null. Additionally, if the user selected "proceed anyway"
+ * in the warning dialog, we pack the extension again with override flags.
+ * @param {!Event} e
* @private
*/
- onWarningConfirmed_: function() {
- this.delegate.packExtension(
- this.lastResponse_.item_path, this.lastResponse_.pem_path,
- this.lastResponse_.override_flags, this.onPackResponse_.bind(this));
- },
+ onAlertClose_: function(e) {
+ e.stopPropagation();
+
+ if (this.lastResponse_.status ==
+ chrome.developerPrivate.PackStatus.SUCCESS) {
+ this.$.dialog.close();
+ return;
+ }
+
+ /* This is only possible for a warning dialog. */
+ if (this.$$('extensions-pack-dialog-alert').returnValue == 'success') {
+ this.delegate.packExtension(
+ this.lastResponse_.item_path, this.lastResponse_.pem_path,
+ this.lastResponse_.override_flags, this.onPackResponse_.bind(this));
+ }
- resetResponse_: function() {
this.lastResponse_ = null;
},
});
diff --git a/chromium/chrome/browser/resources/md_extensions/pack_dialog_alert.html b/chromium/chrome/browser/resources/md_extensions/pack_dialog_alert.html
index 11db084bd02..68bc231c581 100644
--- a/chromium/chrome/browser/resources/md_extensions/pack_dialog_alert.html
+++ b/chromium/chrome/browser/resources/md_extensions/pack_dialog_alert.html
@@ -10,16 +10,19 @@
<dom-module id="extensions-pack-dialog-alert">
<template>
<style include="cr-shared-style paper-button-style">
+ .body {
+ white-space: pre-wrap;
+ word-break: break-word;
+ }
</style>
<dialog is="cr-dialog" id="dialog" close-text="$i18n{close}">
<div class="title" slot="title">[[title_]]</div>
- <div class="body" slot="body">
- [[model.message]]
- </div>
+ <!-- No whitespace or new-lines allowed within the div.body tag. -->
+ <div class="body" slot="body">[[model.message]]</div>
<div class="button-container" slot="button-container">
- <paper-button class="cancel-button" on-tap="onCancelTap_"
- hidden="[[!cancelLabel_]]">
+ <paper-button class$="[[getCancelButtonClass_(confirmLabel_)]]"
+ on-tap="onCancelTap_" hidden="[[!cancelLabel_]]">
[[cancelLabel_]]
</paper-button>
<paper-button class="action-button" on-tap="onConfirmTap_"
diff --git a/chromium/chrome/browser/resources/md_extensions/pack_dialog_alert.js b/chromium/chrome/browser/resources/md_extensions/pack_dialog_alert.js
index 3afe8734260..7c3e475dd27 100644
--- a/chromium/chrome/browser/resources/md_extensions/pack_dialog_alert.js
+++ b/chromium/chrome/browser/resources/md_extensions/pack_dialog_alert.js
@@ -20,8 +20,19 @@ cr.define('extensions', function() {
/** @private */
cancelLabel_: String,
- /** @private */
- confirmLabel_: String,
+ /**
+ * This needs to be initialized to trigger data-binding.
+ * @private
+ */
+ confirmLabel_: {
+ type: String,
+ value: '',
+ }
+ },
+
+ /** @return {string} */
+ get returnValue() {
+ return this.$.dialog.returnValue;
},
/** @override */
@@ -41,8 +52,10 @@ cr.define('extensions', function() {
this.title_ = loadTimeData.getString('packDialogErrorTitle');
this.cancelLabel_ = loadTimeData.getString('ok');
break;
- // If status were success, this dialog should not be attached at all.
case chrome.developerPrivate.PackStatus.SUCCESS:
+ this.title_ = loadTimeData.getString('packDialogTitle');
+ this.cancelLabel_ = loadTimeData.getString('ok');
+ break;
default:
assertNotReached();
return;
@@ -54,6 +67,14 @@ cr.define('extensions', function() {
this.$.dialog.showModal();
},
+ /**
+ * @return {string}
+ * @private
+ */
+ getCancelButtonClass_: function() {
+ return this.confirmLabel_ ? 'cancel-button' : 'action-button';
+ },
+
/** @private */
onCancelTap_: function() {
this.$.dialog.cancel();
@@ -63,7 +84,6 @@ cr.define('extensions', function() {
onConfirmTap_: function() {
// The confirm button should only be available in WARNING state.
assert(this.model.status === chrome.developerPrivate.PackStatus.WARNING);
- this.fire('warning-confirmed');
this.$.dialog.close();
}
});
diff --git a/chromium/chrome/browser/resources/md_extensions/service.js b/chromium/chrome/browser/resources/md_extensions/service.js
index 912dd3e9f54..4d48b0678b5 100644
--- a/chromium/chrome/browser/resources/md_extensions/service.js
+++ b/chromium/chrome/browser/resources/md_extensions/service.js
@@ -16,100 +16,34 @@ cr.define('extensions', function() {
constructor() {
/** @private {boolean} */
this.isDeleting_ = false;
-
- /** @private {extensions.Manager} */
- this.manager_;
-
- /** @private {Array<chrome.developerPrivate.ExtensionInfo>} */
- this.extensions_;
}
- /** @param {extensions.Manager} manager */
- managerReady(manager) {
- this.manager_ = manager;
- this.manager_.set('delegate', this);
-
- // Skip any setup or backend requests if we're in guest-mode.
- // TODO(scottchen): there might be a better place to do this once manager
- // and service become less coupled.
- if (loadTimeData.getBoolean('isGuest')) {
- this.manager_.initPage();
- return;
- }
+ getProfileConfiguration() {
+ return new Promise(function(resolve, reject) {
+ chrome.developerPrivate.getProfileConfiguration(resolve);
+ });
+ }
- const keyboardShortcuts = this.manager_.keyboardShortcuts;
- keyboardShortcuts.addEventListener(
- 'shortcut-updated', this.onExtensionCommandUpdated_.bind(this));
- keyboardShortcuts.addEventListener(
- 'shortcut-capture-started',
- this.onShortcutCaptureChanged_.bind(this, true));
- keyboardShortcuts.addEventListener(
- 'shortcut-capture-ended',
- this.onShortcutCaptureChanged_.bind(this, false));
- chrome.developerPrivate.onProfileStateChanged.addListener(
- this.onProfileStateChanged_.bind(this));
- chrome.developerPrivate.onItemStateChanged.addListener(
- this.onItemStateChanged_.bind(this));
- chrome.developerPrivate.getExtensionsInfo(
- {includeDisabled: true, includeTerminated: true}, extensions => {
- this.extensions_ = extensions;
- for (let extension of extensions)
- this.manager_.addItem(extension);
-
- this.manager_.initPage();
- });
- chrome.developerPrivate.getProfileConfiguration(
- this.onProfileStateChanged_.bind(this));
+ getItemStateChangedTarget() {
+ return chrome.developerPrivate.onItemStateChanged;
}
- /**
- * @param {chrome.developerPrivate.ProfileInfo} profileInfo
- * @private
- */
- onProfileStateChanged_(profileInfo) {
- this.manager_.set('inDevMode', profileInfo.inDeveloperMode);
+ getProfileStateChangedTarget() {
+ return chrome.developerPrivate.onProfileStateChanged;
}
- /**
- * @param {chrome.developerPrivate.EventData} eventData
- * @private
- */
- onItemStateChanged_(eventData) {
- const currentIndex = this.extensions_.findIndex(function(extension) {
- return extension.id == eventData.item_id;
+ getExtensionsInfo() {
+ return new Promise(function(resolve, reject) {
+ chrome.developerPrivate.getExtensionsInfo(
+ {includeDisabled: true, includeTerminated: true}, resolve);
});
+ }
- const EventType = chrome.developerPrivate.EventType;
- switch (eventData.event_type) {
- case EventType.VIEW_REGISTERED:
- case EventType.VIEW_UNREGISTERED:
- case EventType.INSTALLED:
- case EventType.LOADED:
- case EventType.UNLOADED:
- case EventType.ERROR_ADDED:
- case EventType.ERRORS_REMOVED:
- case EventType.PREFS_CHANGED:
- // |extensionInfo| can be undefined in the case of an extension
- // being unloaded right before uninstallation. There's nothing to do
- // here.
- if (!eventData.extensionInfo)
- break;
-
- if (currentIndex >= 0) {
- this.extensions_[currentIndex] = eventData.extensionInfo;
- this.manager_.updateItem(eventData.extensionInfo);
- } else {
- this.extensions_.push(eventData.extensionInfo);
- this.manager_.addItem(eventData.extensionInfo);
- }
- break;
- case EventType.UNINSTALLED:
- this.manager_.removeItem(this.extensions_[currentIndex]);
- this.extensions_.splice(currentIndex, 1);
- break;
- default:
- assertNotReached();
- }
+ /** @override */
+ getExtensionSize(id) {
+ return new Promise(function(resolve, reject) {
+ chrome.developerPrivate.getExtensionSize(id, resolve);
+ });
}
/**
@@ -135,14 +69,15 @@ cr.define('extensions', function() {
/**
* Updates an extension command.
- * @param {!CustomEvent} e
- * @private
+ * @param {string} extensionId
+ * @param {string} commandName
+ * @param {string} keybinding
*/
- onExtensionCommandUpdated_(e) {
+ updateExtensionCommand(extensionId, commandName, keybinding) {
chrome.developerPrivate.updateExtensionCommand({
- extensionId: e.detail.item,
- commandName: e.detail.commandName,
- keybinding: e.detail.keybinding,
+ extensionId: extensionId,
+ commandName: commandName,
+ keybinding: keybinding,
});
}
@@ -154,10 +89,8 @@ cr.define('extensions', function() {
* the default handling on the event also does this. Investigate more in the
* future.
* @param {boolean} isCapturing
- * @param {!CustomEvent} e
- * @private
*/
- onShortcutCaptureChanged_(isCapturing, e) {
+ setShortcutHandlingSuspended(isCapturing) {
chrome.developerPrivate.setShortcutHandlingSuspended(isCapturing);
}
@@ -165,22 +98,26 @@ cr.define('extensions', function() {
* Attempts to load an unpacked extension, optionally as another attempt at
* a previously-specified load.
* @param {string=} opt_retryGuid
+ * @return {!Promise} A signal that loading finished, rejected if any error
+ * occured.
* @private
*/
loadUnpackedHelper_(opt_retryGuid) {
- chrome.developerPrivate.loadUnpacked(
- {failQuietly: true, populateError: true, retryGuid: opt_retryGuid},
- (loadError) => {
- if (chrome.runtime.lastError &&
- chrome.runtime.lastError.message !=
- 'File selection was canceled.') {
- throw new Error(chrome.runtime.lastError.message);
- }
- if (loadError) {
- this.manager_.loadError.loadError = loadError;
- this.manager_.loadError.show();
- }
- });
+ return new Promise(function(resolve, reject) {
+ chrome.developerPrivate.loadUnpacked(
+ {failQuietly: true, populateError: true, retryGuid: opt_retryGuid},
+ (loadError) => {
+ if (chrome.runtime.lastError &&
+ chrome.runtime.lastError.message !=
+ 'File selection was canceled.') {
+ throw new Error(chrome.runtime.lastError.message);
+ }
+ if (loadError)
+ return reject(loadError);
+
+ resolve();
+ });
+ });
}
/** @override */
@@ -244,9 +181,28 @@ cr.define('extensions', function() {
});
}
+ /**
+ * @param {string} url
+ * @override
+ */
+ openUrl(url) {
+ window.open(url);
+ }
+
/** @override */
reloadItem(id) {
- chrome.developerPrivate.reload(id, {failQuietly: false});
+ return new Promise(function(resolve, reject) {
+ chrome.developerPrivate.reload(
+ id, {failQuietly: true, populateErrorForUnpacked: true},
+ (loadError) => {
+ if (loadError) {
+ reject(loadError);
+ return;
+ }
+
+ resolve();
+ });
+ });
}
/** @override */
@@ -255,16 +211,16 @@ cr.define('extensions', function() {
}
/** @override */
- showItemOptionsPage(id) {
- const extension = this.extensions_.find(function(e) {
- return e.id == id;
- });
+ showItemOptionsPage(extension) {
assert(extension && extension.optionsPage);
if (extension.optionsPage.openInTab) {
- chrome.developerPrivate.showOptions(id);
+ chrome.developerPrivate.showOptions(extension.id);
} else {
- extensions.navigation.navigateTo(
- {page: Page.DETAILS, subpage: Dialog.OPTIONS, extensionId: id});
+ extensions.navigation.navigateTo({
+ page: Page.DETAILS,
+ subpage: Dialog.OPTIONS,
+ extensionId: extension.id,
+ });
}
}
@@ -276,12 +232,12 @@ cr.define('extensions', function() {
/** @override */
loadUnpacked() {
- this.loadUnpackedHelper_();
+ return this.loadUnpackedHelper_();
}
/** @override */
retryLoadUnpacked(retryGuid) {
- this.loadUnpackedHelper_(retryGuid);
+ return this.loadUnpackedHelper_(retryGuid);
}
/** @override */
@@ -306,6 +262,7 @@ cr.define('extensions', function() {
/** @override */
updateAllExtensions() {
chrome.developerPrivate.autoUpdate();
+ chrome.metricsPrivate.recordUserAction('Options_UpdateExtensions');
}
/** @override */
@@ -330,6 +287,11 @@ cr.define('extensions', function() {
openDevTools(args) {
chrome.developerPrivate.openDevTools(args);
}
+
+ /** @override */
+ showInFolder(id) {
+ chrome.developerPrivate.showPath(id);
+ }
}
cr.addSingletonGetter(Service);
diff --git a/chromium/chrome/browser/resources/md_extensions/shortcut_input.html b/chromium/chrome/browser/resources/md_extensions/shortcut_input.html
index faf98ef6f44..ad5c9bb03b9 100644
--- a/chromium/chrome/browser/resources/md_extensions/shortcut_input.html
+++ b/chromium/chrome/browser/resources/md_extensions/shortcut_input.html
@@ -8,6 +8,7 @@
<link rel="import" href="chrome://resources/html/cr.html">
<link rel="import" href="chrome://resources/html/i18n_behavior.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button-light.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-input/paper-input.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-styles/color.html">
<link rel="import" href="shortcut_util.html">
@@ -24,7 +25,7 @@
margin-bottom: 0px;
margin-top: 2px; /* Offset underline spacing. */
padding: 0;
- @apply(--cr-primary-text);
+ @apply --cr-primary-text;
};
}
@@ -37,8 +38,12 @@
</style>
<div id="main">
<paper-input id="input" placeholder="$i18n{shortcutTypeAShortcut}"
- value="[[computeText_(capturing_, shortcut, pendingShortcut_)]]"
- no-label-float>
+ error-message="[[getErrorString_(error_,
+ '$i18nPolymer{shortcutIncludeStartModifier}',
+ '$i18nPolymer{shortcutTooManyModifiers}',
+ '$i18nPolymer{shortcutNeedCharacter}')]]"
+ value="[[computeText_(capturing_, shortcut, pendingShortcut_)]]"
+ no-label-float>
</paper-input>
<button id="clear" is="paper-icon-button-light"
class="icon-clear no-overlap" on-tap="onClearTap_"
diff --git a/chromium/chrome/browser/resources/md_extensions/shortcut_input.js b/chromium/chrome/browser/resources/md_extensions/shortcut_input.js
index a6abd7b3e75..d70ebd02624 100644
--- a/chromium/chrome/browser/resources/md_extensions/shortcut_input.js
+++ b/chromium/chrome/browser/resources/md_extensions/shortcut_input.js
@@ -5,6 +5,14 @@
cr.define('extensions', function() {
'use strict';
+ /** @enum {number} */
+ const ShortcutError = {
+ NO_ERROR: 0,
+ INCLUDE_START_MODIFIER: 1,
+ TOO_MANY_MODIFIERS: 2,
+ NEED_CHARACTER: 3,
+ };
+
// The UI to display and manage keyboard shortcuts set for extension commands.
const ShortcutInput = Polymer({
is: 'extensions-shortcut-input',
@@ -12,23 +20,36 @@ cr.define('extensions', function() {
behaviors: [I18nBehavior],
properties: {
+ /** @type {!Object} */
+ delegate: Object,
+
item: {
type: String,
value: '',
},
+
commandName: {
type: String,
value: '',
},
+
shortcut: {
type: String,
value: '',
},
+
/** @private */
capturing_: {
type: Boolean,
value: false,
},
+
+ /** @private {!ShortcutError} */
+ error_: {
+ type: Number,
+ value: 0,
+ },
+
/** @private */
pendingShortcut_: {
type: String,
@@ -36,6 +57,7 @@ cr.define('extensions', function() {
},
},
+ /** @override */
ready: function() {
const node = this.$['input'];
node.addEventListener('mouseup', this.startCapture_.bind(this));
@@ -50,7 +72,7 @@ cr.define('extensions', function() {
if (this.capturing_)
return;
this.capturing_ = true;
- this.fire('shortcut-capture-started');
+ this.delegate.setShortcutHandlingSuspended(true);
},
/** @private */
@@ -59,8 +81,10 @@ cr.define('extensions', function() {
return;
this.pendingShortcut_ = '';
this.capturing_ = false;
- this.$['input'].blur();
- this.fire('shortcut-capture-ended');
+ const input = this.$.input;
+ input.blur();
+ input.invalid = false;
+ this.delegate.setShortcutHandlingSuspended(false);
},
/**
@@ -102,6 +126,23 @@ cr.define('extensions', function() {
},
/**
+ * @param {!ShortcutError} error
+ * @param {string} includeStartModifier
+ * @param {string} tooManyModifiers
+ * @param {string} needCharacter
+ * @return {string} UI string.
+ * @private
+ */
+ getErrorString_: function(
+ error, includeStartModifier, tooManyModifiers, needCharacter) {
+ if (error == ShortcutError.TOO_MANY_MODIFIERS)
+ return tooManyModifiers;
+ if (error == ShortcutError.NEED_CHARACTER)
+ return needCharacter;
+ return includeStartModifier;
+ },
+
+ /**
* @param {!KeyboardEvent} e
* @private
*/
@@ -115,27 +156,34 @@ cr.define('extensions', function() {
// We don't allow both Ctrl and Alt in the same keybinding.
// TODO(devlin): This really should go in extensions.hasValidModifiers,
// but that requires updating the existing page as well.
- if ((e.ctrlKey && e.altKey) || !extensions.hasValidModifiers(e)) {
- this.pendingShortcut_ = 'invalid';
+ if (e.ctrlKey && e.altKey) {
+ this.error_ = ShortcutError.TOO_MANY_MODIFIERS;
+ this.$.input.invalid = true;
+ return;
+ }
+ if (!extensions.hasValidModifiers(e)) {
+ this.pendingShortcut_ = '';
+ this.error_ = ShortcutError.INCLUDE_START_MODIFIER;
+ this.$.input.invalid = true;
return;
}
-
this.pendingShortcut_ = extensions.keystrokeToString(e);
-
- if (extensions.isValidKeyCode(e.keyCode)) {
- this.commitPending_();
- this.endCapture_();
+ if (!extensions.isValidKeyCode(e.keyCode)) {
+ this.error_ = ShortcutError.NEED_CHARACTER;
+ this.$.input.invalid = true;
+ return;
}
+ this.$.input.invalid = false;
+
+ this.commitPending_();
+ this.endCapture_();
},
/** @private */
commitPending_: function() {
this.shortcut = this.pendingShortcut_;
- this.fire('shortcut-updated', {
- keybinding: this.shortcut,
- item: this.item,
- commandName: this.commandName
- });
+ this.delegate.updateExtensionCommand(
+ this.item, this.commandName, this.shortcut);
},
/**
diff --git a/chromium/chrome/browser/resources/md_extensions/sidebar.html b/chromium/chrome/browser/resources/md_extensions/sidebar.html
index bd1887dd6fd..1d49eeec145 100644
--- a/chromium/chrome/browser/resources/md_extensions/sidebar.html
+++ b/chromium/chrome/browser/resources/md_extensions/sidebar.html
@@ -1,74 +1,84 @@
<link rel="import" href="chrome://resources/html/polymer.html">
+<link rel="import" href="chrome://resources/cr_elements/cr_icons_css.html">
<link rel="import" href="chrome://resources/html/cr.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button-light.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/paper-item/paper-item.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/paper-menu/paper-menu.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/iron-selector/iron-selector.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-ripple/paper-ripple.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-styles/color.html">
<link rel="import" href="navigation_helper.html">
<dom-module id="extensions-sidebar">
<template>
- <style>
+ <style include="cr-icons">
:host {
- display: flex;
- flex-direction: column;
+ display: block;
height: 100%;
- white-space: nowrap;
+ overflow-x: hidden;
+ overflow-y: auto;
+ width: 256px;
}
- #section-menu {
- --paper-menu-background-color: transparent;
- --paper-menu-selected-item: {
- background-color: transparent;
- color: var(--google-blue-700);
- font-weight: normal;
- }
+ .cr-icon {
+ -webkit-margin-end: calc(
+ var(--cr-section-padding) - var(--cr-icon-ripple-padding));
+ }
- padding: 0;
+ iron-selector .iron-selected {
+ color: var(--google-blue-700);
}
- #more-extensions {
- -webkit-padding-end: 16px;
- align-items: center;
+ iron-selector .separator {
+ background-color: rgba(0, 0, 0, 0.08);
+ flex-shrink: 0;
+ height: 1px;
+ margin: 8px 0;
+ }
+
+ #sectionMenu {
+ background-color: transparent;
+ color: #5a5a5a;
display: flex;
- justify-content: space-between;
- text-decoration: none;
+ flex: 1;
+ flex-direction: column;
+ padding-top: 8px;
+ user-select: none;
}
.section-item {
+ /* Ensure the focus outline appears correctly (crbug.com/655503). */
+ -webkit-margin-end: 4px;
-webkit-padding-start: 24px;
- color: #5A5A5A;
+ align-items: center;
+ box-sizing: border-box;
+ color: inherit;
cursor: pointer;
- height: 48px;
- }
-
- button[is='paper-icon-button-light'].open-in-new {
- background-image: url(chrome://resources/images/open_in_new.svg);
- background-size: contain;
- height: 15px;
- width: 15px;
+ display: flex;
+ font-weight: 500;
+ justify-content: space-between;
+ min-height: 40px;
+ position: relative;
+ text-decoration: none;
}
</style>
- <paper-menu id="section-menu" selected="{{selected_}}">
- <paper-item class="section-item" id="sections-extensions"
+ <iron-selector id="sectionMenu">
+ <div class="section-item" id="sections-extensions"
on-tap="onExtensionsTap_">
- <span>$i18n{sidebarExtensions}</span>
- </paper-item>
- <paper-item class="section-item" id="sections-apps"
- on-tap="onAppsTap_">
- <span>$i18n{sidebarApps}</span>
- </paper-item>
- <paper-item class="section-item" id="sections-shortcuts"
+ $i18n{sidebarExtensions}
+ <paper-ripple></paper-ripple>
+ </div>
+ <div class="section-item" id="sections-shortcuts"
on-tap="onKeyboardShortcutsTap_">
- <span>$i18n{keyboardShortcuts}</span>
- </paper-item>
- </paper-menu>
- <a class="section-item" id="more-extensions" target="_blank"
- href="$i18n{getMoreExtensionsUrl}">
- <span>$i18n{getMoreExtensions}</span>
- <button class="open-in-new" is="paper-icon-button-light"></button>
- </a>
+ $i18n{keyboardShortcuts}
+ <paper-ripple></paper-ripple>
+ </div>
+ <div class="separator"></div>
+ <a class="section-item" id="more-extensions" target="_blank"
+ href="$i18n{getMoreExtensionsUrl}" on-tap="onMoreExtensionsTap_">
+ <span>$i18n{openChromeWebStore}</span>
+ <div class="cr-icon icon-external"></div>
+ <paper-ripple></paper-ripple>
+ </a>
+ </iron-selector>
</template>
<script src="sidebar.js"></script>
</dom-module>
diff --git a/chromium/chrome/browser/resources/md_extensions/sidebar.js b/chromium/chrome/browser/resources/md_extensions/sidebar.js
index a2fea0dfc20..5f32ee1db98 100644
--- a/chromium/chrome/browser/resources/md_extensions/sidebar.js
+++ b/chromium/chrome/browser/resources/md_extensions/sidebar.js
@@ -5,28 +5,20 @@ cr.define('extensions', function() {
const Sidebar = Polymer({
is: 'extensions-sidebar',
- properties: {
- /** @private {number} */
- selected_: {
- type: Number,
- value: -1,
- },
- },
-
hostAttributes: {
role: 'navigation',
},
- /** @private */
- onExtensionsTap_: function() {
- extensions.navigation.navigateTo(
- {page: Page.LIST, type: extensions.ShowingType.EXTENSIONS});
+ /** @override */
+ attached: function() {
+ this.$.sectionMenu.select(
+ extensions.navigation.getCurrentPage().page == Page.SHORTCUTS ? 1 :
+ 0);
},
/** @private */
- onAppsTap_: function() {
- extensions.navigation.navigateTo(
- {page: Page.LIST, type: extensions.ShowingType.APPS});
+ onExtensionsTap_: function() {
+ extensions.navigation.navigateTo({page: Page.LIST});
},
/** @private */
@@ -34,28 +26,9 @@ cr.define('extensions', function() {
extensions.navigation.navigateTo({page: Page.SHORTCUTS});
},
- /**
- * @param {!PageState} state
- */
- updateSelected: function(state) {
- let selected;
-
- switch (state.page) {
- case Page.LIST:
- if (state.type == extensions.ShowingType.APPS)
- selected = 1;
- else
- selected = 0;
- break;
- case Page.SHORTCUTS:
- selected = 2;
- break;
- default:
- selected = -1;
- break;
- }
-
- this.selected_ = selected;
+ /** @private */
+ onMoreExtensionsTap_: function() {
+ chrome.metricsPrivate.recordUserAction('Options_GetMoreExtensions');
},
});
diff --git a/chromium/chrome/browser/resources/md_extensions/toggle_row.html b/chromium/chrome/browser/resources/md_extensions/toggle_row.html
new file mode 100644
index 00000000000..b326dc8ca00
--- /dev/null
+++ b/chromium/chrome/browser/resources/md_extensions/toggle_row.html
@@ -0,0 +1,49 @@
+<link rel="import" href="chrome://resources/html/polymer.html">
+
+<link rel="import" href="chrome://resources/cr_elements/cr_toggle/cr_toggle.html">
+<link rel="import" href="chrome://resources/cr_elements/shared_style_css.html">
+
+<dom-module id="extensions-toggle-row">
+ <template>
+ <style>
+ :host {
+ @apply --cr-section;
+ flex-direction: column;
+ padding-left: 0;
+ padding-right: 0;
+ touch-action: none;
+ }
+
+ input {
+ display: none;
+ }
+
+ label {
+ align-items: center;
+ box-sizing: border-box;
+ cursor: pointer;
+ display: flex;
+ flex: 1;
+ padding: 0 var(--cr-section-padding);
+ width: 100%;
+ }
+
+ cr-toggle {
+ display: inline-block;
+ }
+
+ :host ::slotted(*) {
+ -webkit-margin-end: 20px;
+ flex: 1;
+ }
+ </style>
+ <label id="label" on-click="onLabelTap_">
+ <input id="native" type="checkbox" checked="[[checked]]"
+ on-change="onNativeChange_" on-click="onNativeClick_">
+ <slot></slot>
+ <cr-toggle id="crToggle" checked="{{checked}}" aria-labelledby="label"
+ on-change="onCrToggleChange_"></cr-toggle>
+ </label>
+ </template>
+ <script src="toggle_row.js"></script>
+</dom-module>
diff --git a/chromium/chrome/browser/resources/md_extensions/toggle_row.js b/chromium/chrome/browser/resources/md_extensions/toggle_row.js
new file mode 100644
index 00000000000..8667db24ce4
--- /dev/null
+++ b/chromium/chrome/browser/resources/md_extensions/toggle_row.js
@@ -0,0 +1,85 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+cr.define('extensions', function() {
+ 'use strict';
+
+ /**
+ * An extensions-toggle-row provides a way of having a clickable row that can
+ * modify a cr-toggle, by leveraging the native <label> functionality. It uses
+ * a hidden native <input type="checkbox"> to achieve this.
+ */
+ const ExtensionsToggleRow = Polymer({
+ is: 'extensions-toggle-row',
+
+ properties: {
+ checked: Boolean,
+ },
+
+ /**
+ * Exposing the clickable part of extensions-toggle-row for testing
+ * purposes.
+ * @return {!HTMLElement}
+ */
+ getLabel() {
+ return this.$.label;
+ },
+
+ /**
+ * @param {!Event}
+ * @private
+ */
+ onLabelTap_: function(e) {
+ // If the interaction sequence (pointerdown+pointerup) began within the
+ // cr-toggle itself, then prevent this event from changing the state of
+ // the toggle.
+ if (this.$.crToggle.shouldIgnoreHostTap(e))
+ e.preventDefault();
+ },
+
+ /**
+ * @param {!Event}
+ * @private
+ */
+ onNativeClick_: function(e) {
+ // Even though the native checkbox is hidden and can't be actually
+ // cilcked/tapped by the user, because it resides within the <label> the
+ // browser emits an extraneous event when the label is clicked. Stop
+ // propagation so that it does not interfere with |onLabelTap_| listener.
+ e.stopPropagation();
+ },
+
+ /**
+ * Fires when the native checkbox changes value. This happens when the user
+ * clicks directly on the <label>.
+ * @param {!Event} e
+ * @private
+ */
+ onNativeChange_: function(e) {
+ e.stopPropagation();
+
+ // Sync value of native checkbox and cr-toggle and |checked|.
+ this.$.crToggle.checked = this.$.native.checked;
+ this.checked = this.$.native.checked;
+
+ this.fire('change', this.checked);
+ },
+
+ /**
+ * Fires
+ * @param {!CustomEvent} e
+ * @private
+ */
+ onCrToggleChange_: function(e) {
+ e.stopPropagation();
+
+ // Sync value of native checkbox and cr-toggle.
+ this.$.native.checked = e.detail;
+
+ this.fire('change', this.checked);
+ },
+ });
+
+ return {ExtensionsToggleRow: ExtensionsToggleRow};
+});
diff --git a/chromium/chrome/browser/resources/md_extensions/toolbar.html b/chromium/chrome/browser/resources/md_extensions/toolbar.html
index c57b165e06f..5e90a25a03c 100644
--- a/chromium/chrome/browser/resources/md_extensions/toolbar.html
+++ b/chromium/chrome/browser/resources/md_extensions/toolbar.html
@@ -14,12 +14,14 @@
<template>
<style include="cr-hidden-style paper-button-style">
:host {
- --toolbar-width: 580px;
+ /* The constant is the height of the tallest control. */
+ --button-row-height: calc(var(--margin-bottom) + 36px);
+ --drawer-transition: 0.3s cubic-bezier(.25, .1, .25, 1);
+ --margin-bottom: 4px;
--toolbar-color: var(--md-toolbar-color);
}
cr-toolbar {
- --cr-toolbar-field-width: var(--toolbar-width);
background: var(--toolbar-color);
}
@@ -31,24 +33,42 @@
--cr-toggle-unchecked-ink-color: white;
}
- .dev-controls {
- background: var(--toolbar-color);
- display: flex;
- justify-content: center;
- width: 100%;
+ #devDrawer[expanded] #button-strip {
+ top: 0;
+ }
+
+ #devDrawer {
+ height: 0;
+ overflow: hidden;
+ position: relative;
+ transition: height var(--drawer-transition);
+ }
+
+ #devDrawer[expanded] {
+ height: var(--button-row-height);
}
#button-strip {
- margin-bottom: 4px;
- /* We left-align the text of the left button with the left edge of the
- search field. Since the buttons have 12px padding, add 24px to the
- width of the button strip (12px each side) to make centering easy. */
- width: calc(var(--toolbar-width) + 2 * 12px);
+ -webkit-margin-end: auto;
+ -webkit-margin-start: auto;
+ background: var(--toolbar-color);
+ margin-bottom: var(--margin-bottom);
+ position: absolute;
+ text-align: center;
+ top: calc(var(--button-row-height) * -1);
+ transition: top var(--drawer-transition);
+ /* Prevent selection of the blank space between buttons. */
+ user-select: none;
+ width: 100%;
}
#button-strip paper-button {
-webkit-margin-end: 16px;
color: white;
+ /* Increase contrast compared to default values. */
+ --paper-button-flat-keyboard-focus: {
+ background: rgba(0, 0, 0, .3);
+ };
}
.more-actions {
@@ -65,15 +85,16 @@
search-prompt="$i18n{search}"
clear-label="$i18n{clearSearch}"
menu-label="$i18n{mainMenu}"
- show-menu="[[!isGuest]]" show-search="[[!isGuest]]">
+ show-menu="[[!isGuest]]" show-search="[[!isGuest]]"
+ narrow-threshold="1000">
<div class="more-actions" hidden$="[[isGuest]]">
<span id="devModeLabel">$i18n{toolbarDevMode}</span>
- <cr-toggle id="dev-mode" on-change="onDevModeChange_"
+ <cr-toggle id="dev-mode" on-change="onDevModeToggleChange_"
checked="[[inDevMode]]" aria-labelledby="devModeLabel">
</cr-toggle>
</div>
</cr-toolbar>
- <div class="dev-controls" hidden$="[[!inDevMode]]">
+ <div id="devDrawer" expanded$="[[expanded_]]">
<div id="button-strip">
<paper-button id="load-unpacked" on-tap="onLoadUnpackedTap_">
$i18n{toolbarLoadUnpacked}
@@ -81,7 +102,8 @@
<paper-button id="pack-extensions" on-tap="onPackTap_">
$i18n{toolbarPack}
</paper-button>
- <paper-button id="update-now" on-tap="onUpdateNowTap_">
+ <paper-button id="update-now" on-tap="onUpdateNowTap_"
+ title="$i18n{toolbarUpdateNowTooltip}">
$i18n{toolbarUpdateNow}
</paper-button>
<if expr="chromeos">
diff --git a/chromium/chrome/browser/resources/md_extensions/toolbar.js b/chromium/chrome/browser/resources/md_extensions/toolbar.js
index f973f10ed3e..2de38b38cc1 100644
--- a/chromium/chrome/browser/resources/md_extensions/toolbar.js
+++ b/chromium/chrome/browser/resources/md_extensions/toolbar.js
@@ -13,7 +13,10 @@ cr.define('extensions', function() {
*/
setProfileInDevMode(inDevMode) {}
- /** Opens the dialog to load unpacked extensions. */
+ /**
+ * Opens the dialog to load unpacked extensions.
+ * @return {!Promise}
+ */
loadUnpacked() {}
/** Updates all extensions. */
@@ -32,6 +35,7 @@ cr.define('extensions', function() {
inDevMode: {
type: Boolean,
value: false,
+ observer: 'onInDevModeChanged_',
},
isGuest: Boolean,
@@ -39,25 +43,59 @@ cr.define('extensions', function() {
// <if expr="chromeos">
kioskEnabled: Boolean,
// </if>
+
+ /** @private */
+ expanded_: {
+ type: Boolean,
+ value: false,
+ },
},
hostAttributes: {
role: 'banner',
},
+ /** @override */
+ ready: function() {
+ this.$.devDrawer.addEventListener('transitionend', () => {
+ this.delegate.setProfileInDevMode(this.$['dev-mode'].checked);
+ });
+ },
+
+ /** @private */
+ onDevModeToggleChange_: function() {
+ const drawer = this.$.devDrawer;
+ if (drawer.hidden) {
+ drawer.hidden = false;
+ // Requesting the offsetTop will cause a reflow (to account for hidden).
+ /** @suppress {suspiciousCode} */ drawer.offsetTop;
+ }
+ this.expanded_ = !this.expanded_;
+
+ chrome.metricsPrivate.recordUserAction(
+ 'Options_ToggleDeveloperMode_' +
+ (this.expanded_ ? 'Enabled' : 'Disabled'));
+ },
+
/** @private */
- onDevModeChange_: function() {
- this.delegate.setProfileInDevMode(this.$['dev-mode'].checked);
+ onInDevModeChanged_: function() {
+ // Set the initial state.
+ this.expanded_ = this.inDevMode;
+ this.$.devDrawer.hidden = !this.inDevMode;
},
/** @private */
onLoadUnpackedTap_: function() {
- this.delegate.loadUnpacked();
+ this.delegate.loadUnpacked().catch(loadError => {
+ this.fire('load-error', loadError);
+ });
+ chrome.metricsPrivate.recordUserAction('Options_LoadUnpackedExtension');
},
/** @private */
onPackTap_: function() {
this.fire('pack-tap');
+ chrome.metricsPrivate.recordUserAction('Options_PackExtension');
},
// <if expr="chromeos">
diff --git a/chromium/chrome/browser/resources/md_extensions/view_manager.js b/chromium/chrome/browser/resources/md_extensions/view_manager.js
index 36e5383065f..011f357c366 100644
--- a/chromium/chrome/browser/resources/md_extensions/view_manager.js
+++ b/chromium/chrome/browser/resources/md_extensions/view_manager.js
@@ -71,19 +71,22 @@ cr.define('extensions', function() {
},
/**
- * @param {!Element} element
- * @param {!string} animation
+ * @param {!Element} view
+ * @param {string} animation
* @return {!Promise}
* @private
*/
- enter_: function(element, animation) {
+ enter_: function(view, animation) {
const animationFunction = extensions.viewAnimations.get(animation);
assert(animationFunction);
- element.classList.add('active');
- element.dispatchEvent(new CustomEvent('view-enter-start'));
- return animationFunction(element).then(function() {
- element.dispatchEvent(new CustomEvent('view-enter-finish'));
+ let effectiveView =
+ view.matches('[is=cr-lazy-render]') ? view.get() : view;
+
+ effectiveView.classList.add('active');
+ effectiveView.dispatchEvent(new CustomEvent('view-enter-start'));
+ return animationFunction(effectiveView).then(() => {
+ effectiveView.dispatchEvent(new CustomEvent('view-enter-finish'));
});
},
@@ -107,20 +110,7 @@ cr.define('extensions', function() {
return Promise.all(promises);
},
-
- /**
- * Helper function to only animate the current view.
- * @param {string} animation
- * @return {!Promise}
- */
- animateCurrentView: function(animation) {
- const currentView = assert(this.querySelector('.active'));
- const animationFunction = extensions.viewAnimations.get(animation);
- assert(animationFunction);
-
- return animationFunction(currentView);
- },
});
return {viewAnimations: viewAnimations, ViewManager: ViewManager};
-}); \ No newline at end of file
+});
diff --git a/chromium/chrome/browser/resources/md_history/OWNERS b/chromium/chrome/browser/resources/md_history/OWNERS
index c85d9424611..5e21905007d 100644
--- a/chromium/chrome/browser/resources/md_history/OWNERS
+++ b/chromium/chrome/browser/resources/md_history/OWNERS
@@ -1,4 +1,3 @@
calamity@chromium.org
-tsergeant@chromium.org
# COMPONENT: UI>Browser>History
diff --git a/chromium/chrome/browser/resources/md_history/app.html b/chromium/chrome/browser/resources/md_history/app.html
index ddd7280cc46..1d5e64876ae 100644
--- a/chromium/chrome/browser/resources/md_history/app.html
+++ b/chromium/chrome/browser/resources/md_history/app.html
@@ -21,6 +21,7 @@
color: var(--primary-text-color);
display: block;
height: 100%;
+ line-height: 1.54; /* 20px. */
overflow: hidden;
}
diff --git a/chromium/chrome/browser/resources/md_history/browser_service.js b/chromium/chrome/browser/resources/md_history/browser_service.js
index 9ee3c8ebdfa..2757ff25868 100644
--- a/chromium/chrome/browser/resources/md_history/browser_service.js
+++ b/chromium/chrome/browser/resources/md_history/browser_service.js
@@ -97,7 +97,7 @@ cr.define('md_history', function() {
*/
recordAction: function(action) {
if (action.indexOf('_') == -1)
- action = 'HistoryPage_' + action;
+ action = `HistoryPage_${action}`;
chrome.send('metricsHandler:recordAction', [action]);
},
diff --git a/chromium/chrome/browser/resources/md_history/history_item.html b/chromium/chrome/browser/resources/md_history/history_item.html
index 0bb3bbe614c..958032b7386 100644
--- a/chromium/chrome/browser/resources/md_history/history_item.html
+++ b/chromium/chrome/browser/resources/md_history/history_item.html
@@ -22,14 +22,6 @@
pointer-events: none;
}
- /** Unresolved paper-icon-button-light styles. */
- button {
- background: none;
- border: none;
- outline: none;
- padding: 0;
- }
-
#main-container {
position: relative;
}
@@ -76,6 +68,8 @@
#checkbox {
height: 40px;
+ margin: 0;
+ padding: 0;
width: 40px;
}
diff --git a/chromium/chrome/browser/resources/md_history/history_list.html b/chromium/chrome/browser/resources/md_history/history_list.html
index 15d42bbae08..b27ce8d74e2 100644
--- a/chromium/chrome/browser/resources/md_history/history_list.html
+++ b/chromium/chrome/browser/resources/md_history/history_list.html
@@ -75,6 +75,8 @@
<template is="cr-lazy-render" id="sharedMenu">
<dialog is="cr-action-menu">
<button id="menuMoreButton" class="dropdown-item"
+ hidden="[[!canSearchMoreFromSite_(
+ searchedTerm, actionMenuModel_.item.domain)]]"
on-tap="onMoreFromSiteTap_">
$i18n{moreFromSite}
</button>
diff --git a/chromium/chrome/browser/resources/md_history/history_list.js b/chromium/chrome/browser/resources/md_history/history_list.js
index c9a11568cef..748e50ef62f 100644
--- a/chromium/chrome/browser/resources/md_history/history_list.js
+++ b/chromium/chrome/browser/resources/md_history/history_list.js
@@ -182,7 +182,7 @@ Polymer({
* @private
*/
changeSelection_: function(index, selected) {
- this.set('historyData_.' + index + '.selected', selected);
+ this.set(`historyData_.${index}.selected`, selected);
if (selected)
this.selectedItems.add(index);
else
@@ -198,7 +198,7 @@ Polymer({
*/
deleteSelected_: function() {
var toBeRemoved = Array.from(this.selectedItems.values())
- .map((index) => this.get('historyData_.' + index));
+ .map((index) => this.get(`historyData_.${index}`));
md_history.BrowserService.getInstance()
.deleteItems(toBeRemoved)
@@ -281,7 +281,7 @@ Polymer({
for (var i = 0; i < this.historyData_.length; i++) {
if (this.historyData_[i].url == url)
- this.set('historyData_.' + i + '.starred', false);
+ this.set(`historyData_.${i}.starred`, false);
}
},
@@ -468,6 +468,16 @@ Polymer({
},
/**
+ * @param {string} searchedTerm
+ * @param {string} domain
+ * @return {boolean}
+ * @private
+ */
+ canSearchMoreFromSite_: function(searchedTerm, domain) {
+ return searchedTerm === '' || searchedTerm !== domain;
+ },
+
+ /**
* @param {HistoryQuery} info
* @param {!Array<HistoryEntry>} results
* @private
diff --git a/chromium/chrome/browser/resources/md_history/history_toolbar.html b/chromium/chrome/browser/resources/md_history/history_toolbar.html
index 12fd39cba14..e9a28f30b9f 100644
--- a/chromium/chrome/browser/resources/md_history/history_toolbar.html
+++ b/chromium/chrome/browser/resources/md_history/history_toolbar.html
@@ -45,7 +45,7 @@
hidden$="[[itemsSelected_]]"
spinner-active="[[spinnerActive]]"
show-menu="[[hasDrawer]]"
- show-menu-promo="[[showMenuPromo]]"
+ show-menu-promo="[[canShowMenuPromo_(showMenuPromo)]]"
menu-label="$i18n{historyMenuButton}"
menu-promo="$i18n{menuPromo}"
close-menu-promo="$i18n{closeMenuPromo}"
diff --git a/chromium/chrome/browser/resources/md_history/history_toolbar.js b/chromium/chrome/browser/resources/md_history/history_toolbar.js
index 7b70d8ea149..3eeab953ba9 100644
--- a/chromium/chrome/browser/resources/md_history/history_toolbar.js
+++ b/chromium/chrome/browser/resources/md_history/history_toolbar.js
@@ -92,6 +92,15 @@ Polymer({
},
/**
+ * @param {boolean} showMenuPromo
+ * @return {boolean}
+ * @private
+ */
+ canShowMenuPromo_: function(showMenuPromo) {
+ return this.showMenuPromo && !loadTimeData.getBoolean('isGuestSession');
+ },
+
+ /**
* @param {!CustomEvent} event
* @private
*/
diff --git a/chromium/chrome/browser/resources/md_history/shared_style.html b/chromium/chrome/browser/resources/md_history/shared_style.html
index 32534a40cca..5961b1553b5 100644
--- a/chromium/chrome/browser/resources/md_history/shared_style.html
+++ b/chromium/chrome/browser/resources/md_history/shared_style.html
@@ -6,6 +6,7 @@
<style include="cr-hidden-style">
a {
color: var(--link-color);
+ text-decoration: none;
}
.card-title {
@@ -50,7 +51,7 @@
white-space: nowrap;
}
- button.icon-button {
+ button[is='paper-icon-button-light'] {
background: none;
border: none;
height: 36px;
@@ -58,15 +59,8 @@
width: 36px;
}
- button.icon-button iron-icon {
- height: 20px;
- width: 20px;
- }
-
button.more-vert-button {
- height: 36px;
padding: 8px;
- width: 36px;
}
button.more-vert-button div {
diff --git a/chromium/chrome/browser/resources/md_history/shared_vars.html b/chromium/chrome/browser/resources/md_history/shared_vars.html
index 2be07afcf76..eff885fafd6 100644
--- a/chromium/chrome/browser/resources/md_history/shared_vars.html
+++ b/chromium/chrome/browser/resources/md_history/shared_vars.html
@@ -20,6 +20,8 @@
--history-item-time-color: #646464;
--interactive-color: var(--google-blue-500);
--item-height: 44px;
+ --iron-icon-height: var(--cr-icon-size);
+ --iron-icon-width: var(--cr-icon-size);
--link-color: var(--google-blue-700);
--primary-text-color: var(--paper-grey-900);
--secondary-text-color: var(--paper-grey-600);
diff --git a/chromium/chrome/browser/resources/md_history/side_bar.html b/chromium/chrome/browser/resources/md_history/side_bar.html
index 8ea9c0262e4..b49c3e2fe5c 100644
--- a/chromium/chrome/browser/resources/md_history/side_bar.html
+++ b/chromium/chrome/browser/resources/md_history/side_bar.html
@@ -84,7 +84,6 @@
#footer-text {
-webkit-padding-end: 16px;
-webkit-padding-start: 24px;
- line-height: 20px;
margin: 24px 0;
}
diff --git a/chromium/chrome/browser/resources/md_history/synced_device_card.html b/chromium/chrome/browser/resources/md_history/synced_device_card.html
index 9e80d9b8083..708f60bcf3c 100644
--- a/chromium/chrome/browser/resources/md_history/synced_device_card.html
+++ b/chromium/chrome/browser/resources/md_history/synced_device_card.html
@@ -48,14 +48,10 @@
}
#right-buttons {
- -webkit-margin-end: 4px;
+ -webkit-margin-end: 12px;
color: var(--secondary-text-color);
}
- #menu-button {
- -webkit-margin-end: 8px;
- }
-
#collapse {
overflow: hidden;
}
@@ -97,7 +93,7 @@
<div></div>
<div></div>
</button>
- <button is="paper-icon-button-light" class="icon-button"
+ <button is="paper-icon-button-light"
id="collapse-button" title$="[[getCollapseTitle_(opened)]]">
<iron-icon icon="[[getCollapseIcon_(opened)]]"
id="dropdown-indicator">
diff --git a/chromium/chrome/browser/resources/md_user_manager/create_profile.html b/chromium/chrome/browser/resources/md_user_manager/create_profile.html
index a14ae723f83..ef416b56a65 100644
--- a/chromium/chrome/browser/resources/md_user_manager/create_profile.html
+++ b/chromium/chrome/browser/resources/md_user_manager/create_profile.html
@@ -22,6 +22,10 @@
<template>
<style
include="shared-styles iron-positioning md-select paper-checkbox-style">
+ :host {
+ align-self: center;
+ }
+
.container {
color: var(--primary-text-color);
width: var(--page-width);
@@ -67,10 +71,8 @@
}
#title-bar {
- border-bottom: var(--user-manager-separator-line);
font-size: 16px;
font-weight: 500;
- padding: 104px 0 16px;
}
#nameInput {
diff --git a/chromium/chrome/browser/resources/md_user_manager/icons.html b/chromium/chrome/browser/resources/md_user_manager/icons.html
deleted file mode 100644
index 2143f12a3a9..00000000000
--- a/chromium/chrome/browser/resources/md_user_manager/icons.html
+++ /dev/null
@@ -1,14 +0,0 @@
-<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="user-manager" size="24">
- <svg>
- <defs>
- <!--
- These icons are copied from Polymer's iron-icons and kept in sorted order.
- See http://goo.gl/Y1OdAq for instructions on adding additional icons.
- -->
- <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>
- </defs>
- </svg>
-</iron-iconset-svg>
diff --git a/chromium/chrome/browser/resources/md_user_manager/supervised_user_create_confirm.html b/chromium/chrome/browser/resources/md_user_manager/supervised_user_create_confirm.html
index 4b50826658d..f87044917b8 100644
--- a/chromium/chrome/browser/resources/md_user_manager/supervised_user_create_confirm.html
+++ b/chromium/chrome/browser/resources/md_user_manager/supervised_user_create_confirm.html
@@ -1,6 +1,5 @@
<link rel="import" href="chrome://resources/html/polymer.html">
-<link rel="import" href="/icons.html">
<link rel="import" href="/profile_browser_proxy.html">
<link rel="import" href="/shared_styles.html">
<link rel="import" href="chrome://resources/html/util.html">
@@ -21,15 +20,8 @@
}
#title-area {
- border-bottom: var(--user-manager-separator-line);
font-size: 16px;
- padding-bottom: 16px;
- }
-
- #title-area iron-icon {
- --iron-icon-height: 20px;
- --iron-icon-width: 20px;
- color: var(--title-icon-color);
+ font-weight: 500;
}
.content-area {
@@ -52,7 +44,6 @@
<div id="container">
<div id="title-area" class="horizontal justified layout">
<span id="title">[[titleText_(profileInfo)]]</span>
- <iron-icon icon="user-manager:supervisor-account"></iron-icon>
</div>
<div class="content-area"
inner-h-t-m-l="[[confirmationMessage_(profileInfo)]]">
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
index 2547500b9ab..5ada724a33f 100644
--- 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
@@ -1,6 +1,5 @@
<link rel="import" href="chrome://resources/html/polymer.html">
-<link rel="import" href="/icons.html">
<link rel="import" href="/shared_styles.html">
<link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/iron-flex-layout-classes.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html">
@@ -19,15 +18,8 @@
}
#title-area {
- border-bottom: var(--user-manager-separator-line);
font-size: 16px;
- padding-bottom: 16px;
- }
-
- #title-area iron-icon {
- --iron-icon-height: 20px;
- --iron-icon-width: 20px;
- color: var(--title-icon-color);
+ font-weight: 500;
}
.content-area {
@@ -50,7 +42,6 @@
<div id="container">
<div id="title-area" class="horizontal justified layout">
<span id="title">$i18n{supervisedUserLearnMoreTitle}</span>
- <iron-icon icon="user-manager:supervisor-account"></iron-icon>
</div>
<div class="content-area">$i18nRaw{supervisedUserLearnMoreText}</div>
<div id="actions">
diff --git a/chromium/chrome/browser/resources/md_user_manager/user_manager.html b/chromium/chrome/browser/resources/md_user_manager/user_manager.html
index 95537c923d2..1d493a4e909 100644
--- a/chromium/chrome/browser/resources/md_user_manager/user_manager.html
+++ b/chromium/chrome/browser/resources/md_user_manager/user_manager.html
@@ -72,6 +72,17 @@
opacity: 0;
}
+ /* The name-container font-sizes is to counteract the countainer's
+ * scale(0.8), so that the text still stays legible. */
+ podrow[ncolumns='6'] .pod .name-container {
+ font-size: 1.25em;
+ transition: font-size 180ms;
+ }
+
+ podrow[ncolumns='6'] .pod.focused .name-container {
+ font-size: 1em;
+ }
+
.pod {
box-shadow: 0 2px 2px 0 rgba(0, 0, 0, .24),
0 0 2px 0 rgba(0, 0, 0, .12);
@@ -289,6 +300,10 @@
padding: 12px;
}
+ .action-box-remove-user-warning-text {
+ max-width: 100%;
+ }
+
.action-box-remove-user-warning > * {
word-wrap: break-word;
}
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
index 10f655aa774..8a4acecdaf6 100644
--- a/chromium/chrome/browser/resources/md_user_manager/user_manager_pages.html
+++ b/chromium/chrome/browser/resources/md_user_manager/user_manager_pages.html
@@ -28,7 +28,7 @@
<neon-animated-pages id="animatedPages" attr-for-selected="id"
selected="[[selectedPage_]]" entry-animation="fade-in-animation"
exit-animation="fade-out-animation">
- <neon-animatable id="create-user-page">
+ <neon-animatable id="create-user-page" on-keydown="stopPropagation_">
<!-- Keep the page alive while visiting the Learn More page. -->
<template is="dom-if"
if="[[isPresentIn_(selectedPage_,
@@ -40,13 +40,15 @@
<neon-animatable id="user-pods-page">
<slot></slot>
</neon-animatable>
- <neon-animatable id="supervised-learn-more-page">
+ <neon-animatable id="supervised-learn-more-page"
+ on-keydown="stopPropagation_">
<template is="dom-if"
if="[[isPresentIn_(selectedPage_, 'supervised-learn-more-page')]]">
<supervised-user-learn-more></supervised-user-learn-more>
</template>
</neon-animatable>
- <neon-animatable id="supervised-create-confirm-page">
+ <neon-animatable id="supervised-create-confirm-page"
+ on-keydown="stopPropagation_">
<template is="dom-if"
if="[[isPresentIn_(selectedPage_,
'supervised-create-confirm-page')]]">
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
index 39b932fd8c0..a579c3d540d 100644
--- a/chromium/chrome/browser/resources/md_user_manager/user_manager_pages.js
+++ b/chromium/chrome/browser/resources/md_user_manager/user_manager_pages.js
@@ -46,6 +46,20 @@ Polymer({
},
/**
+ * This is to prevent events from propagating to the document element, which
+ * erroneously triggers user-pod selections.
+ *
+ * TODO(scottchen): re-examine if its necessary for user_pod_row.js to bind
+ * listeners on the entire document element.
+ *
+ * @param {!Event} e
+ * @private
+ */
+ stopPropagation_: function(e) {
+ e.stopPropagation();
+ },
+
+ /**
* Returns True if the first argument is present in the given set of values.
* @param {string} selectedPage ID of the currently selected page.
* @param {...string} var_args Pages IDs to check the first argument against.
diff --git a/chromium/chrome/browser/resources/media/media_engagement.html b/chromium/chrome/browser/resources/media/media_engagement.html
index d789f520375..fd374ce52d3 100644
--- a/chromium/chrome/browser/resources/media/media_engagement.html
+++ b/chromium/chrome/browser/resources/media/media_engagement.html
@@ -20,6 +20,7 @@
table {
border-collapse: collapse;
+ margin-bottom: 20px;
}
table td,
@@ -54,7 +55,9 @@
.visits-count-cell,
.media-playbacks-count-cell,
- .last-playback-time-cell {
+ .last-playback-time-cell,
+ .audible-playbacks-count-cell,
+ .significant-playbacks-count-cell {
background-color: rgba(230, 230, 230, 0.5);
text-align: right;
}
@@ -72,6 +75,10 @@
outline: none;
}
+ .name-cell {
+ background-color: rgba(230, 230, 230, 0.5);
+ }
+
table tr:hover {
background: rgb(255, 255, 187);
}
@@ -91,6 +98,20 @@
<h1>Media Engagement</h1>
<table>
<thead>
+ <tr id="config-table-header">
+ <th>
+ Setting Name
+ </th>
+ <th>
+ Setting Value
+ </th>
+ </tr>
+ </thead>
+ <tbody id="config-table-body">
+ </tbody>
+ </table>
+ <table>
+ <thead>
<tr id="engagement-table-header">
<th sort-key="origin">
Origin
@@ -99,7 +120,13 @@
Visits
</th>
<th sort-key="mediaPlaybacks" sort-reverse>
- Number of Playbacks
+ Playbacks
+ </th>
+ <th sort-key="audiblePlaybacks" sort-reverse>
+ Audible Playbacks*
+ </th>
+ <th sort-key="significantPlaybacks" sort-reverse>
+ Significant Playbacks*
</th>
<th sort-key="lastMediaPlaybackTime" sort-reverse>
Last Playback
@@ -116,11 +143,17 @@
</tbody>
</table>
+ <p>
+ * These columns are experimental and do not currently affect the MEI score.
+ </p>
+
<template id="datarow">
<tr>
<td class="origin-cell"></td>
<td class="visits-count-cell"></td>
<td class="media-playbacks-count-cell"></td>
+ <td class="audible-playbacks-count-cell"></td>
+ <td class="significant-playbacks-count-cell"></td>
<td class="last-playback-time-cell"></td>
<td class="is-high-cell"></td>
<td class="total-score-cell"></td>
@@ -129,5 +162,11 @@
</td>
</tr>
</template>
+ <template id="configrow">
+ <tr>
+ <td class="name-cell"></td>
+ <td></td>
+ </tr>
+ </template>
</body>
</html>
diff --git a/chromium/chrome/browser/resources/media/media_engagement.js b/chromium/chrome/browser/resources/media/media_engagement.js
index 268f7b1ca2c..0ca0a3cd94c 100644
--- a/chromium/chrome/browser/resources/media/media_engagement.js
+++ b/chromium/chrome/browser/resources/media/media_engagement.js
@@ -18,6 +18,7 @@ var info = null;
var engagementTableBody = null;
var sortReverse = true;
var sortKey = 'totalScore';
+var configTableBody = null;
/**
* Creates a single row in the engagement table.
@@ -30,12 +31,14 @@ function createRow(rowInfo) {
td[0].textContent = rowInfo.origin.url;
td[1].textContent = rowInfo.visits;
td[2].textContent = rowInfo.mediaPlaybacks;
- td[3].textContent = rowInfo.lastMediaPlaybackTime ?
+ td[3].textContent = rowInfo.audiblePlaybacks;
+ td[4].textContent = rowInfo.significantPlaybacks;
+ td[5].textContent = rowInfo.lastMediaPlaybackTime ?
new Date(rowInfo.lastMediaPlaybackTime).toISOString() :
'';
- td[4].textContent = rowInfo.isHigh ? 'Yes' : 'No';
- td[5].textContent = rowInfo.totalScore ? rowInfo.totalScore.toFixed(2) : '0';
- td[6].getElementsByClassName('engagement-bar')[0].style.width =
+ td[6].textContent = rowInfo.isHigh ? 'Yes' : 'No';
+ td[7].textContent = rowInfo.totalScore ? rowInfo.totalScore.toFixed(2) : '0';
+ td[8].getElementsByClassName('engagement-bar')[0].style.width =
(rowInfo.totalScore * 50) + 'px';
return document.importNode(template.content, true);
}
@@ -73,7 +76,8 @@ function compareTableItem(sortKey, a, b) {
return new URL(val1.url).host > new URL(val2.url).host ? 1 : -1;
if (sortKey == 'visits' || sortKey == 'mediaPlaybacks' ||
- sortKey == 'lastMediaPlaybackTime' || sortKey == 'totalScore') {
+ sortKey == 'lastMediaPlaybackTime' || sortKey == 'totalScore' ||
+ sortKey == 'audiblePlaybacks' || sortKey == 'significantPlaybacks') {
return val1 - val2;
}
@@ -82,6 +86,36 @@ function compareTableItem(sortKey, a, b) {
}
/**
+ * Creates a single row in the config table.
+ * @param {string} name The name of the config setting.
+ * @param {string} value The value of the config setting.
+ * @return {!HTMLElement}
+ */
+function createConfigRow(name, value) {
+ var template = $('configrow');
+ var td = template.content.querySelectorAll('td');
+ td[0].textContent = name;
+ td[1].textContent = value;
+ return document.importNode(template.content, true);
+}
+
+/**
+ * Regenerates the config table.
+ * @param {!MediaEngagementConfig} config The config of the MEI service.
+ */
+
+function renderConfigTable(config) {
+ configTableBody.innerHTML = '';
+
+ configTableBody.appendChild(
+ createConfigRow('Min Visits', config.scoreMinVisits));
+ configTableBody.appendChild(
+ createConfigRow('Lower Threshold', config.highScoreLowerThreshold));
+ configTableBody.appendChild(
+ createConfigRow('Upper Threshold', config.highScoreUpperThreshold));
+}
+
+/**
* Regenerates the engagement table from |info|.
*/
function renderTable() {
@@ -100,6 +134,11 @@ function updateEngagementTable() {
renderTable();
pageIsPopulatedResolver.resolve();
});
+
+ // Populate config settings.
+ uiHandler.getMediaEngagementConfig().then(response => {
+ renderConfigTable(response.config);
+ });
}
document.addEventListener('DOMContentLoaded', function() {
@@ -110,6 +149,7 @@ document.addEventListener('DOMContentLoaded', function() {
updateEngagementTable();
engagementTableBody = $('engagement-table-body');
+ configTableBody = $('config-table-body');
// Set table header sort handlers.
var engagementTableHeader = $('engagement-table-header');
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 1087a9ae8db..eb9c718b797 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,7 +1,7 @@
+<link rel="import" href="chrome://resources/cr_elements/icons.html">
<link rel="import" href="chrome://resources/html/polymer.html">
<link rel="import" href="chrome://resources/html/i18n_behavior.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html">
-<link rel="import" href="../../icons/media_router_icons.html">
<dom-module id="issue-banner">
<link rel="import" type="css" href="../../media_router_common.css">
<link rel="import" type="css" href="issue_banner.css">
@@ -9,7 +9,7 @@
<div class$="[[computeIssueClass_(issue)]]">
<div>
<div hidden$="[[computeIsBlockingIssueHidden_(issue)]]">
- <iron-icon icon="media-router:error-outline" id="blocking-icon">
+ <iron-icon icon="cr:error-outline" id="blocking-icon">
</iron-icon>
</div>
<div id="title" aria-live="polite" tabindex="0">[[issue.title]]</div>
diff --git a/chromium/chrome/browser/resources/media_router/elements/route_controls/route_controls.css b/chromium/chrome/browser/resources/media_router/elements/route_controls/route_controls.css
index 3b9b0631cc1..ed76cd9ed9b 100644
--- a/chromium/chrome/browser/resources/media_router/elements/route_controls/route_controls.css
+++ b/chromium/chrome/browser/resources/media_router/elements/route_controls/route_controls.css
@@ -16,13 +16,6 @@
right: 20px;
}
-.ellipsis {
- padding: 0 1%;
- text-overflow: ellipsis;
- white-space: nowrap;
- width: 90%;
-}
-
:host-context([dir='rtl']) #play-pause-volume-hangouts-controls {
transform: scaleX(-1);
}
@@ -48,7 +41,7 @@
#route-description {
margin: 15px 8px 3px 8px;
- overflow: hidden;
+ width: 90%;
}
#route-time-controls {
@@ -87,19 +80,19 @@
padding: 0.3em 0;
}
+paper-checkbox {
+ --paper-checkbox-checked-color: #1976D2;
+}
+
#hangouts-local-present-controls {
- -webkit-font-smoothing: antialiased;
- -webkit-tap-highlight-color: transparent;
cursor: pointer;
display: inline-block;
float: right;
- font-family: 'Roboto', 'Noto', sans-serif;
padding-top: 10.5px;
white-space: nowrap;
}
#hangouts-local-present-checkbox {
- --paper-checkbox-checked-color: #1976D2;
--paper-checkbox-vertical-align: top;
};
@@ -109,3 +102,15 @@
margin-top: 2px;
width: 249px;
}
+
+#mirroring-fullscreen-video-controls {
+ display: inline-block;
+ font-size: 0.8em;
+ margin: 15px 8px 3px 8px;
+ vertical-align: middle;
+ white-space: nowrap;
+}
+
+#mirroring-fullscreen-video-dropdown {
+ width: auto;
+}
diff --git a/chromium/chrome/browser/resources/media_router/elements/route_controls/route_controls.html b/chromium/chrome/browser/resources/media_router/elements/route_controls/route_controls.html
index 7a7ac5df9d9..84bf30214b8 100644
--- a/chromium/chrome/browser/resources/media_router/elements/route_controls/route_controls.html
+++ b/chromium/chrome/browser/resources/media_router/elements/route_controls/route_controls.html
@@ -1,3 +1,4 @@
+<link rel="import" href="chrome://resources/html/md_select_css.html">
<link rel="import" href="chrome://resources/html/polymer.html">
<link rel="import" href="chrome://resources/html/i18n_behavior.html">
<link rel="import" href="chrome://resources/polymer/v1_0/iron-icons/av-icons.html">
@@ -7,10 +8,16 @@
<link rel="import" type="css" href="../../media_router_common.css">
<link rel="import" type="css" href="route_controls.css">
<template>
+ <style include="md-select"></style>
<div id="media-controls">
+ <!--
+ TODO(crbug.com/786208): Remove the div below and always render the
+ description in the details element. And, possibly combine details and
+ controls elements.
+ -->
<div class="ellipsis" id="route-description"
- title="[[displayedDescription_]]">
- [[displayedDescription_]]
+ title="[[routeDescription_]]">
+ [[routeDescription_]]
</div>
<div class="ellipsis" id="route-title" title="[[routeStatus.title]]">
[[routeStatus.title]]
@@ -81,6 +88,23 @@
</paper-checkbox>
</div>
</div>
+ <div id="mirroring-fullscreen-video-controls"
+ hidden="[[!routeStatus.mirroringExtraData]]">
+ [[i18n('fullscreenVideosDropdownTitle')]]
+ <span class="md-select-wrapper">
+ <select class="md-select"
+ id="mirroring-fullscreen-video-dropdown"
+ on-change="onFullscreenVideoDropdownChange_">
+ <option value="[[FullscreenVideoOption_.REMOTE_SCREEN]]">
+ [[i18n('fullscreenVideosRemoteScreen')]]
+ </option>
+ <option value="[[FullscreenVideoOption_.BOTH_SCREENS]]">
+ [[i18n('fullscreenVideosBothScreens')]]
+ </option>
+ </select>
+ <span class="md-select-underline"></span>
+ </span>
+ </div>
</div>
</div>
</template>
diff --git a/chromium/chrome/browser/resources/media_router/elements/route_controls/route_controls.js b/chromium/chrome/browser/resources/media_router/elements/route_controls/route_controls.js
index 00ec83a1893..570f03fe0e8 100644
--- a/chromium/chrome/browser/resources/media_router/elements/route_controls/route_controls.js
+++ b/chromium/chrome/browser/resources/media_router/elements/route_controls/route_controls.js
@@ -12,6 +12,20 @@ Polymer({
properties: {
/**
+ * Set of possible options for playing fullscreen videos when mirroring.
+ * @private {!Object}
+ */
+ FullscreenVideoOption_: {
+ type: Object,
+ value: {
+ // Play on remote screen only.
+ REMOTE_SCREEN: 'remote_screen',
+ // Play on both remote and local screens.
+ BOTH_SCREENS: 'both_screens'
+ }
+ },
+
+ /**
* The current time displayed in seconds, before formatting.
* @private {number}
*/
@@ -21,11 +35,11 @@ Polymer({
},
/**
- * The media description to display. Uses route description if none is
- * provided by the route status object.
+ * The route description to display. Uses the media route description if
+ * none is provided by the media route status object.
* @private {string}
*/
- displayedDescription_: {
+ routeDescription_: {
type: String,
value: '',
},
@@ -50,6 +64,15 @@ Polymer({
},
/**
+ * Keep in sync with media remoting individual user setting.
+ * @private {boolean}
+ */
+ mediaRemotingEnabled_: {
+ type: Boolean,
+ value: true,
+ },
+
+ /**
* The timestamp for when the initial media status was loaded.
* @private {number}
*/
@@ -348,7 +371,7 @@ Polymer({
this.displayedVolume_ = Math.round(newRouteStatus.volume * 100) / 100;
}
if (newRouteStatus.description !== '') {
- this.displayedDescription_ = newRouteStatus.description;
+ this.routeDescription_ = newRouteStatus.description;
}
if (!this.initialLoadTime_) {
this.initialLoadTime_ = Date.now();
@@ -362,6 +385,16 @@ Polymer({
}
this.hangoutsLocalPresent_ = !!newRouteStatus.hangoutsExtraData &&
newRouteStatus.hangoutsExtraData.localPresent;
+ if (newRouteStatus.mirroringExtraData) {
+ // Manually update the selected value on the
+ // mirroring-fullscreen-video-dropdown dropbox.
+ // TODO(imcheng): Avoid doing this by wrapping the dropbox in a Polymer
+ // template, or introduce <paper-dropdown-menu> to the Polymer library.
+ this.$['mirroring-fullscreen-video-dropdown'].value =
+ newRouteStatus.mirroringExtraData.mediaRemotingEnabled ?
+ this.FullscreenVideoOption_.REMOTE_SCREEN :
+ this.FullscreenVideoOption_.BOTH_SCREENS;
+ }
},
/**
@@ -375,8 +408,7 @@ Polymer({
this.stopIncrementingCurrentTime_();
}
if (route && this.routeStatus.description === '') {
- this.displayedDescription_ =
- loadTimeData.getStringF('castingActivityStatus', route.description);
+ this.routeDescription_ = route.description;
}
},
@@ -436,6 +468,19 @@ Polymer({
},
/**
+ * Called when the value on the mirroring-fullscreen-video-dropdown dropdown
+ * menu changes.
+ * @param {!Event} e
+ * @private
+ */
+ onFullscreenVideoDropdownChange_: function(e) {
+ /** @const */ var dropdownValue =
+ this.$['mirroring-fullscreen-video-dropdown'].value;
+ media_router.browserApi.setMediaRemotingEnabled(
+ dropdownValue == this.FullscreenVideoOption_.REMOTE_SCREEN);
+ },
+
+ /**
* Resets the route controls. Called when the route details view is closed.
*/
reset: function() {
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 742647da622..92f8b1a7dd1 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
@@ -17,12 +17,10 @@
text-align: end;
}
-#route-information {
+#route-description {
-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;
}
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 6bc2093cb04..8d91b1beac5 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
@@ -7,9 +7,9 @@
<link rel="import" type="css" href="../../media_router_common.css">
<link rel="import" type="css" href="route_details.css">
<template>
- <div id="route-information"
- hidden$="[[!shouldShowRouteInfoOnly_(controllerType_)]]">
- <span>[[activityStatus_]]</span>
+ <div class="ellipsis" id="route-description" title="[[routeDescription_]]"
+ hidden$="[[!shouldShowRouteDescription_(controllerType_)]]">
+ [[routeDescription_]]
</div>
<template is="dom-if" if="[[shouldAttemptLoadingExtensionView_(route)]]">
<extension-view-wrapper id="extension-view-wrapper" route="[[route]]"
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 b260d818c80..8724cd240f7 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
@@ -9,10 +9,10 @@ Polymer({
properties: {
/**
- * The text for the current casting activity status.
+ * Description of the current casting activity, e.g. "Casting YouTube".
* @private {string|undefined}
*/
- activityStatus_: {
+ routeDescription_: {
type: String,
},
@@ -191,15 +191,12 @@ Polymer({
},
/**
- * Updates |activityStatus_| for the default view.
+ * Updates |routeDescription_| for the default view.
*
* @private
*/
- updateActivityStatus_: function() {
- this.activityStatus_ = this.route ?
- loadTimeData.getStringF(
- 'castingActivityStatus', this.route.description) :
- '';
+ updateRouteDescription_: function() {
+ this.routeDescription_ = this.route ? this.route.description : '';
},
/**
@@ -231,7 +228,7 @@ Polymer({
*/
onRouteChange_: function(newRoute) {
if (this.controllerType_ !== media_router.ControllerType.WEBUI) {
- this.updateActivityStatus_();
+ this.updateRouteDescription_();
}
},
@@ -260,7 +257,7 @@ Polymer({
* the extensionview or the WebUI route controller.
* @private
*/
- shouldShowRouteInfoOnly_: function(controllerType) {
+ shouldShowRouteDescription_: function(controllerType) {
return controllerType === media_router.ControllerType.NONE;
},
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
index 5cf41b8e90d..758151b69db 100644
--- a/chromium/chrome/browser/resources/media_router/icons/media_router_icons.html
+++ b/chromium/chrome/browser/resources/media_router/icons/media_router_icons.html
@@ -10,7 +10,6 @@
<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="close"><path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"></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="folder"><path d="M0 0h24v24H0z" fill="none"></path><path d="M20 6h-8l-2-2H4c-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-2zm0 12H4V8h16v10z"></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="tab"><path d="M21 3H3c-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 16H3V5h10v4h8v10z"></path></g>
diff --git a/chromium/chrome/browser/resources/media_router/media_router.css b/chromium/chrome/browser/resources/media_router/media_router.css
index ad517c4ccee..4b3904a5add 100644
--- a/chromium/chrome/browser/resources/media_router/media_router.css
+++ b/chromium/chrome/browser/resources/media_router/media_router.css
@@ -3,7 +3,6 @@
* found in the LICENSE file. */
body {
- font-family: Roboto;
font-size: 0.75em;
margin: 0;
}
diff --git a/chromium/chrome/browser/resources/media_router/media_router_browser_api.js b/chromium/chrome/browser/resources/media_router/media_router_browser_api.js
index fe5e3b12e0e..9b5724b7401 100644
--- a/chromium/chrome/browser/resources/media_router/media_router_browser_api.js
+++ b/chromium/chrome/browser/resources/media_router/media_router_browser_api.js
@@ -312,6 +312,15 @@ cr.define('media_router.browserApi', function() {
chrome.send('hangouts.setLocalPresent', [localPresent]);
}
+ /**
+ * Sends a command to change the Media Remoting enabled value associated with
+ * current route.
+ * @param {boolean} enabled
+ */
+ function setMediaRemotingEnabled(enabled) {
+ chrome.send('setMediaRemotingEnabled', [enabled]);
+ }
+
return {
acknowledgeFirstRunFlow: acknowledgeFirstRunFlow,
actOnIssue: actOnIssue,
@@ -344,6 +353,7 @@ cr.define('media_router.browserApi', function() {
selectLocalMediaFile: selectLocalMediaFile,
setCurrentMediaMute: setCurrentMediaMute,
setCurrentMediaVolume: setCurrentMediaVolume,
- setHangoutsLocalPresent: setHangoutsLocalPresent
+ setHangoutsLocalPresent: setHangoutsLocalPresent,
+ setMediaRemotingEnabled: setMediaRemotingEnabled
};
});
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 dd22f1cc105..941120df475 100644
--- a/chromium/chrome/browser/resources/media_router/media_router_common.css
+++ b/chromium/chrome/browser/resources/media_router/media_router_common.css
@@ -8,6 +8,9 @@
--dialog-width: 340px;
--navigation-icon-button-size: 36px;
--non-navigation-icon-size: 16px;
+ -webkit-font-smoothing: antialiased;
+ -webkit-tap-highlight-color: transparent;
+ font-family: 'Roboto', 'Noto', sans-serif;
}
.button {
@@ -19,3 +22,14 @@
[hidden] {
display: none !important;
}
+
+.ellipsis {
+ padding: 0 1%;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+#route-description {
+ background-color: white;
+ overflow: hidden;
+}
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 d8252460856..bcb1b1664be 100644
--- a/chromium/chrome/browser/resources/media_router/media_router_data.js
+++ b/chromium/chrome/browser/resources/media_router/media_router_data.js
@@ -250,6 +250,8 @@ cr.define('media_router', function() {
* @param {number} duration The route's duration in seconds.
* @param {number} currentTime The route's current position in seconds.
* Must not be greater than |duration|.
+ * @param {!{mediaRemotingEnabled: boolean}=} mirroringExtraData Only set for
+ * mirroring routes.
* @param {!{localPresent: boolean}=} hangoutsExtraData Only set for Hangouts
* routes.
* @constructor
@@ -260,7 +262,7 @@ cr.define('media_router', function() {
canSetVolume = false, canSeek = false,
playState = media_router.PlayState.PLAYING, isPaused = false,
isMuted = false, volume = 0, duration = 0, currentTime = 0,
- hangoutsExtraData = undefined) {
+ hangoutsExtraData = undefined, mirroringExtraData = undefined) {
/** @type {string} */
this.title = title;
@@ -297,6 +299,9 @@ cr.define('media_router', function() {
/** @type {!{localPresent: boolean}|undefined} */
this.hangoutsExtraData = hangoutsExtraData;
+
+ /** @type {!{mediaRemotingEnabled: boolean}|undefined} */
+ this.mirroringExtraData = mirroringExtraData;
};
/**
diff --git a/chromium/chrome/browser/resources/net_internals/browser_bridge.js b/chromium/chrome/browser/resources/net_internals/browser_bridge.js
index 3068a34fe22..9a9c1c9e284 100644
--- a/chromium/chrome/browser/resources/net_internals/browser_bridge.js
+++ b/chromium/chrome/browser/resources/net_internals/browser_bridge.js
@@ -184,6 +184,10 @@ var BrowserBridge = (function() {
this.send('expectCTAdd', [domain, report_uri, enforce]);
},
+ sendExpectCTTestReport: function(report_uri) {
+ this.send('expectCTTestReport', [report_uri]);
+ },
+
sendGetSessionNetworkStats: function() {
this.send('getSessionNetworkStats');
},
@@ -331,6 +335,11 @@ var BrowserBridge = (function() {
this.expectCTObservers_[i].onExpectCTQueryResult(info);
},
+ receivedExpectCTTestReportResult: function(result) {
+ for (var i = 0; i < this.expectCTObservers_.length; i++)
+ this.expectCTObservers_[i].onExpectCTTestReportResult(result);
+ },
+
receivedONCFileParse: function(error) {
for (var i = 0; i < this.crosONCFileParseObservers_.length; i++)
this.crosONCFileParseObservers_[i].onONCFileParse(error);
diff --git a/chromium/chrome/browser/resources/net_internals/domain_security_policy_view.html b/chromium/chrome/browser/resources/net_internals/domain_security_policy_view.html
index ec6f6a25aed..5eb28dce892 100644
--- a/chromium/chrome/browser/resources/net_internals/domain_security_policy_view.html
+++ b/chromium/chrome/browser/resources/net_internals/domain_security_policy_view.html
@@ -79,6 +79,19 @@
id=expect-ct-view-query-output>
</div>
+ <h4>Send test Expect-CT report</h4>
+
+ <p>Trigger a test report to the given report URI. The report will contain a
+ hostname of "expect-ct-report.test" and dummy data in other fields.</p>
+ <form id=expect-ct-view-test-report-form>
+ <label>Report URI: <input type=text id=expect-ct-view-test-report-uri
+ type="url"></label>
+ <input type=submit value="Send" id=expect-ct-view-test-report-submit>
+ </form>
+ <div style="margin-top: 1em; margin-left: 2em;"
+ id=expect-ct-view-test-report-output>
+ </div>
+
<h3>Delete domain security policies</h3>
<p>
diff --git a/chromium/chrome/browser/resources/net_internals/domain_security_policy_view.js b/chromium/chrome/browser/resources/net_internals/domain_security_policy_view.js
index b345ad282bb..6f0d5a26b17 100644
--- a/chromium/chrome/browser/resources/net_internals/domain_security_policy_view.js
+++ b/chromium/chrome/browser/resources/net_internals/domain_security_policy_view.js
@@ -48,6 +48,10 @@ var DomainSecurityPolicyView = (function() {
$(DomainSecurityPolicyView.QUERY_EXPECT_CT_INPUT_ID);
this.queryExpectCTOutputDiv_ =
$(DomainSecurityPolicyView.QUERY_EXPECT_CT_OUTPUT_DIV_ID);
+ this.testExpectCTReportInput_ =
+ $(DomainSecurityPolicyView.TEST_REPORT_EXPECT_CT_INPUT_ID);
+ this.testExpectCTOutputDiv_ =
+ $(DomainSecurityPolicyView.TEST_REPORT_EXPECT_CT_OUTPUT_DIV_ID);
var form = $(DomainSecurityPolicyView.DELETE_FORM_ID);
form.addEventListener('submit', this.onSubmitDelete_.bind(this), false);
@@ -59,7 +63,7 @@ var DomainSecurityPolicyView = (function() {
form.addEventListener(
'submit', this.onSubmitHSTSPKPQuery_.bind(this), false);
- var form = $(DomainSecurityPolicyView.ADD_EXPECT_CT_FORM_ID);
+ form = $(DomainSecurityPolicyView.ADD_EXPECT_CT_FORM_ID);
form.addEventListener(
'submit', this.onSubmitExpectCTAdd_.bind(this), false);
@@ -67,6 +71,10 @@ var DomainSecurityPolicyView = (function() {
form.addEventListener(
'submit', this.onSubmitExpectCTQuery_.bind(this), false);
+ form = $(DomainSecurityPolicyView.TEST_REPORT_EXPECT_CT_FORM_ID);
+ form.addEventListener(
+ 'submit', this.onSubmitExpectCTTestReport_.bind(this), false);
+
g_browser.addHSTSObserver(this);
g_browser.addExpectCTObserver(this);
}
@@ -116,6 +124,14 @@ var DomainSecurityPolicyView = (function() {
'expect-ct-view-query-submit';
DomainSecurityPolicyView.QUERY_EXPECT_CT_OUTPUT_DIV_ID =
'expect-ct-view-query-output';
+ DomainSecurityPolicyView.TEST_REPORT_EXPECT_CT_INPUT_ID =
+ 'expect-ct-view-test-report-uri';
+ DomainSecurityPolicyView.TEST_REPORT_EXPECT_CT_FORM_ID =
+ 'expect-ct-view-test-report-form';
+ DomainSecurityPolicyView.TEST_REPORT_EXPECT_CT_SUBMIT_ID =
+ 'expect-ct-view-test-report-submit';
+ DomainSecurityPolicyView.TEST_REPORT_EXPECT_CT_OUTPUT_DIV_ID =
+ 'expect-ct-view-test-report-output';
cr.addSingletonGetter(DomainSecurityPolicyView);
@@ -285,7 +301,21 @@ var DomainSecurityPolicyView = (function() {
}
yellowFade(this.queryExpectCTOutputDiv_);
- }
+ },
+
+ onSubmitExpectCTTestReport_: function(event) {
+ g_browser.sendExpectCTTestReport(this.testExpectCTReportInput_.value);
+ event.preventDefault();
+ },
+
+ onExpectCTTestReportResult: function(result) {
+ if (result == 'success') {
+ addTextNode(this.testExpectCTOutputDiv_, 'Test report succeeded');
+ } else {
+ addTextNode(this.testExpectCTOutputDiv_, 'Test report failed');
+ }
+ yellowFade(this.testExpectCTOutputDiv_);
+ },
};
diff --git a/chromium/chrome/browser/resources/net_internals/events_view.js b/chromium/chrome/browser/resources/net_internals/events_view.js
index 679fdbc3fc4..60cd5a8134e 100644
--- a/chromium/chrome/browser/resources/net_internals/events_view.js
+++ b/chromium/chrome/browser/resources/net_internals/events_view.js
@@ -144,13 +144,6 @@ var EventsView = (function() {
},
/**
- * Updates text in the details view when privacy stripping is toggled.
- */
- onPrivacyStrippingChanged: function() {
- this.invalidateDetailsView_();
- },
-
- /**
* Updates text in the details view when time display mode is toggled.
*/
onUseRelativeTimesChanged: function() {
diff --git a/chromium/chrome/browser/resources/net_internals/log_util.js b/chromium/chrome/browser/resources/net_internals/log_util.js
index f690352a5ca..b616f2e1da3 100644
--- a/chromium/chrome/browser/resources/net_internals/log_util.js
+++ b/chromium/chrome/browser/resources/net_internals/log_util.js
@@ -9,8 +9,7 @@ log_util = (function() {
* Creates a new log dump. |events| is a list of all events, |polledData| is
* an object containing the results of each poll, |tabData| is an object
* containing data for individual tabs, |date| is the time the dump was
- * created, as a formatted string, and |privacyStripping| is whether or not
- * private information should be removed from the generated dump.
+ * created, as a formatted string.
*
* Returns the new log dump as an object. Resulting object may have a null
* |numericDate|.
@@ -32,11 +31,7 @@ log_util = (function() {
* tabs not present on the OS the log is from.
*/
function createLogDump(
- userComments, constants, events, polledData, tabData, numericDate,
- privacyStripping) {
- if (privacyStripping)
- events = events.map(stripPrivacyInfo);
-
+ userComments, constants, events, polledData, tabData, numericDate) {
var logDump = {
'userComments': userComments,
'constants': constants,
@@ -57,12 +52,11 @@ log_util = (function() {
* Creates a full log dump using |polledData| and the return value of each
* tab's saveState function and passes it to |callback|.
*/
- function onUpdateAllCompleted(
- userComments, callback, privacyStripping, polledData) {
+ function onUpdateAllCompleted(userComments, callback, polledData) {
var logDump = createLogDump(
userComments, Constants,
EventsTracker.getInstance().getAllCapturedEvents(), polledData,
- getTabData_(), timeutil.getCurrentTime(), privacyStripping);
+ getTabData_(), timeutil.getCurrentTime());
callback(JSON.stringify(logDump));
}
@@ -71,9 +65,9 @@ log_util = (function() {
* loaded. Once a log dump has been created, |callback| is passed the dumped
* text as a string.
*/
- function createLogDumpAsync(userComments, callback, privacyStripping) {
- g_browser.updateAllInfo(onUpdateAllCompleted.bind(
- null, userComments, callback, privacyStripping));
+ function createLogDumpAsync(userComments, callback) {
+ g_browser.updateAllInfo(
+ onUpdateAllCompleted.bind(null, userComments, callback));
}
/**
diff --git a/chromium/chrome/browser/resources/net_internals/log_view_painter.js b/chromium/chrome/browser/resources/net_internals/log_view_painter.js
index edb063bed16..205fcfae847 100644
--- a/chromium/chrome/browser/resources/net_internals/log_view_painter.js
+++ b/chromium/chrome/browser/resources/net_internals/log_view_painter.js
@@ -6,7 +6,6 @@
var createLogEntryTablePrinter;
var proxySettingsToString;
-var stripPrivacyInfo;
// Start of anonymous namespace.
(function() {
@@ -22,8 +21,7 @@ function canCollapseBeginWithEnd(beginEntry) {
* Creates a TablePrinter for use by the above two functions. baseTime is
* the time relative to which other times are displayed.
*/
-createLogEntryTablePrinter = function(
- logEntries, privacyStripping, baseTime, logCreationTime) {
+createLogEntryTablePrinter = function(logEntries, baseTime, logCreationTime) {
var entries = LogGroupEntry.createArrayFrom(logEntries);
var tablePrinter = new TablePrinter();
var parameterOutputter = new ParameterOutputter(tablePrinter);
@@ -66,7 +64,7 @@ createLogEntryTablePrinter = function(
if (typeof entry.orig.params == 'object') {
// Those 5 skipped cells are: two for "t=", and three for "st=".
tablePrinter.setNewRowCellIndent(5 + entry.getDepth());
- writeParameters(entry.orig, privacyStripping, parameterOutputter);
+ writeParameters(entry.orig, parameterOutputter);
tablePrinter.setNewRowCellIndent(0);
}
@@ -240,15 +238,10 @@ var ParameterOutputter = (function() {
* Certain event types have custom pretty printers. Everything else will
* default to a JSON-like format.
*/
-function writeParameters(entry, privacyStripping, out) {
- if (privacyStripping) {
- // If privacy stripping is enabled, remove data as needed.
- entry = stripPrivacyInfo(entry);
- } else {
- // If headers are in an object, convert them to an array for better
- // display.
- entry = reformatHeaders(entry);
- }
+function writeParameters(entry, out) {
+ // If headers are in an object, convert them to an array for better
+ // display.
+ entry = reformatHeaders(entry);
// Use any parameter writer available for this event type.
var paramsWriter = getParameterWriterForEventType(entry.type);
@@ -442,131 +435,6 @@ function reformatHeaders(entry) {
}
/**
- * Removes a cookie or unencrypted login information from a single HTTP header
- * line, if present, and returns the modified line. Otherwise, just returns
- * the original line.
- *
- * Note: this logic should be kept in sync with
- * net::ElideHeaderValueForNetLog in net/http/http_log_util.cc.
- */
-function stripCookieOrLoginInfo(line) {
- var patterns = [
- // Cookie patterns
- /^set-cookie: /i, /^set-cookie2: /i, /^cookie: /i,
-
- // Unencrypted authentication patterns
- /^authorization: \S*\s*/i, /^proxy-authorization: \S*\s*/i
- ];
-
- // Prefix will hold the first part of the string that contains no private
- // information. If null, no part of the string contains private
- // information.
- var prefix = null;
- for (var i = 0; i < patterns.length; i++) {
- var match = patterns[i].exec(line);
- if (match != null) {
- prefix = match[0];
- break;
- }
- }
-
- // Look for authentication information from data received from the server in
- // multi-round Negotiate authentication.
- if (prefix === null) {
- var challengePatterns =
- [/^www-authenticate: (\S*)\s*/i, /^proxy-authenticate: (\S*)\s*/i];
- for (var i = 0; i < challengePatterns.length; i++) {
- var match = challengePatterns[i].exec(line);
- if (!match)
- continue;
-
- // If there's no data after the scheme name, do nothing.
- if (match[0].length == line.length)
- break;
-
- // Ignore lines with commas, as they may contain lists of schemes, and
- // the information we want to hide is Base64 encoded, so has no commas.
- if (line.indexOf(',') >= 0)
- break;
-
- // Ignore Basic and Digest authentication challenges, as they contain
- // public information.
- if (/^basic$/i.test(match[1]) || /^digest$/i.test(match[1]))
- break;
-
- prefix = match[0];
- break;
- }
- }
-
- if (prefix) {
- var suffix = line.slice(prefix.length);
- // If private information has already been removed, keep the line as-is.
- // This is often the case when viewing a loaded log.
- if (suffix.search(/^\[[0-9]+ bytes were stripped\]$/) == -1) {
- return prefix + '[' + suffix.length + ' bytes were stripped]';
- }
- }
-
- return line;
-}
-
-/**
- * Remove debug data from HTTP/2 GOAWAY frame due to privacy considerations,
- * see
- * https://httpwg.github.io/specs/rfc7540.html#GOAWAY.
- *
- * Note: this logic should be kept in sync with
- * net::ElideGoAwayDebugDataForNetLog in net/http/http_log_util.cc.
- */
-function stripGoAwayDebugData(value) {
- return '[' + value.length + ' bytes were stripped]';
-}
-
-/**
- * If |entry| has headers, returns a copy of |entry| with all cookie and
- * unencrypted login text removed. Otherwise, returns original |entry|
- * object.
- * This is needed so that JSON log dumps can be made without affecting the
- * source data. Converts headers stored in objects to arrays.
- */
-stripPrivacyInfo = function(entry) {
- if (!entry.params) {
- return entry;
- }
-
- if (entry.type == EventType.HTTP2_SESSION_GOAWAY &&
- entry.params.debug_data != undefined) {
- // Duplicate the top level object, and |entry.params|. All other fields
- // are
- // just pointers to the original values, as they won't be modified, other
- // than |entry.params.debug_data|.
- entry = shallowCloneObject(entry);
- entry.params = shallowCloneObject(entry.params);
- entry.params.debug_data = stripGoAwayDebugData(entry.params.debug_data);
- return entry;
- }
-
- if (entry.params.headers === undefined ||
- !(entry.params.headers instanceof Object)) {
- return entry;
- }
-
- // Make sure entry's headers are in an array.
- entry = reformatHeaders(entry);
-
- // Duplicate the top level object, and |entry.params|. All other fields are
- // just pointers to the original values, as they won't be modified, other
- // than
- // |entry.params.headers|.
- entry = shallowCloneObject(entry);
- entry.params = shallowCloneObject(entry.params);
-
- entry.params.headers = entry.params.headers.map(stripCookieOrLoginInfo);
- return entry;
-};
-
-/**
* Outputs the request header parameters of |entry| to |out|.
*/
function writeParamsForRequestHeaders(entry, out, consumedParams) {
diff --git a/chromium/chrome/browser/resources/net_internals/main.js b/chromium/chrome/browser/resources/net_internals/main.js
index 6b286ea8b9a..875a93381e3 100644
--- a/chromium/chrome/browser/resources/net_internals/main.js
+++ b/chromium/chrome/browser/resources/net_internals/main.js
@@ -125,10 +125,8 @@ var MainView = (function() {
this.stopCapturing();
if (opt_fileName != undefined) {
// If there's a file name, a log file was loaded, so swap out the status
- // bar to indicate we're no longer capturing events. Also disable
- // hiding cookies, so if the log dump has them, they'll be displayed.
+ // bar to indicate we're no longer capturing events.
this.topBarView_.switchToSubView('loaded').setFileName(opt_fileName);
- SourceTracker.getInstance().setPrivacyStripping(false);
} else {
// Otherwise, the "Stop Capturing" button was presumably pressed.
// Don't disable hiding cookies, so created log dumps won't have them,
@@ -145,8 +143,11 @@ var MainView = (function() {
stopCapturing: function() {
g_browser.disable();
- document.styleSheets[0].insertRule(
- '.hide-when-not-capturing { display: none; }', 0);
+ var sheet = document.createElement('style');
+ sheet.type = 'text/css';
+ sheet.appendChild(document.createTextNode(
+ '.hide-when-not-capturing { display: none; }'));
+ document.head.appendChild(sheet);
},
initTabs_: function() {
diff --git a/chromium/chrome/browser/resources/net_internals/source_entry.js b/chromium/chrome/browser/resources/net_internals/source_entry.js
index bb1db6fcd08..100d72ee66e 100644
--- a/chromium/chrome/browser/resources/net_internals/source_entry.js
+++ b/chromium/chrome/browser/resources/net_internals/source_entry.js
@@ -335,7 +335,7 @@ var SourceEntry = (function() {
*/
createTablePrinter: function() {
return createLogEntryTablePrinter(
- this.entries_, SourceTracker.getInstance().getPrivacyStripping(),
+ this.entries_,
SourceTracker.getInstance().getUseRelativeTimes() ?
timeutil.getBaseTime() :
0,
diff --git a/chromium/chrome/browser/resources/net_internals/source_tracker.js b/chromium/chrome/browser/resources/net_internals/source_tracker.js
index 9e870db49e5..9dce848de5e 100644
--- a/chromium/chrome/browser/resources/net_internals/source_tracker.js
+++ b/chromium/chrome/browser/resources/net_internals/source_tracker.js
@@ -18,11 +18,6 @@ var SourceTracker = (function() {
// Observers that only want to receive lists of updated SourceEntries.
this.sourceEntryObservers_ = [];
- // True when cookies and authentication information should be removed from
- // displayed events. When true, such information should be hidden from
- // all pages.
- this.privacyStripping_ = true;
-
// True when times should be displayed as milliseconds since the first
// event, as opposed to milliseconds since January 1, 1970.
this.useRelativeTimes_ = true;
@@ -135,26 +130,6 @@ var SourceTracker = (function() {
},
/**
- * Sets the value of |privacyStripping_| and informs log observers
- * of the change.
- */
- setPrivacyStripping: function(privacyStripping) {
- this.privacyStripping_ = privacyStripping;
- for (var i = 0; i < this.sourceEntryObservers_.length; ++i) {
- if (this.sourceEntryObservers_[i].onPrivacyStrippingChanged)
- this.sourceEntryObservers_[i].onPrivacyStrippingChanged();
- }
- },
-
- /**
- * Returns whether or not cookies and authentication information should be
- * displayed for events that contain them.
- */
- getPrivacyStripping: function() {
- return this.privacyStripping_;
- },
-
- /**
* Sets the value of |useRelativeTimes_| and informs log observers
* of the change.
*/
@@ -176,12 +151,10 @@ var SourceTracker = (function() {
/**
* Adds a listener of SourceEntries. |observer| will be called back when
- * SourceEntries are added or modified, source entries are deleted, or
- * privacy stripping changes:
+ * SourceEntries are added or modified or source entries are deleted.
*
* observer.onSourceEntriesUpdated(sourceEntries)
* observer.onAllSourceEntriesDeleted()
- * observer.onPrivacyStrippingChanged()
*/
addSourceEntryObserver: function(observer) {
this.sourceEntryObservers_.push(observer);
diff --git a/chromium/chrome/browser/resources/ntp4/app_launcher_promo.png b/chromium/chrome/browser/resources/ntp4/app_launcher_promo.png
deleted file mode 100644
index 7cbae25e752..00000000000
--- a/chromium/chrome/browser/resources/ntp4/app_launcher_promo.png
+++ /dev/null
Binary files differ
diff --git a/chromium/chrome/browser/resources/ntp4/apps_page.css b/chromium/chrome/browser/resources/ntp4/apps_page.css
index c64ad4a8740..48473fc2eea 100644
--- a/chromium/chrome/browser/resources/ntp4/apps_page.css
+++ b/chromium/chrome/browser/resources/ntp4/apps_page.css
@@ -99,64 +99,3 @@
.app .invisible {
visibility: hidden;
}
-
-#app-launcher-promo {
- background-color: white;
- border: 1px solid lightgray;
- border-bottom-width: 3px;
- border-radius: 2px;
- border-top-width: 2px;
- bottom: 90px;
- height: 120px;
- left: 50%;
- margin-left: -300px;
- position: fixed;
- width: 600px;
-}
-
-#app-launcher-promo > .close-button {
- position: absolute;
- right: 10px;
- top: 10px;
- width: 14px;
-}
-
-.apps-promo-text {
- color: #222;
- font-size: 16px;
- left: 30px;
- line-height: 24px;
- position: absolute;
- top: 30px;
-}
-
-.apps-promo-learn-more {
- background-color: rgb(77, 144, 254);
- border: 1px solid rgb(47, 91, 183);
- border-radius: 2px;
- color: white;
- cursor: default;
- font-size: 11px;
- font-weight: bold;
- height: 27px;
- left: 30px;
- line-height: 27px;
- padding: 0 8px;
- position: absolute;
- text-align: center;
- text-decoration: none;
- top: 70px;
- width: 90px;
-}
-
-.apps-promo-learn-more:hover {
- background-image: -webkit-linear-gradient(
- top, rgb(77, 144, 254), rgb(53, 122, 232));
- border: 1px solid rgb(47, 91, 183);
-}
-
-#app-launcher-promo > img {
- bottom: 0;
- position: absolute;
- right: 30px;
-}
diff --git a/chromium/chrome/browser/resources/ntp4/incognito_tab.css b/chromium/chrome/browser/resources/ntp4/incognito_tab.css
index 67bd8c9d471..3b52699d588 100644
--- a/chromium/chrome/browser/resources/ntp4/incognito_tab.css
+++ b/chromium/chrome/browser/resources/ntp4/incognito_tab.css
@@ -1,32 +1,300 @@
-/* Copyright 2013 The Chromium Authors. All rights reserved.
+/* Copyright 2017 The Chromium 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-top: 0;
+ -webkit-font-smoothing: antialiased;
+ font-size: 100%;
+ margin: 0;
}
+/** Typography -------------------------------------------------------------- */
+
.content {
- background-color: #323232;
+ /* This is identical to the default background color. It's necessary to set it
+ for the case when a theme with a background image is installed. */
+ background-color: #303030;
+ color: rgba(255, 255, 255, 0.7);
+ font-size: calc(100% - 2px);
+ line-height: calc(100% + 6px);
+ min-width: 240px;
+}
+
+h1 {
+ color: rgba(255, 255, 255, 0.8);
+ font-size: calc(100% + 8px);
+ font-weight: 400;
+ line-height: calc(100% + 8px);
+}
+
+em {
color: white;
+ font-style: normal;
+}
+
+.learn-more-button {
+ color: rgb(123, 170, 247);
+ text-decoration: none;
}
+/* Small font on small screens. */
+@media (max-width: 240px),
+ (max-height: 320px) {
+ .content {
+ font-size: calc(100% - 4px);
+ line-height: calc(100% + 6px);
+ }
+
+ h1 {
+ font-size: calc(100% + 4px);
+ line-height: calc(100% + 4px);
+ }
+}
+
+/** Icon -------------------------------------------------------------------- */
+
.icon {
content: url(../../../../ui/webui/resources/images/incognito_splash.svg);
- display: inline-block;
height: 120px;
width: 120px;
}
+/* Medium-sized icon on medium-sized screens. */
+@media (max-height: 480px),
+ (max-width: 720px) {
+ .icon {
+ height: 72px;
+ width: 72px;
+ }
+}
+
+/* Very small icon on very small screens. */
+@media (max-width: 720px) {
+ @media (max-width: 240px),
+ (max-height: 480px) {
+ .icon {
+ height: 48px;
+ width: 48px;
+ }
+ }
+}
+
+/** The "Learn more" link --------------------------------------------------- */
+
+/* By default, we only show the inline "Learn more" link. */
+.content > .learn-more-button {
+ display: none;
+}
+
+/* On narrow screens, we show the standalone "Learn more" link. */
+@media (max-width: 720px) {
+ #subtitle > .learn-more-button {
+ display: none;
+ }
+
+ .content > .learn-more-button {
+ display: block;
+ }
+}
+
+/** Layout ------------------------------------------------------------------ */
+
+/* Align the content, icon, and title to to the center. */
+.content {
+ margin-left: auto;
+ margin-right: auto;
+ max-width: 600px;
+}
+
+.icon {
+ margin-left: auto;
+ margin-right: auto;
+}
+
h1 {
- margin-top: .88em;
- opacity: .8;
+ text-align: center;
}
-p {
- opacity: .8;
+/* Align the two columns of bulletpoints next to each other. */
+.bulletpoints {
+ float: left;
}
-.learn-more-button {
- color: rgb(123, 170, 247);
+html[dir=rtl] .bulletpoints {
+ float: right;
+}
+
+.bulletpoints + .bulletpoints {
+ clear: right;
+}
+
+html[dir=rtl] .bulletpoints + .bulletpoints {
+ clear: left;
+}
+
+.clearer {
+ clear: both;
+}
+
+/* On narrow screens, align everything to the left. */
+@media (max-width: 720px) {
+ .content {
+ max-width: 600px !important; /* must override the rule set by JS which
+ * is only valid for width > 720px cases. */
+ text-align: start;
+ }
+
+ .icon {
+ -webkit-margin-start: 0;
+ }
+
+ h1 {
+ text-align: start;
+ }
+
+ .bulletpoints + .bulletpoints,
+ html[dir=rtl] .bulletpoints + .bulletpoints {
+ clear: both;
+ }
+}
+
+/** Paddings and margins ---------------------------------------------------- */
+
+.bulletpoints ul {
+ -webkit-padding-start: 16px;
+ margin: 4px 0 0;
+}
+
+/* Margins of floating elements don't collapse. The margin for bulletpoints
+ * will usually be provided by a neighboring element. */
+.bulletpoints {
+ margin: 0;
+}
+
+.bulletpoints + .bulletpoints {
+ -webkit-margin-start: 40px;
+}
+
+.bulletpoints + .bulletpoints.too-wide {
+ -webkit-margin-start: 0;
+ margin-top: 1.5rem;
+}
+
+/* Wide screens. */
+@media (min-width: 720px) {
+ .icon,
+ h1,
+ #subtitle,
+ .learn-more-button {
+ margin-bottom: 1.5rem;
+ margin-top: 1.5rem;
+ }
+
+ .content {
+ margin-top: 40px;
+ min-width: 240px;
+ padding: 8px 48px 24px;
+ }
+
+ /* Snap the content box to the whole height on short screens. */
+ @media (max-height: 480px) {
+ html,
+ body,
+ .content {
+ height: 100%;
+ }
+
+ .content {
+ margin-bottom: 0;
+ margin-top: 0;
+ padding-bottom: 0;
+ padding-top: 0;
+ }
+
+ .icon {
+ margin-top: 0;
+ padding-top: 32px; /* Define the top offset through the icon's padding,
+ * otherwise the screen height would be 100% + 32px */
+ }
+ }
+
+ /* Smaller vertical margins on very short screens. */
+ @media (max-height: 320px) {
+ h1,
+ #subtitle,
+ .learn-more-button {
+ margin-bottom: 16px;
+ margin-top: 16px;
+ }
+
+ .icon {
+ margin-bottom: 16px;
+ }
+ }
+}
+
+/* Narrow screens */
+@media (max-width: 720px) {
+ .content {
+ padding: 72px 32px;
+ min-width: 176px;
+ }
+
+ .icon,
+ h1,
+ #subtitle,
+ .learn-more-button {
+ margin-bottom: 1.5rem;
+ margin-top: 1.5rem;
+ }
+
+ /* The two columns of bulletpoints are moved under each other. */
+ .bulletpoints + .bulletpoints {
+ -webkit-margin-start: 0;
+ margin-top: 1.5rem;
+ }
+
+ /* Smaller offsets on smaller screens. */
+ @media (max-height: 600px) {
+ .content {
+ padding-top: 48px;
+ }
+
+ .icon,
+ h1,
+ #subtitle,
+ .learn-more-button {
+ margin-bottom: 1rem;
+ margin-top: 1rem;
+ }
+
+ .bulletpoints + .bulletpoints {
+ margin-top: 1rem;
+ }
+ }
+
+ /* Small top offset on very small screens. */
+ @media (max-height: 480px) {
+ .content {
+ padding-top: 32px;
+ }
+ }
+
+ /* Undo the first and last elements margins. */
+ .icon {
+ margin-top: 0;
+ }
+
+ .learn-more-button {
+ margin-bottom: 0;
+ }
+}
+
+/* Very narrow screens. */
+@media (max-width: 240px) {
+ .content {
+ min-width: 192px;
+ padding-left: 24px;
+ padding-right: 24px;
+ }
}
diff --git a/chromium/chrome/browser/resources/ntp4/incognito_tab.html b/chromium/chrome/browser/resources/ntp4/incognito_tab.html
index 5d4a5198c14..52dce6e017b 100644
--- a/chromium/chrome/browser/resources/ntp4/incognito_tab.html
+++ b/chromium/chrome/browser/resources/ntp4/incognito_tab.html
@@ -1,14 +1,14 @@
<!doctype html>
<html dir="$i18n{textdirection}"
- hascustombackground="$i18n{hasCustomBackground}"
- bookmarkbarattached="$i18n{bookmarkbarattached}"
- lang="$i18n{language}">
+ hascustombackground="$i18n{hasCustomBackground}"
+ bookmarkbarattached="$i18n{bookmarkbarattached}"
+ lang="$i18n{language}"
+ class="md">
<head>
<meta charset="utf-8">
<title>$i18n{title}</title>
<meta name="viewport" content="width=device-width">
<link rel="stylesheet" href="chrome://resources/css/text_defaults_md.css">
-<link rel="stylesheet" href="incognito_and_guest_tab.css">
<link rel="stylesheet" href="incognito_tab.css">
<script>
// Until themes can clear the cache, force-reload the theme stylesheet.
@@ -19,28 +19,22 @@ document.write('<link id="incognitothemecss" rel="stylesheet" ' +
</head>
<body>
<div class="content">
- <div class="icon"></div>
+ <div class="icon" role="presentation" alt=""></div>
<h1>$i18n{incognitoTabHeading}</h1>
- <p>$i18n{incognitoTabDescription}</p>
- <p>$i18n{incognitoTabWarning}</p>
+ <p id="subtitle">
+ <span>$i18n{incognitoTabDescription}</span>
+ <a class="learn-more-button"
+ href="$i18n{learnMoreLink}">$i18n{learnMore}</a>
+ </p>
+ <div>
+ <div class="bulletpoints">$i18nRaw{incognitoTabFeatures}</div>
+ <div class="bulletpoints">$i18nRaw{incognitoTabWarning}</div>
+ <div class="clearer"></div>
+ </div>
<a class="learn-more-button" href="$i18n{learnMoreLink}">$i18n{learnMore}</a>
</div>
-
-<script>
-var ntp = {
- /** @param {string} attached */
- setBookmarkBarAttached: function(attached) {
- document.documentElement.setAttribute('bookmarkbarattached', attached);
- },
-
- /** @param {!{hasCustomBackground: boolean}} themeData */
- themeChanged: function(themeData) {
- document.documentElement.setAttribute('hascustombackground',
- themeData.hasCustomBackground);
- document.getElementById('incognitothemecss').href =
- 'chrome://theme/css/incognito_new_tab_theme.css?' + Date.now();
- },
-};
-</script>
+<script src="chrome://resources/js/cr.js"></script>
+<script src="chrome://resources/js/util.js"></script>
+<script src="incognito_tab.js"></script>
</body>
</html>
diff --git a/chromium/chrome/browser/resources/ntp4/md_incognito_tab.js b/chromium/chrome/browser/resources/ntp4/incognito_tab.js
index 4b246225fb8..4b246225fb8 100644
--- a/chromium/chrome/browser/resources/ntp4/md_incognito_tab.js
+++ b/chromium/chrome/browser/resources/ntp4/incognito_tab.js
diff --git a/chromium/chrome/browser/resources/ntp4/md_incognito_tab.css b/chromium/chrome/browser/resources/ntp4/md_incognito_tab.css
deleted file mode 100644
index 3b52699d588..00000000000
--- a/chromium/chrome/browser/resources/ntp4/md_incognito_tab.css
+++ /dev/null
@@ -1,300 +0,0 @@
-/* Copyright 2017 The Chromium 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 {
- -webkit-font-smoothing: antialiased;
- font-size: 100%;
- margin: 0;
-}
-
-/** Typography -------------------------------------------------------------- */
-
-.content {
- /* This is identical to the default background color. It's necessary to set it
- for the case when a theme with a background image is installed. */
- background-color: #303030;
- color: rgba(255, 255, 255, 0.7);
- font-size: calc(100% - 2px);
- line-height: calc(100% + 6px);
- min-width: 240px;
-}
-
-h1 {
- color: rgba(255, 255, 255, 0.8);
- font-size: calc(100% + 8px);
- font-weight: 400;
- line-height: calc(100% + 8px);
-}
-
-em {
- color: white;
- font-style: normal;
-}
-
-.learn-more-button {
- color: rgb(123, 170, 247);
- text-decoration: none;
-}
-
-/* Small font on small screens. */
-@media (max-width: 240px),
- (max-height: 320px) {
- .content {
- font-size: calc(100% - 4px);
- line-height: calc(100% + 6px);
- }
-
- h1 {
- font-size: calc(100% + 4px);
- line-height: calc(100% + 4px);
- }
-}
-
-/** Icon -------------------------------------------------------------------- */
-
-.icon {
- content: url(../../../../ui/webui/resources/images/incognito_splash.svg);
- height: 120px;
- width: 120px;
-}
-
-/* Medium-sized icon on medium-sized screens. */
-@media (max-height: 480px),
- (max-width: 720px) {
- .icon {
- height: 72px;
- width: 72px;
- }
-}
-
-/* Very small icon on very small screens. */
-@media (max-width: 720px) {
- @media (max-width: 240px),
- (max-height: 480px) {
- .icon {
- height: 48px;
- width: 48px;
- }
- }
-}
-
-/** The "Learn more" link --------------------------------------------------- */
-
-/* By default, we only show the inline "Learn more" link. */
-.content > .learn-more-button {
- display: none;
-}
-
-/* On narrow screens, we show the standalone "Learn more" link. */
-@media (max-width: 720px) {
- #subtitle > .learn-more-button {
- display: none;
- }
-
- .content > .learn-more-button {
- display: block;
- }
-}
-
-/** Layout ------------------------------------------------------------------ */
-
-/* Align the content, icon, and title to to the center. */
-.content {
- margin-left: auto;
- margin-right: auto;
- max-width: 600px;
-}
-
-.icon {
- margin-left: auto;
- margin-right: auto;
-}
-
-h1 {
- text-align: center;
-}
-
-/* Align the two columns of bulletpoints next to each other. */
-.bulletpoints {
- float: left;
-}
-
-html[dir=rtl] .bulletpoints {
- float: right;
-}
-
-.bulletpoints + .bulletpoints {
- clear: right;
-}
-
-html[dir=rtl] .bulletpoints + .bulletpoints {
- clear: left;
-}
-
-.clearer {
- clear: both;
-}
-
-/* On narrow screens, align everything to the left. */
-@media (max-width: 720px) {
- .content {
- max-width: 600px !important; /* must override the rule set by JS which
- * is only valid for width > 720px cases. */
- text-align: start;
- }
-
- .icon {
- -webkit-margin-start: 0;
- }
-
- h1 {
- text-align: start;
- }
-
- .bulletpoints + .bulletpoints,
- html[dir=rtl] .bulletpoints + .bulletpoints {
- clear: both;
- }
-}
-
-/** Paddings and margins ---------------------------------------------------- */
-
-.bulletpoints ul {
- -webkit-padding-start: 16px;
- margin: 4px 0 0;
-}
-
-/* Margins of floating elements don't collapse. The margin for bulletpoints
- * will usually be provided by a neighboring element. */
-.bulletpoints {
- margin: 0;
-}
-
-.bulletpoints + .bulletpoints {
- -webkit-margin-start: 40px;
-}
-
-.bulletpoints + .bulletpoints.too-wide {
- -webkit-margin-start: 0;
- margin-top: 1.5rem;
-}
-
-/* Wide screens. */
-@media (min-width: 720px) {
- .icon,
- h1,
- #subtitle,
- .learn-more-button {
- margin-bottom: 1.5rem;
- margin-top: 1.5rem;
- }
-
- .content {
- margin-top: 40px;
- min-width: 240px;
- padding: 8px 48px 24px;
- }
-
- /* Snap the content box to the whole height on short screens. */
- @media (max-height: 480px) {
- html,
- body,
- .content {
- height: 100%;
- }
-
- .content {
- margin-bottom: 0;
- margin-top: 0;
- padding-bottom: 0;
- padding-top: 0;
- }
-
- .icon {
- margin-top: 0;
- padding-top: 32px; /* Define the top offset through the icon's padding,
- * otherwise the screen height would be 100% + 32px */
- }
- }
-
- /* Smaller vertical margins on very short screens. */
- @media (max-height: 320px) {
- h1,
- #subtitle,
- .learn-more-button {
- margin-bottom: 16px;
- margin-top: 16px;
- }
-
- .icon {
- margin-bottom: 16px;
- }
- }
-}
-
-/* Narrow screens */
-@media (max-width: 720px) {
- .content {
- padding: 72px 32px;
- min-width: 176px;
- }
-
- .icon,
- h1,
- #subtitle,
- .learn-more-button {
- margin-bottom: 1.5rem;
- margin-top: 1.5rem;
- }
-
- /* The two columns of bulletpoints are moved under each other. */
- .bulletpoints + .bulletpoints {
- -webkit-margin-start: 0;
- margin-top: 1.5rem;
- }
-
- /* Smaller offsets on smaller screens. */
- @media (max-height: 600px) {
- .content {
- padding-top: 48px;
- }
-
- .icon,
- h1,
- #subtitle,
- .learn-more-button {
- margin-bottom: 1rem;
- margin-top: 1rem;
- }
-
- .bulletpoints + .bulletpoints {
- margin-top: 1rem;
- }
- }
-
- /* Small top offset on very small screens. */
- @media (max-height: 480px) {
- .content {
- padding-top: 32px;
- }
- }
-
- /* Undo the first and last elements margins. */
- .icon {
- margin-top: 0;
- }
-
- .learn-more-button {
- margin-bottom: 0;
- }
-}
-
-/* Very narrow screens. */
-@media (max-width: 240px) {
- .content {
- min-width: 192px;
- padding-left: 24px;
- padding-right: 24px;
- }
-}
diff --git a/chromium/chrome/browser/resources/ntp4/md_incognito_tab.html b/chromium/chrome/browser/resources/ntp4/md_incognito_tab.html
deleted file mode 100644
index 5cad43b07bd..00000000000
--- a/chromium/chrome/browser/resources/ntp4/md_incognito_tab.html
+++ /dev/null
@@ -1,40 +0,0 @@
-<!doctype html>
-<html dir="$i18n{textdirection}"
- hascustombackground="$i18n{hasCustomBackground}"
- bookmarkbarattached="$i18n{bookmarkbarattached}"
- lang="$i18n{language}"
- class="md">
-<head>
-<meta charset="utf-8">
-<title>$i18n{title}</title>
-<meta name="viewport" content="width=device-width">
-<link rel="stylesheet" href="chrome://resources/css/text_defaults_md.css">
-<link rel="stylesheet" href="md_incognito_tab.css">
-<script>
-// Until themes can clear the cache, force-reload the theme stylesheet.
-document.write('<link id="incognitothemecss" rel="stylesheet" ' +
- 'href="chrome://theme/css/incognito_new_tab_theme.css?' +
- Date.now() + '">');
-</script>
-</head>
-<body>
-<div class="content">
- <div class="icon" role="presentation" alt=""></div>
- <h1>$i18n{incognitoTabHeading}</h1>
- <p id="subtitle">
- <span>$i18n{incognitoTabDescription}</span>
- <a class="learn-more-button"
- href="$i18n{learnMoreLink}">$i18n{learnMore}</a>
- </p>
- <div>
- <div class="bulletpoints">$i18nRaw{incognitoTabFeatures}</div>
- <div class="bulletpoints">$i18nRaw{incognitoTabWarning}</div>
- <div class="clearer"></div>
- </div>
- <a class="learn-more-button" href="$i18n{learnMoreLink}">$i18n{learnMore}</a>
-</div>
-<script src="chrome://resources/js/cr.js"></script>
-<script src="chrome://resources/js/util.js"></script>
-<script src="md_incognito_tab.js"></script>
-</body>
-</html>
diff --git a/chromium/chrome/browser/resources/ntp4/new_tab.html b/chromium/chrome/browser/resources/ntp4/new_tab.html
index bc44bba405b..d6f57b23e2a 100644
--- a/chromium/chrome/browser/resources/ntp4/new_tab.html
+++ b/chromium/chrome/browser/resources/ntp4/new_tab.html
@@ -78,18 +78,6 @@ document.write('<link id="themecss" rel="stylesheet" ' +
</div>
</div>
- <div id="app-launcher-promo" hidden>
- <div class="apps-promo-text">$i18n{appsPromoTitle}</div>
- <a href="https://chrome.google.com/webstore/launcher"
- id="apps-promo-learn-more" class="apps-promo-learn-more">
- $i18n{learn_more}
- </a>
- <img src="app_launcher_promo.png">
- <button class="close-button custom-appearance"
- id="app-launcher-promo-close-button">
- </button>
- </div>
-
<div id="footer">
<div id="footer-border"></div>
<div id="footer-content">
diff --git a/chromium/chrome/browser/resources/ntp4/new_tab.js b/chromium/chrome/browser/resources/ntp4/new_tab.js
index bcf8a7b028b..c6564c4f062 100644
--- a/chromium/chrome/browser/resources/ntp4/new_tab.js
+++ b/chromium/chrome/browser/resources/ntp4/new_tab.js
@@ -76,15 +76,6 @@ cr.define('ntp', function() {
*/
function onLoad() {
sectionsToWaitFor = 1;
- if (loadTimeData.getBoolean('showAppLauncherPromo')) {
- $('app-launcher-promo-close-button')
- .addEventListener('click', function() {
- chrome.send('stopShowingAppLauncherPromo');
- });
- $('apps-promo-learn-more').addEventListener('click', function() {
- chrome.send('onLearnMore');
- });
- }
measureNavDots();
newTabView = new NewTabView();
diff --git a/chromium/chrome/browser/resources/ntp4/page_list_view.js b/chromium/chrome/browser/resources/ntp4/page_list_view.js
index 89bb392b521..3f2e99b8ca5 100644
--- a/chromium/chrome/browser/resources/ntp4/page_list_view.js
+++ b/chromium/chrome/browser/resources/ntp4/page_list_view.js
@@ -402,7 +402,6 @@ cr.define('ntp', function() {
this.appsLoaded_ = true;
cr.dispatchSimpleEvent(document, 'sectionready', true, true);
}
- this.updateAppLauncherPromoHiddenState_();
},
/**
@@ -460,25 +459,6 @@ cr.define('ntp', function() {
},
/**
- * Callback invoked by chrome whenever the app launcher promo pref changes.
- * @param {boolean} show Identifies if we should show or hide the promo.
- */
- appLauncherPromoPrefChangeCallback: function(show) {
- loadTimeData.overrideValues({showAppLauncherPromo: show});
- this.updateAppLauncherPromoHiddenState_();
- },
-
- /**
- * 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');
- },
-
- /**
* Invoked whenever the pages in apps-page-list have changed so that
* the Slider knows about the new elements.
*/
@@ -632,7 +612,6 @@ cr.define('ntp', function() {
assert(shownPageIndex >= 0);
this.shownPageIndex = shownPageIndex;
chrome.send('pageSelected', [this.shownPageIndex]);
- this.updateAppLauncherPromoHiddenState_();
},
/**
diff --git a/chromium/chrome/browser/resources/offline_pages/offline_internals.css b/chromium/chrome/browser/resources/offline_pages/offline_internals.css
index 534ae985fa9..d8ad7a582d6 100644
--- a/chromium/chrome/browser/resources/offline_pages/offline_internals.css
+++ b/chromium/chrome/browser/resources/offline_pages/offline_internals.css
@@ -47,6 +47,10 @@ li:nth-child(2n) {
background-color: lavender;
}
+dialog {
+ border: none;
+}
+
#current-status {
font-size: 15px;
}
@@ -55,3 +59,10 @@ li:nth-child(2n) {
font-family: monospace;
white-space: pre-wrap;
}
+
+#dump-box {
+ box-sizing: border-box;
+ display: block;
+ resize: none;
+ width: 100%;
+}
diff --git a/chromium/chrome/browser/resources/offline_pages/offline_internals.html b/chromium/chrome/browser/resources/offline_pages/offline_internals.html
index 2590edbda99..013cfd09390 100644
--- a/chromium/chrome/browser/resources/offline_pages/offline_internals.html
+++ b/chromium/chrome/browser/resources/offline_pages/offline_internals.html
@@ -19,8 +19,15 @@
<div>
<span id="current-status"></span>
<button id="refresh">Refresh page</button>
- <button id="download">Dump</button>
+ <button id="dump">Dump</button>
</div>
+ <dialog id="dump-modal">
+ <textarea id="dump-box" name="json-box" rows="10" cols="40" readonly>
+ </textarea>
+ <button id="copy-to-clipboard">Copy</button>
+ <button id="close-dump">Close</button>
+ <span id="dump-info"></span>
+ </dialog>
<h2>Event Logs</h2>
<div>
diff --git a/chromium/chrome/browser/resources/offline_pages/offline_internals.js b/chromium/chrome/browser/resources/offline_pages/offline_internals.js
index 2605b0b781a..d9034ccda18 100644
--- a/chromium/chrome/browser/resources/offline_pages/offline_internals.js
+++ b/chromium/chrome/browser/resources/offline_pages/offline_internals.js
@@ -35,18 +35,18 @@ cr.define('offlineInternals', function() {
var template = $('stored-pages-table-row');
var td = template.content.querySelectorAll('td');
- for (var i = 0; i < pages.length; i++) {
+ for (let page of pages) {
var checkbox = td[0].querySelector('input');
- checkbox.setAttribute('value', pages[i].id);
+ checkbox.setAttribute('value', page.id);
var link = td[1].querySelector('a');
- link.setAttribute('href', pages[i].onlineUrl);
- link.textContent = pages[i].onlineUrl;
+ link.setAttribute('href', page.onlineUrl);
+ link.textContent = page.onlineUrl;
- td[2].textContent = pages[i].namespace;
- td[3].textContent = Math.round(pages[i].size / 1024);
- td[4].textContent = pages[i].isExpired;
- td[5].textContent = pages[i].requestOrigin;
+ td[2].textContent = page.namespace;
+ td[3].textContent = Math.round(page.size / 1024);
+ td[4].textContent = page.isExpired;
+ td[5].textContent = page.requestOrigin;
var row = document.importNode(template.content, true);
storedPagesTable.appendChild(row);
@@ -65,14 +65,14 @@ cr.define('offlineInternals', function() {
var template = $('request-queue-table-row');
var td = template.content.querySelectorAll('td');
- for (var i = 0; i < requests.length; i++) {
+ for (let request of requests) {
var checkbox = td[0].querySelector('input');
- checkbox.setAttribute('value', requests[i].id);
+ checkbox.setAttribute('value', request.id);
- td[1].textContent = requests[i].onlineUrl;
- td[2].textContent = new Date(requests[i].creationTime);
- td[3].textContent = requests[i].status;
- td[4].textContent = requests[i].requestOrigin;
+ td[1].textContent = request.onlineUrl;
+ td[2].textContent = new Date(request.creationTime);
+ td[3].textContent = request.status;
+ td[4].textContent = request.requestOrigin;
var row = document.importNode(template.content, true);
requestQueueTable.appendChild(row);
@@ -171,15 +171,33 @@ cr.define('offlineInternals', function() {
/**
* Downloads all the stored page and request queue information into a file.
+ * Also translates all the fields representing datetime into human-readable
+ * date strings.
* TODO(chili): Create a CSV writer that can abstract out the line joining.
*/
- function download() {
+ function dumpAsJson() {
var json = JSON.stringify(
- {offlinePages: offlinePages, savePageRequests: savePageRequests}, null,
+ {offlinePages: offlinePages, savePageRequests: savePageRequests},
+ function(key, value) {
+ return key.endsWith('Time') ? new Date(value).toString() : value;
+ },
2);
- window.open(
- 'data:application/json,' + encodeURIComponent(json), 'dump.json');
+ $('dump-box').value = json;
+ $('dump-info').textContent = '';
+ $('dump-modal').showModal();
+ $('dump-box').select();
+ }
+
+ function closeDump() {
+ $('dump-modal').close();
+ $('dump-box').value = '';
+ }
+
+ function copyDump() {
+ $('dump-box').select();
+ document.execCommand('copy');
+ $('dump-info').textContent = 'Copied to clipboard!';
}
/**
@@ -260,22 +278,19 @@ cr.define('offlineInternals', function() {
}
var incognito = loadTimeData.getBoolean('isIncognito');
- $('delete-all-pages').disabled = incognito;
- $('delete-selected-pages').disabled = incognito;
- $('delete-all-requests').disabled = incognito;
- $('delete-selected-requests').disabled = incognito;
- $('log-model-on').disabled = incognito;
- $('log-model-off').disabled = incognito;
- $('log-request-on').disabled = incognito;
- $('log-request-off').disabled = incognito;
- $('refresh').disabled = incognito;
+ ['delete-all-pages', 'delete-selected-pages', 'delete-all-requests',
+ 'delete-selected-requests', 'log-model-on', 'log-model-off',
+ 'log-request-on', 'log-request-off', 'refresh']
+ .forEach(el => $(el).disabled = incognito);
$('delete-all-pages').onclick = deleteAllPages;
$('delete-selected-pages').onclick = deleteSelectedPages;
$('delete-all-requests').onclick = deleteAllRequests;
$('delete-selected-requests').onclick = deleteSelectedRequests;
$('refresh').onclick = refreshAll;
- $('download').onclick = download;
+ $('dump').onclick = dumpAsJson;
+ $('close-dump').onclick = closeDump;
+ $('copy-to-clipboard').onclick = copyDump;
$('log-model-on').onclick = togglePageModelLog.bind(this, true);
$('log-model-off').onclick = togglePageModelLog.bind(this, false);
$('log-request-on').onclick = toggleRequestQueueLog.bind(this, true);
diff --git a/chromium/chrome/browser/resources/offline_pages/offline_internals_browser_proxy.js b/chromium/chrome/browser/resources/offline_pages/offline_internals_browser_proxy.js
index b30b277609c..04edadc8093 100644
--- a/chromium/chrome/browser/resources/offline_pages/offline_internals_browser_proxy.js
+++ b/chromium/chrome/browser/resources/offline_pages/offline_internals_browser_proxy.js
@@ -25,7 +25,7 @@ var OfflinePage;
* creationTime: number,
* id: string,
* namespace: string,
- * lastAttempt: number,
+ * lastAttemptTime: number,
* requestOrigin: string
* }}
*/
diff --git a/chromium/chrome/browser/resources/password_manager_internals/OWNERS b/chromium/chrome/browser/resources/password_manager_internals/OWNERS
deleted file mode 100644
index e8e1954be35..00000000000
--- a/chromium/chrome/browser/resources/password_manager_internals/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-mkwst@chromium.org
-vabr@chromium.org
-
-# COMPONENT: UI>Browser>Passwords
diff --git a/chromium/chrome/browser/resources/password_manager_internals/password_manager_internals.css b/chromium/chrome/browser/resources/password_manager_internals/password_manager_internals.css
deleted file mode 100644
index 09a6603607a..00000000000
--- a/chromium/chrome/browser/resources/password_manager_internals/password_manager_internals.css
+++ /dev/null
@@ -1,31 +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.
- *
- * chrome://password-manager-internals/ */
-
-#logging-note {
- font-style: italic;
-}
-
-#logging-note-incognito {
- font-style: italic;
-}
-
-/* Initially, nothing is visible, to avoid flicker. */
-#log-entries,
-#logging-note,
-#logging-note-incognito {
- display: none;
-}
-
-/* Visibility settings for non-Incognito tabs. */
-[data-incognito=false] #log-entries,
-[data-incognito=false] #logging-note {
- display: block;
-}
-
-/* Visibility settings for Incognito tabs. */
-[data-incognito=true] #logging-note-incognito {
- display: block;
-}
diff --git a/chromium/chrome/browser/resources/password_manager_internals/password_manager_internals.html b/chromium/chrome/browser/resources/password_manager_internals/password_manager_internals.html
deleted file mode 100644
index 0339d394d7a..00000000000
--- a/chromium/chrome/browser/resources/password_manager_internals/password_manager_internals.html
+++ /dev/null
@@ -1,25 +0,0 @@
-<!doctype html>
-<html>
-<head>
-<!-- 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. -->
-<script src="chrome://resources/js/util.js"></script>
-<script src="chrome://password-manager-internals/password_manager_internals.js"></script>
-<title>Password Manager Internals</title>
-<link rel="stylesheet" href="chrome://resources/css/chrome_shared.css">
-<link rel="stylesheet" href="password_manager_internals.css">
-</head>
-<body>
-<h1>Password Manager Internals</h1>
-<div id="logging-note">
- Captured password manager logs are listed below. Logs are cleared and no
- longer captured when all password-manager-internals pages are closed.
-</div>
-<div id="logging-note-incognito">
- Captured password manager logs are <em>not available</em> in Incognito.
-</div>
-<div id="log-entries">
-</div>
-</body>
-</html>
diff --git a/chromium/chrome/browser/resources/password_manager_internals/password_manager_internals.js b/chromium/chrome/browser/resources/password_manager_internals/password_manager_internals.js
deleted file mode 100644
index ca5637e01b5..00000000000
--- a/chromium/chrome/browser/resources/password_manager_internals/password_manager_internals.js
+++ /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.
-
-function addSavePasswordProgressLog(logText) {
- var logDiv = $('log-entries');
- if (!logDiv)
- return;
- logDiv.appendChild(document.createElement('hr'));
- var textDiv = document.createElement('div');
- textDiv.innerText = logText;
- logDiv.appendChild(textDiv);
-}
-
-function notifyAboutIncognito(isIncognito) {
- document.body.dataset.incognito = isIncognito;
-}
diff --git a/chromium/chrome/browser/resources/password_manager_internals_resources.grd b/chromium/chrome/browser/resources/password_manager_internals_resources.grd
deleted file mode 100644
index ed63cbbeb1a..00000000000
--- a/chromium/chrome/browser/resources/password_manager_internals_resources.grd
+++ /dev/null
@@ -1,16 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<grit latest_public_release="0" current_release="1" output_all_resource_defines="false">
- <outputs>
- <output filename="grit/password_manager_internals_resources.h" type="rc_header">
- <emit emit_type='prepend'></emit>
- </output>
- <output filename="password_manager_internals_resources.pak" type="data_package" />
- </outputs>
- <release seq="1">
- <includes>
- <include name="IDR_PASSWORD_MANAGER_INTERNALS_PASSWORD_MANAGER_INTERNALS_HTML" file="password_manager_internals/password_manager_internals.html" flattenhtml="true" allowexternalscript="false" compress="gzip" type="BINDATA" />
- <include name="IDR_PASSWORD_MANAGER_INTERNALS_PASSWORD_MANAGER_INTERNALS_JS" file="password_manager_internals/password_manager_internals.js" flattenhtml="true" compress="gzip" type="BINDATA" />
- <include name="IDR_PASSWORD_MANAGER_INTERNALS_PASSWORD_MANAGER_INTERNALS_CSS" file="password_manager_internals/password_manager_internals.css" flattenhtml="true" compress="gzip" type="BINDATA" />
- </includes>
- </release>
-</grit>
diff --git a/chromium/chrome/browser/resources/pdf/compiled_resources2.gyp b/chromium/chrome/browser/resources/pdf/compiled_resources2.gyp
index 05a86018b37..655323d32f2 100644
--- a/chromium/chrome/browser/resources/pdf/compiled_resources2.gyp
+++ b/chromium/chrome/browser/resources/pdf/compiled_resources2.gyp
@@ -14,12 +14,19 @@
'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
},
{
+ 'target_name': 'pdf_fitting_type',
+ 'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
'target_name': 'gesture_detector',
'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
},
{
'target_name': 'open_pdf_params_parser',
'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
+ 'dependencies': [
+ 'pdf_fitting_type',
+ ],
},
{
'target_name': 'pdf_scripting_api',
diff --git a/chromium/chrome/browser/resources/pdf/elements/viewer-page-selector/viewer-page-selector.html b/chromium/chrome/browser/resources/pdf/elements/viewer-page-selector/viewer-page-selector.html
index e0edf8a39e2..8ada7527043 100644
--- a/chromium/chrome/browser/resources/pdf/elements/viewer-page-selector/viewer-page-selector.html
+++ b/chromium/chrome/browser/resources/pdf/elements/viewer-page-selector/viewer-page-selector.html
@@ -7,7 +7,7 @@
<style>
:host {
color: #fff;
- font-size: 123%;
+ font-size: 1.23rem;
}
:host ::selection {
@@ -47,9 +47,10 @@
text-align: start;
}
+ #input,
#slash,
#pagelength {
- font-size: 81%;
+ font-size: 0.81rem;
}
</style>
<paper-input-container id="pageselector" no-label-float>
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 9ca3d05e7c8..1a99c68e78a 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
@@ -29,7 +29,7 @@
#title {
@apply(--layout-flex-5);
- font-size: 107%;
+ font-size: 0.87rem;
font-weight: 500;
overflow: hidden;
text-overflow: ellipsis;
diff --git a/chromium/chrome/browser/resources/pdf/elements/viewer-toolbar-dropdown/viewer-toolbar-dropdown.html b/chromium/chrome/browser/resources/pdf/elements/viewer-toolbar-dropdown/viewer-toolbar-dropdown.html
index 83947a3e12f..2e3e6182753 100644
--- a/chromium/chrome/browser/resources/pdf/elements/viewer-toolbar-dropdown/viewer-toolbar-dropdown.html
+++ b/chromium/chrome/browser/resources/pdf/elements/viewer-toolbar-dropdown/viewer-toolbar-dropdown.html
@@ -58,7 +58,7 @@
h1 {
border-bottom: 1px solid rgb(219, 219, 219);
- font-size: 107.6%;
+ font-size: 0.87rem;
font-weight: 500;
margin: 0;
padding: 14px 28px;
diff --git a/chromium/chrome/browser/resources/pdf/elements/viewer-zoom-toolbar/viewer-zoom-toolbar.js b/chromium/chrome/browser/resources/pdf/elements/viewer-zoom-toolbar/viewer-zoom-toolbar.js
index f76c8cb596b..565cc488334 100644
--- a/chromium/chrome/browser/resources/pdf/elements/viewer-zoom-toolbar/viewer-zoom-toolbar.js
+++ b/chromium/chrome/browser/resources/pdf/elements/viewer-zoom-toolbar/viewer-zoom-toolbar.js
@@ -4,8 +4,8 @@
(function() {
-var FIT_TO_PAGE = 0;
-var FIT_TO_WIDTH = 1;
+var FIT_TO_PAGE_BUTTON_STATE = 0;
+var FIT_TO_WIDTH_BUTTON_STATE = 1;
Polymer({
is: 'viewer-zoom-toolbar',
@@ -35,10 +35,10 @@ Polymer({
* Handle clicks of the fit-button.
*/
fitToggle: function() {
- if (this.$['fit-button'].activeIndex == FIT_TO_WIDTH)
- this.fire('fit-to-width');
- else
- this.fire('fit-to-page');
+ this.fireFitToChangedEvent_(
+ this.$['fit-button'].activeIndex == FIT_TO_WIDTH_BUTTON_STATE ?
+ FittingType.FIT_TO_WIDTH :
+ FittingType.FIT_TO_PAGE);
},
/**
@@ -49,21 +49,33 @@ Polymer({
// Toggle the button state since there was no mouse click.
var button = this.$['fit-button'];
- if (button.activeIndex == FIT_TO_WIDTH)
- button.activeIndex = FIT_TO_PAGE;
- else
- button.activeIndex = FIT_TO_WIDTH;
+ button.activeIndex =
+ (button.activeIndex == FIT_TO_WIDTH_BUTTON_STATE ?
+ FIT_TO_PAGE_BUTTON_STATE :
+ FIT_TO_WIDTH_BUTTON_STATE);
},
/**
- * Handle forcing zoom to fit-to-page via scripting.
+ * Handle forcing zoom via scripting to a fitting type.
+ * @param {FittingType} fittingType Page fitting type to force.
*/
- forceFitToPage: function() {
- this.fire('fit-to-page');
+ forceFit: function(fittingType) {
+ this.fireFitToChangedEvent_(fittingType);
+
+ // Set the button state since there was no mouse click.
+ var nextButtonState =
+ (fittingType == FittingType.FIT_TO_WIDTH ? FIT_TO_PAGE_BUTTON_STATE :
+ FIT_TO_WIDTH_BUTTON_STATE);
+ this.$['fit-button'].activeIndex = nextButtonState;
+ },
- // Set the button state since there was no mouse click. Since the zoom is
- // set to fit-to-page, the button should do fit-to-width on the next click.
- this.$['fit-button'].activeIndex = FIT_TO_WIDTH;
+ /**
+ * @private
+ * Fire a 'fit-to-changed' {CustomEvent} with the given FittingType as detail.
+ * @param {FittingType} fittingType to include as payload.
+ */
+ fireFitToChangedEvent_: function(fittingType) {
+ this.fire('fit-to-changed', fittingType);
},
/**
diff --git a/chromium/chrome/browser/resources/pdf/gesture_detector.js b/chromium/chrome/browser/resources/pdf/gesture_detector.js
index 811bfe28b5b..2af88ee0349 100644
--- a/chromium/chrome/browser/resources/pdf/gesture_detector.js
+++ b/chromium/chrome/browser/resources/pdf/gesture_detector.js
@@ -22,18 +22,17 @@ class GestureDetector {
/** @type {function(!Event)} */ (this.onTouchStart_.bind(this)),
{passive: true});
+ let boundOnTouch =
+ /** @type {function(!Event)} */ (this.onTouch_.bind(this));
+ this.element_.addEventListener('touchmove', boundOnTouch, {passive: false});
+ this.element_.addEventListener('touchend', boundOnTouch, {passive: true});
this.element_.addEventListener(
- 'touchmove',
- /** @type {function(!Event)} */ (this.onTouch_.bind(this)),
- {passive: false});
- this.element_.addEventListener(
- 'touchend',
- /** @type {function(!Event)} */ (this.onTouch_.bind(this)),
- {passive: true});
+ 'touchcancel', boundOnTouch, {passive: true});
+
this.element_.addEventListener(
- 'touchcancel',
- /** @type {function(!Event)} */ (this.onTouch_.bind(this)),
- {passive: true});
+ 'wheel',
+ /** @type {function(!Event)} */ (this.onWheel_.bind(this)),
+ {passive: false});
this.pinchStartEvent_ = null;
this.lastTouchTouchesCount_ = 0;
@@ -41,6 +40,19 @@ class GestureDetector {
/** @private {?TouchEvent} */
this.lastEvent_ = null;
+ /**
+ * The scale relative to the start of the pinch when handling ctrl-wheels.
+ * null when there is no ongoing pinch.
+ * @private {?number}
+ */
+ this.accumulatedWheelScale_ = null;
+ /**
+ * A timeout ID from setTimeout used for sending the pinchend event when
+ * handling ctrl-wheels.
+ * @private {?number}
+ */
+ this.wheelEndTimeout_ = null;
+
/** @private {!Map<string, !Array<!Function>>} */
this.listeners_ =
new Map([['pinchstart', []], ['pinchupdate', []], ['pinchend', []]]);
@@ -140,6 +152,63 @@ class GestureDetector {
}
/**
+ * The callback for wheel events on the element.
+ * @private
+ * @param {!WheelEvent} event Wheel event on the element.
+ */
+ onWheel_(event) {
+ // We handle ctrl-wheels to invoke our own pinch zoom. On Mac, synthetic
+ // ctrl-wheels are created from trackpad pinches. We handle these ourselves
+ // to prevent the browser's native pinch zoom. We also use our pinch
+ // zooming mechanism for handling non-synthetic ctrl-wheels. This allows us
+ // to anchor the zoom around the mouse position instead of the scroll
+ // position.
+ if (!event.ctrlKey)
+ return;
+
+ event.preventDefault();
+
+ let wheelScale = Math.exp(-event.deltaY / 100);
+ // Clamp scale changes from the wheel event as they can be
+ // quite dramatic for non-synthetic ctrl-wheels.
+ let scale = Math.min(1.25, Math.max(0.75, wheelScale));
+ let position = {x: event.clientX, y: event.clientY};
+
+ if (this.accumulatedWheelScale_ == null) {
+ this.accumulatedWheelScale_ = 1.0;
+ this.notify_({type: 'pinchstart', center: position});
+ }
+
+ this.accumulatedWheelScale_ *= scale;
+ this.notify_({
+ type: 'pinchupdate',
+ scaleRatio: scale,
+ direction: scale > 1.0 ? 'in' : 'out',
+ startScaleRatio: this.accumulatedWheelScale_,
+ center: position
+ });
+
+ // We don't get any phase information for the ctrl-wheels, so we don't know
+ // when the gesture ends. We'll just use a timeout to send the pinch end
+ // event a short time after the last ctrl-wheel we see.
+ if (this.wheelEndTimeout_ != null) {
+ window.clearTimeout(this.wheelEndTimeout_);
+ this.wheelEndTimeout_ = null;
+ }
+ let gestureEndDelayMs = 100;
+ let endEvent = {
+ type: 'pinchend',
+ startScaleRatio: this.accumulatedWheelScale_,
+ center: position
+ };
+ this.wheelEndTimeout_ = window.setTimeout(function(endEvent) {
+ this.notify_(endEvent);
+ this.wheelEndTimeout_ = null;
+ this.accumulatedWheelScale_ = null;
+ }.bind(this), gestureEndDelayMs, endEvent);
+ }
+
+ /**
* Computes the change in scale between this touch event
* and a previous one.
* @private
diff --git a/chromium/chrome/browser/resources/pdf/index.html b/chromium/chrome/browser/resources/pdf/index.html
index 8382c4b8525..96a13be132e 100644
--- a/chromium/chrome/browser/resources/pdf/index.html
+++ b/chromium/chrome/browser/resources/pdf/index.html
@@ -28,6 +28,7 @@
<viewer-error-screen id="error-screen"></viewer-error-screen>
</body>
+<script src="pdf_fitting_type.js"></script>
<script src="toolbar_manager.js"></script>
<script src="viewport.js"></script>
<script src="open_pdf_params_parser.js"></script>
diff --git a/chromium/chrome/browser/resources/pdf/open_pdf_params_parser.js b/chromium/chrome/browser/resources/pdf/open_pdf_params_parser.js
index 2eefdec662e..e573656c3fd 100644
--- a/chromium/chrome/browser/resources/pdf/open_pdf_params_parser.js
+++ b/chromium/chrome/browser/resources/pdf/open_pdf_params_parser.js
@@ -2,6 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+var OpenPDFParamsParser;
+
+(function() {
+
'use strict';
/**
@@ -11,34 +15,32 @@
* the page number for a named destination.
* @constructor
*/
-function OpenPDFParamsParser(getNamedDestinationsFunction) {
+OpenPDFParamsParser = function(getNamedDestinationsFunction) {
this.outstandingRequests_ = [];
this.getNamedDestinationsFunction_ = getNamedDestinationsFunction;
-}
+};
OpenPDFParamsParser.prototype = {
/**
* @private
- * Parse zoom parameter of open PDF parameters. If this
- * parameter is passed while opening PDF then PDF should be opened
- * at the specified zoom level.
+ * Parse zoom parameter of open PDF parameters. The PDF should be opened at
+ * the specified zoom level.
* @param {string} paramValue zoom value.
- * @param {Object} viewportPosition to store zoom and position value.
+ * @return {Object} Map with zoom parameters (zoom and position).
*/
- parseZoomParam_: function(paramValue, viewportPosition) {
+ parseZoomParam_: function(paramValue) {
var paramValueSplit = paramValue.split(',');
- if ((paramValueSplit.length != 1) && (paramValueSplit.length != 3))
- return;
+ if (paramValueSplit.length != 1 && paramValueSplit.length != 3)
+ return {};
// User scale of 100 means zoom value of 100% i.e. zoom factor of 1.0.
var zoomFactor = parseFloat(paramValueSplit[0]) / 100;
if (isNaN(zoomFactor))
- return;
+ return {};
// Handle #zoom=scale.
if (paramValueSplit.length == 1) {
- viewportPosition['zoom'] = zoomFactor;
- return;
+ return {'zoom': zoomFactor};
}
// Handle #zoom=scale,left,top.
@@ -46,8 +48,43 @@ OpenPDFParamsParser.prototype = {
x: parseFloat(paramValueSplit[1]),
y: parseFloat(paramValueSplit[2])
};
- viewportPosition['position'] = position;
- viewportPosition['zoom'] = zoomFactor;
+ return {'position': position, 'zoom': zoomFactor};
+ },
+
+ /**
+ * @private
+ * Parse view parameter of open PDF parameters. The PDF should be opened at
+ * the specified fitting type mode and position.
+ * @param {string} paramValue view value.
+ * @return {Object} Map with view parameters (view and viewPosition).
+ */
+ parseViewParam_: function(paramValue) {
+ var viewModeComponents = paramValue.toLowerCase().split(',');
+ if (viewModeComponents.length < 1)
+ return {};
+
+ var params = {};
+ var viewMode = viewModeComponents[0];
+ var acceptsPositionParam;
+ if (viewMode === 'fit') {
+ params['view'] = FittingType.FIT_TO_PAGE;
+ acceptsPositionParam = false;
+ } else if (viewMode === 'fith') {
+ params['view'] = FittingType.FIT_TO_WIDTH;
+ acceptsPositionParam = true;
+ } else if (viewMode === 'fitv') {
+ params['view'] = FittingType.FIT_TO_HEIGHT;
+ acceptsPositionParam = true;
+ }
+
+ if (!acceptsPositionParam || viewModeComponents.length < 2)
+ return params;
+
+ var position = parseFloat(viewModeComponents[1]);
+ if (!isNaN(position))
+ params['viewPosition'] = position;
+
+ return params;
},
/**
@@ -108,28 +145,29 @@ OpenPDFParamsParser.prototype = {
* @param {Function} callback function to be called with viewport info.
*/
getViewportFromUrlParams: function(url, callback) {
- var viewportPosition = {};
- viewportPosition['url'] = url;
+ var params = {};
+ params['url'] = url;
- var paramsDictionary = this.parseUrlParams_(url);
+ var urlParams = this.parseUrlParams_(url);
- if ('page' in paramsDictionary) {
+ if ('page' in urlParams) {
// |pageNumber| is 1-based, but goToPage() take a zero-based page number.
- var pageNumber = parseInt(paramsDictionary['page'], 10);
+ var pageNumber = parseInt(urlParams['page'], 10);
if (!isNaN(pageNumber) && pageNumber > 0)
- viewportPosition['page'] = pageNumber - 1;
+ params['page'] = pageNumber - 1;
}
- if ('zoom' in paramsDictionary)
- this.parseZoomParam_(paramsDictionary['zoom'], viewportPosition);
+ if ('view' in urlParams)
+ Object.assign(params, this.parseViewParam_(urlParams['view']));
- if (viewportPosition.page === undefined &&
- 'nameddest' in paramsDictionary) {
- this.outstandingRequests_.push(
- {callback: callback, viewportPosition: viewportPosition});
- this.getNamedDestinationsFunction_(paramsDictionary['nameddest']);
+ if ('zoom' in urlParams)
+ Object.assign(params, this.parseZoomParam_(urlParams['zoom']));
+
+ if (params.page === undefined && 'nameddest' in urlParams) {
+ this.outstandingRequests_.push({callback: callback, params: params});
+ this.getNamedDestinationsFunction_(urlParams['nameddest']);
} else {
- callback(viewportPosition);
+ callback(params);
}
},
@@ -142,7 +180,9 @@ OpenPDFParamsParser.prototype = {
onNamedDestinationReceived: function(pageNumber) {
var outstandingRequest = this.outstandingRequests_.shift();
if (pageNumber != -1)
- outstandingRequest.viewportPosition.page = pageNumber;
- outstandingRequest.callback(outstandingRequest.viewportPosition);
+ outstandingRequest.params.page = pageNumber;
+ outstandingRequest.callback(outstandingRequest.params);
},
};
+
+}());
diff --git a/chromium/chrome/browser/resources/pdf/pdf.js b/chromium/chrome/browser/resources/pdf/pdf.js
index acb36ab187d..dcbf3d3a35e 100644
--- a/chromium/chrome/browser/resources/pdf/pdf.js
+++ b/chromium/chrome/browser/resources/pdf/pdf.js
@@ -187,8 +187,7 @@ function PDFViewer(browserApi) {
// Setup the button event listeners.
this.zoomToolbar_ = $('zoom-toolbar');
this.zoomToolbar_.addEventListener(
- 'fit-to-width', this.viewport_.fitToWidth.bind(this.viewport_));
- this.zoomToolbar_.addEventListener('fit-to-page', this.fitToPage_.bind(this));
+ 'fit-to-changed', this.fitToChanged_.bind(this));
this.zoomToolbar_.addEventListener(
'zoom-in', this.viewport_.zoomIn.bind(this.viewport_));
this.zoomToolbar_.addEventListener(
@@ -196,7 +195,7 @@ function PDFViewer(browserApi) {
this.gestureDetector_ = new GestureDetector(this.plugin_);
this.gestureDetector_.addEventListener(
- 'pinchstart', this.viewport_.pinchZoomStart.bind(this.viewport_));
+ 'pinchstart', this.onPinchStart_.bind(this));
this.sentPinchEvent_ = false;
this.gestureDetector_.addEventListener(
'pinchupdate', this.onPinchUpdate_.bind(this));
@@ -281,8 +280,8 @@ PDFViewer.prototype = {
this.toolbarManager_.hideToolbarsAfterTimeout(e);
var pageUpHandler = () => {
- // Go to the previous page if we are fit-to-page.
- if (this.viewport_.fittingType == Viewport.FittingType.FIT_TO_PAGE) {
+ // Go to the previous page if we are fit-to-page or fit-to-height.
+ if (this.viewport_.isPagedMode()) {
this.viewport_.goToPage(this.viewport_.getMostVisiblePage() - 1);
// Since we do the movement of the page.
e.preventDefault();
@@ -292,8 +291,8 @@ PDFViewer.prototype = {
}
};
var pageDownHandler = () => {
- // Go to the next page if we are fit-to-page.
- if (this.viewport_.fittingType == Viewport.FittingType.FIT_TO_PAGE) {
+ // Go to the next page if we are fit-to-page or fit-to-height.
+ if (this.viewport_.isPagedMode()) {
this.viewport_.goToPage(this.viewport_.getMostVisiblePage() + 1);
// Since we do the movement of the page.
e.preventDefault();
@@ -441,11 +440,19 @@ PDFViewer.prototype = {
/**
* @private
- * Set zoom to "fit to page".
+ * Request to change the viewport fitting type.
+ * @param {CustomEvent} e Event received with the new FittingType as detail.
*/
- fitToPage_: function() {
- this.viewport_.fitToPage();
- this.toolbarManager_.forceHideTopToolbar();
+ fitToChanged_: function(e) {
+ if (e.detail == FittingType.FIT_TO_PAGE) {
+ this.viewport_.fitToPage();
+ this.toolbarManager_.forceHideTopToolbar();
+ } else if (e.detail == FittingType.FIT_TO_WIDTH) {
+ this.viewport_.fitToWidth();
+ } else if (e.detail == FittingType.FIT_TO_HEIGHT) {
+ this.viewport_.fitToHeight();
+ this.toolbarManager_.forceHideTopToolbar();
+ }
},
/**
@@ -493,21 +500,37 @@ PDFViewer.prototype = {
* Handle open pdf parameters. This function updates the viewport as per
* the parameters mentioned in the url while opening pdf. The order is
* important as later actions can override the effects of previous actions.
- * @param {Object} viewportPosition The initial position of the viewport to be
- * displayed.
+ * @param {Object} params The open params passed in the URL.
*/
- handleURLParams_: function(viewportPosition) {
- if (viewportPosition.page != undefined)
- this.viewport_.goToPage(viewportPosition.page);
- if (viewportPosition.position) {
+ handleURLParams_: function(params) {
+ if (params.page != undefined)
+ this.viewport_.goToPage(params.page);
+
+ if (params.position) {
// Make sure we don't cancel effect of page parameter.
this.viewport_.position = {
- x: this.viewport_.position.x + viewportPosition.position.x,
- y: this.viewport_.position.y + viewportPosition.position.y
+ x: this.viewport_.position.x + params.position.x,
+ y: this.viewport_.position.y + params.position.y
};
}
- if (viewportPosition.zoom)
- this.viewport_.setZoom(viewportPosition.zoom);
+
+ if (params.zoom)
+ this.viewport_.setZoom(params.zoom);
+
+ if (params.view) {
+ this.isUserInitiatedEvent_ = false;
+ this.zoomToolbar_.forceFit(params.view);
+ if (params.viewPosition) {
+ var zoomedPositionShift = params.viewPosition * this.viewport_.zoom;
+ var currentViewportPosition = this.viewport_.position;
+ if (params.view == FittingType.FIT_TO_WIDTH)
+ currentViewportPosition.y += zoomedPositionShift;
+ else if (params.view == FittingType.FIT_TO_HEIGHT)
+ currentViewportPosition.x += zoomedPositionShift;
+ this.viewport_.position = currentViewportPosition;
+ }
+ this.isUserInitiatedEvent_ = true;
+ }
},
/**
@@ -660,6 +683,13 @@ PDFViewer.prototype = {
case 'setIsSelecting':
this.viewportScroller_.setEnableScrolling(message.data.isSelecting);
break;
+ case 'setIsEditMode':
+ // TODO(hnakashima): Replace this with final visual indication from UX.
+ if (message.data.isEditMode)
+ this.toolbar_.docTitle = document.title + ' (edit mode)';
+ else
+ this.toolbar_.docTitle = document.title;
+ break;
case 'getNamedDestinationReply':
this.paramsParser_.onNamedDestinationReceived(message.data.pageNumber);
break;
@@ -763,6 +793,19 @@ PDFViewer.prototype = {
/**
* @private
+ * A callback that's called when the start of a pinch zoom is detected.
+ * @param {!Object} e the pinch event.
+ */
+ onPinchStart_: function(e) {
+ // We also use rAF for pinch start, so that if there is a pinch end event
+ // scheduled by rAF, this pinch start will be sent after.
+ window.requestAnimationFrame(() => {
+ this.viewport_.pinchZoomStart(e);
+ });
+ },
+
+ /**
+ * @private
* A callback that's called after the viewport changes.
*/
viewportChanged_: function() {
@@ -874,7 +917,7 @@ PDFViewer.prototype = {
if (!this.inPrintPreviewMode_) {
this.inPrintPreviewMode_ = true;
this.isUserInitiatedEvent_ = false;
- this.zoomToolbar_.forceFitToPage();
+ this.zoomToolbar_.forceFit(FittingType.FIT_TO_PAGE);
this.isUserInitiatedEvent_ = true;
}
diff --git a/chromium/chrome/browser/resources/pdf/pdf_fitting_type.js b/chromium/chrome/browser/resources/pdf/pdf_fitting_type.js
new file mode 100644
index 00000000000..41a14f09242
--- /dev/null
+++ b/chromium/chrome/browser/resources/pdf/pdf_fitting_type.js
@@ -0,0 +1,16 @@
+// Copyright 2017 The Chromium 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';
+
+/**
+ * Enumeration of page fitting types.
+ * @enum {string}
+ */
+var FittingType = {
+ NONE: 'none',
+ FIT_TO_PAGE: 'fit-to-page',
+ FIT_TO_WIDTH: 'fit-to-width',
+ FIT_TO_HEIGHT: 'fit-to-height'
+};
diff --git a/chromium/chrome/browser/resources/pdf/viewport.js b/chromium/chrome/browser/resources/pdf/viewport.js
index e82551d1080..53e1b17ea60 100644
--- a/chromium/chrome/browser/resources/pdf/viewport.js
+++ b/chromium/chrome/browser/resources/pdf/viewport.js
@@ -16,15 +16,6 @@ function getIntersectionHeight(rect1, rect2) {
}
/**
- * Makes sure that the scale level doesn't get out of the limits.
- * @param {number} scale The new scale level.
- * @return {number} The scale clamped within the limits.
- */
-function clampScale(scale) {
- return Math.min(5, Math.max(0.25, scale));
-}
-
-/**
* Computes vector between two points.
* @param {!Object} p1 The first point.
* @param {!Object} p2 The second point.
@@ -74,7 +65,7 @@ function Viewport(
this.documentDimensions_ = null;
this.pageDimensions_ = [];
this.scrollbarWidth_ = scrollbarWidth;
- this.fittingType_ = Viewport.FittingType.NONE;
+ this.fittingType_ = FittingType.NONE;
this.defaultZoom_ = defaultZoom;
this.topToolbarHeight_ = topToolbarHeight;
this.prevScale_ = 1;
@@ -88,16 +79,6 @@ function Viewport(
}
/**
- * Enumeration of page fitting types.
- * @enum {string}
- */
-Viewport.FittingType = {
- NONE: 'none',
- FIT_TO_PAGE: 'fit-to-page',
- FIT_TO_WIDTH: 'fit-to-width'
-};
-
-/**
* Enumeration of pinch states.
* This should match PinchPhase enum in pdf/out_of_process_instance.h
* @enum {number}
@@ -138,6 +119,17 @@ Viewport.ZOOM_FACTOR_RANGE = {
};
/**
+ * Clamps the zoom factor (or page scale factor) to be within the limits.
+ * @param {number} factor The zoom/scale factor.
+ * @return {number} The factor clamped within the limits.
+ */
+Viewport.clampZoom = function(factor) {
+ return Math.max(
+ Viewport.ZOOM_FACTOR_RANGE.min,
+ Math.min(factor, Viewport.ZOOM_FACTOR_RANGE.max));
+};
+
+/**
* The width of the page shadow around pages in pixels.
*/
Viewport.PAGE_SHADOW = {
@@ -240,10 +232,12 @@ Viewport.prototype = {
* Called when the viewport size changes.
*/
resize_: function() {
- if (this.fittingType_ == Viewport.FittingType.FIT_TO_PAGE)
+ if (this.fittingType_ == FittingType.FIT_TO_PAGE)
this.fitToPageInternal_(false);
- else if (this.fittingType_ == Viewport.FittingType.FIT_TO_WIDTH)
+ else if (this.fittingType_ == FittingType.FIT_TO_WIDTH)
this.fitToWidth();
+ else if (this.fittingType_ == FittingType.FIT_TO_HEIGHT)
+ this.fitToHeightInternal_(false);
else
this.updateViewport_();
},
@@ -369,7 +363,7 @@ Viewport.prototype = {
this.allowedToChangeZoom_,
'Called Viewport.setPinchZoomInternal_ without calling ' +
'Viewport.mightZoom_.');
- this.internalZoom_ = clampScale(this.internalZoom_ * scaleDelta);
+ this.internalZoom_ = Viewport.clampZoom(this.internalZoom_ * scaleDelta);
var newCenterInContent = this.frameToContent(center);
var delta = {
@@ -408,12 +402,9 @@ Viewport.prototype = {
* @param {number} newZoom the zoom level to zoom to.
*/
setZoom: function(newZoom) {
- this.fittingType_ = Viewport.FittingType.NONE;
- newZoom = Math.max(
- Viewport.ZOOM_FACTOR_RANGE.min,
- Math.min(newZoom, Viewport.ZOOM_FACTOR_RANGE.max));
+ this.fittingType_ = FittingType.NONE;
this.mightZoom_(() => {
- this.setZoomInternal_(newZoom);
+ this.setZoomInternal_(Viewport.clampZoom(newZoom));
this.updateViewport_();
});
},
@@ -449,7 +440,7 @@ Viewport.prototype = {
},
/**
- * @type {Viewport.FittingType} the fitting type the viewport is currently in.
+ * @type {FittingType} the fitting type the viewport is currently in.
*/
get fittingType() {
return this.fittingType_;
@@ -477,7 +468,8 @@ Viewport.prototype = {
if (top <= y && bottom > y)
return page;
- else if (top > y)
+
+ if (top > y)
max = page - 1;
else
min = page + 1;
@@ -516,25 +508,28 @@ Viewport.prototype = {
/**
* @private
- * Compute the zoom level for fit-to-page or fit-to-width. |pageDimensions| is
- * the dimensions for a given page and if |widthOnly| is true, it indicates
- * that fit-to-page zoom should be computed rather than fit-to-page.
- * @param {Object} pageDimensions the dimensions of a given page
- * @param {boolean} widthOnly a bool indicating whether fit-to-page or
- * fit-to-width should be computed.
+ * Compute the zoom level for fit-to-page, fit-to-width or fit-to-height.
+ *
+ * At least one of {fitWidth, fitHeight} must be true.
+ *
+ * @param {Object} pageDimensions the dimensions of a given page in px.
+ * @param {boolean} fitWidth a bool indicating whether the whole width of the
+ * page needs to be in the viewport.
+ * @param {boolean} fitHeight a bool indicating whether the whole height of
+ * the page needs to be in the viewport.
* @return {number} the internal zoom to set
*/
- computeFittingZoom_: function(pageDimensions, widthOnly) {
+ computeFittingZoom_: function(pageDimensions, fitWidth, fitHeight) {
+ assert(
+ fitWidth || fitHeight,
+ 'Invalid parameters. At least one of fitWidth and fitHeight must be ' +
+ 'true.');
+
// First compute the zoom without scrollbars.
- var zoomWidth = this.window_.innerWidth / pageDimensions.width;
- var zoom;
- var zoomHeight;
- if (widthOnly) {
- zoom = zoomWidth;
- } else {
- zoomHeight = this.window_.innerHeight / pageDimensions.height;
- zoom = Math.min(zoomWidth, zoomHeight);
- }
+ var zoom = this.computeFittingZoomGivenDimensions_(
+ fitWidth, fitHeight, this.window_.innerWidth, this.window_.innerHeight,
+ pageDimensions.width, pageDimensions.height);
+
// Check if there needs to be any scrollbars.
var needsScrollbars = this.documentNeedsScrollbars_(zoom);
@@ -566,43 +561,110 @@ Viewport.prototype = {
windowWithScrollbars.width -= scrollbarWidth;
// Recompute the zoom.
- zoomWidth = windowWithScrollbars.width / pageDimensions.width;
- if (widthOnly) {
- zoom = zoomWidth;
- } else {
- zoomHeight = windowWithScrollbars.height / pageDimensions.height;
- zoom = Math.min(zoomWidth, zoomHeight);
- }
+ zoom = this.computeFittingZoomGivenDimensions_(
+ fitWidth, fitHeight, windowWithScrollbars.width,
+ windowWithScrollbars.height, pageDimensions.width,
+ pageDimensions.height);
+
return this.zoomManager_.internalZoomComponent(zoom);
},
/**
- * Zoom the viewport so that the page-width consumes the entire viewport.
+ * @private
+ * Compute a zoom level given the dimensions to fit and the actual numbers
+ * in those dimensions.
+ *
+ * @param {boolean} fitWidth make sure the page width is totally contained in
+ * the window.
+ * @param {boolean} fitHeight make sure the page height is totally contained
+ * in the window.
+ * @param {number} windowWidth the width of the window in px.
+ * @param {number} windowHeight the height of the window in px.
+ * @param {number} pageWidth the width of the page in px.
+ * @param {number} pageHeight the height of the page in px.
+ * @return {number} the internal zoom to set
+ */
+ computeFittingZoomGivenDimensions_: function(
+ fitWidth, fitHeight, windowWidth, windowHeight, pageWidth, pageHeight) {
+ // Assumes at least one of {fitWidth, fitHeight} is set.
+ var zoomWidth;
+ var zoomHeight;
+
+ if (fitWidth)
+ zoomWidth = windowWidth / pageWidth;
+
+ if (fitHeight)
+ zoomHeight = windowHeight / pageHeight;
+
+ if (!fitWidth && fitHeight)
+ return zoomHeight;
+ if (fitWidth && !fitHeight)
+ return zoomWidth;
+
+ // Assume fitWidth && fitHeight
+ return Math.min(zoomWidth, zoomHeight);
+ },
+
+ /**
+ * Zoom the viewport so that the page width consumes the entire viewport.
*/
fitToWidth: function() {
this.mightZoom_(() => {
- this.fittingType_ = Viewport.FittingType.FIT_TO_WIDTH;
+ this.fittingType_ = FittingType.FIT_TO_WIDTH;
if (!this.documentDimensions_)
return;
// When computing fit-to-width, the maximum width of a page in the
// document is used, which is equal to the size of the document width.
this.setZoomInternal_(
- this.computeFittingZoom_(this.documentDimensions_, true));
+ this.computeFittingZoom_(this.documentDimensions_, true, false));
+ this.updateViewport_();
+ });
+ },
+
+ /**
+ * @private
+ * Zoom the viewport so that the page height consumes the entire viewport.
+ * @param {boolean} scrollToTopOfPage Set to true if the viewport should be
+ * scrolled to the top of the current page. Set to false if the viewport
+ * should remain at the current scroll position.
+ */
+ fitToHeightInternal_: function(scrollToTopOfPage) {
+ this.mightZoom_(() => {
+ this.fittingType_ = FittingType.FIT_TO_HEIGHT;
+ if (!this.documentDimensions_)
+ return;
var page = this.getMostVisiblePage();
+ // When computing fit-to-height, the maximum height of the current page
+ // is used.
+ var dimensions = {
+ width: 0,
+ height: this.pageDimensions_[page].height,
+ };
+ this.setZoomInternal_(this.computeFittingZoom_(dimensions, false, true));
+ if (scrollToTopOfPage) {
+ this.position = {x: 0, y: this.pageDimensions_[page].y * this.zoom};
+ }
this.updateViewport_();
});
},
/**
+ * Zoom the viewport so that the page height consumes the entire viewport.
+ */
+ fitToHeight: function() {
+ this.fitToHeightInternal_(true);
+ },
+
+ /**
* @private
- * Zoom the viewport so that a page consumes the entire viewport.
+ * Zoom the viewport so that a page consumes as much as possible of the it.
* @param {boolean} scrollToTopOfPage Set to true if the viewport should be
* scrolled to the top of the current page. Set to false if the viewport
* should remain at the current scroll position.
*/
fitToPageInternal_: function(scrollToTopOfPage) {
this.mightZoom_(() => {
- this.fittingType_ = Viewport.FittingType.FIT_TO_PAGE;
+ this.fittingType_ = FittingType.FIT_TO_PAGE;
if (!this.documentDimensions_)
return;
var page = this.getMostVisiblePage();
@@ -611,7 +673,7 @@ Viewport.prototype = {
width: this.documentDimensions_.width,
height: this.pageDimensions_[page].height,
};
- this.setZoomInternal_(this.computeFittingZoom_(dimensions, false));
+ this.setZoomInternal_(this.computeFittingZoom_(dimensions, true, true));
if (scrollToTopOfPage) {
this.position = {x: 0, y: this.pageDimensions_[page].y * this.zoom};
}
@@ -632,7 +694,7 @@ Viewport.prototype = {
*/
zoomOut: function() {
this.mightZoom_(() => {
- this.fittingType_ = Viewport.FittingType.NONE;
+ this.fittingType_ = FittingType.NONE;
var nextZoom = Viewport.ZOOM_FACTORS[0];
for (var i = 0; i < Viewport.ZOOM_FACTORS.length; i++) {
if (Viewport.ZOOM_FACTORS[i] < this.internalZoom_)
@@ -648,7 +710,7 @@ Viewport.prototype = {
*/
zoomIn: function() {
this.mightZoom_(() => {
- this.fittingType_ = Viewport.FittingType.NONE;
+ this.fittingType_ = FittingType.NONE;
var nextZoom = Viewport.ZOOM_FACTORS[Viewport.ZOOM_FACTORS.length - 1];
for (var i = Viewport.ZOOM_FACTORS.length - 1; i >= 0; i--) {
if (Viewport.ZOOM_FACTORS[i] > this.internalZoom_)
@@ -675,7 +737,7 @@ Viewport.prototype = {
var needsScrollbars =
this.documentNeedsScrollbars_(this.zoomManager_.applyBrowserZoom(
- clampScale(this.internalZoom_ * scaleDelta)));
+ Viewport.clampZoom(this.internalZoom_ * scaleDelta)));
this.pinchCenter_ = e.center;
@@ -754,10 +816,10 @@ Viewport.prototype = {
page = this.pageDimensions_.length - 1;
var dimensions = this.pageDimensions_[page];
var toolbarOffset = 0;
- // Unless we're in fit to page mode, scroll above the page by
- // |this.topToolbarHeight_| so that the toolbar isn't covering it
+ // Unless we're in fit to page or fit to height mode, scroll above the
+ // page by |this.topToolbarHeight_| so that the toolbar isn't covering it
// initially.
- if (this.fittingType_ != Viewport.FittingType.FIT_TO_PAGE)
+ if (!this.isPagedMode())
toolbarOffset = this.topToolbarHeight_;
this.position = {
x: dimensions.x * this.zoom,
@@ -779,7 +841,7 @@ Viewport.prototype = {
if (initialDimensions) {
this.setZoomInternal_(Math.min(
this.defaultZoom_,
- this.computeFittingZoom_(this.documentDimensions_, true)));
+ this.computeFittingZoom_(this.documentDimensions_, true, false)));
this.position = {x: 0, y: -this.topToolbarHeight_};
}
this.contentSizeChanged_();
@@ -829,5 +891,19 @@ Viewport.prototype = {
width: insetDimensions.width * this.zoom,
height: insetDimensions.height * this.zoom
};
+ },
+
+ /**
+ * Check if the current fitting type is a paged mode.
+ *
+ * In a paged mode, page up and page down scroll to the top of the
+ * previous/next page and part of the page is under the toolbar.
+ *
+ * @return {boolean} Whether the current fitting type is a paged mode.
+ */
+ isPagedMode: function(page) {
+ return (
+ this.fittingType_ == FittingType.FIT_TO_PAGE ||
+ this.fittingType_ == FittingType.FIT_TO_HEIGHT);
}
};
diff --git a/chromium/chrome/browser/resources/plugin_metadata/plugins_linux.json b/chromium/chrome/browser/resources/plugin_metadata/plugins_linux.json
index 99b6cf673f3..e9af78d3794 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": 26,
+ "x-version": 27,
"google-talk": {
"mime_types": [
],
@@ -80,9 +80,9 @@
],
"versions": [
{
- "version": "27.0.0.187",
+ "version": "28.0.0.137",
"status": "up_to_date",
- "reference": "https://helpx.adobe.com/security/products/flash-player/apsb17-33.html"
+ "reference": "https://helpx.adobe.com/security/products/flash-player/apsb18-01.html"
}
],
"lang": "en-US",
diff --git a/chromium/chrome/browser/resources/plugin_metadata/plugins_mac.json b/chromium/chrome/browser/resources/plugin_metadata/plugins_mac.json
index a85342825f9..6192e094ef0 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": 32,
+ "x-version": 33,
"google-talk": {
"mime_types": [
],
@@ -115,9 +115,9 @@
],
"versions": [
{
- "version": "27.0.0.187",
+ "version": "28.0.0.137",
"status": "requires_authorization",
- "reference": "https://helpx.adobe.com/security/products/flash-player/apsb17-33.html"
+ "reference": "https://helpx.adobe.com/security/products/flash-player/apsb18-01.html"
}
],
"lang": "en-US",
diff --git a/chromium/chrome/browser/resources/plugin_metadata/plugins_win.json b/chromium/chrome/browser/resources/plugin_metadata/plugins_win.json
index c5b325b08c2..9b5418e3fa5 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": 41,
+ "x-version": 42,
"google-talk": {
"mime_types": [
],
@@ -137,9 +137,9 @@
],
"versions": [
{
- "version": "27.0.0.187",
+ "version": "28.0.0.137",
"status": "requires_authorization",
- "reference": "https://helpx.adobe.com/security/products/flash-player/apsb17-33.html"
+ "reference": "https://helpx.adobe.com/security/products/flash-player/apsb18-01.html"
}
],
"lang": "en-US",
diff --git a/chromium/chrome/browser/resources/policy_tool.css b/chromium/chrome/browser/resources/policy_tool.css
index 7361ccbd141..7ddad45a113 100644
--- a/chromium/chrome/browser/resources/policy_tool.css
+++ b/chromium/chrome/browser/resources/policy_tool.css
@@ -39,3 +39,7 @@ tbody.value-editing-on .value {
#saving span {
font-weight: bold;
}
+
+#session-actions {
+ float: left;
+}
diff --git a/chromium/chrome/browser/resources/policy_tool.html b/chromium/chrome/browser/resources/policy_tool.html
index 8af70271184..12b62273d24 100644
--- a/chromium/chrome/browser/resources/policy_tool.html
+++ b/chromium/chrome/browser/resources/policy_tool.html
@@ -51,6 +51,9 @@
</span>
</section>
<section id="sessions">
+ <div id="session-actions">
+ <button id="delete-session-button">-</button>
+ </div>
<select size="4" id="session-list">
</select>
</section>
diff --git a/chromium/chrome/browser/resources/policy_tool.js b/chromium/chrome/browser/resources/policy_tool.js
index 871322846d4..c3e321ce583 100644
--- a/chromium/chrome/browser/resources/policy_tool.js
+++ b/chromium/chrome/browser/resources/policy_tool.js
@@ -108,6 +108,14 @@ policy.Page.prototype.initialize = function() {
this.enableEditing();
chrome.send('resetSession');
};
+
+ $('delete-session-button').onclick = () => {
+ var sessionName = $('session-list').value;
+ if (sessionName) {
+ chrome.send('deleteSession', [sessionName]);
+ }
+ };
+
// Notify the browser that the page has loaded, causing it to send the
// list of all known policies and the values from the default session.
chrome.send('initialized');
@@ -255,18 +263,6 @@ policy.PolicyTable.prototype.getDictionary = function() {
return result;
};
-// Add error showing function.
-
-/**
- * Shows an error message to the user.
- * @param {String} message_name Identifier for the error message.
- */
-policy.showErrorMessage = function(message_name) {
- // TODO(urusant): improve error showing.
- alert(loadTimeData.getString(message_name));
- console.log(loadTimeData.getString(message_name));
-};
-
// Call the main inttialization function when the page finishes loading.
document.addEventListener(
'DOMContentLoaded',
diff --git a/chromium/chrome/browser/resources/print_preview/.eslintrc.js b/chromium/chrome/browser/resources/print_preview/.eslintrc.js
new file mode 100644
index 00000000000..847d6e99509
--- /dev/null
+++ b/chromium/chrome/browser/resources/print_preview/.eslintrc.js
@@ -0,0 +1,13 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module.exports = {
+ 'env': {
+ 'browser': true,
+ 'es6': true,
+ },
+ 'rules': {
+ 'no-var': 'error',
+ },
+};
diff --git a/chromium/chrome/browser/resources/print_preview/cloud_print_interface.js b/chromium/chrome/browser/resources/print_preview/cloud_print_interface.js
index 2527074c3ef..079d4ff5c83 100644
--- a/chromium/chrome/browser/resources/print_preview/cloud_print_interface.js
+++ b/chromium/chrome/browser/resources/print_preview/cloud_print_interface.js
@@ -24,154 +24,88 @@ cloudprint.CloudPrintInterfaceEventType = {
cr.define('cloudprint', function() {
'use strict';
- var CloudPrintInterfaceEventType = cloudprint.CloudPrintInterfaceEventType;
-
- /**
- * API to the Google Cloud Print service.
- * @param {string} baseUrl Base part of the Google Cloud Print service URL
- * with no trailing slash. For example,
- * 'https://www.google.com/cloudprint'.
- * @param {!print_preview.NativeLayer} nativeLayer Native layer used to get
- * Auth2 tokens.
- * @param {!print_preview.UserInfo} userInfo User information repository.
- * @param {boolean} isInAppKioskMode Whether the print preview is in App
- * Kiosk mode.
- * @constructor
- * @extends {cr.EventTarget}
- */
- function CloudPrintInterface(
- baseUrl, nativeLayer, userInfo, isInAppKioskMode) {
- /**
- * The base URL of the Google Cloud Print API.
- * @type {string}
- * @private
- */
- this.baseUrl_ = baseUrl;
-
- /**
- * Used to get Auth2 tokens.
- * @type {!print_preview.NativeLayer}
- * @private
- */
- this.nativeLayer_ = nativeLayer;
-
- /**
- * User information repository.
- * @type {!print_preview.UserInfo}
- * @private
- */
- this.userInfo_ = userInfo;
-
- /**
- * Whether Print Preview is in App Kiosk mode, basically, use only printers
- * available for the device.
- * @type {boolean}
- * @private
- */
- this.isInAppKioskMode_ = isInAppKioskMode;
-
- /**
- * Currently logged in users (identified by email) mapped to the Google
- * session index.
- * @type {!Object<number>}
- * @private
- */
- this.userSessionIndex_ = {};
-
- /**
- * Stores last received XSRF tokens for each user account. Sent as
- * a parameter with every request.
- * @type {!Object<string>}
- * @private
- */
- this.xsrfTokens_ = {};
-
- /**
- * Outstanding cloud destination search requests.
- * @type {!Array<!cloudprint.CloudPrintRequest>}
- * @private
- */
- this.outstandingCloudSearchRequests_ = [];
-
- /**
- * Promise that will be resolved when the access token for
- * DestinationOrigin.DEVICE is available. Null if there is no request
- * currently pending.
- * @private {?Promise<string>}
- */
- this.accessTokenRequestPromise_ = null;
-
- }
-
- /**
- * Content type header value for a URL encoded HTTP request.
- * @type {string}
- * @const
- * @private
- */
- CloudPrintInterface.URL_ENCODED_CONTENT_TYPE_ =
- 'application/x-www-form-urlencoded';
-
- /**
- * Multi-part POST request boundary used in communication with Google
- * Cloud Print.
- * @type {string}
- * @const
- * @private
- */
- CloudPrintInterface.MULTIPART_BOUNDARY_ =
- '----CloudPrintFormBoundaryjc9wuprokl8i';
-
- /**
- * Content type header value for a multipart HTTP request.
- * @type {string}
- * @const
- * @private
- */
- CloudPrintInterface.MULTIPART_CONTENT_TYPE_ =
- 'multipart/form-data; boundary=' +
- CloudPrintInterface.MULTIPART_BOUNDARY_;
-
- /**
- * Regex that extracts Chrome's version from the user-agent string.
- * @type {!RegExp}
- * @const
- * @private
- */
- CloudPrintInterface.VERSION_REGEXP_ = /.*Chrome\/([\d\.]+)/i;
-
- /**
- * Enumeration of JSON response fields from Google Cloud Print API.
- * @enum {string}
- * @private
- */
- CloudPrintInterface.JsonFields_ = {PRINTER: 'printer'};
-
- /**
- * Could Print origins used to search printers.
- * @type {!Array<!print_preview.DestinationOrigin>}
- * @const
- * @private
- */
- CloudPrintInterface.CLOUD_ORIGINS_ = [
- print_preview.DestinationOrigin.COOKIES,
- print_preview.DestinationOrigin.DEVICE
- ];
-
- CloudPrintInterface.prototype = {
- __proto__: cr.EventTarget.prototype,
+ const CloudPrintInterfaceEventType = cloudprint.CloudPrintInterfaceEventType;
+
+ class CloudPrintInterface extends cr.EventTarget {
+ /**
+ * API to the Google Cloud Print service.
+ * @param {string} baseUrl Base part of the Google Cloud Print service URL
+ * with no trailing slash. For example,
+ * 'https://www.google.com/cloudprint'.
+ * @param {!print_preview.NativeLayer} nativeLayer Native layer used to get
+ * Auth2 tokens.
+ * @param {!print_preview.UserInfo} userInfo User information repository.
+ * @param {boolean} isInAppKioskMode Whether the print preview is in App
+ * Kiosk mode.
+ */
+ constructor(baseUrl, nativeLayer, userInfo, isInAppKioskMode) {
+ super();
+
+ /**
+ * The base URL of the Google Cloud Print API.
+ * @private {string}
+ */
+ this.baseUrl_ = baseUrl;
+
+ /**
+ * Used to get Auth2 tokens.
+ * @private {!print_preview.NativeLayer}
+ */
+ this.nativeLayer_ = nativeLayer;
+
+ /**
+ * User information repository.
+ * @private {!print_preview.UserInfo}
+ */
+ this.userInfo_ = userInfo;
+
+ /**
+ * Whether Print Preview is in App Kiosk mode, basically, use only
+ * printers available for the device.
+ * @private {boolean}
+ */
+ this.isInAppKioskMode_ = isInAppKioskMode;
+
+ /**
+ * Currently logged in users (identified by email) mapped to the Google
+ * session index.
+ * @private {!Object<number>}
+ */
+ this.userSessionIndex_ = {};
+
+ /**
+ * Stores last received XSRF tokens for each user account. Sent as
+ * a parameter with every request.
+ * @private {!Object<string>}
+ */
+ this.xsrfTokens_ = {};
+
+ /**
+ * Outstanding cloud destination search requests.
+ * @private {!Array<!cloudprint.CloudPrintRequest>}
+ */
+ this.outstandingCloudSearchRequests_ = [];
+
+ /**
+ * Promise that will be resolved when the access token for
+ * DestinationOrigin.DEVICE is available. Null if there is no request
+ * currently pending.
+ * @private {?Promise<string>}
+ */
+ this.accessTokenRequestPromise_ = null;
+ }
/** @return {string} Base URL of the Google Cloud Print service. */
get baseUrl() {
return this.baseUrl_;
- },
+ }
/**
* @return {boolean} Whether a search for cloud destinations is in progress.
*/
get isCloudDestinationSearchInProgress() {
return this.outstandingCloudSearchRequests_.length > 0;
- },
+ }
/**
* Sends Google Cloud Print search API request.
@@ -181,10 +115,9 @@ cr.define('cloudprint', function() {
* searches destinations for {@code opt_origin} only, otherwise starts
* searches for all origins.
*/
- search: function(opt_account, opt_origin) {
- var account = opt_account || '';
- var origins =
- opt_origin && [opt_origin] || CloudPrintInterface.CLOUD_ORIGINS_;
+ search(opt_account, opt_origin) {
+ const account = opt_account || '';
+ let origins = opt_origin && [opt_origin] || CLOUD_ORIGINS_;
if (this.isInAppKioskMode_) {
origins = origins.filter(function(origin) {
return origin != print_preview.DestinationOrigin.COOKIES;
@@ -193,7 +126,7 @@ cr.define('cloudprint', function() {
this.abortSearchRequests_(origins);
this.search_(true, account, origins);
this.search_(false, account, origins);
- },
+ }
/**
* Sends Google Cloud Print search API requests.
@@ -206,8 +139,8 @@ cr.define('cloudprint', function() {
* search printers for.
* @private
*/
- search_: function(isRecent, account, origins) {
- var params = [
+ search_(isRecent, account, origins) {
+ const params = [
new HttpParam('connection_status', 'ALL'),
new HttpParam('client', 'chrome'), new HttpParam('use_cdd', 'true')
];
@@ -215,34 +148,34 @@ cr.define('cloudprint', function() {
params.push(new HttpParam('q', '^recent'));
}
origins.forEach(function(origin) {
- var cpRequest = this.buildRequest_(
+ const cpRequest = this.buildRequest_(
'GET', 'search', params, origin, account,
this.onSearchDone_.bind(this, isRecent));
this.outstandingCloudSearchRequests_.push(cpRequest);
this.sendOrQueueRequest_(cpRequest);
}, this);
- },
+ }
/**
* Sends Google Cloud Print printer sharing invitations API requests.
* @param {string} account Account the request is sent for.
*/
- invites: function(account) {
- var params = [
+ invites(account) {
+ const params = [
new HttpParam('client', 'chrome'),
];
this.sendOrQueueRequest_(this.buildRequest_(
'GET', 'invites', params, print_preview.DestinationOrigin.COOKIES,
account, this.onInvitesDone_.bind(this)));
- },
+ }
/**
* Accepts or rejects printer sharing invitation.
* @param {!print_preview.Invitation} invitation Invitation to process.
* @param {boolean} accept Whether to accept this invitation.
*/
- processInvite: function(invitation, accept) {
- var params = [
+ processInvite(invitation, accept) {
+ const params = [
new HttpParam('printerid', invitation.destination.id),
new HttpParam('email', invitation.scopeId),
new HttpParam('accept', accept ? 'true' : 'false'),
@@ -252,7 +185,7 @@ cr.define('cloudprint', function() {
'POST', 'processinvite', params, invitation.destination.origin,
invitation.destination.account,
this.onProcessInviteDone_.bind(this, invitation, accept)));
- },
+ }
/**
* Sends a Google Cloud Print submit API request.
@@ -263,14 +196,13 @@ cr.define('cloudprint', function() {
* @param {!print_preview.DocumentInfo} documentInfo Document data model.
* @param {string} data Base64 encoded data of the document.
*/
- submit: function(destination, printTicketStore, documentInfo, data) {
- var result =
- CloudPrintInterface.VERSION_REGEXP_.exec(navigator.userAgent);
- var chromeVersion = 'unknown';
+ submit(destination, printTicketStore, documentInfo, data) {
+ const result = VERSION_REGEXP_.exec(navigator.userAgent);
+ let chromeVersion = 'unknown';
if (result && result.length == 2) {
chromeVersion = result[1];
}
- var params = [
+ const params = [
new HttpParam('printerid', destination.id),
new HttpParam('contentType', 'dataUrl'),
new HttpParam('title', documentInfo.title),
@@ -280,11 +212,11 @@ cr.define('cloudprint', function() {
new HttpParam('tag', '__google__chrome_version=' + chromeVersion),
new HttpParam('tag', '__google__os=' + navigator.platform)
];
- var cpRequest = this.buildRequest_(
+ const cpRequest = this.buildRequest_(
'POST', 'submit', params, destination.origin, destination.account,
this.onSubmitDone_.bind(this));
this.sendOrQueueRequest_(cpRequest);
- },
+ }
/**
* Sends a Google Cloud Print printer API request.
@@ -296,15 +228,15 @@ cr.define('cloudprint', function() {
* to get printer) and, if the active user account is not the one
* requested, {@code account} is activated and printer request reissued.
*/
- printer: function(printerId, origin, account) {
- var params = [
+ printer(printerId, origin, account) {
+ const params = [
new HttpParam('printerid', printerId), new HttpParam('use_cdd', 'true'),
new HttpParam('printer_connection_status', 'true')
];
this.sendOrQueueRequest_(this.buildRequest_(
'GET', 'printer', params, origin, account || '',
this.onPrinterDone_.bind(this, printerId)));
- },
+ }
/**
* Builds request to the Google Cloud Print API.
@@ -321,10 +253,10 @@ cr.define('cloudprint', function() {
* @return {!cloudprint.CloudPrintRequest} Partially prepared request.
* @private
*/
- buildRequest_: function(method, action, params, origin, account, callback) {
- var url = this.baseUrl_ + '/' + action + '?xsrf=';
+ buildRequest_(method, action, params, origin, account, callback) {
+ let url = this.baseUrl_ + '/' + action + '?xsrf=';
if (origin == print_preview.DestinationOrigin.COOKIES) {
- var xsrfToken = this.xsrfTokens_[account];
+ const xsrfToken = this.xsrfTokens_[account];
if (!xsrfToken) {
// TODO(rltoscano): Should throw an error if not a read-only action or
// issue an xsrf token request.
@@ -332,13 +264,13 @@ cr.define('cloudprint', function() {
url = url + xsrfToken;
}
if (account) {
- var index = this.userSessionIndex_[account] || 0;
+ const index = this.userSessionIndex_[account] || 0;
if (index > 0) {
url += '&authuser=' + index;
}
}
}
- var body = null;
+ let body = null;
if (params) {
if (method == 'GET') {
url = params.reduce(function(partialUrl, param) {
@@ -349,29 +281,29 @@ cr.define('cloudprint', function() {
body = params.reduce(function(partialBody, param) {
return partialBody + 'Content-Disposition: form-data; name=\"' +
param.name + '\"\r\n\r\n' + param.value + '\r\n--' +
- CloudPrintInterface.MULTIPART_BOUNDARY_ + '\r\n';
- }, '--' + CloudPrintInterface.MULTIPART_BOUNDARY_ + '\r\n');
+ MULTIPART_BOUNDARY_ + '\r\n';
+ }, '--' + MULTIPART_BOUNDARY_ + '\r\n');
}
}
- var headers = {};
+ const headers = {};
headers['X-CloudPrint-Proxy'] = 'ChromePrintPreview';
if (method == 'GET') {
- headers['Content-Type'] = CloudPrintInterface.URL_ENCODED_CONTENT_TYPE_;
+ headers['Content-Type'] = URL_ENCODED_CONTENT_TYPE_;
} else if (method == 'POST') {
- headers['Content-Type'] = CloudPrintInterface.MULTIPART_CONTENT_TYPE_;
+ headers['Content-Type'] = MULTIPART_CONTENT_TYPE_;
}
- var xhr = new XMLHttpRequest();
+ const xhr = new XMLHttpRequest();
xhr.open(method, url, true);
xhr.withCredentials = (origin == print_preview.DestinationOrigin.COOKIES);
- for (var header in headers) {
+ for (const header in headers) {
xhr.setRequestHeader(header, headers[header]);
}
return new cloudprint.CloudPrintRequest(
xhr, body, origin, account, callback);
- },
+ }
/**
* Sends a request to the Google Cloud Print API or queues if it needs to
@@ -379,7 +311,7 @@ cr.define('cloudprint', function() {
* @param {!cloudprint.CloudPrintRequest} request Request to send or queue.
* @private
*/
- sendOrQueueRequest_: function(request) {
+ sendOrQueueRequest_(request) {
if (request.origin == print_preview.DestinationOrigin.COOKIES) {
this.sendRequest_(request);
return;
@@ -392,18 +324,18 @@ cr.define('cloudprint', function() {
this.accessTokenRequestPromise_.then(
this.onAccessTokenReady_.bind(this, request));
- },
+ }
/**
* Sends a request to the Google Cloud Print API.
* @param {!cloudprint.CloudPrintRequest} request Request to send.
* @private
*/
- sendRequest_: function(request) {
+ sendRequest_(request) {
request.xhr.onreadystatechange =
this.onReadyStateChange_.bind(this, request);
request.xhr.send(request.body);
- },
+ }
/**
* Creates a Google Cloud Print interface error that is ready to dispatch.
@@ -414,8 +346,8 @@ cr.define('cloudprint', function() {
* @return {!Event} Google Cloud Print interface error event.
* @private
*/
- createErrorEvent_: function(type, request) {
- var errorEvent = new Event(type);
+ createErrorEvent_(type, request) {
+ const errorEvent = new Event(type);
errorEvent.status = request.xhr.status;
if (request.xhr.status == 200) {
errorEvent.errorCode = request.result['errorCode'];
@@ -426,7 +358,7 @@ cr.define('cloudprint', function() {
}
errorEvent.origin = request.origin;
return errorEvent;
- },
+ }
/**
* Updates user info and session index from the {@code request} response.
@@ -434,16 +366,16 @@ cr.define('cloudprint', function() {
* info from.
* @private
*/
- setUsers_: function(request) {
+ setUsers_(request) {
if (request.origin == print_preview.DestinationOrigin.COOKIES) {
- var users = request.result['request']['users'] || [];
+ const users = request.result['request']['users'] || [];
this.userSessionIndex_ = {};
- for (var i = 0; i < users.length; i++) {
+ for (let i = 0; i < users.length; i++) {
this.userSessionIndex_[users[i]] = i;
}
this.userInfo_.setUsers(request.result['request']['user'], users);
}
- },
+ }
/**
* Terminates search requests for requested {@code origins}.
@@ -451,7 +383,7 @@ cr.define('cloudprint', function() {
* to terminate search requests for.
* @private
*/
- abortSearchRequests_: function(origins) {
+ abortSearchRequests_(origins) {
this.outstandingCloudSearchRequests_ =
this.outstandingCloudSearchRequests_.filter(function(request) {
if (origins.indexOf(request.origin) >= 0) {
@@ -460,7 +392,7 @@ cr.define('cloudprint', function() {
}
return true;
});
- },
+ }
/**
* Called when a native layer receives access token. Assumes that the
@@ -470,7 +402,7 @@ cr.define('cloudprint', function() {
* @param {string} accessToken The access token obtained.
* @private
*/
- onAccessTokenReady_: function(request, accessToken) {
+ onAccessTokenReady_(request, accessToken) {
assert(request.origin == print_preview.DestinationOrigin.DEVICE);
if (accessToken) {
request.xhr.setRequestHeader(
@@ -482,7 +414,7 @@ cr.define('cloudprint', function() {
request.callback(request);
}
this.accessTokenRequestPromise_ = null;
- },
+ }
/**
* Called when the ready-state of a XML http request changes.
@@ -490,7 +422,7 @@ cr.define('cloudprint', function() {
* @param {!cloudprint.CloudPrintRequest} request Request that was changed.
* @private
*/
- onReadyStateChange_: function(request) {
+ onReadyStateChange_(request) {
if (request.xhr.readyState == 4) {
if (request.xhr.status == 200) {
request.result =
@@ -501,10 +433,9 @@ cr.define('cloudprint', function() {
request.result['xsrf_token'];
}
}
- request.status = request.xhr.status;
request.callback(request);
}
- },
+ }
/**
* Called when the search request completes.
@@ -514,8 +445,8 @@ cr.define('cloudprint', function() {
* completed.
* @private
*/
- onSearchDone_: function(isRecent, request) {
- var lastRequestForThisOrigin = true;
+ onSearchDone_(isRecent, request) {
+ let lastRequestForThisOrigin = true;
this.outstandingCloudSearchRequests_ =
this.outstandingCloudSearchRequests_.filter(function(item) {
if (item != request && item.origin == request.origin) {
@@ -523,19 +454,19 @@ cr.define('cloudprint', function() {
}
return item != request;
});
- var activeUser = '';
+ let activeUser = '';
if (request.origin == print_preview.DestinationOrigin.COOKIES) {
activeUser = request.result && request.result['request'] &&
request.result['request']['user'];
}
- var event = null;
+ let event = null;
if (request.xhr.status == 200 && request.result['success']) {
// Extract printers.
- var printerListJson = request.result['printers'] || [];
- var printerList = [];
+ const printerListJson = request.result['printers'] || [];
+ const printerList = [];
printerListJson.forEach(function(printerJson) {
try {
- printerList.push(cloudprint.CloudDestinationParser.parse(
+ printerList.push(cloudprint.parseCloudDestination(
printerJson, request.origin, activeUser));
} catch (err) {
console.error('Unable to parse cloud print destination: ' + err);
@@ -555,7 +486,7 @@ cr.define('cloudprint', function() {
event.user = activeUser;
event.searchDone = lastRequestForThisOrigin;
this.dispatchEvent(event);
- },
+ }
/**
* Called when invitations search request completes.
@@ -563,19 +494,19 @@ cr.define('cloudprint', function() {
* completed.
* @private
*/
- onInvitesDone_: function(request) {
- var event = null;
- var activeUser = (request.result && request.result['request'] &&
- request.result['request']['user']) ||
+ onInvitesDone_(request) {
+ let event = null;
+ const activeUser = (request.result && request.result['request'] &&
+ request.result['request']['user']) ||
'';
if (request.xhr.status == 200 && request.result['success']) {
// Extract invitations.
- var invitationListJson = request.result['invites'] || [];
- var invitationList = [];
+ const invitationListJson = request.result['invites'] || [];
+ const invitationList = [];
invitationListJson.forEach(function(invitationJson) {
try {
invitationList.push(
- cloudprint.InvitationParser.parse(invitationJson, activeUser));
+ cloudprint.parseInvitation(invitationJson, activeUser));
} catch (e) {
console.error('Unable to parse invitation: ' + e);
}
@@ -589,7 +520,7 @@ cr.define('cloudprint', function() {
}
event.user = activeUser;
this.dispatchEvent(event);
- },
+ }
/**
* Called when invitation processing request completes.
@@ -599,16 +530,16 @@ cr.define('cloudprint', function() {
* completed.
* @private
*/
- onProcessInviteDone_: function(invitation, accept, request) {
- var event = null;
- var activeUser = (request.result && request.result['request'] &&
- request.result['request']['user']) ||
+ onProcessInviteDone_(invitation, accept, request) {
+ let event = null;
+ const activeUser = (request.result && request.result['request'] &&
+ request.result['request']['user']) ||
'';
if (request.xhr.status == 200 && request.result['success']) {
event = new Event(CloudPrintInterfaceEventType.PROCESS_INVITE_DONE);
if (accept) {
try {
- event.printer = cloudprint.CloudDestinationParser.parse(
+ event.printer = cloudprint.parseCloudDestination(
request.result['printer'], request.origin, activeUser);
} catch (e) {
console.error('Failed to parse cloud print destination: ' + e);
@@ -622,7 +553,7 @@ cr.define('cloudprint', function() {
event.accept = accept;
event.user = activeUser;
this.dispatchEvent(event);
- },
+ }
/**
* Called when the submit request completes.
@@ -630,18 +561,18 @@ cr.define('cloudprint', function() {
* completed.
* @private
*/
- onSubmitDone_: function(request) {
+ onSubmitDone_(request) {
if (request.xhr.status == 200 && request.result['success']) {
- var submitDoneEvent =
+ const submitDoneEvent =
new Event(CloudPrintInterfaceEventType.SUBMIT_DONE);
submitDoneEvent.jobId = request.result['job']['id'];
this.dispatchEvent(submitDoneEvent);
} else {
- var errorEvent = this.createErrorEvent_(
+ const errorEvent = this.createErrorEvent_(
CloudPrintInterfaceEventType.SUBMIT_FAILED, request);
this.dispatchEvent(errorEvent);
}
- },
+ }
/**
* Called when the printer request completes.
@@ -650,7 +581,7 @@ cr.define('cloudprint', function() {
* completed.
* @private
*/
- onPrinterDone_: function(destinationId, request) {
+ onPrinterDone_(destinationId, request) {
// Special handling of the first printer request. It does not matter at
// this point, whether printer was found or not.
if (request.origin == print_preview.DestinationOrigin.COOKIES &&
@@ -673,14 +604,14 @@ cr.define('cloudprint', function() {
}
// Process response.
if (request.xhr.status == 200 && request.result['success']) {
- var activeUser = '';
+ let activeUser = '';
if (request.origin == print_preview.DestinationOrigin.COOKIES) {
activeUser = request.result['request']['user'];
}
- var printerJson = request.result['printers'][0];
- var printer;
+ const printerJson = request.result['printers'][0];
+ let printer;
try {
- printer = cloudprint.CloudDestinationParser.parse(
+ printer = cloudprint.parseCloudDestination(
printerJson, request.origin, activeUser);
} catch (err) {
console.error(
@@ -688,93 +619,135 @@ cr.define('cloudprint', function() {
JSON.stringify(printerJson));
return;
}
- var printerDoneEvent =
+ const printerDoneEvent =
new Event(CloudPrintInterfaceEventType.PRINTER_DONE);
printerDoneEvent.printer = printer;
this.dispatchEvent(printerDoneEvent);
} else {
- var errorEvent = this.createErrorEvent_(
+ const errorEvent = this.createErrorEvent_(
CloudPrintInterfaceEventType.PRINTER_FAILED, request);
errorEvent.destinationId = destinationId;
errorEvent.destinationOrigin = request.origin;
this.dispatchEvent(errorEvent);
}
- },
- };
+ }
+ }
/**
- * Data structure that holds data for Cloud Print requests.
- * @param {!XMLHttpRequest} xhr Partially prepared http request.
- * @param {string} body Data to send with POST requests.
- * @param {!print_preview.DestinationOrigin} origin Origin for destination.
- * @param {?string} account Account the request is sent for. Can be
- * {@code null} or empty string if the request is not cookie bound or
- * is sent on behalf of the primary user.
- * @param {function(!cloudprint.CloudPrintRequest)} callback Callback to
- * invoke when request completes.
- * @constructor
+ * Content type header value for a URL encoded HTTP request.
+ * @const {string}
+ * @private
*/
- function CloudPrintRequest(xhr, body, origin, account, callback) {
- /**
- * Partially prepared http request.
- * @type {!XMLHttpRequest}
- */
- this.xhr = xhr;
-
- /**
- * Data to send with POST requests.
- * @type {string}
- */
- this.body = body;
-
- /**
- * Origin for destination.
- * @type {!print_preview.DestinationOrigin}
- */
- this.origin = origin;
+ const URL_ENCODED_CONTENT_TYPE_ = 'application/x-www-form-urlencoded';
- /**
- * User account this request is expected to be executed for.
- * @type {?string}
- */
- this.account = account;
+ /**
+ * Multi-part POST request boundary used in communication with Google
+ * Cloud Print.
+ * @const {string}
+ * @private
+ */
+ const MULTIPART_BOUNDARY_ = '----CloudPrintFormBoundaryjc9wuprokl8i';
- /**
- * Callback to invoke when request completes.
- * @type {function(!cloudprint.CloudPrintRequest)}
- */
- this.callback = callback;
+ /**
+ * Content type header value for a multipart HTTP request.
+ * @const {string}
+ * @private
+ */
+ const MULTIPART_CONTENT_TYPE_ =
+ 'multipart/form-data; boundary=' + MULTIPART_BOUNDARY_;
- /**
- * Result for requests.
- * @type {Object} JSON response.
- */
- this.result = null;
- }
+ /**
+ * Regex that extracts Chrome's version from the user-agent string.
+ * @const {!RegExp}
+ * @private
+ */
+ const VERSION_REGEXP_ = /.*Chrome\/([\d\.]+)/i;
/**
- * Data structure that represents an HTTP parameter.
- * @param {string} name Name of the parameter.
- * @param {string} value Value of the parameter.
- * @constructor
+ * Could Print origins used to search printers.
+ * @const {!Array<!print_preview.DestinationOrigin>}
+ * @private
*/
- function HttpParam(name, value) {
- /**
- * Name of the parameter.
- * @type {string}
- */
- this.name = name;
+ const CLOUD_ORIGINS_ = [
+ print_preview.DestinationOrigin.COOKIES,
+ print_preview.DestinationOrigin.DEVICE
+ ];
+ class CloudPrintRequest {
/**
- * Name of the value.
- * @type {string}
+ * Data structure that holds data for Cloud Print requests.
+ * @param {!XMLHttpRequest} xhr Partially prepared http request.
+ * @param {string} body Data to send with POST requests.
+ * @param {!print_preview.DestinationOrigin} origin Origin for destination.
+ * @param {?string} account Account the request is sent for. Can be
+ * {@code null} or empty string if the request is not cookie bound or
+ * is sent on behalf of the primary user.
+ * @param {function(!cloudprint.CloudPrintRequest)} callback Callback to
+ * invoke when request completes.
*/
- this.value = value;
+ constructor(xhr, body, origin, account, callback) {
+ /**
+ * Partially prepared http request.
+ * @type {!XMLHttpRequest}
+ */
+ this.xhr = xhr;
+
+ /**
+ * Data to send with POST requests.
+ * @type {string}
+ */
+ this.body = body;
+
+ /**
+ * Origin for destination.
+ * @type {!print_preview.DestinationOrigin}
+ */
+ this.origin = origin;
+
+ /**
+ * User account this request is expected to be executed for.
+ * @type {?string}
+ */
+ this.account = account;
+
+ /**
+ * Callback to invoke when request completes.
+ * @type {function(!cloudprint.CloudPrintRequest)}
+ */
+ this.callback = callback;
+
+ /**
+ * Result for requests.
+ * @type {Object} JSON response.
+ */
+ this.result = null;
+ }
+ }
+
+ class HttpParam {
+ /**
+ * Data structure that represents an HTTP parameter.
+ * @param {string} name Name of the parameter.
+ * @param {string} value Value of the parameter.
+ */
+ constructor(name, value) {
+ /**
+ * Name of the parameter.
+ * @type {string}
+ */
+ this.name = name;
+
+ /**
+ * Name of the value.
+ * @type {string}
+ */
+ this.value = value;
+ }
}
// Export
return {
CloudPrintInterface: CloudPrintInterface,
- CloudPrintRequest: CloudPrintRequest
+ CloudPrintRequest: CloudPrintRequest,
};
});
diff --git a/chromium/chrome/browser/resources/print_preview/common/overlay.js b/chromium/chrome/browser/resources/print_preview/common/overlay.js
index 2680aad2853..94e29e43411 100644
--- a/chromium/chrome/browser/resources/print_preview/common/overlay.js
+++ b/chromium/chrome/browser/resources/print_preview/common/overlay.js
@@ -36,7 +36,7 @@ cr.define('print_preview', function() {
e.preventDefault();
this.cancel();
} else if (e.keyCode == 13) {
- var activeElementTag = document.activeElement ?
+ const activeElementTag = document.activeElement ?
document.activeElement.tagName.toUpperCase() :
'';
if (activeElementTag != 'BUTTON' && activeElementTag != 'SELECT') {
diff --git a/chromium/chrome/browser/resources/print_preview/common/search_box.js b/chromium/chrome/browser/resources/print_preview/common/search_box.js
index d8db692974f..859c99977cf 100644
--- a/chromium/chrome/browser/resources/print_preview/common/search_box.js
+++ b/chromium/chrome/browser/resources/print_preview/common/search_box.js
@@ -96,12 +96,12 @@ cr.define('print_preview', function() {
*/
dispatchSearchEvent_: function() {
this.timeout_ = null;
- var searchEvent = new Event(SearchBox.EventType.SEARCH);
- var query = this.getQuery_();
+ const searchEvent = new Event(SearchBox.EventType.SEARCH);
+ const query = this.getQuery_();
searchEvent.query = query;
if (query) {
// Generate regexp-safe query by escaping metacharacters.
- var safeQuery = query.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
+ const safeQuery = query.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
searchEvent.queryRegExp = new RegExp('(' + safeQuery + ')', 'ig');
} else {
searchEvent.queryRegExp = null;
diff --git a/chromium/chrome/browser/resources/print_preview/common/search_bubble.js b/chromium/chrome/browser/resources/print_preview/common/search_bubble.js
index ab78aa57d93..ff64969a55d 100644
--- a/chromium/chrome/browser/resources/print_preview/common/search_bubble.js
+++ b/chromium/chrome/browser/resources/print_preview/common/search_bubble.js
@@ -11,7 +11,7 @@ cr.define('print_preview', function() {
* @extends {HTMLDivElement}
*/
function SearchBubble(text) {
- var el = cr.doc.createElement('div');
+ const el = cr.doc.createElement('div');
SearchBubble.decorate(el);
el.content = text;
return el;
@@ -49,7 +49,7 @@ cr.define('print_preview', function() {
/** Attach the bubble to the element. */
attachTo: function(element) {
- var parent = element.parentElement;
+ const parent = element.parentElement;
if (!parent)
return;
if (parent.tagName == 'TD') {
@@ -72,8 +72,8 @@ cr.define('print_preview', function() {
dispose: function() {
clearInterval(this.intervalId);
- var child = this.wrapper || this;
- var parent = child.parentNode;
+ const child = this.wrapper || this;
+ const parent = child.parentNode;
if (parent)
parent.removeChild(child);
},
@@ -84,16 +84,16 @@ cr.define('print_preview', function() {
*/
updatePosition: function() {
// This bubble is 'owned' by the next sibling.
- var owner = (this.wrapper || this).nextSibling;
+ const owner = (this.wrapper || this).nextSibling;
// If there isn't an offset parent, we have nothing to do.
if (!owner.offsetParent)
return;
// Position the bubble below the location of the owner.
- var left =
+ const left =
owner.offsetLeft + owner.offsetWidth / 2 - this.offsetWidth / 2;
- var top = owner.offsetTop + owner.offsetHeight;
+ const top = owner.offsetTop + owner.offsetHeight;
// Update the position in the CSS. Cache the last values for
// best performance.
diff --git a/chromium/chrome/browser/resources/print_preview/compiled_resources2.gyp b/chromium/chrome/browser/resources/print_preview/compiled_resources2.gyp
index 3f740401d6d..854ca2d0bd8 100644
--- a/chromium/chrome/browser/resources/print_preview/compiled_resources2.gyp
+++ b/chromium/chrome/browser/resources/print_preview/compiled_resources2.gyp
@@ -25,6 +25,15 @@
],
},
'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
- }
+ },
+ {
+ 'target_name': 'print_preview_utils',
+ 'dependencies': [
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
+ 'data/compiled_resources2.gyp:size',
+ 'data/compiled_resources2.gyp:coordinate2d'
+ ],
+ 'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
],
}
diff --git a/chromium/chrome/browser/resources/print_preview/component.js b/chromium/chrome/browser/resources/print_preview/component.js
index 02109b85b7f..00227848188 100644
--- a/chromium/chrome/browser/resources/print_preview/component.js
+++ b/chromium/chrome/browser/resources/print_preview/component.js
@@ -148,7 +148,7 @@ cr.define('print_preview', function() {
* component's children.
*/
removeChild: function(child) {
- var childIdx = this.children_.indexOf(child);
+ const childIdx = this.children_.indexOf(child);
if (childIdx != -1) {
this.children_.splice(childIdx, 1);
}
@@ -202,10 +202,10 @@ cr.define('print_preview', function() {
* @protected
*/
cloneTemplateInternal: function(templateId, opt_keepHidden) {
- var templateEl = $(templateId);
+ const templateEl = $(templateId);
assert(
templateEl != null, 'Could not find element with ID: ' + templateId);
- var el = assertInstanceof(templateEl.cloneNode(true), HTMLElement);
+ const el = assertInstanceof(templateEl.cloneNode(true), HTMLElement);
el.id = '';
if (!opt_keepHidden) {
setIsVisible(el, true);
diff --git a/chromium/chrome/browser/resources/print_preview/data/app_state.js b/chromium/chrome/browser/resources/print_preview/data/app_state.js
index 6e14236ee9c..68d75b878f7 100644
--- a/chromium/chrome/browser/resources/print_preview/data/app_state.js
+++ b/chromium/chrome/browser/resources/print_preview/data/app_state.js
@@ -46,13 +46,13 @@ print_preview.AppStateRecentDestination;
*/
function makeRecentDestination(destination) {
return {
- id: destination.id_,
- origin: destination.origin_,
- account: destination.account_ || '',
+ id: destination.id,
+ origin: destination.origin,
+ account: destination.account || '',
capabilities: destination.capabilities,
- displayName: destination.displayName_ || '',
- extensionId: destination.extensionId_ || '',
- extensionName: destination.extensionName_ || '',
+ displayName: destination.displayName || '',
+ extensionId: destination.extensionId || '',
+ extensionName: destination.extensionName || '',
};
}
@@ -65,6 +65,8 @@ cr.define('print_preview', function() {
constructor() {
/**
* Internal representation of application state.
+ * Must contain only plain objects or classes that override the
+ * toJSON() method.
* @private {!Object}
*/
this.state_ = {};
@@ -100,7 +102,7 @@ cr.define('print_preview', function() {
* @return {boolean} Whether the selected destination is valid.
*/
isSelectedDestinationValid() {
- var selected = this.selectedDestination;
+ const selected = this.selectedDestination;
return !!selected && !!selected.id && !!selected.origin;
}
@@ -143,7 +145,7 @@ cr.define('print_preview', function() {
init(serializedAppStateStr) {
if (serializedAppStateStr) {
try {
- var state = JSON.parse(serializedAppStateStr);
+ const state = JSON.parse(serializedAppStateStr);
if (!!state &&
state[print_preview.AppStateField.VERSION] == AppState.VERSION_) {
this.state_ = /** @type {!Object} */ (state);
@@ -161,7 +163,8 @@ cr.define('print_preview', function() {
} else if (!(this.state_[print_preview.AppStateField
.RECENT_DESTINATIONS] instanceof
Array)) {
- var tmp = this.state_[print_preview.AppStateField.RECENT_DESTINATIONS];
+ const tmp =
+ this.state_[print_preview.AppStateField.RECENT_DESTINATIONS];
this.state_[print_preview.AppStateField.RECENT_DESTINATIONS] = [tmp];
} else if (
!this.state_[print_preview.AppStateField.RECENT_DESTINATIONS][0] ||
@@ -209,8 +212,8 @@ cr.define('print_preview', function() {
// Determine if this destination is already in the recent destinations,
// and where in the array it is located.
- var newDestination = makeRecentDestination(dest);
- var indexFound =
+ const newDestination = makeRecentDestination(dest);
+ let indexFound =
this.state_[print_preview.AppStateField.RECENT_DESTINATIONS]
.findIndex(function(recent) {
return (
@@ -219,7 +222,9 @@ cr.define('print_preview', function() {
});
// No change
- if (indexFound == 0) {
+ if (indexFound == 0 &&
+ this.selectedDestination.capabilities ==
+ newDestination.capabilities) {
this.persist_();
return;
}
diff --git a/chromium/chrome/browser/resources/print_preview/data/cloud_parsers.js b/chromium/chrome/browser/resources/print_preview/data/cloud_parsers.js
index 25e16c1e4e1..8d8f043adad 100644
--- a/chromium/chrome/browser/resources/print_preview/data/cloud_parsers.js
+++ b/chromium/chrome/browser/resources/print_preview/data/cloud_parsers.js
@@ -5,15 +5,11 @@
cr.define('cloudprint', function() {
'use strict';
- /** Namespace which contains a method to parse cloud destinations directly. */
- function CloudDestinationParser() {}
-
/**
* Enumeration of cloud destination field names.
* @enum {string}
- * @private
*/
- CloudDestinationParser.Field_ = {
+ const CloudDestinationField = {
CAPABILITIES: 'capabilities',
CONNECTION_STATUS: 'connectionStatus',
DESCRIPTION: 'description',
@@ -26,32 +22,45 @@ cr.define('cloudprint', function() {
/**
* Special tag that denotes whether the destination has been recently used.
- * @type {string}
- * @const
- * @private
+ * @const {string}
*/
- CloudDestinationParser.RECENT_TAG_ = '^recent';
+ const RECENT_TAG = '^recent';
/**
* Special tag that denotes whether the destination is owned by the user.
- * @type {string}
- * @const
- * @private
+ * @const {string}
*/
- CloudDestinationParser.OWNED_TAG_ = '^own';
+ const OWNED_TAG = '^own';
/**
* Enumeration of cloud destination types that are supported by print preview.
* @enum {string}
- * @private
*/
- CloudDestinationParser.CloudType_ = {
+ const DestinationCloudType = {
ANDROID: 'ANDROID_CHROME_SNAPSHOT',
DOCS: 'DOCS',
IOS: 'IOS_CHROME_SNAPSHOT'
};
/**
+ * Parses the destination type.
+ * @param {string} typeStr Destination type given by the Google Cloud Print
+ * server.
+ * @return {!print_preview.DestinationType} Destination type.
+ * @private
+ */
+ function parseType(typeStr) {
+ if (typeStr == DestinationCloudType.ANDROID ||
+ typeStr == DestinationCloudType.IOS) {
+ return print_preview.DestinationType.MOBILE;
+ }
+ if (typeStr == DestinationCloudType.DOCS) {
+ return print_preview.DestinationType.GOOGLE_PROMOTED;
+ }
+ return print_preview.DestinationType.GOOGLE;
+ }
+
+ /**
* Parses a destination from JSON from a Google Cloud Print search or printer
* response.
* @param {!Object} json Object that represents a Google Cloud Print search or
@@ -62,76 +71,52 @@ cr.define('cloudprint', function() {
* empty string, if origin != COOKIES.
* @return {!print_preview.Destination} Parsed destination.
*/
- CloudDestinationParser.parse = function(json, origin, account) {
- if (!json.hasOwnProperty(CloudDestinationParser.Field_.ID) ||
- !json.hasOwnProperty(CloudDestinationParser.Field_.TYPE) ||
- !json.hasOwnProperty(CloudDestinationParser.Field_.DISPLAY_NAME)) {
+ function parseCloudDestination(json, origin, account) {
+ if (!json.hasOwnProperty(CloudDestinationField.ID) ||
+ !json.hasOwnProperty(CloudDestinationField.TYPE) ||
+ !json.hasOwnProperty(CloudDestinationField.DISPLAY_NAME)) {
throw Error('Cloud destination does not have an ID or a display name');
}
- var id = json[CloudDestinationParser.Field_.ID];
- var tags = json[CloudDestinationParser.Field_.TAGS] || [];
- var connectionStatus =
- json[CloudDestinationParser.Field_.CONNECTION_STATUS] ||
+ const id = json[CloudDestinationField.ID];
+ const tags = json[CloudDestinationField.TAGS] || [];
+ const connectionStatus = json[CloudDestinationField.CONNECTION_STATUS] ||
print_preview.DestinationConnectionStatus.UNKNOWN;
- var optionalParams = {
+ const optionalParams = {
account: account,
tags: tags,
- isOwned: arrayContains(tags, CloudDestinationParser.OWNED_TAG_),
+ isOwned: arrayContains(tags, OWNED_TAG),
lastAccessTime:
- parseInt(json[CloudDestinationParser.Field_.LAST_ACCESS], 10) ||
- Date.now(),
+ parseInt(json[CloudDestinationField.LAST_ACCESS], 10) || Date.now(),
cloudID: id,
- description: json[CloudDestinationParser.Field_.DESCRIPTION]
+ description: json[CloudDestinationField.DESCRIPTION]
};
- var cloudDest = new print_preview.Destination(
- id,
- CloudDestinationParser.parseType_(
- json[CloudDestinationParser.Field_.TYPE]),
- origin, json[CloudDestinationParser.Field_.DISPLAY_NAME],
- arrayContains(tags, CloudDestinationParser.RECENT_TAG_) /*isRecent*/,
- connectionStatus, optionalParams);
- if (json.hasOwnProperty(CloudDestinationParser.Field_.CAPABILITIES)) {
+ const cloudDest = new print_preview.Destination(
+ id, parseType(json[CloudDestinationField.TYPE]), origin,
+ json[CloudDestinationField.DISPLAY_NAME],
+ arrayContains(tags, RECENT_TAG) /*isRecent*/, connectionStatus,
+ optionalParams);
+ if (json.hasOwnProperty(CloudDestinationField.CAPABILITIES)) {
cloudDest.capabilities = /** @type {!print_preview.Cdd} */ (
- json[CloudDestinationParser.Field_.CAPABILITIES]);
+ json[CloudDestinationField.CAPABILITIES]);
}
return cloudDest;
- };
-
- /**
- * Parses the destination type.
- * @param {string} typeStr Destination type given by the Google Cloud Print
- * server.
- * @return {!print_preview.DestinationType} Destination type.
- * @private
- */
- CloudDestinationParser.parseType_ = function(typeStr) {
- if (typeStr == CloudDestinationParser.CloudType_.ANDROID ||
- typeStr == CloudDestinationParser.CloudType_.IOS) {
- return print_preview.DestinationType.MOBILE;
- }
- if (typeStr == CloudDestinationParser.CloudType_.DOCS) {
- return print_preview.DestinationType.GOOGLE_PROMOTED;
- }
- return print_preview.DestinationType.GOOGLE;
- };
-
- /** Namespace which contains a method to parse printer sharing invitation. */
- function InvitationParser() {}
+ }
/**
* Enumeration of invitation field names.
* @enum {string}
- * @private
*/
- InvitationParser
- .Field_ = {PRINTER: 'printer', RECEIVER: 'receiver', SENDER: 'sender'};
+ const InvitationField = {
+ PRINTER: 'printer',
+ RECEIVER: 'receiver',
+ SENDER: 'sender'
+ };
/**
* Enumeration of cloud destination types that are supported by print preview.
* @enum {string}
- * @private
*/
- InvitationParser.AclType_ =
+ const InvitationAclType =
{DOMAIN: 'DOMAIN', GROUP: 'GROUP', PUBLIC: 'PUBLIC', USER: 'USER'};
/**
@@ -140,44 +125,44 @@ cr.define('cloudprint', function() {
* @param {string} account The account this invitation is sent for.
* @return {!print_preview.Invitation} Parsed invitation.
*/
- InvitationParser.parse = function(json, account) {
- if (!json.hasOwnProperty(InvitationParser.Field_.SENDER) ||
- !json.hasOwnProperty(InvitationParser.Field_.RECEIVER) ||
- !json.hasOwnProperty(InvitationParser.Field_.PRINTER)) {
+ function parseInvitation(json, account) {
+ if (!json.hasOwnProperty(InvitationField.SENDER) ||
+ !json.hasOwnProperty(InvitationField.RECEIVER) ||
+ !json.hasOwnProperty(InvitationField.PRINTER)) {
throw Error('Invitation does not have necessary info.');
}
- var nameFormatter = function(name, scope) {
+ const nameFormatter = function(name, scope) {
return name && scope ? (name + ' (' + scope + ')') : (name || scope);
};
- var sender = json[InvitationParser.Field_.SENDER];
- var senderName = nameFormatter(sender['name'], sender['email']);
+ const sender = json[InvitationField.SENDER];
+ const senderName = nameFormatter(sender['name'], sender['email']);
- var receiver = json[InvitationParser.Field_.RECEIVER];
- var receiverName = '';
- var receiverType = receiver['type'];
- if (receiverType == InvitationParser.AclType_.USER) {
+ const receiver = json[InvitationField.RECEIVER];
+ let receiverName = '';
+ const receiverType = receiver['type'];
+ if (receiverType == InvitationAclType.USER) {
// It's a personal invitation, empty name indicates just that.
} else if (
- receiverType == InvitationParser.AclType_.GROUP ||
- receiverType == InvitationParser.AclType_.DOMAIN) {
+ receiverType == InvitationAclType.GROUP ||
+ receiverType == InvitationAclType.DOMAIN) {
receiverName = nameFormatter(receiver['name'], receiver['scope']);
} else {
throw Error('Invitation of unsupported receiver type');
}
- var destination = cloudprint.CloudDestinationParser.parse(
- json[InvitationParser.Field_.PRINTER],
- print_preview.DestinationOrigin.COOKIES, account);
+ const destination = cloudprint.parseCloudDestination(
+ json[InvitationField.PRINTER], print_preview.DestinationOrigin.COOKIES,
+ account);
return new print_preview.Invitation(
senderName, receiverName, destination, receiver, account);
- };
+ }
// Export
return {
- CloudDestinationParser: CloudDestinationParser,
- InvitationParser: InvitationParser
+ parseCloudDestination: parseCloudDestination,
+ parseInvitation: parseInvitation,
};
});
diff --git a/chromium/chrome/browser/resources/print_preview/data/compiled_resources2.gyp b/chromium/chrome/browser/resources/print_preview/data/compiled_resources2.gyp
new file mode 100644
index 00000000000..d69be6dfbcb
--- /dev/null
+++ b/chromium/chrome/browser/resources/print_preview/data/compiled_resources2.gyp
@@ -0,0 +1,58 @@
+# Copyright 2017 The Chromium 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': 'destination',
+ 'dependencies': [
+ '../compiled_resources2.gyp:print_preview_utils',
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:load_time_data',
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'document_info',
+ 'dependencies': [
+ 'margins',
+ 'size',
+ 'coordinate2d',
+ 'printable_area',
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
+ '<(DEPTH)/ui/webui/resources/js/cr/compiled_resources2.gyp:event_target',
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'margins',
+ 'dependencies': [
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'printable_area',
+ 'dependencies': [
+ 'size',
+ 'coordinate2d',
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'size',
+ 'dependencies': [
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'coordinate2d',
+ '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/print_preview/data/coordinate2d.html b/chromium/chrome/browser/resources/print_preview/data/coordinate2d.html
new file mode 100644
index 00000000000..a121f0962c8
--- /dev/null
+++ b/chromium/chrome/browser/resources/print_preview/data/coordinate2d.html
@@ -0,0 +1,3 @@
+<link rel="import" href="chrome://resources/html/cr.html">
+
+<script src="coordinate2d.js"></script>
diff --git a/chromium/chrome/browser/resources/print_preview/data/destination.html b/chromium/chrome/browser/resources/print_preview/data/destination.html
new file mode 100644
index 00000000000..5e1d05995fc
--- /dev/null
+++ b/chromium/chrome/browser/resources/print_preview/data/destination.html
@@ -0,0 +1,4 @@
+<link rel="import" href="chrome://resources/html/cr.html">
+<link rel="import" href="../print_preview_utils.html">
+
+<script src="destination.js"></script>
diff --git a/chromium/chrome/browser/resources/print_preview/data/destination.js b/chromium/chrome/browser/resources/print_preview/data/destination.js
index e98026cea19..dd2db7704cf 100644
--- a/chromium/chrome/browser/resources/print_preview/data/destination.js
+++ b/chromium/chrome/browser/resources/print_preview/data/destination.js
@@ -56,39 +56,54 @@ print_preview.DestinationProvisionalType = {
};
/**
+ * Capabilities of a print destination represented in a CDD.
+ *
+ * @typedef {{
+ * vendor_capability: !Array<{Object}>,
+ * collate: ({default: (boolean|undefined)}|undefined),
+ * color: ({
+ * option: !Array<{
+ * type: (string|undefined),
+ * vendor_id: (string|undefined),
+ * custom_display_name: (string|undefined),
+ * is_default: (boolean|undefined)
+ * }>
+ * }|undefined),
+ * copies: ({default: (number|undefined),
+ * max: (number|undefined)}|undefined),
+ * duplex: ({option: !Array<{type: (string|undefined),
+ * is_default: (boolean|undefined)}>}|undefined),
+ * page_orientation: ({
+ * option: !Array<{type: (string|undefined),
+ * is_default: (boolean|undefined)}>
+ * }|undefined),
+ * media_size: ({
+ * option: !Array<{
+ * type: (string|undefined),
+ * vendor_id: (string|undefined),
+ * custom_display_name: (string|undefined),
+ * is_default: (boolean|undefined)
+ * }>
+ * }|undefined),
+ * dpi: ({
+ * option: !Array<{
+ * vendor_id: (string|undefined),
+ * height_microns: number,
+ * width_microns: number,
+ * is_default: (boolean|undefined)
+ * }>
+ * }|undefined)
+ * }}
+ */
+print_preview.CddCapabilities;
+
+/**
* The CDD (Cloud Device Description) describes the capabilities of a print
* destination.
*
* @typedef {{
* version: string,
- * printer: {
- * vendor_capability: !Array<{Object}>,
- * collate: ({default: (boolean|undefined)}|undefined),
- * color: ({
- * option: !Array<{
- * type: (string|undefined),
- * vendor_id: (string|undefined),
- * custom_display_name: (string|undefined),
- * is_default: (boolean|undefined)
- * }>
- * }|undefined),
- * copies: ({default: (number|undefined),
- * max: (number|undefined)}|undefined),
- * duplex: ({option: !Array<{type: (string|undefined),
- * is_default: (boolean|undefined)}>}|undefined),
- * page_orientation: ({
- * option: !Array<{type: (string|undefined),
- * is_default: (boolean|undefined)}>
- * }|undefined),
- * media_size: ({
- * option: !Array<{
- * type: (string|undefined),
- * vendor_id: (string|undefined),
- * custom_display_name: (string|undefined),
- * is_default: (boolean|undefined)
- * }>
- * }|undefined)
- * }
+ * printer: !print_preview.CddCapabilities,
* }}
*/
print_preview.Cdd;
@@ -430,8 +445,8 @@ cr.define('print_preview', function() {
if (!this.isOffline) {
return '';
}
- var offlineDurationMs = Date.now() - this.lastAccessTime_;
- var offlineMessageId;
+ const offlineDurationMs = Date.now() - this.lastAccessTime_;
+ let offlineMessageId;
if (offlineDurationMs > 31622400000.0) { // One year.
offlineMessageId = 'offlineForYear';
} else if (offlineDurationMs > 2678400000.0) { // One month.
diff --git a/chromium/chrome/browser/resources/print_preview/data/destination_match.js b/chromium/chrome/browser/resources/print_preview/data/destination_match.js
index 165aa22f013..260a6411f31 100644
--- a/chromium/chrome/browser/resources/print_preview/data/destination_match.js
+++ b/chromium/chrome/browser/resources/print_preview/data/destination_match.js
@@ -11,7 +11,7 @@ cr.define('print_preview', function() {
* return {?print_preview.PrinterType} The corresponding PrinterType.
* Returns null if no match is found.
*/
- var originToType = function(origin) {
+ const originToType = function(origin) {
if (origin === print_preview.DestinationOrigin.LOCAL ||
origin === print_preview.DestinationOrigin.CROS) {
return print_preview.PrinterType.LOCAL_PRINTER;
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 80072b56887..cd83d8f608a 100644
--- a/chromium/chrome/browser/resources/print_preview/data/destination_store.js
+++ b/chromium/chrome/browser/resources/print_preview/data/destination_store.js
@@ -22,15 +22,15 @@ cr.define('print_preview', function() {
* localize.
* @return {!print_preview.Cdd} Localized capabilities.
*/
- var localizeCapabilities = function(capabilities) {
+ const localizeCapabilities = function(capabilities) {
if (!capabilities.printer)
return capabilities;
- var mediaSize = capabilities.printer.media_size;
+ const mediaSize = capabilities.printer.media_size;
if (!mediaSize)
return capabilities;
- for (var i = 0, media; (media = mediaSize.option[i]); i++) {
+ for (let i = 0, media; (media = mediaSize.option[i]); i++) {
// No need to patch capabilities with localized names provided.
if (!media.custom_display_name_localized) {
media.custom_display_name = media.custom_display_name ||
@@ -46,9 +46,9 @@ cr.define('print_preview', function() {
* @param {!Object} b Media to compare.
* @return {number} 1 if a > b, -1 if a < b, or 0 if a == b.
*/
- var compareMediaNames = function(a, b) {
- var nameA = a.custom_display_name_localized || a.custom_display_name;
- var nameB = b.custom_display_name_localized || b.custom_display_name;
+ const compareMediaNames = function(a, b) {
+ const nameA = a.custom_display_name_localized || a.custom_display_name;
+ const nameB = b.custom_display_name_localized || b.custom_display_name;
return nameA == nameB ? 0 : (nameA > nameB ? 1 : -1);
};
@@ -59,11 +59,11 @@ cr.define('print_preview', function() {
* @return {!print_preview.Cdd} Localized capabilities.
* @private
*/
- var sortMediaSizes = function(capabilities) {
+ const sortMediaSizes = function(capabilities) {
if (!capabilities.printer)
return capabilities;
- var mediaSize = capabilities.printer.media_size;
+ const mediaSize = capabilities.printer.media_size;
if (!mediaSize)
return capabilities;
@@ -75,15 +75,15 @@ cr.define('print_preview', function() {
// - Japanese
// - Other metric
// Otherwise, assume they are custom sizes.
- var categoryStandardNA = [];
- var categoryStandardCN = [];
- var categoryStandardISO = [];
- var categoryStandardJP = [];
- var categoryStandardMisc = [];
- var categoryCustom = [];
- for (var i = 0, media; (media = mediaSize.option[i]); i++) {
- var name = media.name || 'CUSTOM';
- var category;
+ const categoryStandardNA = [];
+ const categoryStandardCN = [];
+ const categoryStandardISO = [];
+ const categoryStandardJP = [];
+ const categoryStandardMisc = [];
+ const categoryCustom = [];
+ for (let i = 0, media; (media = mediaSize.option[i]); i++) {
+ const name = media.name || 'CUSTOM';
+ let category;
if (name.startsWith('NA_')) {
category = categoryStandardNA;
} else if (
@@ -288,6 +288,26 @@ cr.define('print_preview', function() {
}
/**
+ * @param {?string} filterAccount Account to filter recent destinations by.
+ * @return {!Array<!print_preview.Destination>} List of recent destinations
+ */
+ getRecentDestinations(filterAccount) {
+ let recentDestinations = [];
+ this.appState_.recentDestinations.forEach(function(recentDestination) {
+ const origin = recentDestination.origin;
+ const id = recentDestination.id;
+ const account = recentDestination.account || '';
+ const destination =
+ this.destinationMap_[this.getDestinationKey_(origin, id, account)];
+ if (destination &&
+ (!destination.account || destination.account == filterAccount)) {
+ recentDestinations.push(destination);
+ }
+ }.bind(this));
+ return recentDestinations;
+ }
+
+ /**
* @return {print_preview.Destination} The currently selected destination or
* {@code null} if none is selected.
*/
@@ -302,21 +322,21 @@ cr.define('print_preview', function() {
}
/**
- * @return {boolean} Whether a search for local destinations is in progress.
+ * @return {boolean} Whether a search for print destinations is in progress.
*/
- get isLocalDestinationSearchInProgress() {
- return Array.from(this.destinationSearchStatus_.values())
- .some(
- el => el ===
- print_preview.DestinationStorePrinterSearchStatus.SEARCHING);
- }
+ get isPrintDestinationSearchInProgress() {
+ let isLocalDestinationSearchInProgress =
+ Array.from(this.destinationSearchStatus_.values())
+ .some(
+ el => el ===
+ print_preview.DestinationStorePrinterSearchStatus
+ .SEARCHING);
+ if (isLocalDestinationSearchInProgress)
+ return true;
- /**
- * @return {boolean} Whether a search for cloud destinations is in progress.
- */
- get isCloudDestinationSearchInProgress() {
- return !!this.cloudPrintInterface_ &&
+ let isCloudDestinationSearchInProgress = !!this.cloudPrintInterface_ &&
this.cloudPrintInterface_.isCloudDestinationSearchInProgress;
+ return isCloudDestinationSearchInProgress;
}
/**
@@ -352,7 +372,7 @@ cr.define('print_preview', function() {
this.createLocalPdfPrintDestination_();
if (!this.appState_.isSelectedDestinationValid()) {
- var destinationMatch = this.convertToDestinationMatch_(
+ const destinationMatch = this.convertToDestinationMatch_(
serializedDefaultDestinationSelectionRulesStr);
if (destinationMatch) {
this.fetchMatchingDestination_(destinationMatch);
@@ -366,21 +386,21 @@ cr.define('print_preview', function() {
return;
}
- var origin = null;
- var id = '';
- var account = '';
- var name = '';
- var capabilities = null;
- var extensionId = '';
- var extensionName = '';
- var foundDestination = false;
+ let origin = null;
+ let id = '';
+ let account = '';
+ let name = '';
+ let capabilities = null;
+ let extensionId = '';
+ let extensionName = '';
+ let foundDestination = false;
if (this.appState_.recentDestinations) {
// Run through the destinations forward. As soon as we find a
// destination, don't select any future destinations, just mark
// them recent. Otherwise, there is a race condition between selecting
// destinations/updating the print ticket and this selecting a new
// destination that causes random print preview errors.
- for (var i = 0; i < this.appState_.recentDestinations.length; i++) {
+ for (let i = 0; i < this.appState_.recentDestinations.length; i++) {
origin = this.appState_.recentDestinations[i].origin;
id = this.appState_.recentDestinations[i].id;
account = this.appState_.recentDestinations[i].account || '';
@@ -389,7 +409,7 @@ cr.define('print_preview', function() {
extensionId = this.appState_.recentDestinations[i].extensionId || '';
extensionName =
this.appState_.recentDestinations[i].extensionName || '';
- var candidate = this.destinationMap_[this.getDestinationKey_(
+ const candidate = this.destinationMap_[this.getDestinationKey_(
origin, id, account)];
if (candidate != null) {
if (!foundDestination && !this.useSystemDefaultAsDefault_)
@@ -413,10 +433,10 @@ cr.define('print_preview', function() {
print_preview.DestinationOrigin.LOCAL :
this.platformOrigin_;
account = '';
- var candidate =
+ const systemDefaultCandidate =
this.destinationMap_[this.getDestinationKey_(origin, id, account)];
- if (candidate != null) {
- this.selectDestination(candidate);
+ if (systemDefaultCandidate != null) {
+ this.selectDestination(systemDefaultCandidate);
return;
}
@@ -450,7 +470,7 @@ cr.define('print_preview', function() {
this.autoSelectMatchingDestination_ =
this.createExactDestinationMatch_(origin, id);
- var type = print_preview.originToType(origin);
+ const type = print_preview.originToType(origin);
if (type == print_preview.PrinterType.LOCAL_PRINTER) {
this.nativeLayer_.getPrinterCapabilities(id, type).then(
this.onCapabilitiesSet_.bind(this, origin, id),
@@ -474,7 +494,7 @@ cr.define('print_preview', function() {
// Create a fake selectedDestination_ that is not actually in the
// destination store. When the real destination is created, this
// destination will be overwritten.
- var params =
+ const params =
(origin === print_preview.DestinationOrigin.PRIVET) ? {} : {
description: '',
extensionId: extensionId,
@@ -506,7 +526,7 @@ cr.define('print_preview', function() {
*/
fetchMatchingDestination_(destinationMatch) {
this.autoSelectMatchingDestination_ = destinationMatch;
- var type = destinationMatch.getType();
+ const type = destinationMatch.getType();
if (type != null) { // Local, Privet, or Extension.
this.startLoadDestinations(type);
} else if (
@@ -526,7 +546,7 @@ cr.define('print_preview', function() {
* @private
*/
convertToDestinationMatch_(serializedDefaultDestinationSelectionRulesStr) {
- var matchRules = null;
+ let matchRules = null;
try {
if (serializedDefaultDestinationSelectionRulesStr) {
matchRules =
@@ -538,14 +558,14 @@ cr.define('print_preview', function() {
if (!matchRules)
return null;
- var isLocal = !matchRules.kind || matchRules.kind == 'local';
- var isCloud = !matchRules.kind || matchRules.kind == 'cloud';
+ const isLocal = !matchRules.kind || matchRules.kind == 'local';
+ const isCloud = !matchRules.kind || matchRules.kind == 'cloud';
if (!isLocal && !isCloud) {
console.error('Unsupported type: "' + matchRules.kind + '"');
return null;
}
- var origins = [];
+ const origins = [];
if (isLocal) {
origins.push(print_preview.DestinationOrigin.LOCAL);
origins.push(print_preview.DestinationOrigin.PRIVET);
@@ -557,7 +577,7 @@ cr.define('print_preview', function() {
origins.push(print_preview.DestinationOrigin.DEVICE);
}
- var idRegExp = null;
+ let idRegExp = null;
try {
if (matchRules.idPattern) {
idRegExp = new RegExp(matchRules.idPattern || '.*');
@@ -566,7 +586,7 @@ cr.define('print_preview', function() {
console.error('Failed to parse regexp for "id": ' + e);
}
- var displayNameRegExp = null;
+ let displayNameRegExp = null;
try {
if (matchRules.namePattern) {
displayNameRegExp = new RegExp(matchRules.namePattern || '.*');
@@ -689,7 +709,7 @@ cr.define('print_preview', function() {
// Request destination capabilities from backend, since they are not
// known yet.
if (destination.capabilities == null) {
- var type = print_preview.originToType(destination.origin);
+ const type = print_preview.originToType(destination.origin);
if (type !== null) {
this.nativeLayer_.getPrinterCapabilities(destination.id, type)
.then(
@@ -742,7 +762,7 @@ cr.define('print_preview', function() {
* PROVISIONAL_DESTINATION_RESOLVED event.
*/
this.removeProvisionalDestination_(destination.id);
- var parsedDestination =
+ const parsedDestination =
print_preview.parseExtensionDestination(destinationInfo);
this.insertIntoStore_(parsedDestination);
this.dispatchProvisionalDestinationResolvedEvent_(
@@ -765,7 +785,7 @@ cr.define('print_preview', function() {
* @private
*/
selectPdfDestination_() {
- var saveToPdfKey = this.getDestinationKey_(
+ const saveToPdfKey = this.getDestinationKey_(
print_preview.DestinationOrigin.LOCAL,
print_preview.Destination.GooglePromotedId.SAVE_AS_PDF, '');
this.selectDestination(
@@ -823,7 +843,8 @@ cr.define('print_preview', function() {
*/
startLoadCloudDestinations(opt_origin) {
if (this.cloudPrintInterface_ != null) {
- var origins = this.loadedCloudOrigins_[this.userInfo_.activeUser] || [];
+ const origins =
+ this.loadedCloudOrigins_[this.userInfo_.activeUser] || [];
if (origins.length == 0 ||
(opt_origin && origins.indexOf(opt_origin) < 0)) {
this.cloudPrintInterface_.search(
@@ -836,7 +857,7 @@ cr.define('print_preview', function() {
/** Requests load of COOKIE based cloud destinations. */
reloadUserCookieBasedDestinations() {
- var origins = this.loadedCloudOrigins_[this.userInfo_.activeUser] || [];
+ const origins = this.loadedCloudOrigins_[this.userInfo_.activeUser] || [];
if (origins.indexOf(print_preview.DestinationOrigin.COOKIES) >= 0) {
cr.dispatchSimpleEvent(
this, DestinationStore.EventType.DESTINATION_SEARCH_DONE);
@@ -849,7 +870,7 @@ cr.define('print_preview', function() {
/** Initiates loading of all known destination types. */
startLoadAllDestinations() {
this.startLoadCloudDestinations();
- for (var printerType of Object.values(print_preview.PrinterType)) {
+ for (const printerType of Object.values(print_preview.PrinterType)) {
if (printerType !== print_preview.PrinterType.PDF_PRINTER)
this.startLoadDestinations(printerType);
}
@@ -859,7 +880,7 @@ cr.define('print_preview', function() {
* Wait for a privet device to be registered.
*/
waitForRegister(id) {
- var privetType = print_preview.PrinterType.PRIVET_PRINTER;
+ const privetType = print_preview.PrinterType.PRIVET_PRINTER;
this.nativeLayer_.getPrinters(privetType)
.then(this.onDestinationSearchDone_.bind(this, privetType));
this.waitForRegisterDestination_ = id;
@@ -891,7 +912,7 @@ cr.define('print_preview', function() {
* destination if it was resolved successfully.
*/
dispatchProvisionalDestinationResolvedEvent_(provisionalId, destination) {
- var event = new Event(
+ const event = new Event(
DestinationStore.EventType.PROVISIONAL_DESTINATION_RESOLVED);
event.provisionalId = provisionalId;
event.destination = destination;
@@ -920,7 +941,7 @@ cr.define('print_preview', function() {
* @private
*/
insertDestinations_(destinations) {
- var inserted = false;
+ let inserted = false;
destinations.forEach(destination => {
if (Array.isArray(destination)) {
// privet printers return arrays of 1 or 2 printers
@@ -949,7 +970,7 @@ cr.define('print_preview', function() {
cr.dispatchSimpleEvent(
this, DestinationStore.EventType.DESTINATIONS_INSERTED);
if (this.autoSelectMatchingDestination_) {
- var destinationsToSearch =
+ const destinationsToSearch =
opt_destination && [opt_destination] || this.destinations_;
destinationsToSearch.some(function(destination) {
if (this.autoSelectMatchingDestination_.match(destination)) {
@@ -974,7 +995,8 @@ cr.define('print_preview', function() {
print_preview.PrinterType.LOCAL_PRINTER) {
destination.capabilities_ = sortMediaSizes(destination.capabilities_);
}
- var existingDestination = this.destinationMap_[this.getKey_(destination)];
+ const existingDestination =
+ this.destinationMap_[this.getKey_(destination)];
if (existingDestination != null) {
existingDestination.capabilities = destination.capabilities;
} else {
@@ -1015,8 +1037,8 @@ cr.define('print_preview', function() {
* @private
*/
insertIntoStore_(destination) {
- var key = this.getKey_(destination);
- var existingDestination = this.destinationMap_[key];
+ const key = this.getKey_(destination);
+ const existingDestination = this.destinationMap_[key];
if (existingDestination == null) {
destination.isRecent |=
this.appState_.recentDestinations.some(function(recent) {
@@ -1064,7 +1086,7 @@ cr.define('print_preview', function() {
this.destinationMap_ = {};
this.selectDestination(null);
this.loadedCloudOrigins_ = {};
- for (var printerType of Object.values(print_preview.PrinterType)) {
+ for (const printerType of Object.values(print_preview.PrinterType)) {
if (printerType !== print_preview.PrinterType.PDF_PRINTER) {
this.destinationSearchStatus_.set(
printerType,
@@ -1107,9 +1129,9 @@ cr.define('print_preview', function() {
* @private
*/
onCapabilitiesSet_(origin, id, settingsInfo) {
- var dest = null;
+ let dest = null;
if (origin !== print_preview.DestinationOrigin.PRIVET) {
- var key = this.getDestinationKey_(origin, id, '');
+ const key = this.getDestinationKey_(origin, id, '');
dest = this.destinationMap_[key];
}
if (!dest) {
@@ -1122,7 +1144,15 @@ cr.define('print_preview', function() {
print_preview.originToType(origin), assert(settingsInfo.printer));
}
if (dest) {
- var updateDestination = destination => {
+ if ((origin === print_preview.DestinationOrigin.LOCAL ||
+ origin === print_preview.DestinationOrigin.CROS) &&
+ dest.capabilities) {
+ // If capabilities are already set for this destination ignore new
+ // results. This prevents custom margins from being cleared as long
+ // as the user does not change to a new non-recent destination.
+ return;
+ }
+ const updateDestination = destination => {
destination.capabilities = settingsInfo.capabilities;
this.updateDestination_(destination);
};
@@ -1148,7 +1178,7 @@ cr.define('print_preview', function() {
'Failed to get print capabilities for printer ' + destinationId);
if (this.selectedDestination_ &&
this.selectedDestination_.id == destinationId) {
- var event =
+ const event =
new Event(DestinationStore.EventType.SELECTED_DESTINATION_INVALID);
event.destinationId = destinationId;
this.dispatchEvent(event);
@@ -1171,7 +1201,7 @@ cr.define('print_preview', function() {
this.insertDestinations_(event.printers);
}
if (event.searchDone) {
- var origins = this.loadedCloudOrigins_[event.user] || [];
+ const origins = this.loadedCloudOrigins_[event.user] || [];
if (origins.indexOf(event.origin) < 0) {
this.loadedCloudOrigins_[event.user] = origins.concat([event.origin]);
}
@@ -1234,7 +1264,7 @@ cr.define('print_preview', function() {
*/
onPrintersAdded_(type, printers) {
if (type == print_preview.PrinterType.PRIVET_PRINTER) {
- var printer =
+ const printer =
/** !print_preview.PrivetPrinterDescription */ (printers[0]);
if (printer.serviceName == this.waitForRegisterDestination_ &&
!printer.isUnregistered) {
diff --git a/chromium/chrome/browser/resources/print_preview/data/document_info.html b/chromium/chrome/browser/resources/print_preview/data/document_info.html
new file mode 100644
index 00000000000..d814e19a661
--- /dev/null
+++ b/chromium/chrome/browser/resources/print_preview/data/document_info.html
@@ -0,0 +1,7 @@
+<link rel="import" href="chrome://resources/html/cr.html">
+<link rel="import" href="chrome://resources/html/cr/event_target.html">
+<link rel="import" href="size.html">
+<link rel="import" href="coordinate2d.html">
+<link rel="import" href="printable_area.html">
+
+<script src="document_info.js"></script>
diff --git a/chromium/chrome/browser/resources/print_preview/data/document_info.js b/chromium/chrome/browser/resources/print_preview/data/document_info.js
index 2e286f35ead..8881596f6f3 100644
--- a/chromium/chrome/browser/resources/print_preview/data/document_info.js
+++ b/chromium/chrome/browser/resources/print_preview/data/document_info.js
@@ -5,110 +5,93 @@
cr.define('print_preview', function() {
'use strict';
- /**
- * Data model which contains information related to the document to print.
- * @constructor
- * @extends {cr.EventTarget}
- */
- function DocumentInfo() {
- cr.EventTarget.call(this);
-
- /**
- * Whether the document is styled by CSS media styles.
- * @type {boolean}
- * @private
- */
- this.hasCssMediaStyles_ = false;
-
- /**
- * Whether the document has selected content.
- * @type {boolean}
- * @private
- */
- this.hasSelection_ = false;
-
- /**
- * Whether the document to print is modifiable (i.e. can be reflowed).
- * @type {boolean}
- * @private
- */
- this.isModifiable_ = true;
-
- /**
- * Whether scaling of the document is prohibited.
- * @type {boolean}
- * @private
- */
- this.isScalingDisabled_ = false;
-
- /**
- * Margins of the document in points.
- * @type {print_preview.Margins}
- * @private
- */
- this.margins_ = null;
-
- /**
- * Number of pages in the document to print.
- * @type {number}
- * @private
- */
- this.pageCount_ = 0;
-
- // Create the document info with some initial settings. Actual
- // page-related information won't be set until preview generation occurs,
- // so we'll use some defaults until then. This way, the print ticket store
- // will be valid even if no preview can be generated.
- var initialPageSize = new print_preview.Size(612, 792); // 8.5"x11"
-
- /**
- * Size of the pages of the document in points.
- * @type {!print_preview.Size}
- * @private
- */
- this.pageSize_ = initialPageSize;
-
- /**
- * Printable area of the document in points.
- * @type {!print_preview.PrintableArea}
- * @private
- */
- this.printableArea_ = new print_preview.PrintableArea(
- new print_preview.Coordinate2d(0, 0), initialPageSize);
-
- /**
- * Title of document.
- * @type {string}
- * @private
- */
- this.title_ = '';
-
- /**
- * Whether this data model has been initialized.
- * @type {boolean}
- * @private
- */
- this.isInitialized_ = false;
- }
-
- /**
- * Event types dispatched by this data model.
- * @enum {string}
- */
- DocumentInfo.EventType = {CHANGE: 'print_preview.DocumentInfo.CHANGE'};
-
- DocumentInfo.prototype = {
- __proto__: cr.EventTarget.prototype,
+ class DocumentInfo extends cr.EventTarget {
+ /**
+ * Data model which contains information related to the document to print.
+ */
+ constructor() {
+ super();
+
+ /**
+ * Whether the document is styled by CSS media styles.
+ * @private {boolean}
+ */
+ this.hasCssMediaStyles_ = false;
+
+ /**
+ * Whether the document has selected content.
+ * @private {boolean}
+ */
+ this.hasSelection_ = false;
+
+ /**
+ * Whether the document to print is modifiable (i.e. can be reflowed).
+ * @private {boolean}
+ */
+ this.isModifiable_ = true;
+
+ /**
+ * Whether scaling of the document is prohibited.
+ * @private {boolean}
+ */
+ this.isScalingDisabled_ = false;
+
+ /**
+ * Scaling required to fit to page.
+ * @private {number}
+ */
+ this.fitToPageScaling_ = 100;
+
+ /**
+ * Margins of the document in points.
+ * @private {print_preview.Margins}
+ */
+ this.margins_ = null;
+
+ /**
+ * Number of pages in the document to print.
+ * @private {number}
+ */
+ this.pageCount_ = 0;
+
+ /**
+ * Size of the pages of the document in points. Actual page-related
+ * information won't be set until preview generation occurs, so use
+ * a default value until then. This way, the print ticket store will be
+ * valid even if no preview can be generated.
+ * @private {!print_preview.Size}
+ */
+ this.pageSize_ = new print_preview.Size(612, 792); // 8.5"x11"
+
+ /**
+ * Printable area of the document in points.
+ * @private {!print_preview.PrintableArea}
+ */
+ this.printableArea_ = new print_preview.PrintableArea(
+ new print_preview.Coordinate2d(0, 0), this.pageSize_);
+
+ /**
+ * Title of document.
+ * @private {string}
+ */
+ this.title_ = '';
+
+ /**
+ * Whether this data model has been initialized.
+ * @private {boolean}
+ */
+ this.isInitialized_ = false;
+ }
/** @return {boolean} Whether the document is styled by CSS media styles. */
get hasCssMediaStyles() {
return this.hasCssMediaStyles_;
- },
+ }
/** @return {boolean} Whether the document has selected content. */
get hasSelection() {
return this.hasSelection_;
- },
+ }
/**
* @return {boolean} Whether the document to print is modifiable (i.e. can
@@ -116,22 +99,27 @@ cr.define('print_preview', function() {
*/
get isModifiable() {
return this.isModifiable_;
- },
+ }
/** @return {boolean} Whether scaling of the document is prohibited. */
get isScalingDisabled() {
return this.isScalingDisabled_;
- },
+ }
+
+ /** @return {number} Scaling required to fit to page. */
+ get fitToPageScaling() {
+ return this.fitToPageScaling_;
+ }
/** @return {print_preview.Margins} Margins of the document in points. */
get margins() {
return this.margins_;
- },
+ }
/** @return {number} Number of pages in the document to print. */
get pageCount() {
return this.pageCount_;
- },
+ }
/**
* @return {!print_preview.Size} Size of the pages of the document in
@@ -139,7 +127,7 @@ cr.define('print_preview', function() {
*/
get pageSize() {
return this.pageSize_;
- },
+ }
/**
* @return {!print_preview.PrintableArea} Printable area of the document in
@@ -147,12 +135,12 @@ cr.define('print_preview', function() {
*/
get printableArea() {
return this.printableArea_;
- },
+ }
/** @return {string} Title of document. */
get title() {
return this.title_;
- },
+ }
/**
* Initializes the state of the data model and dispatches a CHANGE event.
@@ -161,13 +149,13 @@ cr.define('print_preview', function() {
* @param {boolean} hasSelection Whether the document has user-selected
* content.
*/
- init: function(isModifiable, title, hasSelection) {
+ init(isModifiable, title, hasSelection) {
this.isModifiable_ = isModifiable;
this.title_ = title;
this.hasSelection_ = hasSelection;
this.isInitialized_ = true;
cr.dispatchSimpleEvent(this, DocumentInfo.EventType.CHANGE);
- },
+ }
/**
* Updates whether scaling is disabled for the document and dispatches a
@@ -175,24 +163,24 @@ cr.define('print_preview', function() {
* @param {boolean} isScalingDisabled Whether scaling of the document is
* prohibited.
*/
- updateIsScalingDisabled: function(isScalingDisabled) {
+ updateIsScalingDisabled(isScalingDisabled) {
if (this.isInitialized_ && this.isScalingDisabled_ != isScalingDisabled) {
this.isScalingDisabled_ = isScalingDisabled;
cr.dispatchSimpleEvent(this, DocumentInfo.EventType.CHANGE);
}
- },
+ }
/**
* Updates the total number of pages in the document and dispatches a CHANGE
* event.
* @param {number} pageCount Number of pages in the document.
*/
- updatePageCount: function(pageCount) {
+ updatePageCount(pageCount) {
if (this.isInitialized_ && this.pageCount_ != pageCount) {
this.pageCount_ = pageCount;
cr.dispatchSimpleEvent(this, DocumentInfo.EventType.CHANGE);
}
- },
+ }
/**
* Updates information about each page and dispatches a CHANGE event.
@@ -204,8 +192,7 @@ cr.define('print_preview', function() {
* media styles.
* @param {print_preview.Margins} margins Margins of the document in points.
*/
- updatePageInfo: function(
- printableArea, pageSize, hasCssMediaStyles, margins) {
+ updatePageInfo(printableArea, pageSize, hasCssMediaStyles, margins) {
if (this.isInitialized_ &&
(!this.printableArea_.equals(printableArea) ||
!this.pageSize_.equals(pageSize) ||
@@ -218,7 +205,13 @@ cr.define('print_preview', function() {
cr.dispatchSimpleEvent(this, DocumentInfo.EventType.CHANGE);
}
}
- };
+ }
+
+ /**
+ * Event types dispatched by this data model.
+ * @enum {string}
+ */
+ DocumentInfo.EventType = {CHANGE: 'print_preview.DocumentInfo.CHANGE'};
// Export
return {DocumentInfo: DocumentInfo};
diff --git a/chromium/chrome/browser/resources/print_preview/data/invitation_store.js b/chromium/chrome/browser/resources/print_preview/data/invitation_store.js
index 41f654fac14..72ed0849a0d 100644
--- a/chromium/chrome/browser/resources/print_preview/data/invitation_store.js
+++ b/chromium/chrome/browser/resources/print_preview/data/invitation_store.js
@@ -17,66 +17,52 @@ print_preview.InvitationStoreLoadStatus = {
cr.define('print_preview', function() {
'use strict';
- /**
- * Printer sharing invitations data store.
- * @param {!print_preview.UserInfo} userInfo User information repository.
- * @constructor
- * @extends {cr.EventTarget}
- */
- function InvitationStore(userInfo) {
- cr.EventTarget.call(this);
-
+ class InvitationStore extends cr.EventTarget {
/**
- * User information repository.
- * @private {!print_preview.UserInfo}
+ * Printer sharing invitations data store.
+ * @param {!print_preview.UserInfo} userInfo User information repository.
*/
- this.userInfo_ = userInfo;
-
- /**
- * Maps user account to the list of invitations for this account.
- * @private {!Object<!Array<!print_preview.Invitation>>}
- */
- this.invitations_ = {};
-
- /**
- * Maps user account to the flag whether the invitations for this account
- * were successfully loaded.
- * @private {!Object<print_preview.InvitationStoreLoadStatus>}
- */
- this.loadStatus_ = {};
-
- /**
- * Event tracker used to track event listeners of the destination store.
- * @private {!EventTracker}
- */
- this.tracker_ = new EventTracker();
-
- /**
- * Used to fetch and process invitations.
- * @private {cloudprint.CloudPrintInterface}
- */
- this.cloudPrintInterface_ = null;
-
- /**
- * Invitation being processed now. Only one invitation can be processed at
- * a time.
- * @private {print_preview.Invitation}
- */
- this.invitationInProgress_ = null;
- }
-
- /**
- * Event types dispatched by the data store.
- * @enum {string}
- */
- InvitationStore.EventType = {
- INVITATION_PROCESSED: 'print_preview.InvitationStore.INVITATION_PROCESSED',
- INVITATION_SEARCH_DONE:
- 'print_preview.InvitationStore.INVITATION_SEARCH_DONE'
- };
-
- InvitationStore.prototype = {
- __proto__: cr.EventTarget.prototype,
+ constructor(userInfo) {
+ super();
+
+ /**
+ * User information repository.
+ * @private {!print_preview.UserInfo}
+ */
+ this.userInfo_ = userInfo;
+
+ /**
+ * Maps user account to the list of invitations for this account.
+ * @private {!Object<!Array<!print_preview.Invitation>>}
+ */
+ this.invitations_ = {};
+
+ /**
+ * Maps user account to the flag whether the invitations for this account
+ * were successfully loaded.
+ * @private {!Object<print_preview.InvitationStoreLoadStatus>}
+ */
+ this.loadStatus_ = {};
+
+ /**
+ * Event tracker used to track event listeners of the destination store.
+ * @private {!EventTracker}
+ */
+ this.tracker_ = new EventTracker();
+
+ /**
+ * Used to fetch and process invitations.
+ * @private {cloudprint.CloudPrintInterface}
+ */
+ this.cloudPrintInterface_ = null;
+
+ /**
+ * Invitation being processed now. Only one invitation can be processed at
+ * a time.
+ * @private {print_preview.Invitation}
+ */
+ this.invitationInProgress_ = null;
+ }
/**
* @return {print_preview.Invitation} Currently processed invitation or
@@ -84,23 +70,23 @@ cr.define('print_preview', function() {
*/
get invitationInProgress() {
return this.invitationInProgress_;
- },
+ }
/**
* @param {string} account Account to filter invitations by.
* @return {!Array<!print_preview.Invitation>} List of invitations for the
* {@code account}.
*/
- invitations: function(account) {
+ invitations(account) {
return this.invitations_[account] || [];
- },
+ }
/**
* Sets the invitation store's Google Cloud Print interface.
* @param {!cloudprint.CloudPrintInterface} cloudPrintInterface Interface
* to set.
*/
- setCloudPrintInterface: function(cloudPrintInterface) {
+ setCloudPrintInterface(cloudPrintInterface) {
assert(this.cloudPrintInterface_ == null);
this.cloudPrintInterface_ = cloudPrintInterface;
this.tracker_.add(
@@ -119,10 +105,10 @@ cr.define('print_preview', function() {
this.cloudPrintInterface_,
cloudprint.CloudPrintInterfaceEventType.PROCESS_INVITE_FAILED,
this.onCloudPrintProcessInviteFailed_.bind(this));
- },
+ }
/** Initiates loading of cloud printer sharing invitations. */
- startLoadingInvitations: function() {
+ startLoadingInvitations() {
if (!this.cloudPrintInterface_)
return;
if (!this.userInfo_.activeUser)
@@ -139,26 +125,26 @@ cr.define('print_preview', function() {
this.loadStatus_[this.userInfo_.activeUser] =
print_preview.InvitationStoreLoadStatus.IN_PROGRESS;
this.cloudPrintInterface_.invites(this.userInfo_.activeUser);
- },
+ }
/**
* Accepts or rejects the {@code invitation}, based on {@code accept} value.
* @param {!print_preview.Invitation} invitation Invitation to process.
* @param {boolean} accept Whether to accept this invitation.
*/
- processInvitation: function(invitation, accept) {
+ processInvitation(invitation, accept) {
if (this.invitationInProgress_)
return;
this.invitationInProgress_ = invitation;
this.cloudPrintInterface_.processInvite(invitation, accept);
- },
+ }
/**
* Removes processed invitation from the internal storage.
* @param {!print_preview.Invitation} invitation Processed invitation.
* @private
*/
- invitationProcessed_: function(invitation) {
+ invitationProcessed_(invitation) {
if (this.invitations_.hasOwnProperty(invitation.account)) {
this.invitations_[invitation.account] =
this.invitations_[invitation.account].filter(function(i) {
@@ -167,31 +153,31 @@ cr.define('print_preview', function() {
}
if (this.invitationInProgress_ == invitation)
this.invitationInProgress_ = null;
- },
+ }
/**
* Called when printer sharing invitations are fetched.
* @param {Event} event Contains the list of invitations.
* @private
*/
- onCloudPrintInvitesDone_: function(event) {
+ onCloudPrintInvitesDone_(event) {
this.loadStatus_[event.user] =
print_preview.InvitationStoreLoadStatus.DONE;
this.invitations_[event.user] = event.invitations;
cr.dispatchSimpleEvent(
this, InvitationStore.EventType.INVITATION_SEARCH_DONE);
- },
+ }
/**
* Called when printer sharing invitations fetch has failed.
* @param {Event} event Contains the reason of failure.
* @private
*/
- onCloudPrintInvitesFailed_: function(event) {
+ onCloudPrintInvitesFailed_(event) {
this.loadStatus_[event.user] =
print_preview.InvitationStoreLoadStatus.FAILED;
- },
+ }
/**
* Called when printer sharing invitation was processed successfully.
@@ -199,11 +185,11 @@ cr.define('print_preview', function() {
* newly accepted destination.
* @private
*/
- onCloudPrintProcessInviteDone_: function(event) {
+ onCloudPrintProcessInviteDone_(event) {
this.invitationProcessed_(event.invitation);
cr.dispatchSimpleEvent(
this, InvitationStore.EventType.INVITATION_PROCESSED);
- },
+ }
/**
* Called when /printer call completes. Updates the specified destination's
@@ -212,12 +198,22 @@ cr.define('print_preview', function() {
* destination.
* @private
*/
- onCloudPrintProcessInviteFailed_: function(event) {
+ onCloudPrintProcessInviteFailed_(event) {
this.invitationProcessed_(event.invitation);
// TODO: Display an error.
cr.dispatchSimpleEvent(
this, InvitationStore.EventType.INVITATION_PROCESSED);
}
+ }
+
+ /**
+ * Event types dispatched by the data store.
+ * @enum {string}
+ */
+ InvitationStore.EventType = {
+ INVITATION_PROCESSED: 'print_preview.InvitationStore.INVITATION_PROCESSED',
+ INVITATION_SEARCH_DONE:
+ 'print_preview.InvitationStore.INVITATION_SEARCH_DONE'
};
// Export
diff --git a/chromium/chrome/browser/resources/print_preview/data/local_parsers.js b/chromium/chrome/browser/resources/print_preview/data/local_parsers.js
index 9b09d62e06f..e2f1597c963 100644
--- a/chromium/chrome/browser/resources/print_preview/data/local_parsers.js
+++ b/chromium/chrome/browser/resources/print_preview/data/local_parsers.js
@@ -16,7 +16,7 @@ cr.define('print_preview', function() {
* For EXTENSION_PRINTER => print_preview.ProvisionalDestinationInfo
* @return {!Array<!print_preview.Destination> | !print_preview.Destination}
*/
- var parseDestination = function(type, printer) {
+ function parseDestination(type, printer) {
if (type === print_preview.PrinterType.LOCAL_PRINTER) {
return parseLocalDestination(
/** @type {!print_preview.LocalDestinationInfo} */ (printer));
@@ -31,7 +31,7 @@ cr.define('print_preview', function() {
}
assertNotReached('Unknown printer type ' + type);
return [];
- };
+ }
/**
* Parses a local print destination.
@@ -39,8 +39,8 @@ cr.define('print_preview', function() {
* describing a local print destination.
* @return {!print_preview.Destination} Parsed local print destination.
*/
- var parseLocalDestination = function(destinationInfo) {
- var options = {
+ function parseLocalDestination(destinationInfo) {
+ const options = {
description: destinationInfo.printerDescription,
isEnterprisePrinter: destinationInfo.cupsEnterprisePrinter
};
@@ -57,7 +57,7 @@ cr.define('print_preview', function() {
print_preview.DestinationOrigin.LOCAL,
destinationInfo.printerName, false /*isRecent*/,
print_preview.DestinationConnectionStatus.ONLINE, options);
- };
+ }
/**
* Parses a privet destination as one or more local printers.
@@ -66,8 +66,8 @@ cr.define('print_preview', function() {
* @return {!print_preview.Destination |
* !Array<!print_preview.Destination>} Parsed destination info.
*/
- var parsePrivetDestination = function(destinationInfo) {
- var returnedPrinters = [];
+ function parsePrivetDestination(destinationInfo) {
+ const returnedPrinters = [];
if (destinationInfo.hasLocalPrinting) {
returnedPrinters.push(new print_preview.Destination(
@@ -87,7 +87,7 @@ cr.define('print_preview', function() {
return returnedPrinters.length === 1 ? returnedPrinters[0] :
returnedPrinters;
- };
+ }
/**
* Parses an extension destination from an extension supplied printer
@@ -96,8 +96,8 @@ cr.define('print_preview', function() {
* describing an extension printer.
* @return {!print_preview.Destination} Parsed destination.
*/
- var parseExtensionDestination = function(destinationInfo) {
- var provisionalType = destinationInfo.provisional ?
+ function parseExtensionDestination(destinationInfo) {
+ const provisionalType = destinationInfo.provisional ?
print_preview.DestinationProvisionalType.NEEDS_USB_PERMISSION :
print_preview.DestinationProvisionalType.NONE;
@@ -111,7 +111,7 @@ cr.define('print_preview', function() {
extensionName: destinationInfo.extensionName || '',
provisionalType: provisionalType
});
- };
+ }
// Export
return {
diff --git a/chromium/chrome/browser/resources/print_preview/data/margins.js b/chromium/chrome/browser/resources/print_preview/data/margins.js
index b7bef50c686..23088d9770d 100644
--- a/chromium/chrome/browser/resources/print_preview/data/margins.js
+++ b/chromium/chrome/browser/resources/print_preview/data/margins.js
@@ -2,6 +2,18 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+cr.exportPath('print_preview.ticket_items');
+/**
+ * Enumeration of the orientations of margins.
+ * @enum {string}
+ */
+print_preview.ticket_items.CustomMarginsOrientation = {
+ TOP: 'top',
+ RIGHT: 'right',
+ BOTTOM: 'bottom',
+ LEFT: 'left'
+};
+
cr.define('print_preview', function() {
'use strict';
@@ -63,7 +75,7 @@ cr.define('print_preview', function() {
* modification made to the specified margin.
*/
set(orientation, value) {
- var newValue = this.clone_();
+ const newValue = this.clone_();
newValue[orientation] = value;
return new Margins(
newValue[print_preview.ticket_items.CustomMarginsOrientation.TOP],
@@ -81,7 +93,7 @@ cr.define('print_preview', function() {
if (other == null) {
return false;
}
- for (var orientation in this.value_) {
+ for (const orientation in this.value_) {
if (this.value_[orientation] != other.value_[orientation]) {
return false;
}
@@ -99,8 +111,8 @@ cr.define('print_preview', function() {
* @private
*/
clone_() {
- var clone = {};
- for (var o in this.value_) {
+ const clone = {};
+ for (const o in this.value_) {
clone[o] = this.value_[o];
}
return clone;
diff --git a/chromium/chrome/browser/resources/print_preview/data/measurement_system.js b/chromium/chrome/browser/resources/print_preview/data/measurement_system.js
index 1548de6b4e1..eaaa45c6ae2 100644
--- a/chromium/chrome/browser/resources/print_preview/data/measurement_system.js
+++ b/chromium/chrome/browser/resources/print_preview/data/measurement_system.js
@@ -13,73 +13,52 @@ print_preview.MeasurementSystemUnitType = {
IMPERIAL: 1 // inches
};
+/**
+ * @typedef {{precision: number,
+ * decimalPlaces: number,
+ * ptsPerUnit: number,
+ * unitSymbol: string}}
+ */
+print_preview.MeasurementSystemPrefs;
+
cr.define('print_preview', function() {
'use strict';
- /**
- * Measurement system of the print preview. Used to parse and serialize point
- * measurements into the system's local units (e.g. millimeters, inches).
- * @param {string} thousandsDelimeter Delimeter between thousands digits.
- * @param {string} decimalDelimeter Delimeter between integers and decimals.
- * @param {!print_preview.MeasurementSystemUnitType} unitType Measurement
- * unit type of the system.
- * @constructor
- */
- function MeasurementSystem(thousandsDelimeter, decimalDelimeter, unitType) {
- this.thousandsDelimeter_ = thousandsDelimeter || ',';
- this.decimalDelimeter_ = decimalDelimeter || '.';
- this.unitType_ = unitType;
- }
-
- /**
- * Maximum resolution of local unit values.
- * @type {!Object<!print_preview.MeasurementSystemUnitType, number>}
- * @private
- */
- MeasurementSystem.Precision_ = {};
- MeasurementSystem.Precision_[print_preview.MeasurementSystemUnitType.METRIC] =
- 0.5;
- MeasurementSystem
- .Precision_[print_preview.MeasurementSystemUnitType.IMPERIAL] = 0.01;
-
- /**
- * Maximum number of decimal places to keep for local unit.
- * @type {!Object<!print_preview.MeasurementSystemUnitType, number>}
- * @private
- */
- MeasurementSystem.DecimalPlaces_ = {};
- MeasurementSystem
- .DecimalPlaces_[print_preview.MeasurementSystemUnitType.METRIC] = 1;
- MeasurementSystem
- .DecimalPlaces_[print_preview.MeasurementSystemUnitType.IMPERIAL] = 2;
-
- /**
- * Number of points per inch.
- * @type {number}
- * @const
- * @private
- */
- MeasurementSystem.PTS_PER_INCH_ = 72.0;
-
- /**
- * Number of points per millimeter.
- * @type {number}
- * @const
- * @private
- */
- MeasurementSystem.PTS_PER_MM_ = MeasurementSystem.PTS_PER_INCH_ / 25.4;
+ class MeasurementSystem {
+ /**
+ * Measurement system of the print preview. Used to parse and serialize
+ * point measurements into the system's local units (e.g. millimeters,
+ * inches).
+ * @param {string} thousandsDelimeter Delimeter between thousands digits.
+ * @param {string} decimalDelimeter Delimeter between integers and decimals.
+ * @param {!print_preview.MeasurementSystemUnitType} unitType Measurement
+ * unit type of the system.
+ */
+ constructor(thousandsDelimeter, decimalDelimeter, unitType) {
+ /**
+ * The thousands delimeter to use when displaying numbers.
+ * @private {string}
+ */
+ this.thousandsDelimeter_ = thousandsDelimeter || ',';
+
+ /**
+ * The decimal delimeter to use when displaying numbers.
+ * @private {string}
+ */
+ this.decimalDelimeter_ = decimalDelimeter || '.';
+
+ assert(measurementSystemPrefs.has(unitType));
+ /**
+ * The measurement system preferences based on the unit type.
+ * @private {!print_preview.MeasurementSystemPrefs}
+ */
+ this.measurementSystemPrefs_ = measurementSystemPrefs.get(unitType);
+ }
- MeasurementSystem.prototype = {
/** @return {string} The unit type symbol of the measurement system. */
get unitSymbol() {
- if (this.unitType_ == print_preview.MeasurementSystemUnitType.METRIC) {
- return 'mm';
- }
- if (this.unitType_ == print_preview.MeasurementSystemUnitType.IMPERIAL) {
- return '"';
- }
- throw Error('Unit type not supported: ' + this.unitType_);
- },
+ return this.measurementSystemPrefs_.unitSymbol;
+ }
/**
* @return {string} The thousands delimeter character of the measurement
@@ -87,7 +66,7 @@ cr.define('print_preview', function() {
*/
get thousandsDelimeter() {
return this.thousandsDelimeter_;
- },
+ }
/**
* @return {string} The decimal delimeter character of the measurement
@@ -95,49 +74,70 @@ cr.define('print_preview', function() {
*/
get decimalDelimeter() {
return this.decimalDelimeter_;
- },
+ }
- setSystem: function(thousandsDelimeter, decimalDelimeter, unitType) {
+ /**
+ * Sets the measurement system based on the delimeters and unit type.
+ * @param {string} thousandsDelimeter The thousands delimeter to use
+ * @param {string} decimalDelimeter The decimal delimeter to use
+ * @param {!print_preview.MeasurementSystemUnitType} unitType Measurement
+ * unit type of the system.
+ */
+ setSystem(thousandsDelimeter, decimalDelimeter, unitType) {
this.thousandsDelimeter_ = thousandsDelimeter;
this.decimalDelimeter_ = decimalDelimeter;
- this.unitType_ = unitType;
- },
+ assert(measurementSystemPrefs.has(unitType));
+ this.measurementSystemPrefs_ = measurementSystemPrefs.get(unitType);
+ }
/**
* Rounds a value in the local system's units to the appropriate precision.
* @param {number} value Value to round.
* @return {number} Rounded value.
*/
- roundValue: function(value) {
- var precision = MeasurementSystem.Precision_[this.unitType_];
- var roundedValue = Math.round(value / precision) * precision;
+ roundValue(value) {
+ const precision = this.measurementSystemPrefs_.precision;
+ const roundedValue = Math.round(value / precision) * precision;
// Truncate
- return +roundedValue.toFixed(
- MeasurementSystem.DecimalPlaces_[this.unitType_]);
- },
+ return +roundedValue.toFixed(this.measurementSystemPrefs_.decimalPlaces);
+ }
/**
* @param {number} pts Value in points to convert to local units.
* @return {number} Value in local units.
*/
- convertFromPoints: function(pts) {
- if (this.unitType_ == print_preview.MeasurementSystemUnitType.METRIC) {
- return pts / MeasurementSystem.PTS_PER_MM_;
- }
- return pts / MeasurementSystem.PTS_PER_INCH_;
- },
+ convertFromPoints(pts) {
+ return pts / this.measurementSystemPrefs_.ptsPerUnit;
+ }
/**
* @param {number} localUnits Value in local units to convert to points.
* @return {number} Value in points.
*/
- convertToPoints: function(localUnits) {
- if (this.unitType_ == print_preview.MeasurementSystemUnitType.METRIC) {
- return localUnits * MeasurementSystem.PTS_PER_MM_;
- }
- return localUnits * MeasurementSystem.PTS_PER_INCH_;
+ convertToPoints(localUnits) {
+ return localUnits * this.measurementSystemPrefs_.ptsPerUnit;
}
- };
+ }
+
+ /**
+ * Maximum resolution and number of decimal places for local unit values.
+ * @private {!Map<!print_preview.MeasurementSystemUnitType,
+ * !print_preview.MeasurementSystemPrefs>}
+ */
+ const measurementSystemPrefs = new Map([
+ [
+ print_preview.MeasurementSystemUnitType.METRIC, {
+ precision: 0.5,
+ decimalPlaces: 1,
+ ptsPerUnit: 72.0 / 25.4,
+ unitSymbol: 'mm'
+ }
+ ],
+ [
+ print_preview.MeasurementSystemUnitType.IMPERIAL,
+ {precision: 0.01, decimalPlaces: 2, ptsPerUnit: 72.0, unitSymbol: '"'}
+ ]
+ ]);
// Export
return {MeasurementSystem: MeasurementSystem};
diff --git a/chromium/chrome/browser/resources/print_preview/data/print_ticket_store.js b/chromium/chrome/browser/resources/print_preview/data/print_ticket_store.js
index 6675843b53e..9a643f1263a 100644
--- a/chromium/chrome/browser/resources/print_preview/data/print_ticket_store.js
+++ b/chromium/chrome/browser/resources/print_preview/data/print_ticket_store.js
@@ -47,6 +47,12 @@ cr.define('print_preview', function() {
this.documentInfo_ = documentInfo;
/**
+ * The destination that capabilities were last received for.
+ * @private {?print_preview.Destination}
+ */
+ this.destination_ = null;
+
+ /**
* Printing capabilities of Chromium and the currently selected
* destination.
* @type {!print_preview.CapabilitiesHolder}
@@ -421,12 +427,12 @@ cr.define('print_preview', function() {
destination.capabilities,
'Trying to create a Google Cloud Print print ticket for a ' +
'destination with no print capabilities');
- var cjt = {version: '1.0', print: {}};
+ const cjt = {version: '1.0', print: {}};
if (this.collate.isCapabilityAvailable() && this.collate.isUserEdited()) {
cjt.print.collate = {collate: this.collate.getValue()};
}
if (this.color.isCapabilityAvailable() && this.color.isUserEdited()) {
- var selectedOption = this.color.getSelectedOption();
+ const selectedOption = this.color.getSelectedOption();
if (!selectedOption) {
console.error('Could not find correct color option');
} else {
@@ -445,12 +451,12 @@ cr.define('print_preview', function() {
};
}
if (this.mediaSize.isCapabilityAvailable()) {
- var value = this.mediaSize.getValue();
+ const mediaValue = this.mediaSize.getValue();
cjt.print.media_size = {
- width_microns: value.width_microns,
- height_microns: value.height_microns,
- is_continuous_feed: value.is_continuous_feed,
- vendor_id: value.vendor_id
+ width_microns: mediaValue.width_microns,
+ height_microns: mediaValue.height_microns,
+ is_continuous_feed: mediaValue.is_continuous_feed,
+ vendor_id: mediaValue.vendor_id
};
}
if (!this.landscape.isCapabilityAvailable()) {
@@ -465,18 +471,18 @@ cr.define('print_preview', function() {
};
}
if (this.dpi.isCapabilityAvailable()) {
- var value = this.dpi.getValue();
+ const dpiValue = this.dpi.getValue();
cjt.print.dpi = {
- horizontal_dpi: value.horizontal_dpi,
- vertical_dpi: value.vertical_dpi,
- vendor_id: value.vendor_id
+ horizontal_dpi: dpiValue.horizontal_dpi,
+ vertical_dpi: dpiValue.vertical_dpi,
+ vendor_id: dpiValue.vendor_id
};
}
if (this.vendorItems.isCapabilityAvailable() &&
this.vendorItems.isUserEdited()) {
- var items = this.vendorItems.ticketItems;
+ const items = this.vendorItems.ticketItems;
cjt.print.vendor_ticket_item = [];
- for (var itemId in items) {
+ for (const itemId in items) {
if (items.hasOwnProperty(itemId)) {
cjt.print.vendor_ticket_item.push(
{id: itemId, value: items[itemId]});
@@ -517,7 +523,11 @@ cr.define('print_preview', function() {
* @private
*/
onSelectedDestinationCapabilitiesReady_() {
- if (this.capabilitiesHolder_.get() != null) {
+ const selectedDestination = this.destinationStore_.selectedDestination;
+ const isFirstUpdate = this.capabilitiesHolder_.get() == null;
+ // Only clear the ticket items if the user selected a new destination
+ // and this is not the first update.
+ if (!isFirstUpdate && this.destination_ != selectedDestination) {
this.customMargins_.updateValue(null);
if (this.marginsType_.getValue() ==
print_preview.ticket_items.MarginsTypeValue.CUSTOM) {
@@ -526,10 +536,9 @@ cr.define('print_preview', function() {
}
this.vendorItems_.updateValue({});
}
- var caps =
- assert(this.destinationStore_.selectedDestination.capabilities);
- var isFirstUpdate = this.capabilitiesHolder_.get() == null;
+ const caps = assert(selectedDestination.capabilities);
this.capabilitiesHolder_.set(caps);
+ this.destination_ = selectedDestination;
if (isFirstUpdate) {
this.isInitialized_ = true;
cr.dispatchSimpleEvent(this, PrintTicketStore.EventType.INITIALIZE);
diff --git a/chromium/chrome/browser/resources/print_preview/data/printable_area.html b/chromium/chrome/browser/resources/print_preview/data/printable_area.html
new file mode 100644
index 00000000000..d6801fda881
--- /dev/null
+++ b/chromium/chrome/browser/resources/print_preview/data/printable_area.html
@@ -0,0 +1,5 @@
+<link rel="import" href="chrome://resources/html/cr.html">
+<link rel="import" href="size.html">
+<link rel="import" href="coordinate2d.html">
+
+<script src="printable_area.js"></script>
diff --git a/chromium/chrome/browser/resources/print_preview/data/size.html b/chromium/chrome/browser/resources/print_preview/data/size.html
new file mode 100644
index 00000000000..8eeefa075d2
--- /dev/null
+++ b/chromium/chrome/browser/resources/print_preview/data/size.html
@@ -0,0 +1,3 @@
+<link rel="import" href="chrome://resources/html/cr.html">
+
+<script src="size.js"></script>
diff --git a/chromium/chrome/browser/resources/print_preview/data/ticket_items/collate.js b/chromium/chrome/browser/resources/print_preview/data/ticket_items/collate.js
index 227cf03cf2d..9deaf2a895d 100644
--- a/chromium/chrome/browser/resources/print_preview/data/ticket_items/collate.js
+++ b/chromium/chrome/browser/resources/print_preview/data/ticket_items/collate.js
@@ -32,7 +32,7 @@ cr.define('print_preview.ticket_items', function() {
/** @override */
getDefaultValueInternal() {
- var capability = this.getCollateCapability_();
+ const capability = this.getCollateCapability_();
return capability.hasOwnProperty('default') ? capability.default : true;
}
@@ -46,7 +46,7 @@ cr.define('print_preview.ticket_items', function() {
* @private
*/
getCollateCapability_() {
- var dest = this.getSelectedDestInternal();
+ const dest = this.getSelectedDestInternal();
return (dest && dest.capabilities && dest.capabilities.printer &&
dest.capabilities.printer.collate) ||
null;
diff --git a/chromium/chrome/browser/resources/print_preview/data/ticket_items/color.js b/chromium/chrome/browser/resources/print_preview/data/ticket_items/color.js
index a78d6ccc9e1..2df29ad3ba2 100644
--- a/chromium/chrome/browser/resources/print_preview/data/ticket_items/color.js
+++ b/chromium/chrome/browser/resources/print_preview/data/ticket_items/color.js
@@ -27,12 +27,12 @@ cr.define('print_preview.ticket_items', function() {
/** @override */
isCapabilityAvailable() {
- var capability = this.capability;
+ const capability = this.capability;
if (!capability) {
return false;
}
- var hasColor = false;
- var hasMonochrome = false;
+ let hasColor = false;
+ let hasMonochrome = false;
capability.option.forEach(function(option) {
hasColor = hasColor || (Color.COLOR_TYPES_.indexOf(option.type) >= 0);
hasMonochrome = hasMonochrome ||
@@ -43,7 +43,7 @@ cr.define('print_preview.ticket_items', function() {
/** @return {Object} Color capability of the selected destination. */
get capability() {
- var dest = this.getSelectedDestInternal();
+ const dest = this.getSelectedDestInternal();
return (dest && dest.capabilities && dest.capabilities.printer &&
dest.capabilities.printer.color) ||
null;
@@ -51,13 +51,13 @@ cr.define('print_preview.ticket_items', function() {
/** @return {Object} Color option corresponding to the current value. */
getSelectedOption() {
- var capability = this.capability;
- var options = capability ? capability.option : null;
+ const capability = this.capability;
+ const options = capability ? capability.option : null;
if (options) {
- var typesToLookFor =
+ const typesToLookFor =
this.getValue() ? Color.COLOR_TYPES_ : Color.MONOCHROME_TYPES_;
- for (var i = 0; i < typesToLookFor.length; i++) {
- var matchingOptions = options.filter(function(option) {
+ for (let i = 0; i < typesToLookFor.length; i++) {
+ const matchingOptions = options.filter(function(option) {
return option.type == typesToLookFor[i];
});
if (matchingOptions.length > 0) {
@@ -70,8 +70,8 @@ cr.define('print_preview.ticket_items', function() {
/** @override */
getDefaultValueInternal() {
- var capability = this.capability;
- var defaultOption =
+ const capability = this.capability;
+ const defaultOption =
capability ? this.getDefaultColorOption_(capability.option) : null;
return defaultOption &&
(Color.COLOR_TYPES_.indexOf(defaultOption.type) >= 0);
@@ -82,7 +82,7 @@ cr.define('print_preview.ticket_items', function() {
// TODO(rltoscano): Get rid of this check based on destination ID. These
// destinations should really update their CDDs to have only one color
// option that has type 'STANDARD_COLOR'.
- var dest = this.getSelectedDestInternal();
+ const dest = this.getSelectedDestInternal();
if (dest) {
if (dest.id == print_preview.Destination.GooglePromotedId.DOCS ||
dest.type == print_preview.DestinationType.MOBILE) {
@@ -101,7 +101,7 @@ cr.define('print_preview.ticket_items', function() {
* @private
*/
getDefaultColorOption_(options) {
- var defaultOptions = options.filter(function(option) {
+ const defaultOptions = options.filter(function(option) {
return option.is_default;
});
return (defaultOptions.length == 0) ? null : defaultOptions[0];
diff --git a/chromium/chrome/browser/resources/print_preview/data/ticket_items/copies.js b/chromium/chrome/browser/resources/print_preview/data/ticket_items/copies.js
index 84f20a7cb2f..560e54b2d52 100644
--- a/chromium/chrome/browser/resources/print_preview/data/ticket_items/copies.js
+++ b/chromium/chrome/browser/resources/print_preview/data/ticket_items/copies.js
@@ -29,13 +29,13 @@ cr.define('print_preview.ticket_items', function() {
/** @return {number} The number of copies indicated by the ticket item. */
getValueAsNumber() {
- var value = this.getValue();
+ const value = this.getValue();
return value == '' ? 0 : parseInt(value, 10);
}
/** @override */
getDefaultValueInternal() {
- var cap = this.getCopiesCapability_();
+ const cap = this.getCopiesCapability_();
return cap.hasOwnProperty('default') ? cap.default : '1';
}
@@ -49,7 +49,7 @@ cr.define('print_preview.ticket_items', function() {
* @private
*/
getCopiesCapability_() {
- var dest = this.getSelectedDestInternal();
+ const dest = this.getSelectedDestInternal();
return (dest && dest.capabilities && dest.capabilities.printer &&
dest.capabilities.printer.copies) ||
null;
diff --git a/chromium/chrome/browser/resources/print_preview/data/ticket_items/custom_margins.js b/chromium/chrome/browser/resources/print_preview/data/ticket_items/custom_margins.js
index a29bc892378..4b2579bd2a8 100644
--- a/chromium/chrome/browser/resources/print_preview/data/ticket_items/custom_margins.js
+++ b/chromium/chrome/browser/resources/print_preview/data/ticket_items/custom_margins.js
@@ -2,23 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-cr.exportPath('print_preview.ticket_items');
-
-/**
- * Enumeration of the orientations of margins.
- * @enum {string}
- */
-print_preview.ticket_items.CustomMarginsOrientation = {
- TOP: 'top',
- RIGHT: 'right',
- BOTTOM: 'bottom',
- LEFT: 'left'
-};
-
cr.define('print_preview.ticket_items', function() {
'use strict';
- var CustomMarginsOrientation =
+ const CustomMarginsOrientation =
print_preview.ticket_items.CustomMarginsOrientation;
class CustomMargins extends print_preview.ticket_items.TicketItem {
@@ -38,10 +25,10 @@ cr.define('print_preview.ticket_items', function() {
/** @override */
wouldValueBeValid(value) {
- var margins = /** @type {!print_preview.Margins} */ (value);
- for (var key in CustomMarginsOrientation) {
- var o = CustomMarginsOrientation[key];
- var max = this.getMarginMax_(
+ const margins = /** @type {!print_preview.Margins} */ (value);
+ for (const key in CustomMarginsOrientation) {
+ const o = CustomMarginsOrientation[key];
+ const max = this.getMarginMax_(
o, margins.get(CustomMargins.OppositeOrientation_[o]));
if (margins.get(o) > max || margins.get(o) < 0) {
return false;
@@ -66,14 +53,14 @@ cr.define('print_preview.ticket_items', function() {
* @return {number} Maximum value in points of the specified margin.
*/
getMarginMax(orientation) {
- var oppositeOrient = CustomMargins.OppositeOrientation_[orientation];
- var margins = /** @type {!print_preview.Margins} */ (this.getValue());
+ const oppositeOrient = CustomMargins.OppositeOrientation_[orientation];
+ const margins = /** @type {!print_preview.Margins} */ (this.getValue());
return this.getMarginMax_(orientation, margins.get(oppositeOrient));
}
/** @override */
updateValue(value) {
- var margins = /** @type {!print_preview.Margins} */ (value);
+ let margins = /** @type {!print_preview.Margins} */ (value);
if (margins != null) {
margins = new print_preview.Margins(
Math.round(margins.get(CustomMarginsOrientation.TOP)),
@@ -93,9 +80,10 @@ cr.define('print_preview.ticket_items', function() {
* @param {number} value Updated margin value in points.
*/
updateMargin(orientation, value) {
- var margins = /** @type {!print_preview.Margins} */ (this.getValue());
- var oppositeOrientation = CustomMargins.OppositeOrientation_[orientation];
- var max =
+ const margins = /** @type {!print_preview.Margins} */ (this.getValue());
+ const oppositeOrientation =
+ CustomMargins.OppositeOrientation_[orientation];
+ const max =
this.getMarginMax_(orientation, margins.get(oppositeOrientation));
value = Math.max(0, Math.min(max, value));
this.updateValue(margins.set(orientation, value));
@@ -122,12 +110,12 @@ cr.define('print_preview.ticket_items', function() {
* @private
*/
getMarginMax_(orientation, oppositeMargin) {
- var dimensionLength = (orientation == CustomMarginsOrientation.TOP ||
- orientation == CustomMarginsOrientation.BOTTOM) ?
+ const dimensionLength = (orientation == CustomMarginsOrientation.TOP ||
+ orientation == CustomMarginsOrientation.BOTTOM) ?
this.getDocumentInfoInternal().pageSize.height :
this.getDocumentInfoInternal().pageSize.width;
- var totalMargin =
+ const totalMargin =
dimensionLength - CustomMargins.MINIMUM_MARGINS_DISTANCE_;
return Math.round(totalMargin > 0 ? totalMargin - oppositeMargin : 0);
}
diff --git a/chromium/chrome/browser/resources/print_preview/data/ticket_items/dpi.js b/chromium/chrome/browser/resources/print_preview/data/ticket_items/dpi.js
index 218c7cc9b8f..60c401ac920 100644
--- a/chromium/chrome/browser/resources/print_preview/data/ticket_items/dpi.js
+++ b/chromium/chrome/browser/resources/print_preview/data/ticket_items/dpi.js
@@ -36,7 +36,7 @@ cr.define('print_preview.ticket_items', function() {
/** @override */
isValueEqual(value) {
- var myValue = this.getValue();
+ const myValue = this.getValue();
return myValue.horizontal_dpi == value.horizontal_dpi &&
myValue.vertical_dpi == value.vertical_dpi &&
myValue.vendor_id == value.vendor_id;
@@ -44,7 +44,7 @@ cr.define('print_preview.ticket_items', function() {
/** @return {Object} DPI capability of the selected destination. */
get capability() {
- var destination = this.getSelectedDestInternal();
+ const destination = this.getSelectedDestInternal();
return (destination && destination.capabilities &&
destination.capabilities.printer &&
destination.capabilities.printer.dpi) ||
@@ -53,7 +53,7 @@ cr.define('print_preview.ticket_items', function() {
/** @override */
getDefaultValueInternal() {
- var defaultOptions = this.capability.option.filter(function(option) {
+ const defaultOptions = this.capability.option.filter(function(option) {
return option.is_default;
});
return defaultOptions.length > 0 ? defaultOptions[0] : null;
diff --git a/chromium/chrome/browser/resources/print_preview/data/ticket_items/duplex.js b/chromium/chrome/browser/resources/print_preview/data/ticket_items/duplex.js
index 6d061d70360..e7c63426a2b 100644
--- a/chromium/chrome/browser/resources/print_preview/data/ticket_items/duplex.js
+++ b/chromium/chrome/browser/resources/print_preview/data/ticket_items/duplex.js
@@ -27,12 +27,12 @@ cr.define('print_preview.ticket_items', function() {
/** @override */
isCapabilityAvailable() {
- var cap = this.getDuplexCapability_();
+ const cap = this.getDuplexCapability_();
if (!cap) {
return false;
}
- var hasLongEdgeOption = false;
- var hasSimplexOption = false;
+ let hasLongEdgeOption = false;
+ let hasSimplexOption = false;
cap.option.forEach(function(option) {
hasLongEdgeOption = hasLongEdgeOption || option.type == 'LONG_EDGE';
hasSimplexOption = hasSimplexOption || option.type == 'NO_DUPLEX';
@@ -42,8 +42,8 @@ cr.define('print_preview.ticket_items', function() {
/** @override */
getDefaultValueInternal() {
- var cap = this.getDuplexCapability_();
- var defaultOptions = cap.option.filter(function(option) {
+ const cap = this.getDuplexCapability_();
+ const defaultOptions = cap.option.filter(function(option) {
return option.is_default;
});
return defaultOptions.length == 0 ? false :
@@ -60,7 +60,7 @@ cr.define('print_preview.ticket_items', function() {
* @private
*/
getDuplexCapability_() {
- var dest = this.getSelectedDestInternal();
+ const dest = this.getSelectedDestInternal();
return (dest && dest.capabilities && dest.capabilities.printer &&
dest.capabilities.printer.duplex) ||
null;
diff --git a/chromium/chrome/browser/resources/print_preview/data/ticket_items/header_footer.js b/chromium/chrome/browser/resources/print_preview/data/ticket_items/header_footer.js
index f69389f27c9..77d29c8e755 100644
--- a/chromium/chrome/browser/resources/print_preview/data/ticket_items/header_footer.js
+++ b/chromium/chrome/browser/resources/print_preview/data/ticket_items/header_footer.js
@@ -70,7 +70,7 @@ cr.define('print_preview.ticket_items', function() {
print_preview.ticket_items.MarginsTypeValue.NO_MARGINS) {
return false;
}
- var microns = this.landscape_.getValue() ?
+ const microns = this.landscape_.getValue() ?
this.mediaSize_.getValue().width_microns :
this.mediaSize_.getValue().height_microns;
if (microns < HeaderFooter.MINIMUM_HEIGHT_MICRONS_) {
@@ -82,7 +82,7 @@ cr.define('print_preview.ticket_items', function() {
print_preview.ticket_items.MarginsTypeValue.MINIMUM) {
return true;
}
- var margins;
+ let margins;
if (this.marginsType_.getValue() ==
print_preview.ticket_items.MarginsTypeValue.CUSTOM) {
if (!this.customMargins_.isValid()) {
@@ -92,7 +92,7 @@ cr.define('print_preview.ticket_items', function() {
} else {
margins = this.getDocumentInfoInternal().margins;
}
- var orientEnum = print_preview.ticket_items.CustomMarginsOrientation;
+ const orientEnum = print_preview.ticket_items.CustomMarginsOrientation;
return margins == null || margins.get(orientEnum.TOP) > 0 ||
margins.get(orientEnum.BOTTOM) > 0;
}
diff --git a/chromium/chrome/browser/resources/print_preview/data/ticket_items/landscape.js b/chromium/chrome/browser/resources/print_preview/data/ticket_items/landscape.js
index 5c8ef4f6438..8fe4850203c 100644
--- a/chromium/chrome/browser/resources/print_preview/data/ticket_items/landscape.js
+++ b/chromium/chrome/browser/resources/print_preview/data/ticket_items/landscape.js
@@ -49,11 +49,11 @@ cr.define('print_preview.ticket_items', function() {
/** @override */
isCapabilityAvailable() {
- var cap = this.getPageOrientationCapability_();
+ const cap = this.getPageOrientationCapability_();
if (!cap)
return false;
- var hasAutoOrPortraitOption = false;
- var hasLandscapeOption = false;
+ let hasAutoOrPortraitOption = false;
+ let hasLandscapeOption = false;
cap.option.forEach(function(option) {
hasAutoOrPortraitOption = hasAutoOrPortraitOption ||
option.type == 'AUTO' || option.type == 'PORTRAIT';
@@ -70,8 +70,8 @@ cr.define('print_preview.ticket_items', function() {
/** @override */
getDefaultValueInternal() {
- var cap = this.getPageOrientationCapability_();
- var defaultOptions = cap.option.filter(function(option) {
+ const cap = this.getPageOrientationCapability_();
+ const defaultOptions = cap.option.filter(function(option) {
return option.is_default;
});
return defaultOptions.length == 0 ? false :
@@ -80,7 +80,7 @@ cr.define('print_preview.ticket_items', function() {
/** @override */
getCapabilityNotAvailableValueInternal() {
- var doc = this.getDocumentInfoInternal();
+ const doc = this.getDocumentInfoInternal();
return doc.hasCssMediaStyles ?
(doc.pageSize.width > doc.pageSize.height) :
false;
@@ -88,7 +88,7 @@ cr.define('print_preview.ticket_items', function() {
/** @override */
updateValueInternal(value) {
- var updateMargins = !this.isValueEqual(value);
+ const updateMargins = !this.isValueEqual(value);
print_preview.ticket_items.TicketItem.prototype.updateValueInternal.call(
this, value);
if (updateMargins) {
@@ -104,7 +104,7 @@ cr.define('print_preview.ticket_items', function() {
* @param {string} value Option to check.
*/
hasOption(value) {
- var cap = this.getPageOrientationCapability_();
+ const cap = this.getPageOrientationCapability_();
if (!cap)
return false;
return cap.option.some(function(option) {
@@ -117,7 +117,7 @@ cr.define('print_preview.ticket_items', function() {
* @private
*/
getPageOrientationCapability_() {
- var dest = this.getSelectedDestInternal();
+ const dest = this.getSelectedDestInternal();
return (dest && dest.capabilities && dest.capabilities.printer &&
dest.capabilities.printer.page_orientation) ||
null;
diff --git a/chromium/chrome/browser/resources/print_preview/data/ticket_items/media_size.js b/chromium/chrome/browser/resources/print_preview/data/ticket_items/media_size.js
index 8f49b7eaaba..6302e0b418d 100644
--- a/chromium/chrome/browser/resources/print_preview/data/ticket_items/media_size.js
+++ b/chromium/chrome/browser/resources/print_preview/data/ticket_items/media_size.js
@@ -54,7 +54,7 @@ cr.define('print_preview.ticket_items', function() {
/** @override */
isCapabilityAvailable() {
- var knownSizeToSaveAsPdf =
+ const knownSizeToSaveAsPdf =
(!this.getDocumentInfoInternal().isModifiable ||
this.getDocumentInfoInternal().hasCssMediaStyles) &&
this.getSelectedDestInternal() &&
@@ -65,7 +65,7 @@ cr.define('print_preview.ticket_items', function() {
/** @override */
isValueEqual(value) {
- var myValue = this.getValue();
+ const myValue = this.getValue();
return myValue.width_microns == value.width_microns &&
myValue.height_microns == value.height_microns &&
myValue.is_continuous_feed == value.is_continuous_feed &&
@@ -74,7 +74,7 @@ cr.define('print_preview.ticket_items', function() {
/** @return {Object} Media size capability of the selected destination. */
get capability() {
- var destination = this.getSelectedDestInternal();
+ const destination = this.getSelectedDestInternal();
return (destination && destination.capabilities &&
destination.capabilities.printer &&
destination.capabilities.printer.media_size) ||
@@ -83,7 +83,7 @@ cr.define('print_preview.ticket_items', function() {
/** @override */
getDefaultValueInternal() {
- var defaultOptions = this.capability.option.filter(function(option) {
+ const defaultOptions = this.capability.option.filter(function(option) {
return option.is_default;
});
return defaultOptions.length > 0 ? defaultOptions[0] : null;
@@ -96,7 +96,7 @@ cr.define('print_preview.ticket_items', function() {
/** @override */
updateValueInternal(value) {
- var updateMargins = !this.isValueEqual(value);
+ const updateMargins = !this.isValueEqual(value);
print_preview.ticket_items.TicketItem.prototype.updateValueInternal.call(
this, value);
if (updateMargins) {
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 23de286cfe4..ab4a9c81c05 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
@@ -20,7 +20,7 @@ cr.define('print_preview.ticket_items', function() {
/** @override */
wouldValueBeValid(value) {
- var result = pageRangeTextToPageRanges(
+ const result = pageRangeTextToPageRanges(
value, this.getDocumentInfoInternal().pageCount);
return Array.isArray(result);
}
@@ -30,7 +30,7 @@ cr.define('print_preview.ticket_items', function() {
* page range string.
*/
getPageNumberSet() {
- var pageNumberList = pageRangeTextToPageList(
+ const pageNumberList = pageRangeTextToPageList(
this.getValueAsString_(), this.getDocumentInfoInternal().pageCount);
return new print_preview.PageNumberSet(pageNumberList);
}
@@ -63,7 +63,7 @@ cr.define('print_preview.ticket_items', function() {
* ranges.
*/
getPageRanges() {
- var pageRanges = pageRangeTextToPageRanges(this.getValueAsString_());
+ const pageRanges = pageRangeTextToPageRanges(this.getValueAsString_());
return Array.isArray(pageRanges) ? pageRanges : [];
}
@@ -74,7 +74,7 @@ cr.define('print_preview.ticket_items', function() {
* page ranges.
*/
getDocumentPageRanges() {
- var pageRanges = pageRangeTextToPageRanges(
+ const pageRanges = pageRangeTextToPageRanges(
this.getValueAsString_(), this.getDocumentInfoInternal().pageCount);
return Array.isArray(pageRanges) ? pageRanges : [];
}
@@ -90,7 +90,7 @@ cr.define('print_preview.ticket_items', function() {
* @return {!PageRangeStatus}
*/
checkValidity() {
- var pageRanges = pageRangeTextToPageRanges(
+ const pageRanges = pageRangeTextToPageRanges(
this.getValueAsString_(), this.getDocumentInfoInternal().pageCount);
return Array.isArray(pageRanges) ? PageRangeStatus.NO_ERROR : pageRanges;
}
diff --git a/chromium/chrome/browser/resources/print_preview/data/ticket_items/scaling.js b/chromium/chrome/browser/resources/print_preview/data/ticket_items/scaling.js
index 6ecc989d0e1..ab890bc9326 100644
--- a/chromium/chrome/browser/resources/print_preview/data/ticket_items/scaling.js
+++ b/chromium/chrome/browser/resources/print_preview/data/ticket_items/scaling.js
@@ -37,7 +37,7 @@ cr.define('print_preview.ticket_items', function() {
isCapabilityAvailable() {
// This is not a function of the printer, but should be disabled if we are
// saving a PDF to a PDF.
- var knownSizeToSaveAsPdf =
+ const knownSizeToSaveAsPdf =
(!this.getDocumentInfoInternal().isModifiable ||
this.getDocumentInfoInternal().hasCssMediaStyles) &&
this.getSelectedDestInternal() &&
@@ -48,7 +48,7 @@ cr.define('print_preview.ticket_items', function() {
/** @return {number} The scaling percentage indicated by the ticket item. */
getValueAsNumber() {
- var value = this.getValue() == '' ? 0 : parseInt(this.getValue(), 10);
+ const value = this.getValue() == '' ? 0 : parseInt(this.getValue(), 10);
assert(!isNaN(value));
return value;
}
diff --git a/chromium/chrome/browser/resources/print_preview/data/ticket_items/ticket_item.js b/chromium/chrome/browser/resources/print_preview/data/ticket_items/ticket_item.js
index 9d543289ea7..c402eab30fb 100644
--- a/chromium/chrome/browser/resources/print_preview/data/ticket_items/ticket_item.js
+++ b/chromium/chrome/browser/resources/print_preview/data/ticket_items/ticket_item.js
@@ -131,7 +131,7 @@ cr.define('print_preview.ticket_items', function() {
*/
updateValue(value) {
// Use comparison with capabilities for event.
- var sendUpdateEvent = !this.isValueEqual(value);
+ const sendUpdateEvent = !this.isValueEqual(value);
// Don't lose requested value if capability is not available.
this.updateValueInternal(value);
if (this.appState_ && (this.field_ != null) &&
diff --git a/chromium/chrome/browser/resources/print_preview/data/ticket_items/vendor_items.js b/chromium/chrome/browser/resources/print_preview/data/ticket_items/vendor_items.js
index 0bdcd9f9e5c..8b3342445c5 100644
--- a/chromium/chrome/browser/resources/print_preview/data/ticket_items/vendor_items.js
+++ b/chromium/chrome/browser/resources/print_preview/data/ticket_items/vendor_items.js
@@ -49,7 +49,7 @@ cr.define('print_preview.ticket_items', function() {
/** @return {boolean} Whether the ticket item was modified by the user. */
isUserEdited() {
// If there's at least one ticket item stored in values, it was edited.
- for (var key in this.items_) {
+ for (const key in this.items_) {
if (this.items_.hasOwnProperty(key))
return true;
}
@@ -58,7 +58,7 @@ cr.define('print_preview.ticket_items', function() {
/** @return {Object} Vendor capabilities of the selected destination. */
get capability() {
- var destination = this.destinationStore_ ?
+ const destination = this.destinationStore_ ?
this.destinationStore_.selectedDestination :
null;
if (!destination)
@@ -86,7 +86,7 @@ cr.define('print_preview.ticket_items', function() {
updateValue(values) {
this.items_ = {};
if (typeof values == 'object') {
- for (var key in values) {
+ for (const key in values) {
if (values.hasOwnProperty(key) && typeof values[key] == 'string') {
// Let's empirically limit each value at 2K.
this.items_[key] = values[key].substring(0, 2048);
diff --git a/chromium/chrome/browser/resources/print_preview/data/user_info.js b/chromium/chrome/browser/resources/print_preview/data/user_info.js
index 5076052302c..46d62bb7622 100644
--- a/chromium/chrome/browser/resources/print_preview/data/user_info.js
+++ b/chromium/chrome/browser/resources/print_preview/data/user_info.js
@@ -5,51 +5,38 @@
cr.define('print_preview', function() {
'use strict';
- /**
- * Repository which stores information about the user. Events are dispatched
- * when the information changes.
- * @constructor
- * @extends {cr.EventTarget}
- */
- function UserInfo() {
- cr.EventTarget.call(this);
-
+ class UserInfo extends cr.EventTarget {
/**
- * Email address of the logged in user or {@code null} if no user is logged
- * in. In case of Google multilogin, can be changed by the user.
- * @private {?string}
+ * Repository which stores information about the user. Events are dispatched
+ * when the information changes.
*/
- this.activeUser_ = null;
-
- /**
- * Email addresses of the logged in users or empty array if no user is
- * logged in. {@code null} if not known yet.
- * @private {?Array<string>}
- */
- this.users_ = null;
- }
+ constructor() {
+ super();
- /**
- * Enumeration of event types dispatched by the user info.
- * @enum {string}
- */
- UserInfo.EventType = {
- ACTIVE_USER_CHANGED: 'print_preview.UserInfo.ACTIVE_USER_CHANGED',
- USERS_CHANGED: 'print_preview.UserInfo.USERS_CHANGED'
- };
+ /**
+ * Email address of the logged in user or {@code null} if no user is
+ * logged in. In case of Google multilogin, can be changed by the user.
+ * @private {?string}
+ */
+ this.activeUser_ = null;
- UserInfo.prototype = {
- __proto__: cr.EventTarget.prototype,
+ /**
+ * Email addresses of the logged in users or empty array if no user is
+ * logged in. {@code null} if not known yet.
+ * @private {?Array<string>}
+ */
+ this.users_ = null;
+ }
/** @return {boolean} Whether user accounts are already retrieved. */
get initialized() {
return this.users_ != null;
- },
+ }
/** @return {boolean} Whether user is logged in or not. */
get loggedIn() {
return !!this.activeUser;
- },
+ }
/**
* @return {?string} Email address of the logged in user or {@code null} if
@@ -57,15 +44,19 @@ cr.define('print_preview', function() {
*/
get activeUser() {
return this.activeUser_;
- },
+ }
- /** Changes active user. */
+ /**
+ * Changes active user.
+ * @param {?string} activeUser Email address for the user to be set as
+ * active.
+ */
set activeUser(activeUser) {
- if (this.activeUser_ != activeUser) {
+ if (!!activeUser && this.activeUser_ != activeUser) {
this.activeUser_ = activeUser;
cr.dispatchSimpleEvent(this, UserInfo.EventType.ACTIVE_USER_CHANGED);
}
- },
+ }
/**
* @return {?Array<string>} Email addresses of the logged in users or
@@ -73,18 +64,27 @@ cr.define('print_preview', function() {
*/
get users() {
return this.users_;
- },
+ }
/**
* Sets logged in user accounts info.
* @param {string} activeUser Active user account (email).
* @param {!Array<string>} users List of currently logged in accounts.
*/
- setUsers: function(activeUser, users) {
+ setUsers(activeUser, users) {
this.activeUser_ = activeUser;
this.users_ = users || [];
cr.dispatchSimpleEvent(this, UserInfo.EventType.USERS_CHANGED);
- },
+ }
+ }
+
+ /**
+ * Enumeration of event types dispatched by the user info.
+ * @enum {string}
+ */
+ UserInfo.EventType = {
+ ACTIVE_USER_CHANGED: 'print_preview.UserInfo.ACTIVE_USER_CHANGED',
+ USERS_CHANGED: 'print_preview.UserInfo.USERS_CHANGED'
};
return {UserInfo: UserInfo};
diff --git a/chromium/chrome/browser/resources/print_preview/native_layer.js b/chromium/chrome/browser/resources/print_preview/native_layer.js
index 3aaa9947da1..e79740216ed 100644
--- a/chromium/chrome/browser/resources/print_preview/native_layer.js
+++ b/chromium/chrome/browser/resources/print_preview/native_layer.js
@@ -197,8 +197,8 @@ cr.define('print_preview', function() {
*/
getNativeColorModel_(destination, color) {
// For non-local printers native color model is ignored anyway.
- var option = destination.isLocal ? color.getSelectedOption() : null;
- var nativeColorModel = parseInt(option ? option.vendor_id : null, 10);
+ const option = destination.isLocal ? color.getSelectedOption() : null;
+ const nativeColorModel = parseInt(option ? option.vendor_id : null, 10);
if (isNaN(nativeColorModel)) {
return color.getValue() ? NativeLayer.ColorMode_.COLOR :
NativeLayer.ColorMode_.GRAY;
@@ -228,7 +228,7 @@ cr.define('print_preview', function() {
printTicketStore.isTicketValidForPreview(),
'Trying to generate preview when ticket is not valid');
- var ticket = {
+ const ticket = {
'pageRange': printTicketStore.pageRange.getDocumentPageRanges(),
'mediaSize': printTicketStore.mediaSize.getValue(),
'landscape': printTicketStore.landscape.getValue(),
@@ -274,8 +274,8 @@ cr.define('print_preview', function() {
if (printTicketStore.marginsType.isCapabilityAvailable() &&
printTicketStore.marginsType.getValue() ==
print_preview.ticket_items.MarginsTypeValue.CUSTOM) {
- var customMargins = printTicketStore.customMargins.getValue();
- var orientationEnum =
+ const customMargins = printTicketStore.customMargins.getValue();
+ const orientationEnum =
print_preview.ticket_items.CustomMarginsOrientation;
ticket['marginsCustom'] = {
'marginTop': customMargins.get(orientationEnum.TOP),
@@ -295,8 +295,6 @@ cr.define('print_preview', function() {
* @param {!print_preview.Destination} destination Destination to print to.
* @param {!print_preview.PrintTicketStore} printTicketStore Used to get the
* state of the print ticket.
- * @param {cloudprint.CloudPrintInterface} cloudPrintInterface Interface
- * to Google Cloud Print.
* @param {!print_preview.DocumentInfo} documentInfo Document data model.
* @param {boolean=} opt_isOpenPdfInPreview Whether to open the PDF in the
* system's preview application.
@@ -306,8 +304,8 @@ cr.define('print_preview', function() {
* finished or rejected.
*/
print(
- destination, printTicketStore, cloudPrintInterface, documentInfo,
- opt_isOpenPdfInPreview, opt_showSystemDialog) {
+ destination, printTicketStore, documentInfo, opt_isOpenPdfInPreview,
+ opt_showSystemDialog) {
assert(
printTicketStore.isTicketValid(),
'Trying to print when ticket is not valid');
@@ -316,7 +314,10 @@ cr.define('print_preview', function() {
!opt_showSystemDialog || (cr.isWindows && destination.isLocal),
'Implemented for Windows only');
- var ticket = {
+ // Note: update
+ // chrome/browser/ui/webui/print_preview/print_preview_handler_unittest.cc
+ // with any changes to ticket creation.
+ const ticket = {
'mediaSize': printTicketStore.mediaSize.getValue(),
'pageCount': printTicketStore.pageRange.getPageNumberSet().size,
'landscape': printTicketStore.landscape.getValue(),
@@ -361,8 +362,8 @@ cr.define('print_preview', function() {
if (printTicketStore.marginsType.isCapabilityAvailable() &&
printTicketStore.marginsType.isValueEqual(
print_preview.ticket_items.MarginsTypeValue.CUSTOM)) {
- var customMargins = printTicketStore.customMargins.getValue();
- var orientationEnum =
+ const customMargins = printTicketStore.customMargins.getValue();
+ const orientationEnum =
print_preview.ticket_items.CustomMarginsOrientation;
ticket['marginsCustom'] = {
'marginTop': customMargins.get(orientationEnum.TOP),
@@ -433,19 +434,12 @@ cr.define('print_preview', function() {
return cr.sendWithPromise('signIn', addAccount);
}
- /** Navigates the user to the system printer settings interface. */
- manageLocalPrinters() {
- chrome.send('manageLocalPrinters');
- }
-
/**
- * Navigates the user to the Google Cloud Print management page.
- * @param {?string} user Email address of the user to open the management
- * page for (user must be currently logged in, indeed) or {@code null}
- * to open this page for the primary user.
+ * Navigates the user to the Chrome printing setting page to manage local
+ * printers and Google cloud printers.
*/
- manageCloudPrinters(user) {
- chrome.send('manageCloudPrinters', [user || '']);
+ managePrinters() {
+ chrome.send('managePrinters');
}
/** Forces browser to open a new tab with the given URL address. */
@@ -471,14 +465,6 @@ cr.define('print_preview', function() {
}
/**
- * Notifies the metrics handler to record an action.
- * @param {string} action The action to record.
- */
- recordAction(action) {
- chrome.send('metricsHandler:recordAction', [action]);
- }
-
- /**
* Notifies the metrics handler to record a histogram value.
* @param {string} histogram The name of the histogram to record
* @param {number} bucket The bucket to record
@@ -491,7 +477,7 @@ cr.define('print_preview', function() {
}
/** @private {?print_preview.NativeLayer} */
- var currentInstance = null;
+ let currentInstance = null;
/**
* Constant values matching printing::DuplexMode enum.
diff --git a/chromium/chrome/browser/resources/print_preview/new/advanced_options_settings.html b/chromium/chrome/browser/resources/print_preview/new/advanced_options_settings.html
new file mode 100644
index 00000000000..554ba1337a4
--- /dev/null
+++ b/chromium/chrome/browser/resources/print_preview/new/advanced_options_settings.html
@@ -0,0 +1,23 @@
+<link rel="import" href="chrome://resources/html/polymer.html">
+
+<link rel="import" href="button_css.html">
+<link rel="import" href="print_preview_shared_css.html">
+<link rel="import" href="settings_section.html">
+
+<dom-module id="print-preview-advanced-options-settings">
+ <template>
+ <style include="print-preview-shared button">
+ :host button {
+ min-height: 28px;
+ width: 100%;
+ }
+ </style>
+ <print-preview-settings-section>
+ <span slot="title">$i18n{advancedOptionsLabel}</span>
+ <div slot="controls">
+ <button>$i18n{showAdvancedOptions}</button>
+ </div>
+ </print-preview-settings-section>
+ </template>
+ <script src="advanced_options_settings.js"></script>
+</dom-module>
diff --git a/chromium/chrome/browser/resources/print_preview/new/advanced_options_settings.js b/chromium/chrome/browser/resources/print_preview/new/advanced_options_settings.js
new file mode 100644
index 00000000000..6df05eb6896
--- /dev/null
+++ b/chromium/chrome/browser/resources/print_preview/new/advanced_options_settings.js
@@ -0,0 +1,7 @@
+// Copyright 2017 The Chromium 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: 'print-preview-advanced-options-settings',
+});
diff --git a/chromium/chrome/browser/resources/print_preview/new/app.html b/chromium/chrome/browser/resources/print_preview/new/app.html
new file mode 100644
index 00000000000..bde13b165c8
--- /dev/null
+++ b/chromium/chrome/browser/resources/print_preview/new/app.html
@@ -0,0 +1,95 @@
+<link rel="import" href="chrome://resources/html/polymer.html">
+
+<link rel="import" href="model.html">
+<link rel="import" href="header.html">
+<link rel="import" href="destination_settings.html">
+<link rel="import" href="pages_settings.html">
+<link rel="import" href="copies_settings.html">
+<link rel="import" href="layout_settings.html">
+<link rel="import" href="color_settings.html">
+<link rel="import" href="media_size_settings.html">
+<link rel="import" href="margins_settings.html">
+<link rel="import" href="dpi_settings.html">
+<link rel="import" href="scaling_settings.html">
+<link rel="import" href="other_options_settings.html">
+<link rel="import" href="advanced_options_settings.html">
+
+<dom-module id="print-preview-app">
+ <template>
+ <style>
+ :host {
+ display: flex;
+ height: 100%;
+ }
+
+ #sidebar {
+ -webkit-border-end: 1px solid #c8c8c8;
+ background-color: white;
+ display: flex;
+ flex-direction: column;
+ max-width: 310px;
+ min-width: 310px;
+ }
+
+ #settings-sections {
+ background: #fbfbfb;
+ border-top: 1px solid #f3f3f3;
+ flex: 1;
+ overflow: auto;
+ }
+
+ #previewArea {
+ -webkit-border-start: 1px solid #dcdcdc;
+ align-items: center;
+ background-color: #e6e6e6;
+ display: flex;
+ flex: 1;
+ justify-content: center;
+ }
+ </style>
+ <print-preview-model id="model" settings="{{settings}}"
+ destination="{{destination}}" document-info="{{documentInfo}}"
+ state="{{state}}"></print-preview-model>
+ <div id="sidebar">
+ <print-preview-header destination="[[destination]]" state="[[state]]"
+ settings="[[settings]]"></print-preview-header>
+ <div id="settings-sections">
+ <print-preview-destination-settings destination="[[destination]]">
+ </print-preview-destination-settings>
+ <print-preview-pages-settings settings="{{settings}}"
+ document-info="[[documentInfo]]"
+ hidden$="[[!settings.pages.available]]">
+ </print-preview-pages-settings>
+ <print-preview-copies-settings settings="{{settings}}"
+ hidden$="[[!settings.copies.available]]">
+ </print-preview-copies-settings>
+ <print-preview-layout-settings settings="{{settings}}"
+ hidden$="[[!settings.layout.available]]">
+ </print-preview-layout-settings>
+ <print-preview-color-settings settings="{{settings}}"
+ hidden$="[[!settings.color.available]]">
+ </print-preview-color-settings>
+ <print-preview-media-size-settings settings="{{settings}}"
+ hidden$="[[!settings.mediaSize.available]]">
+ </print-preview-media-size-settings>
+ <print-preview-margins-settings settings="{{settings}}"
+ hidden$="[[!settings.margins.available]]">
+ </print-preview-margins-settings>
+ <print-preview-dpi-settings settings="{{settings}}"
+ hidden$="[[!settings.dpi.available]]">
+ </print-preview-dpi-settings>
+ <print-preview-scaling-settings settings="{{settings}}"
+ document-info="[[documentInfo]]"
+ hidden$="[[!settings.scaling.available]]">
+ </print-preview-scaling-settings>
+ <print-preview-other-options-settings settings="{{settings}}">
+ </print-preview-other-options-settings>
+ <print-preview-advanced-options-settings settings="{{settings}}"
+ hidden$="[[!settings.vendorItems.available]]">
+ </print-preview-advanced-options-settings>
+ </div>
+ </div>
+ <div id="previewArea">preview area</div>
+ </template>
+ <script src="app.js"></script>
+</dom-module>
diff --git a/chromium/chrome/browser/resources/print_preview/new/app.js b/chromium/chrome/browser/resources/print_preview/new/app.js
new file mode 100644
index 00000000000..9ca31b13b63
--- /dev/null
+++ b/chromium/chrome/browser/resources/print_preview/new/app.js
@@ -0,0 +1,37 @@
+// Copyright 2017 The Chromium 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: 'print-preview-app',
+
+ properties: {
+ /**
+ * Object containing current settings of Print Preview, for use by Polymer
+ * controls.
+ * @type {!Object}
+ */
+ settings: {
+ type: Object,
+ notify: true,
+ },
+
+ /** @type {print_preview.Destination} */
+ destination: {
+ type: Object,
+ notify: true,
+ },
+
+ /** @type {print_preview.DocumentInfo} */
+ documentInfo: {
+ type: Object,
+ notify: true,
+ },
+
+ /** @type {!print_preview_new.State} */
+ state: {
+ type: Object,
+ notify: true,
+ },
+ },
+});
diff --git a/chromium/chrome/browser/resources/print_preview/new/button_css.html b/chromium/chrome/browser/resources/print_preview/new/button_css.html
new file mode 100644
index 00000000000..d33555445a4
--- /dev/null
+++ b/chromium/chrome/browser/resources/print_preview/new/button_css.html
@@ -0,0 +1,26 @@
+<!-- Styles copied from resources/css/widgets.css. -->
+<link rel="import" href="chrome://resources/html/polymer.html">
+<link rel="import" href="print_preview_shared_css.html">
+
+<dom-module id="button">
+ <template>
+ <style include="print-preview-shared">
+ button {
+ -webkit-padding-end: 10px;
+ -webkit-padding-start: 10px;
+ }
+
+ <if expr="not is_ios">
+ button:enabled:hover {
+ background-image: linear-gradient(#f0f0f0, #f0f0f0 38%, #e0e0e0);
+ @apply(--print-preview-hover);
+ }
+ </if>
+
+ button:enabled:active {
+ background-image: linear-gradient(#e7e7e7, #e7e7e7 38%, #d7d7d7);
+ @apply(--print-preview-active);
+ }
+ </style>
+ </template>
+</dom-module>
diff --git a/chromium/chrome/browser/resources/print_preview/new/checkbox_radio_css.html b/chromium/chrome/browser/resources/print_preview/new/checkbox_radio_css.html
new file mode 100644
index 00000000000..f2564079cbd
--- /dev/null
+++ b/chromium/chrome/browser/resources/print_preview/new/checkbox_radio_css.html
@@ -0,0 +1,123 @@
+<!-- Styles copied from resources/css/widgets.css. -->
+<link rel="import" href="chrome://resources/html/polymer.html">
+<link rel="import" href="print_preview_shared_css.html">
+
+<dom-module id="checkbox-radio">
+ <template>
+ <style include="print-preview-shared">
+ input[type='checkbox'] {
+ height: 13px;
+ position: relative;
+ vertical-align: middle;
+ width: 13px;
+ }
+
+ input[type='radio'] {
+ /* OVERRIDE */
+ border-radius: 100%;
+ height: 15px;
+ position: relative;
+ vertical-align: middle;
+ width: 15px;
+ }
+
+ input[type='checkbox']:checked::before {
+ background-image: url(chrome://resources/images/check.png);
+ background-size: 100% 100%;
+ content: '';
+ display: block;
+ height: 100%;
+ user-select: none;
+ width: 100%;
+ }
+
+ input[type='radio']:checked::before {
+ background-color: #666;
+ border-radius: 100%;
+ bottom: 3px;
+ content: '';
+ display: block;
+ left: 3px;
+ position: absolute;
+ right: 3px;
+ top: 3px;
+ }
+
+ <if expr="not is_ios">
+ input:enabled:hover:-webkit-any([type='checkbox'],
+ [type='radio']) {
+ background-image:
+ linear-gradient(#f0f0f0, #f0f0f0 38%, #e0e0e0);
+ @apply(--print-preview-hover);
+ }
+ </if>
+
+ input:enabled:active:-webkit-any([type='checkbox'],
+ [type='radio']) {
+ background-image: linear-gradient(#e7e7e7, #e7e7e7 38%, #d7d7d7);
+ @apply(--print-preview-active);
+ }
+
+ input:disabled:-webkit-any([type='checkbox'],
+ [type='radio']) {
+ opacity: .75;
+ }
+
+ /* Checkbox/radio helpers ***********************************************
+ *
+ * .checkbox and .radio classes wrap labels. Checkboxes and radios should
+ * use these classes with the markup structure:
+ *
+ * <div class="checkbox">
+ * <label>
+ * <input type="checkbox">
+ * <span>
+ * </label>
+ * </div>
+ */
+
+ :-webkit-any(.checkbox, .radio) label {
+ /* Don't expand horizontally: <http://crbug.com/112091>. */
+ align-items: center;
+ display: flex;
+ user-select: none;
+ }
+
+ .radio label {
+ padding-bottom: 5px;
+ padding-top: 10px;
+ }
+
+ .checkbox label {
+ padding-bottom: 7px;
+ padding-top: 7px;
+ }
+
+ :-webkit-any(.checkbox, .radio) label input {
+ flex-shrink: 0;
+ }
+
+ :-webkit-any(.checkbox, .radio) label input ~ span {
+ -webkit-margin-start: 0.6em;
+ /* Make sure long spans wrap at the same horizontal position they
+ * start.
+ */
+ display: block;
+ }
+
+ :-webkit-any(.checkbox, .radio) label:hover {
+ color: black;
+ }
+
+ :host .radio input[type='radio'],
+ :host label input[type='checkbox'] {
+ --min-size: 13.19px;
+ --size: 1.1em;
+ height: var(--size);
+ min-height: var(--min-size);
+ min-width: var(--min-size);
+ width: var(--size);
+ }
+ </style>
+ </template>
+</dom-module>
diff --git a/chromium/chrome/browser/resources/print_preview/new/color_settings.html b/chromium/chrome/browser/resources/print_preview/new/color_settings.html
new file mode 100644
index 00000000000..cca961b8623
--- /dev/null
+++ b/chromium/chrome/browser/resources/print_preview/new/color_settings.html
@@ -0,0 +1,22 @@
+<link rel="import" href="chrome://resources/html/polymer.html">
+
+<link rel="import" href="print_preview_shared_css.html">
+<link rel="import" href="select_css.html">
+<link rel="import" href="settings_section.html">
+
+<dom-module id="print-preview-color-settings">
+ <template>
+ <style include="print-preview-shared select">
+ </style>
+ <print-preview-settings-section>
+ <span id="color-label" slot="title">$i18n{optionColor}</span>
+ <div slot="controls">
+ <select aria-labelledby="color-label">
+ <option value="bw" selected>$i18n{optionBw}</option>
+ <option value="color">$i18n{optionColor}</option>
+ </select>
+ </div>
+ </print-preview-settings-section>
+ </template>
+ <script src="color_settings.js"></script>
+</dom-module>
diff --git a/chromium/chrome/browser/resources/print_preview/new/color_settings.js b/chromium/chrome/browser/resources/print_preview/new/color_settings.js
new file mode 100644
index 00000000000..b28f250afeb
--- /dev/null
+++ b/chromium/chrome/browser/resources/print_preview/new/color_settings.js
@@ -0,0 +1,7 @@
+// Copyright 2017 The Chromium 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: 'print-preview-color-settings',
+});
diff --git a/chromium/chrome/browser/resources/print_preview/new/compiled_resources2.gyp b/chromium/chrome/browser/resources/print_preview/new/compiled_resources2.gyp
new file mode 100644
index 00000000000..d8e8670920c
--- /dev/null
+++ b/chromium/chrome/browser/resources/print_preview/new/compiled_resources2.gyp
@@ -0,0 +1,135 @@
+# Copyright 2017 The Chromium 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': 'app',
+ 'dependencies': [
+ 'header',
+ 'destination_settings',
+ 'pages_settings',
+ 'copies_settings',
+ 'layout_settings',
+ 'color_settings',
+ 'media_size_settings',
+ 'margins_settings',
+ 'dpi_settings',
+ 'scaling_settings',
+ 'other_options_settings',
+ 'advanced_options_settings',
+ 'model',
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'header',
+ 'dependencies': [
+ '../data/compiled_resources2.gyp:destination',
+ 'settings_behavior',
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:load_time_data',
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'destination_settings',
+ 'dependencies': [
+ '../data/compiled_resources2.gyp:destination',
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'pages_settings',
+ 'dependencies': [
+ 'settings_behavior',
+ '../data/compiled_resources2.gyp:document_info',
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:load_time_data',
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'copies_settings',
+ 'dependencies': [
+ 'number_settings_section',
+ 'settings_behavior',
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'layout_settings',
+ 'dependencies': [
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'color_settings',
+ 'dependencies': [
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'media_size_settings',
+ 'dependencies': [
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'margins_settings',
+ 'dependencies': [
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'dpi_settings',
+ 'dependencies': [
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'scaling_settings',
+ 'dependencies': [
+ '../data/compiled_resources2.gyp:document_info',
+ 'number_settings_section',
+ 'settings_behavior',
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'other_options_settings',
+ 'dependencies': [
+ 'settings_behavior',
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'advanced_options_settings',
+ 'dependencies': [
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'number_settings_section',
+ 'dependencies': [
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'settings_behavior',
+ 'dependencies': [
+ 'model',
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:assert',
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'model',
+ 'dependencies': [
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
+ '../data/compiled_resources2.gyp:destination',
+ '../data/compiled_resources2.gyp:document_info',
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ }
+ ],
+}
diff --git a/chromium/chrome/browser/resources/print_preview/new/copies_settings.html b/chromium/chrome/browser/resources/print_preview/new/copies_settings.html
new file mode 100644
index 00000000000..f6d9374fe18
--- /dev/null
+++ b/chromium/chrome/browser/resources/print_preview/new/copies_settings.html
@@ -0,0 +1,28 @@
+<link rel="import" href="chrome://resources/html/polymer.html">
+
+<link rel="import" href="checkbox_radio_css.html">
+<link rel="import" href="number_settings_section.html">
+<link rel="import" href="print_preview_shared_css.html">
+<link rel="import" href="settings_behavior.html">
+
+<dom-module id="print-preview-copies-settings">
+ <template>
+ <style include="print-preview-shared checkbox-radio input">
+ </style>
+ <print-preview-number-settings-section max-value="999" min-value=1
+ default-value="1" input-label="$i18n{copiesLabel}"
+ input-string="{{inputString_}}" input-valid="{{inputValid_}}"
+ hint-message="$i18n{copiesInstruction}">
+ <div slot="opt-inside-content" class="collate-container checkbox"
+ aria-live="polite"
+ hidden$="[[collateHidden_(inputString_, inputValid_)]]">
+ <label>
+ <input class="collate" type="checkbox" checked
+ aria-labelledby="copies-collate-label">
+ <span id="copies-collate-label">$i18n{optionCollate}</span>
+ </label>
+ </div>
+ </print-preview-number-settings-section>
+ </template>
+ <script src="copies_settings.js"></script>
+</dom-module>
diff --git a/chromium/chrome/browser/resources/print_preview/new/copies_settings.js b/chromium/chrome/browser/resources/print_preview/new/copies_settings.js
new file mode 100644
index 00000000000..b58408ff391
--- /dev/null
+++ b/chromium/chrome/browser/resources/print_preview/new/copies_settings.js
@@ -0,0 +1,56 @@
+// Copyright 2017 The Chromium 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: 'print-preview-copies-settings',
+
+ behaviors: [SettingsBehavior],
+
+ properties: {
+ /** @private {string} */
+ inputString_: String,
+
+ /** @private {boolean} */
+ inputValid_: Boolean,
+ },
+
+ /** @private {boolean} */
+ isInitialized_: false,
+
+ observers: [
+ 'onInputChanged_(inputString_, inputValid_)',
+ 'onInitialized_(settings.copies.value)'
+ ],
+
+ /**
+ * Updates the input string when the setting has been initialized.
+ * @private
+ */
+ onInitialized_: function() {
+ if (this.isInitialized_)
+ return;
+ this.isInitialized_ = true;
+ const copies = this.getSetting('copies');
+ this.set('inputString_', copies.value);
+ },
+
+ /**
+ * Updates model.copies and model.copiesInvalid based on the validity
+ * and current value of the copies input.
+ * @private
+ */
+ onInputChanged_: function() {
+ this.setSetting(
+ 'copies', this.inputValid_ ? parseInt(this.inputString_, 10) : 1);
+ this.setSettingValid('copies', this.inputValid_);
+ },
+
+ /**
+ * @return {boolean} Whether collate checkbox should be hidden.
+ * @private
+ */
+ collateHidden_: function() {
+ return !this.inputValid_ || parseInt(this.inputString_, 10) == 1;
+ },
+});
diff --git a/chromium/chrome/browser/resources/print_preview/new/destination_settings.html b/chromium/chrome/browser/resources/print_preview/new/destination_settings.html
new file mode 100644
index 00000000000..d2882dde447
--- /dev/null
+++ b/chromium/chrome/browser/resources/print_preview/new/destination_settings.html
@@ -0,0 +1,81 @@
+<link rel="import" href="chrome://resources/html/polymer.html">
+
+<link rel="import" href="chrome://resources/cr_elements/hidden_style_css.html">
+<link rel="import" href="button_css.html">
+<link rel="import" href="../data/destination.html">
+<link rel="import" href="print_preview_shared_css.html">
+<link rel="import" href="throbber_css.html">
+<link rel="import" href="settings_section.html">
+
+<dom-module id="print-preview-destination-settings">
+ <template>
+ <style include="print-preview-shared button throbber cr-hidden-style">
+ :host button {
+ margin-top: 10px;
+ }
+
+ .throbber {
+ margin-top: 6px;
+ }
+
+ .destination-settings-box,
+ .throbber-container {
+ align-items: center;
+ display: flex;
+ min-height: 28px;
+ }
+
+ .destination-icon {
+ -webkit-margin-end: 8px;
+ height: 24px;
+ vertical-align: middle;
+ width: 24px;
+ }
+
+ .destination-info-wrapper {
+ display: flex;
+ flex: 1;
+ flex-direction: column;
+ width: 100%;
+ }
+
+ .destination-info-wrapper > div,
+ .destination-throbber-name {
+ flex: 1;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ }
+
+ .destination-throbber-name,
+ .destination-name {
+ font-size: 110%;
+ }
+
+ .destination-location {
+ opacity: 0.4;
+ }
+ </style>
+ <print-preview-settings-section class="multirow-controls">
+ <span slot="title">$i18n{destinationLabel}</span>
+ <div slot="controls">
+ <div class="throbber-container" hidden="[[!loadingDestination_]]">
+ <div class="throbber"></div>
+ <div class="destination-throbber-name"></div>
+ </div>
+ <div class="destination-settings-box" hidden="[[loadingDestination_]]">
+ <img class="destination-icon"
+ src="[[destination.iconUrl]]" alt="">
+ <div class="destination-info-wrapper">
+ <div class="destination-name">[[destination.id]]</div>
+ <div class="destination-location">[[destination.hint]]</div>
+ <div class="destination-offline-status">
+ [[destination.offlineStatusText]]</div>
+ </div>
+ </div>
+ <button>$i18n{changeDestination}</button>
+ </div>
+ </print-preview-settings-section>
+ </template>
+ <script src="destination_settings.js"></script>
+</dom-module>
diff --git a/chromium/chrome/browser/resources/print_preview/new/destination_settings.js b/chromium/chrome/browser/resources/print_preview/new/destination_settings.js
new file mode 100644
index 00000000000..6fde6cc0895
--- /dev/null
+++ b/chromium/chrome/browser/resources/print_preview/new/destination_settings.js
@@ -0,0 +1,27 @@
+// Copyright 2017 The Chromium 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: 'print-preview-destination-settings',
+
+ properties: {
+ /** @type {!print_preview.Destination} */
+ destination: Object,
+
+ /** @private {boolean} */
+ loadingDestination_: Boolean,
+ },
+
+ /** @override */
+ ready: function() {
+ this.loadingDestination_ = true;
+ // Simulate transition from spinner to destination.
+ setTimeout(this.doneLoading_.bind(this), 5000);
+ },
+
+ /** @private */
+ doneLoading_: function() {
+ this.loadingDestination_ = false;
+ },
+});
diff --git a/chromium/chrome/browser/resources/print_preview/new/dpi_settings.html b/chromium/chrome/browser/resources/print_preview/new/dpi_settings.html
new file mode 100644
index 00000000000..d7988acd78a
--- /dev/null
+++ b/chromium/chrome/browser/resources/print_preview/new/dpi_settings.html
@@ -0,0 +1,20 @@
+<link rel="import" href="chrome://resources/html/polymer.html">
+
+<link rel="import" href="print_preview_shared_css.html">
+<link rel="import" href="select_css.html">
+<link rel="import" href="settings_section.html">
+
+<dom-module id="print-preview-dpi-settings">
+ <template>
+ <style include="print-preview-shared select">
+ </style>
+ <print-preview-settings-section>
+ <span id="dpi-label" slot="title">$i18n{dpiLabel}</span>
+ <div slot="controls">
+ <select aria-labelledby="dpi-label">
+ </select>
+ </div>
+ </print-preview-settings-section>
+ </template>
+ <script src="dpi_settings.js"></script>
+</dom-module>
diff --git a/chromium/chrome/browser/resources/print_preview/new/dpi_settings.js b/chromium/chrome/browser/resources/print_preview/new/dpi_settings.js
new file mode 100644
index 00000000000..62bf5e2dad2
--- /dev/null
+++ b/chromium/chrome/browser/resources/print_preview/new/dpi_settings.js
@@ -0,0 +1,7 @@
+// Copyright 2017 The Chromium 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: 'print-preview-dpi-settings',
+});
diff --git a/chromium/chrome/browser/resources/print_preview/new/header.html b/chromium/chrome/browser/resources/print_preview/new/header.html
new file mode 100644
index 00000000000..e16008da496
--- /dev/null
+++ b/chromium/chrome/browser/resources/print_preview/new/header.html
@@ -0,0 +1,85 @@
+<link rel="import" href="chrome://resources/html/polymer.html">
+
+<link rel="import" href="button_css.html">
+<link rel="import" href="../data/destination.html">
+<link rel="import" href="settings_behavior.html">
+<link rel="import" href="print_preview_shared_css.html">
+<link rel="import" href="strings.html">
+
+<dom-module id="print-preview-header">
+ <template>
+ <style include="print-preview-shared button">
+ :host {
+ -webkit-padding-end: 19px;
+ -webkit-padding-start: 20px;
+ background-color: #f6f6f6;
+ border-bottom: 1px solid #d2d2d2;
+ display: block;
+ padding-bottom: 20px;
+ padding-top: 6px;
+ }
+
+ .title {
+ color: black;
+ font-size: 1.25em;
+ font-weight: normal;
+ margin: 0;
+ padding-bottom: 12px;
+ padding-top: 10px;
+ }
+
+ .summary {
+ display: block;
+ min-height: 34px;
+ }
+
+ #button-strip {
+ display: flex;
+ flex-direction: row;
+ justify-content: flex-end;
+ }
+
+ #button-strip button {
+ -webkit-margin-start: 9px;
+ display: block;
+ }
+
+ #button-strip button.loading {
+ cursor: progress;
+ }
+
+ #button-strip button.default {
+ font-kerning: none;
+ font-weight: bold;
+ }
+
+ #button-strip button.default:not(:focus):not(:disabled) {
+ border-color: #808080;
+ }
+
+ #button-strip button.print:enabled {
+ background-color: rgb(77, 144, 254);
+ background-image:
+ linear-gradient(to bottom, rgb(77, 144, 254), rgb(71, 135, 237));
+ border: 1px solid rgb(48, 121, 237);
+ color: #fff;
+ text-shadow: 0 1px rgba(0,0,0,0.1);
+ }
+ </style>
+ <h1 class="title">$i18n{title}</h1>
+ <span class="summary"
+ aria-label="[[getSummaryLabel_(currentErrorOrState_, labelInfo_)]]"
+ inner-h-t-m-l="[[getSummary_(currentErrorOrState_, labelInfo_)]]">
+ </span>
+ <div id="button-strip">
+ <button class="cancel" on-tap="onCancelButtonTap_">
+ $i18n{cancel}
+ </button>
+ <button class="print default" on-tap="onPrintButtonTap_"
+ disabled$="[[printButtonDisabled_(currentErrorOrState_)]]">
+ [[getPrintButton_(destination.id)]]
+ </button>
+ </div>
+ </template>
+ <script src="header.js"></script>
+</dom-module>
diff --git a/chromium/chrome/browser/resources/print_preview/new/header.js b/chromium/chrome/browser/resources/print_preview/new/header.js
new file mode 100644
index 00000000000..a9aed406475
--- /dev/null
+++ b/chromium/chrome/browser/resources/print_preview/new/header.js
@@ -0,0 +1,190 @@
+// Copyright 2017 The Chromium 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: 'print-preview-header',
+
+ behaviors: [SettingsBehavior],
+
+ properties: {
+ /** @type {!print_preview.Destination} */
+ destination: Object,
+
+ /** @type {!print_preview_new.State} */
+ state: Object,
+
+ /** @private {boolean} */
+ printInProgress_: {
+ type: Boolean,
+ notify: true,
+ value: false,
+ },
+
+ /**
+ * @private {?string} Null value indicates that there is no error or
+ * state to display in the summary.
+ */
+ currentErrorOrState_: {
+ type: String,
+ computed: 'computeErrorOrStateString_(state.*, ' +
+ 'settings.copies.valid, settings.scaling.valid, ' +
+ 'settings.pages.valid, printInProgress_)'
+ },
+
+ /**
+ * @private {{numPages: number,
+ * numSheets: number,
+ * pagesLabel: string,
+ * summaryLabel: string}}
+ */
+ labelInfo_: {
+ type: Object,
+ computed: 'getLabelInfo_(currentErrorOrState_, destination.id, ' +
+ 'settings.copies.value, settings.pages.value, ' +
+ 'settings.duplex.value)'
+ },
+ },
+
+ /** @private */
+ onPrintButtonTap_: function() {
+ this.printInProgress_ = true;
+ },
+
+ /** @private */
+ onCancelButtonTap_: function() {
+ this.printInProgress_ = false;
+ },
+
+ /**
+ * @return {boolean}
+ * @private
+ */
+ isPdfOrDrive_: function() {
+ return this.destination.id ==
+ print_preview.Destination.GooglePromotedId.SAVE_AS_PDF ||
+ this.destination.id == print_preview.Destination.GooglePromotedId.DOCS;
+ },
+
+ /**
+ * @return {string}
+ * @private
+ */
+ getPrintButton_: function() {
+ return loadTimeData.getString(
+ this.isPdfOrDrive_() ? 'saveButton' : 'printButton');
+ },
+
+ /**
+ * @return {?string}
+ * @private
+ */
+ computeErrorOrStateString_: function() {
+ if (this.state.cloudPrintError != '')
+ return this.state.cloudPrintError;
+ if (this.state.privetExtensionError != '')
+ return this.state.privetExtensionError;
+ if (this.state.invalidSettings || this.state.previewFailed ||
+ this.state.previewLoading || !this.getSetting('copies').valid ||
+ !this.getSetting('scaling').valid || !this.getSetting('pages').valid) {
+ return '';
+ }
+ if (this.printInProgress_) {
+ return loadTimeData.getString(
+ this.isPdfOrDrive_() ? 'saving' : 'printing');
+ }
+ return null;
+ },
+
+ /**
+ * @return {{numPages: number,
+ * numSheets: number,
+ * pagesLabel: string,
+ * summaryLabel: string}}
+ * @private
+ */
+ getLabelInfo_: function() {
+ const saveToPdfOrDrive = this.isPdfOrDrive_();
+ let numPages = this.getSetting('pages').value.length;
+ let numSheets = numPages;
+ if (!saveToPdfOrDrive && this.getSetting('duplex').value) {
+ numSheets = Math.ceil(numPages / 2);
+ }
+
+ const copies = /** @type {number} */ (this.getSetting('copies').value);
+ numSheets *= copies;
+ numPages *= copies;
+
+ const pagesLabel = loadTimeData.getString('printPreviewPageLabelPlural');
+ let summaryLabel;
+ if (numSheets > 1) {
+ summaryLabel = saveToPdfOrDrive ?
+ pagesLabel :
+ loadTimeData.getString('printPreviewSheetsLabelPlural');
+ } else {
+ summaryLabel = loadTimeData.getString(
+ saveToPdfOrDrive ? 'printPreviewPageLabelSingular' :
+ 'printPreviewSheetsLabelSingular');
+ }
+ return {
+ numPages: numPages,
+ numSheets: numSheets,
+ pagesLabel: pagesLabel,
+ summaryLabel: summaryLabel
+ };
+ },
+
+ /**
+ * @return {boolean}
+ * @private
+ */
+ printButtonDisabled_: function() {
+ return this.currentErrorOrState_ != null;
+ },
+
+ /**
+ * @return {string}
+ * @private
+ */
+ getSummary_: function() {
+ let html = this.currentErrorOrState_;
+ if (html != null)
+ return html;
+ const labelInfo = this.labelInfo_;
+ if (labelInfo.numPages != labelInfo.numSheets) {
+ html = loadTimeData.getStringF(
+ 'printPreviewSummaryFormatLong',
+ '<b>' + labelInfo.numSheets.toLocaleString() + '</b>',
+ '<b>' + labelInfo.summaryLabel + '</b>',
+ labelInfo.numPages.toLocaleString(), labelInfo.pagesLabel);
+ } else {
+ html = loadTimeData.getStringF(
+ 'printPreviewSummaryFormatShort',
+ '<b>' + labelInfo.numSheets.toLocaleString() + '</b>',
+ '<b>' + labelInfo.summaryLabel + '</b>');
+ }
+
+ // Removing extra spaces from within the string.
+ html = html.replace(/\s{2,}/g, ' ');
+ return html;
+ },
+
+ /**
+ * @return {string}
+ * @private
+ */
+ getSummaryLabel_: function() {
+ if (this.currentErrorOrState_ != null)
+ return this.currentErrorOrState_;
+ const labelInfo = this.labelInfo_;
+ if (labelInfo.numPages != labelInfo.numSheets) {
+ return loadTimeData.getStringF(
+ 'printPreviewSummaryFormatLong', labelInfo.numSheets.toLocaleString(),
+ labelInfo.summaryLabel, labelInfo.numPages.toLocaleString(),
+ labelInfo.pagesLabel);
+ }
+ return loadTimeData.getStringF(
+ 'printPreviewSummaryFormatShort', labelInfo.numSheets.toLocaleString(),
+ labelInfo.summaryLabel);
+ }
+});
diff --git a/chromium/chrome/browser/resources/print_preview/new/input_css.html b/chromium/chrome/browser/resources/print_preview/new/input_css.html
new file mode 100644
index 00000000000..e326dc4bfa6
--- /dev/null
+++ b/chromium/chrome/browser/resources/print_preview/new/input_css.html
@@ -0,0 +1,33 @@
+<link rel="import" href="chrome://resources/html/polymer.html">
+
+<dom-module id="input">
+ <template>
+ <style>
+ .input-settings-section {
+ --error-text-color: rgb(140, 20, 20);
+
+ --invalid-input-style: {
+ background: rgb(255, 240, 240);
+ color: var(--error-text-color);
+ }
+ }
+
+ input:invalid,
+ :host .input-settings-section input.invalid {
+ @apply --invalid-input-style;
+ }
+
+ span.hint {
+ background: white;
+ color: var(--error-text-color);
+ font-size: 0.9em;
+ font-weight: bold;
+ height: auto;
+ margin-bottom: -5px;
+ margin-top: 5px;
+ padding-bottom: 5px;
+ user-select: text;
+ }
+ </style>
+ </template>
+</dom-module>
diff --git a/chromium/chrome/browser/resources/print_preview/new/layout_settings.html b/chromium/chrome/browser/resources/print_preview/new/layout_settings.html
new file mode 100644
index 00000000000..d283f42ada5
--- /dev/null
+++ b/chromium/chrome/browser/resources/print_preview/new/layout_settings.html
@@ -0,0 +1,21 @@
+<link rel="import" href="chrome://resources/html/polymer.html">
+
+<link rel="import" href="print_preview_shared_css.html">
+<link rel="import" href="select_css.html">
+<link rel="import" href="settings_section.html">
+
+<dom-module id="print-preview-layout-settings">
+ <template>
+ <style include="print-preview-shared select"></style>
+ <print-preview-settings-section>
+ <span id="layout-label" slot="title">$i18n{layoutLabel}</span>
+ <div slot="controls">
+ <select aria-labelledby="layout-label">
+ <option value="portrait" selected>$i18n{optionPortrait}</option>
+ <option value="landscape">$i18n{optionLandscape}</option>
+ </select>
+ </div>
+ </print-preview-settings-section>
+ </template>
+ <script src="layout_settings.js"></script>
+</dom-module>
diff --git a/chromium/chrome/browser/resources/print_preview/new/layout_settings.js b/chromium/chrome/browser/resources/print_preview/new/layout_settings.js
new file mode 100644
index 00000000000..21bac56700e
--- /dev/null
+++ b/chromium/chrome/browser/resources/print_preview/new/layout_settings.js
@@ -0,0 +1,7 @@
+// Copyright 2017 The Chromium 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: 'print-preview-layout-settings',
+});
diff --git a/chromium/chrome/browser/resources/print_preview/new/margins_settings.html b/chromium/chrome/browser/resources/print_preview/new/margins_settings.html
new file mode 100644
index 00000000000..bffdaac1bb1
--- /dev/null
+++ b/chromium/chrome/browser/resources/print_preview/new/margins_settings.html
@@ -0,0 +1,27 @@
+<link rel="import" href="chrome://resources/html/polymer.html">
+
+<link rel="import" href="print_preview_shared_css.html">
+<link rel="import" href="select_css.html">
+<link rel="import" href="settings_section.html">
+
+<dom-module id="print-preview-margins-settings">
+ <template>
+ <style include="print-preview-shared select">
+ </style>
+ <print-preview-settings-section>
+ <span id="margins-label" slot="title">$i18n{marginsLabel}</span>
+ <div slot="controls">
+ <select aria-labelledby="margins-label">
+ <!-- The order of these options must match the natural order of their
+ values, which come from
+ print_preview.ticket_items.MarginsTypeValue. -->
+ <option value="0" selected>$i18n{defaultMargins}</option>
+ <option value="1">$i18n{noMargins}</option>
+ <option value="2">$i18n{minimumMargins}</option>
+ <option value="3">$i18n{customMargins}</option>
+ </select>
+ </div>
+ </print-preview-settings-section>
+ </template>
+ <script src="margins_settings.js"></script>
+</dom-module>
diff --git a/chromium/chrome/browser/resources/print_preview/new/margins_settings.js b/chromium/chrome/browser/resources/print_preview/new/margins_settings.js
new file mode 100644
index 00000000000..d0e942300ba
--- /dev/null
+++ b/chromium/chrome/browser/resources/print_preview/new/margins_settings.js
@@ -0,0 +1,7 @@
+// Copyright 2017 The Chromium 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: 'print-preview-margins-settings',
+});
diff --git a/chromium/chrome/browser/resources/print_preview/new/media_size_settings.html b/chromium/chrome/browser/resources/print_preview/new/media_size_settings.html
new file mode 100644
index 00000000000..a7e74065e51
--- /dev/null
+++ b/chromium/chrome/browser/resources/print_preview/new/media_size_settings.html
@@ -0,0 +1,20 @@
+<link rel="import" href="chrome://resources/html/polymer.html">
+
+<link rel="import" href="print_preview_shared_css.html">
+<link rel="import" href="select_css.html">
+<link rel="import" href="settings_section.html">
+
+<dom-module id="print-preview-media-size-settings">
+ <template>
+ <style include="print-preview-shared select">
+ </style>
+ <print-preview-settings-section>
+ <span id="media-size-label" slot="title">$i18n{mediaSizeLabel}</span>
+ <div slot="controls">
+ <select aria-labelledby="media-size-label">
+ </select>
+ </div>
+ </print-preview-settings-section>
+ </template>
+ <script src="media_size_settings.js"></script>
+</dom-module>
diff --git a/chromium/chrome/browser/resources/print_preview/new/media_size_settings.js b/chromium/chrome/browser/resources/print_preview/new/media_size_settings.js
new file mode 100644
index 00000000000..e425ec73a47
--- /dev/null
+++ b/chromium/chrome/browser/resources/print_preview/new/media_size_settings.js
@@ -0,0 +1,7 @@
+// Copyright 2017 The Chromium 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: 'print-preview-media-size-settings',
+});
diff --git a/chromium/chrome/browser/resources/print_preview/new/model.html b/chromium/chrome/browser/resources/print_preview/new/model.html
new file mode 100644
index 00000000000..3c40ff26599
--- /dev/null
+++ b/chromium/chrome/browser/resources/print_preview/new/model.html
@@ -0,0 +1,6 @@
+<link rel="import" href="chrome://resources/html/polymer.html">
+
+<link rel="import" href="../data/destination.html">
+<link rel="import" href="../data/document_info.html">
+
+<script src="model.js"></script>
diff --git a/chromium/chrome/browser/resources/print_preview/new/model.js b/chromium/chrome/browser/resources/print_preview/new/model.js
new file mode 100644
index 00000000000..2925555aaa0
--- /dev/null
+++ b/chromium/chrome/browser/resources/print_preview/new/model.js
@@ -0,0 +1,338 @@
+// Copyright 2017 The Chromium 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('print_preview_new');
+
+/**
+ * @typedef {{
+ * value: *,
+ * valid: boolean,
+ * available: boolean,
+ * updatesPreview: boolean
+ * }}
+ */
+print_preview_new.Setting;
+
+/**
+ * @typedef {{
+ * previewLoading: boolean,
+ * previewFailed: boolean,
+ * cloudPrintError: string,
+ * privetExtensionError: string,
+ * invalidSettings: boolean,
+ * }}
+ */
+print_preview_new.State;
+
+Polymer({
+ is: 'print-preview-model',
+
+ properties: {
+ /**
+ * Object containing current settings of Print Preview, for use by Polymer
+ * controls.
+ * @type {{
+ * pages: !print_preview_new.Setting,
+ * copies: !print_preview_new.Setting,
+ * collate: !print_preview_new.Setting,
+ * layout: !print_preview_new.Setting,
+ * color: !print_preview_new.Setting,
+ * mediaSize: !print_preview_new.Setting,
+ * margins: !print_preview_new.Setting,
+ * dpi: !print_preview_new.Setting,
+ * fitToPage: !print_preview_new.Setting,
+ * scaling: !print_preview_new.Setting,
+ * duplex: !print_preview_new.Setting,
+ * cssBackground: !print_preview_new.Setting,
+ * selectionOnly: !print_preview_new.Setting,
+ * headerFooter: !print_preview_new.Setting,
+ * rasterize: !print_preview_new.Setting,
+ * vendorItems: !print_preview_new.Setting,
+ * }}
+ */
+ settings: {
+ type: Object,
+ notify: true,
+ value: {
+ pages: {
+ value: [1, 2, 3, 4, 5],
+ valid: true,
+ available: true,
+ updatesPreview: true,
+ },
+ copies: {
+ value: '1',
+ valid: true,
+ available: true,
+ updatesPreview: false,
+ },
+ collate: {
+ value: true,
+ valid: true,
+ available: true,
+ updatesPreview: false,
+ },
+ layout: {
+ value: false, /* portrait */
+ valid: true,
+ available: true,
+ updatesPreview: true,
+ },
+ color: {
+ value: true, /* color */
+ valid: true,
+ available: true,
+ updatesPreview: true,
+ },
+ mediaSize: {
+ value: {
+ width_microns: 215900,
+ height_microns: 279400,
+ },
+ valid: true,
+ available: true,
+ updatesPreview: true,
+ },
+ margins: {
+ value: 0,
+ valid: true,
+ available: true,
+ updatesPreview: true,
+ },
+ dpi: {
+ value: {},
+ valid: true,
+ available: true,
+ updatesPreview: false,
+ },
+ fitToPage: {
+ value: false,
+ valid: true,
+ available: true,
+ updatesPreview: true,
+ },
+ scaling: {
+ value: '100',
+ valid: true,
+ available: true,
+ updatesPreview: true,
+ },
+ duplex: {
+ value: true,
+ valid: true,
+ available: true,
+ updatesPreview: false,
+ },
+ cssBackground: {
+ value: false,
+ valid: true,
+ available: true,
+ updatesPreview: true,
+ },
+ selectionOnly: {
+ value: false,
+ valid: true,
+ available: true,
+ updatesPreview: true,
+ },
+ headerFooter: {
+ value: true,
+ valid: true,
+ available: true,
+ updatesPreview: true,
+ },
+ rasterize: {
+ value: false,
+ valid: true,
+ available: true,
+ updatesPreview: false,
+ },
+ vendorItems: {
+ value: {},
+ valid: true,
+ available: true,
+ updatesPreview: false,
+ },
+ },
+ },
+
+ /** @type {print_preview.Destination} */
+ destination: {
+ type: Object,
+ notify: true,
+ value: function() {
+ const dest = new print_preview.Destination(
+ 'Foo Printer', print_preview.DestinationType.LOCAL,
+ print_preview.DestinationOrigin.LOCAL, 'Foo Printer', true,
+ print_preview.DestinationConnectionStatus.ONLINE,
+ {description: 'PrinterBrandAA 12345'});
+ dest.capabilities = {
+ version: '1.0',
+ printer: {
+ collate: {default: true},
+ color: {
+ option: [
+ {type: 'STANDARD_COLOR', is_default: true},
+ {type: 'STANDARD_MONOCHROME'}
+ ]
+ },
+ copies: {default: 1, max: 1000},
+ dpi: {
+ option: [
+ {horizontal_dpi: 200, vertical_dpi: 200, is_default: true},
+ {horizontal_dpi: 100, vertical_dpi: 100},
+ ]
+ },
+ duplex: {
+ option: [
+ {type: 'NO_DUPLEX', is_default: true}, {type: 'LONG_EDGE'},
+ {type: 'SHORT_EDGE'}
+ ]
+ },
+ page_orientation: {
+ option: [
+ {type: 'PORTRAIT', is_default: true}, {type: 'LANDSCAPE'},
+ {type: 'AUTO'}
+ ]
+ },
+ media_size: {
+ option: [
+ {
+ name: 'NA_LETTER',
+ width_microns: 215900,
+ height_microns: 279400,
+ is_default: true,
+ custom_display_name: 'Letter',
+ },
+ {
+ name: 'CUSTOM_SQUARE',
+ width_microns: 215900,
+ height_microns: 215900,
+ custom_display_name: 'CUSTOM_SQUARE',
+ }
+ ]
+ },
+ vendor_capability: [],
+ }
+ };
+ return dest;
+ },
+ },
+
+ /** @type {print_preview.DocumentInfo} */
+ documentInfo: {
+ type: Object,
+ notify: true,
+ value: function() {
+ const info = new print_preview.DocumentInfo();
+ info.init(false, 'DocumentTitle', true);
+ info.updatePageCount(5);
+ info.fitToPageScaling_ = 94;
+ return info;
+ },
+ },
+
+ /** @type {!print_preview_new.State} */
+ state: {
+ type: Object,
+ notify: true,
+ value: {
+ previewLoading: false,
+ previewFailed: false,
+ cloudPrintError: '',
+ privetExtensionError: '',
+ invalidSettings: false,
+ },
+ },
+ },
+
+ observers:
+ ['updateSettingsAvailable_(' +
+ 'destination.id, destination.capabilities, ' +
+ 'documentInfo.isModifiable, documentInfo.hasCssMediaStyles,' +
+ 'documentInfo.hasSelection)'],
+ /**
+ * @private {!Array<string>} List of capability types considered color.
+ * @const
+ */
+ COLOR_TYPES_: ['STANDARD_COLOR', 'CUSTOM_COLOR'],
+
+ /**
+ * @private {!Array<string>} List of capability types considered monochrome.
+ * @const
+ */
+ MONOCHROME_TYPES_: ['STANDARD_MONOCHROME', 'CUSTOM_MONOCHROME'],
+
+ /**
+ * Updates the availability of the settings sections.
+ * @private
+ */
+ updateSettingsAvailable_: function() {
+ const caps = (!!this.destination && !!this.destination.capabilities) ?
+ this.destination.capabilities.printer :
+ null;
+ const isSaveToPdf = this.destination.id ==
+ print_preview.Destination.GooglePromotedId.SAVE_AS_PDF;
+ const knownSizeToSaveAsPdf = isSaveToPdf &&
+ (!this.documentInfo.isModifiable ||
+ this.documentInfo.hasCssMediaStyles);
+
+ this.set('settings.copies.available', !!caps && !!(caps.copies));
+ this.set('settings.collate.available', !!caps && !!(caps.collate));
+ this.set('settings.layout.available', this.isLayoutAvailable_(caps));
+ this.set('settings.color.available', this.isColorAvailable_(caps));
+ this.set('settings.margins.available', this.documentInfo.isModifiable);
+ this.set(
+ 'settings.mediaSize.available',
+ !!caps && !!caps.media_size && !knownSizeToSaveAsPdf);
+ this.set(
+ 'settings.dpi.available',
+ !!caps && !!caps.dpi && !!caps.dpi.option &&
+ caps.dpi.option.length > 1);
+ this.set(
+ 'settings.fitToPage.available',
+ !this.documentInfo.isModifiable && !isSaveToPdf);
+ this.set('settings.scaling.available', !knownSizeToSaveAsPdf);
+ this.set('settings.duplex.available', !!caps && !!caps.duplex);
+ this.set(
+ 'settings.cssBackground.available', this.documentInfo.isModifiable);
+ this.set(
+ 'settings.selectionOnly.available',
+ this.documentInfo.isModifiable && this.documentInfo.hasSelection);
+ this.set('settings.headerFooter.available', this.documentInfo.isModifiable);
+ this.set('settings.rasterize.available', !this.documentInfo.isModifiable);
+ },
+
+ /** @param {?print_preview.CddCapabilities} caps The printer capabilities. */
+ isLayoutAvailable_: function(caps) {
+ if (!caps || !caps.page_orientation || !caps.page_orientation.option ||
+ !this.documentInfo.isModifiable ||
+ this.documentInfo.hasCssMediaStyles) {
+ return false;
+ }
+ let hasAutoOrPortraitOption = false;
+ let hasLandscapeOption = false;
+ caps.page_orientation.option.forEach(option => {
+ hasAutoOrPortraitOption = hasAutoOrPortraitOption ||
+ option.type == 'AUTO' || option.type == 'PORTRAIT';
+ hasLandscapeOption = hasLandscapeOption || option.type == 'LANDSCAPE';
+ });
+ return hasLandscapeOption && hasAutoOrPortraitOption;
+ },
+
+ /** @param {?print_preview.CddCapabilities} caps The printer capabilities. */
+ isColorAvailable_: function(caps) {
+ if (!caps || !caps.color || !caps.color.option)
+ return false;
+ let hasColor = false;
+ let hasMonochrome = false;
+ caps.color.option.forEach(option => {
+ const type = assert(option.type);
+ hasColor = hasColor || this.COLOR_TYPES_.includes(option.type);
+ hasMonochrome =
+ hasMonochrome || this.MONOCHROME_TYPES_.includes(option.type);
+ });
+ return hasColor && hasMonochrome;
+ },
+});
diff --git a/chromium/chrome/browser/resources/print_preview/new/number_settings_section.html b/chromium/chrome/browser/resources/print_preview/new/number_settings_section.html
new file mode 100644
index 00000000000..dfea6be0f89
--- /dev/null
+++ b/chromium/chrome/browser/resources/print_preview/new/number_settings_section.html
@@ -0,0 +1,48 @@
+<link rel="import" href="chrome://resources/html/polymer.html">
+
+<link rel="import" href="input_css.html">
+<link rel="import" href="print_preview_shared_css.html">
+<link rel="import" href="settings_section.html">
+
+<dom-module id="print-preview-number-settings-section">
+ <template>
+ <style include="print-preview-shared input">
+ input[type='number'] {
+ -webkit-margin-end: 16px;
+ margin-bottom: 2.5px;
+ margin-top: 2.5px;
+ }
+
+ :host(.multirow-controls) [slot='title'] {
+ --settings-section-title-style: {
+ padding-top: 7px;
+ align-self: flex-start;
+ }
+ }
+
+ :host .input-wrapper {
+ align-items: center;
+ display: flex;
+ width: 100%;
+ }
+ </style>
+ <print-preview-settings-section
+ class="input-settings-section multirow-controls">
+ <span slot="title" id="section-title">[[inputLabel]]</span>
+ <div slot="controls">
+ <slot name="opt-outside-content"></slot>
+ <span class="input-wrapper">
+ <input class="user-value" type="number" value="{{inputString::input}}"
+ max="[[maxValue]]" min="[[minValue]]" on-blur="onBlur_"
+ on-keydown="onKeydown_" aria-labelled-by="section-title">
+ <slot name="opt-inside-content"></slot>
+ </span>
+ <span class="hint" aria-live="polite"
+ hidden$="[[hintHidden_(inputString, inputValid)]]">
+ [[hintMessage]]
+ </span>
+ </div>
+ </print-preview-settings-section>
+ </template>
+ <script src="number_settings_section.js"></script>
+</dom-module>
diff --git a/chromium/chrome/browser/resources/print_preview/new/number_settings_section.js b/chromium/chrome/browser/resources/print_preview/new/number_settings_section.js
new file mode 100644
index 00000000000..4084b852b71
--- /dev/null
+++ b/chromium/chrome/browser/resources/print_preview/new/number_settings_section.js
@@ -0,0 +1,70 @@
+// Copyright 2017 The Chromium 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: 'print-preview-number-settings-section',
+
+ properties: {
+ /** @type {string} */
+ inputString: {
+ type: String,
+ notify: true,
+ },
+
+ /** @type {boolean} */
+ inputValid: {
+ type: Boolean,
+ notify: true,
+ computed: 'computeValid_(inputString)',
+ },
+
+ /** @type {string} */
+ defaultValue: String,
+
+ /** @type {number} */
+ maxValue: Number,
+
+ /** @type {number} */
+ minValue: Number,
+
+ /** @type {string} */
+ inputLabel: String,
+
+ /** @type {string} */
+ hintMessage: String,
+ },
+
+ /**
+ * @param {!KeyboardEvent} e The keyboard event
+ */
+ onKeydown_: function(e) {
+ if (e.key == '.' || e.key == 'e' || e.key == '-')
+ e.preventDefault();
+ },
+
+ /** @private */
+ onBlur_: function() {
+ if (this.inputString == '')
+ this.set('inputString', this.defaultValue);
+ },
+
+ /**
+ * @return {boolean} Whether input value represented by inputString is
+ * valid.
+ * @private
+ */
+ computeValid_: function() {
+ // Make sure value updates first, in case inputString was updated by JS.
+ this.$$('.user-value').value = this.inputString;
+ return this.$$('.user-value').validity.valid && this.inputString != '';
+ },
+
+ /**
+ * @return {boolean} Whether error message should be hidden.
+ * @private
+ */
+ hintHidden_: function() {
+ return this.inputValid || this.inputString == '';
+ },
+});
diff --git a/chromium/chrome/browser/resources/print_preview/new/other_options_settings.html b/chromium/chrome/browser/resources/print_preview/new/other_options_settings.html
new file mode 100644
index 00000000000..71349530d43
--- /dev/null
+++ b/chromium/chrome/browser/resources/print_preview/new/other_options_settings.html
@@ -0,0 +1,48 @@
+<link rel="import" href="chrome://resources/html/polymer.html">
+
+<link rel="import" href="checkbox_radio_css.html">
+<link rel="import" href="print_preview_shared_css.html">
+<link rel="import" href="settings_section.html">
+
+<dom-module id="print-preview-other-options-settings">
+ <template>
+ <style include="print-preview-shared checkbox-radio">
+ </style>
+ <print-preview-settings-section class="multirow-controls">
+ <span slot="title" id="options-label">$i18n{optionsLabel}</span>
+ <div slot="controls" class="checkbox">
+ <div id="header-footer-container">
+ <label aria-live="polite">
+ <input type="checkbox">
+ <span>$i18n{optionHeaderFooter}</span>
+ </label>
+ </div>
+ <div id="duplex-container">
+ <label aria-live="polite">
+ <input type="checkbox" checked="{{duplexValue_::change}}">
+ <span>$i18n{optionTwoSided}</span>
+ </label>
+ </div>
+ <div id="css-background-container">
+ <label aria-live="polite">
+ <input type="checkbox">
+ <span>$i18n{optionBackgroundColorsAndImages}</span>
+ </label>
+ </div>
+ <div id="rasterize-container">
+ <label aria-live="polite">
+ <input type="checkbox">
+ <span>$i18n{optionRasterize}</span>
+ </label>
+ </div>
+ <div id="selection-only-container">
+ <label aria-live="polite">
+ <input type="checkbox">
+ <span>$i18n{optionSelectionOnly}</span>
+ </label>
+ </div>
+ </div>
+ </print-preview-settings-section>
+ </template>
+ <script src="other_options_settings.js"></script>
+</dom-module>
diff --git a/chromium/chrome/browser/resources/print_preview/new/other_options_settings.js b/chromium/chrome/browser/resources/print_preview/new/other_options_settings.js
new file mode 100644
index 00000000000..5399d54526d
--- /dev/null
+++ b/chromium/chrome/browser/resources/print_preview/new/other_options_settings.js
@@ -0,0 +1,32 @@
+// Copyright 2017 The Chromium 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: 'print-preview-other-options-settings',
+
+ behaviors: [SettingsBehavior],
+
+ properties: {
+ /** @private {boolean} */
+ duplexValue_: Boolean,
+ },
+
+ observers: [
+ 'onInitialized_(settings.duplex.value)',
+ 'onDuplexChange_(duplexValue_)',
+ ],
+
+ isInitialized_: false,
+
+ onInitialized_: function() {
+ if (this.isInitialized_)
+ return;
+ this.set('duplexValue_', this.getSetting('duplex').value);
+ this.isInitialized_ = true;
+ },
+
+ onDuplexChange_: function() {
+ this.setSetting('duplex', this.duplexValue_);
+ },
+});
diff --git a/chromium/chrome/browser/resources/print_preview/new/pages_settings.html b/chromium/chrome/browser/resources/print_preview/new/pages_settings.html
new file mode 100644
index 00000000000..72fc32d2160
--- /dev/null
+++ b/chromium/chrome/browser/resources/print_preview/new/pages_settings.html
@@ -0,0 +1,58 @@
+<link rel="import" href="chrome://resources/html/polymer.html">
+
+<link rel="import" href="chrome://resources/html/cr.html">
+<link rel="import" href="checkbox_radio_css.html">
+<link rel="import" href="../data/document_info.html">
+<link rel="import" href="input_css.html">
+<link rel="import" href="print_preview_shared_css.html">
+<link rel="import" href="settings_behavior.html">
+<link rel="import" href="settings_section.html">
+
+<dom-module id="print-preview-pages-settings">
+ <template>
+ <style include="print-preview-shared checkbox-radio input">
+ :host .radio .user-value {
+ -webkit-margin-start: 0.6em;
+ flex: 1;
+ width: 100%;
+ }
+
+ [slot='title'] {
+ --settings-section-title-style: {
+ padding-top: 7px;
+ align-self: flex-start;
+ }
+ }
+ </style>
+ <print-preview-settings-section
+ class="input-settings-section multirow-controls">
+ <span slot="title">$i18n{pagesLabel}</span>
+ <div slot="controls">
+ <div class="radio">
+ <label><input type="radio" name="pages" id="all-radio-button"
+ checked="{{allSelected_::change}}">
+ <span>$i18n{optionAllPages}</span>
+ </label>
+ <label class="custom-input-wrapper"
+ for="page-settings-custom-input" tabindex=-1>
+ <input type="radio" name="pages" id="custom-radio-button"
+ on-click="onCustomRadioClick_">
+ <input class="user-value" type="text"
+ value="{{inputString_::input}}" id="page-settings-custom-input"
+ checked="{{customSelected_::change}}"
+ pattern="([0-9]*(-)?[0-9]*(,)( )?)*([0-9]*(-)?[0-9]*(,)?( )?)?"
+ on-focus="onCustomInputFocus_" on-blur="onCustomInputBlur_"
+ placeholder="$i18n{examplePageRangeText}"
+ aria-label="$i18n{examplePageRangeText}">
+ </label>
+ </div>
+ <span class="hint" aria-live="polite"
+ inner-h-t-m-l="[[getHintMessage_(errorState_,
+ documentInfo.pageCount)]]"
+ hidden$="[[hintHidden_(inputString_, errorState_)]]">
+ </span>
+ </div>
+ </print-preview-settings-section>
+ </template>
+ <script src="pages_settings.js"></script>
+</dom-module>
diff --git a/chromium/chrome/browser/resources/print_preview/new/pages_settings.js b/chromium/chrome/browser/resources/print_preview/new/pages_settings.js
new file mode 100644
index 00000000000..7b1408b6ac2
--- /dev/null
+++ b/chromium/chrome/browser/resources/print_preview/new/pages_settings.js
@@ -0,0 +1,215 @@
+// Copyright 2017 The Chromium 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('print_preview_new');
+
+/** @enum {number} */
+const PagesInputErrorState = {
+ NO_ERROR: 0,
+ INVALID_SYNTAX: 1,
+ OUT_OF_BOUNDS: 2,
+};
+
+Polymer({
+ is: 'print-preview-pages-settings',
+
+ behaviors: [SettingsBehavior],
+
+ properties: {
+ /** @type {!print_preview.DocumentInfo} */
+ documentInfo: Object,
+
+ /** @private {string} */
+ inputString_: {
+ type: String,
+ value: '',
+ },
+
+ /** @private {!Array<number>} */
+ allPagesArray_: {
+ type: Array,
+ computed: 'computeAllPagesArray_(documentInfo.pageCount)',
+ },
+
+ /** @private {boolean} */
+ allSelected_: {
+ type: Boolean,
+ value: true,
+ },
+
+ /** @private {boolean} */
+ customSelected_: {
+ type: Boolean,
+ value: false,
+ },
+
+ /** @private {!Array<number>} */
+ pagesToPrint_: {
+ type: Array,
+ computed: 'computePagesToPrint_(' +
+ 'inputString_, allSelected_, allPagesArray_)',
+ },
+
+ /** @private {!PagesInputErrorState} */
+ errorState_: {
+ type: Number,
+ computed: 'computeErrorState_(pagesToPrint_)',
+ },
+
+ },
+
+ observers: [
+ 'onRangeChange_(errorState_, pagesToPrint_)',
+ 'onRadioChange_(allSelected_, customSelected_)'
+ ],
+
+ /**
+ * @return {!Array<number>}
+ * @private
+ */
+ computeAllPagesArray_: function() {
+ const array = new Array(this.documentInfo.pageCount);
+ for (let i = 0; i < array.length; i++)
+ array[i] = i + 1;
+ return array;
+ },
+
+ /**
+ * Updates pages to print and error state based on the validity and
+ * current value of the input.
+ * @return {!Array<number>}
+ * @private
+ */
+ computePagesToPrint_: function() {
+ if (this.allSelected_ || this.inputString_.trim() == '')
+ return this.allPagesArray_;
+ if (!this.$$('.user-value').validity.valid)
+ return [];
+
+ const pages = [];
+ const added = {};
+ const ranges = this.inputString_.split(',');
+ const maxPage = this.allPagesArray_.length;
+ for (let range of ranges) {
+ range = range.trim();
+ if (range == '')
+ continue;
+ const limits = range.split('-');
+ let min = parseInt(limits[0], 10);
+ if (min < 1)
+ return [];
+ if (limits.length == 1) {
+ if (min > maxPage)
+ return [-1];
+ if (!added.hasOwnProperty(min)) {
+ pages.push(min);
+ added[min] = true;
+ }
+ continue;
+ }
+
+ let max = parseInt(limits[1], 10);
+ if (isNaN(min))
+ min = 1;
+ if (isNaN(max))
+ max = maxPage;
+ if (min > max)
+ return [];
+ if (max > maxPage)
+ return [-1];
+ for (let i = min; i <= max; i++) {
+ if (!added.hasOwnProperty(i)) {
+ pages.push(i);
+ added[i] = true;
+ }
+ }
+ }
+ return pages;
+ },
+
+ /**
+ * @return {!PagesInputErrorState}
+ * @private
+ */
+ computeErrorState_: function() {
+ if (this.pagesToPrint_.length == 0)
+ return PagesInputErrorState.INVALID_SYNTAX;
+ if (this.pagesToPrint_[0] == -1)
+ return PagesInputErrorState.OUT_OF_BOUNDS;
+ return PagesInputErrorState.NO_ERROR;
+ },
+
+ /**
+ * Updates the model with pages and validity, and adds error styling if
+ * needed.
+ * @private
+ */
+ onRangeChange_: function() {
+ if (this.errorState_ != PagesInputErrorState.NO_ERROR) {
+ this.setSettingValid('pages', false);
+ this.$$('.user-value').classList.add('invalid');
+ return;
+ }
+ this.$$('.user-value').classList.remove('invalid');
+ this.setSettingValid('pages', true);
+ this.setSetting('pages', this.pagesToPrint_);
+ },
+
+ /** @private */
+ onRadioChange_: function() {
+ if (this.$$('#all-radio-button').checked)
+ this.customSelected_ = false;
+ if (this.$$('#custom-radio-button').checked)
+ this.allSelected_ = false;
+ },
+
+ /** @private */
+ onCustomRadioClick_: function() {
+ this.$$('#page-settings-custom-input').focus();
+ },
+
+ /** @private */
+ onCustomInputFocus_: function() {
+ this.$$('#all-radio-button').checked = false;
+ this.$$('#custom-radio-button').checked = true;
+ this.customSelected_ = true;
+ },
+
+ /**
+ * @param {Event} event Contains information about where focus is going.
+ * @private
+ */
+ onCustomInputBlur_: function(event) {
+ if (this.inputString_.trim() == '' &&
+ event.relatedTarget != this.$$('.custom-input-wrapper') &&
+ event.relatedTarget != this.$$('#custom-radio-button')) {
+ this.$$('#all-radio-button').checked = true;
+ this.$$('#custom-radio-button').checked = false;
+ this.allSelected_ = true;
+ }
+ },
+
+ /**
+ * @return {string} Gets message to show as hint.
+ * @private
+ */
+ getHintMessage_: function() {
+ if (this.errorState_ == PagesInputErrorState.INVALID_SYNTAX) {
+ return loadTimeData.getStringF(
+ 'pageRangeSyntaxInstruction',
+ loadTimeData.getString('examplePageRangeText'));
+ } else {
+ return loadTimeData.getStringF(
+ 'pageRangeLimitInstructionWithValue', this.documentInfo.pageCount);
+ }
+ },
+
+ /**
+ * @return {boolean} Whether to hide the hint.
+ * @private
+ */
+ hintHidden_: function() {
+ return this.errorState_ == PagesInputErrorState.NO_ERROR;
+ }
+});
diff --git a/chromium/chrome/browser/resources/print_preview/new/print_preview_shared_css.html b/chromium/chrome/browser/resources/print_preview/new/print_preview_shared_css.html
new file mode 100644
index 00000000000..63bcc781674
--- /dev/null
+++ b/chromium/chrome/browser/resources/print_preview/new/print_preview_shared_css.html
@@ -0,0 +1,136 @@
+<!-- Most styles copied from resources/css/widgets.css. -->
+<link rel="import" href="chrome://resources/html/polymer.html">
+
+<dom-module id="print-preview-shared">
+ <template>
+ <style>
+ h1 {
+ line-height: 1;
+ user-select: none;
+ }
+
+ /* Default state ********************************************************/
+
+ button,
+ input[type='button'],
+ select,
+ input[type='checkbox'],
+ input[type='radio'] {
+ -webkit-appearance: none;
+ background-image: linear-gradient(#ededed, #ededed 38%, #dedede);
+ border: 1px solid rgba(0, 0, 0, 0.25);
+ border-radius: 2px;
+ box-shadow: 0 1px 0 rgba(0, 0, 0, 0.08),
+ inset 0 1px 2px rgba(255, 255, 255, 0.75);
+ color: #444;
+ font: inherit;
+ margin: 0 1px 0 0;
+ outline: none;
+ text-shadow: 0 1px 0 rgb(240, 240, 240);
+ user-select: none;
+ }
+
+ button,
+ input[type='button'],
+ select {
+ min-height: 2em;
+ min-width: 4em;
+ padding-bottom: 1px;
+ <if expr="is_win or is_macosx">
+ /* The following platform-specific rule is necessary to get adjacent
+ * buttons, text inputs, and so forth to align on their borders while
+ * also aligning on the text's baselines. */
+ padding-bottom: 2px;
+ </if>
+ padding-top: 1px;
+ }
+
+ input[type='number'],
+ input[type='search'],
+ input[type='text'],
+ input:not([type]),
+ textarea {
+ border: 1px solid #bfbfbf;
+ border-radius: 2px;
+ box-sizing: border-box;
+ color: #444;
+ font: inherit;
+ margin: 0;
+ /* Use min-height to accommodate addditional padding for touch as
+ * needed. */
+ min-height: 2em;
+ outline: none;
+ padding: 3px;
+ <if expr="is_win or is_macosx or is_ios">
+ /* For better alignment between adjacent buttons and inputs. */
+ padding-bottom: 4px;
+ </if>
+ }
+
+ :root {
+ <if expr="not is_ios">
+ /* Hover **************************************************************/
+ --print-preview-hover: {
+ border-color: rgba(0, 0, 0, 0.3);
+ box-shadow: 0 1px 0 rgba(0, 0, 0, 0.12),
+ inset 0 1px 2px rgba(255, 255, 255, 0.95);
+ color: black;
+ };
+ </if>
+
+ /* Active *************************************************************/
+ --print-preview-active: {
+ box-shadow: none;
+ text-shadow: none;
+ };
+ }
+
+ /* Disabled *************************************************************/
+
+ :disabled:-webkit-any(
+ button,
+ input[type='button'],
+ select) {
+ background-image: linear-gradient(#f1f1f1, #f1f1f1 38%, #e6e6e6);
+ border-color: rgba(80, 80, 80, 0.2);
+ box-shadow: 0 1px 0 rgba(80, 80, 80, 0.08),
+ inset 0 1px 2px rgba(255, 255, 255, 0.75);
+ color: #aaa;
+ }
+
+ input:disabled:-webkit-any([type='search'],
+ [type='text'],
+ :not([type])) {
+ color: #999;
+ }
+
+ /* Focus ****************************************************************/
+
+ :enabled:focus:-webkit-any(
+ select,
+ input[type='checkbox'],
+ input[type='number'],
+ input[type='radio'],
+ input[type='search'],
+ input[type='text'],
+ input:not([type]),
+ button,
+ input[type='button']) {
+ /* We use border color because it follows the border radius (unlike
+ * outline). This is particularly noticeable on mac. */
+ border-color: rgb(77, 144, 254);
+ outline: none;
+ /* OVERRIDE */
+ transition: border-color 200ms;
+ }
+
+ html:not(.focus-outline-visible)
+ :enabled:focus:-webkit-any(input[type='checkbox'],
+ input[type='radio'],
+ button) {
+ border-color: rgba(0,0,0,0.25);
+ }
+
+ </style>
+ </template>
+</dom-module>
diff --git a/chromium/chrome/browser/resources/print_preview/new/scaling_settings.html b/chromium/chrome/browser/resources/print_preview/new/scaling_settings.html
new file mode 100644
index 00000000000..6386cd27cab
--- /dev/null
+++ b/chromium/chrome/browser/resources/print_preview/new/scaling_settings.html
@@ -0,0 +1,28 @@
+<link rel="import" href="chrome://resources/html/polymer.html">
+
+<link rel="import" href="checkbox_radio_css.html">
+<link rel="import" href="../data/document_info.html">
+<link rel="import" href="number_settings_section.html">
+<link rel="import" href="print_preview_shared_css.html">
+<link rel="import" href="settings_behavior.html">
+
+<dom-module id="print-preview-scaling-settings">
+ <template>
+ <style include="print-preview-shared checkbox-radio">
+ </style>
+ <print-preview-number-settings-section max-value=200 min-value=10
+ default-value="100" input-label="$i18n{scalingLabel}"
+ input-string="{{inputString_}}" input-valid="{{inputValid_}}"
+ hint-message="$i18n{scalingInstruction}" class="multirow-controls">
+ <div slot="opt-outside-content" id="fit-to-page-container"
+ class="checkbox" hidden$="[[!settings.fitToPage.available]]">
+ <label aria-live="polite">
+ <input class="checkbox" type="checkbox"
+ on-change="onFitToPageChange_">
+ <span>$i18n{optionFitToPage}</span>
+ </label>
+ </div>
+ </print-preview-number-settings-section>
+ </template>
+ <script src="scaling_settings.js"></script>
+</dom-module>
diff --git a/chromium/chrome/browser/resources/print_preview/new/scaling_settings.js b/chromium/chrome/browser/resources/print_preview/new/scaling_settings.js
new file mode 100644
index 00000000000..a6495e85baf
--- /dev/null
+++ b/chromium/chrome/browser/resources/print_preview/new/scaling_settings.js
@@ -0,0 +1,80 @@
+// Copyright 2017 The Chromium 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: 'print-preview-scaling-settings',
+
+ behaviors: [SettingsBehavior],
+
+ properties: {
+ /** @type {Object} */
+ documentInfo: Object,
+
+ /** @private {string} */
+ inputString_: String,
+
+ /** @private {boolean} */
+ inputValid_: Boolean,
+ },
+
+ /** @private {string} */
+ lastValidScaling_: '100',
+
+ /** @private {number} */
+ fitToPageFlag_: 0,
+
+ /** @private {boolean} */
+ isInitialized_: false,
+
+ observers: [
+ 'onInputChanged_(inputString_, inputValid_, documentInfo.isModifiable)',
+ 'onInitialized_(settings.scaling.value)'
+ ],
+
+ /**
+ * Updates the input string when the setting has been initialized.
+ * @private
+ */
+ onInitialized_: function() {
+ // Avoid loops from setting inputString_ -> onInputChanged_ sets scaling
+ // value -> onInitialized_ sets inputString_
+ if (this.isInitialized_)
+ return;
+ this.isInitialized_ = true;
+ const scaling = this.getSetting('scaling');
+ this.inputString_ = /** @type {string} */ (scaling.value);
+ },
+
+ /**
+ * Updates model.settings.scaling based on the validity and current value of
+ * the scaling input.
+ * @private
+ */
+ onInputChanged_: function() {
+ if (this.fitToPageFlag_ > 0) {
+ this.fitToPageFlag_--;
+ } else {
+ const checkbox = this.$$('.checkbox input[type="checkbox"]');
+ if (checkbox.checked && !this.documentInfo.isModifiable) {
+ checkbox.checked = false;
+ } else if (this.inputValid_) {
+ this.lastValidScaling_ = this.inputString_;
+ }
+ this.setSetting('scaling', this.inputString_);
+ }
+ this.setSettingValid('scaling', this.inputValid_);
+ },
+
+ /**
+ * Updates scaling as needed based on the value of the fit to page checkbox.
+ */
+ onFitToPageChange_: function() {
+ if (this.$$('.checkbox input[type="checkbox"]').checked) {
+ this.fitToPageFlag_ = 2;
+ this.set('inputString_', this.documentInfo.fitToPageScaling);
+ } else {
+ this.set('inputString_', this.lastValidScaling_);
+ }
+ },
+});
diff --git a/chromium/chrome/browser/resources/print_preview/new/select_css.html b/chromium/chrome/browser/resources/print_preview/new/select_css.html
new file mode 100644
index 00000000000..5a316158da1
--- /dev/null
+++ b/chromium/chrome/browser/resources/print_preview/new/select_css.html
@@ -0,0 +1,40 @@
+<!-- Most styles copied from resources/css/widgets.css. -->
+<link rel="import" href="chrome://resources/html/polymer.html">
+
+<dom-module id="select">
+ <template>
+ <style include="print-preview-shared">
+ select {
+ -webkit-appearance: none;
+ -webkit-padding-end: 24px;
+ -webkit-padding-start: 10px;
+ /* OVERRIDE */
+ background-image: url(chrome://resources/images/select.png),
+ linear-gradient(#ededed, #ededed 38%, #dedede);
+ background-position: right center;
+ background-repeat: no-repeat;
+ height: 28px;
+ width: 100%;
+ }
+
+ <if expr="not is_ios">
+ select:enabled:hover {
+ background-image: url(chrome://resources/images/select.png),
+ linear-gradient(#f0f0f0, #f0f0f0 38%, #e0e0e0);
+ @apply(--print-preview-hover);
+ }
+ </if>
+
+ select:enabled:active {
+ background-image: url(chrome://resources/images/select.png),
+ linear-gradient(#e7e7e7, #e7e7e7 38%, #d7d7d7);
+ @apply(--print-preview-active);
+ }
+
+ select:disabled {
+ background-image: url(chrome://resources/images/disabled_select.png),
+ linear-gradient(#f1f1f1, #f1f1f1 38%, #e6e6e6);
+ }
+ </style>
+ </template>
+</dom-module>
diff --git a/chromium/chrome/browser/resources/print_preview/new/settings_behavior.html b/chromium/chrome/browser/resources/print_preview/new/settings_behavior.html
new file mode 100644
index 00000000000..72cf371c35d
--- /dev/null
+++ b/chromium/chrome/browser/resources/print_preview/new/settings_behavior.html
@@ -0,0 +1,3 @@
+<link rel="import" href="chrome://resources/html/assert.html">
+
+<script src="settings_behavior.js"></script>
diff --git a/chromium/chrome/browser/resources/print_preview/new/settings_behavior.js b/chromium/chrome/browser/resources/print_preview/new/settings_behavior.js
new file mode 100644
index 00000000000..9d295229086
--- /dev/null
+++ b/chromium/chrome/browser/resources/print_preview/new/settings_behavior.js
@@ -0,0 +1,48 @@
+// Copyright 2017 The Chromium 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 */
+const SettingsBehavior = {
+ properties: {
+ /** @type {Object} */
+ settings: {
+ type: Object,
+ notify: true,
+ },
+ },
+
+ /**
+ * @param {string} settingName Name of the setting to get.
+ * @return {print_preview_new.Setting} The setting object.
+ */
+ getSetting: function(settingName) {
+ const setting = /** @type {print_preview_new.Setting} */ (
+ this.get(settingName, this.settings));
+ assert(!!setting, 'Setting is missing: ' + settingName);
+ return setting;
+ },
+
+ /**
+ * @param {string} settingName Name of the setting to set
+ * @param {boolean | string | number | Array | Object} value The value to set
+ * the setting to.
+ */
+ setSetting: function(settingName, value) {
+ const setting = this.getSetting(settingName);
+ this.set(`settings.${settingName}.value`, value);
+ },
+
+ /**
+ * @param {string} settingName Name of the setting to set
+ * @param {boolean} valid Whether the setting value is currently valid.
+ */
+ setSettingValid: function(settingName, valid) {
+ const setting = this.getSetting(settingName);
+ // Should not set the setting to invalid if it is not available, as there
+ // is no way for the user to change the value in this case.
+ if (!valid)
+ assert(setting.available, 'Setting is not available: ' + settingName);
+ this.set(`settings.${settingName}.valid`, valid);
+ }
+};
diff --git a/chromium/chrome/browser/resources/print_preview/new/settings_section.html b/chromium/chrome/browser/resources/print_preview/new/settings_section.html
new file mode 100644
index 00000000000..be94c427342
--- /dev/null
+++ b/chromium/chrome/browser/resources/print_preview/new/settings_section.html
@@ -0,0 +1,34 @@
+<link rel="import" href="chrome://resources/html/polymer.html">
+
+<dom-module id="print-preview-settings-section">
+ <template>
+ <style>
+ :host {
+ align-items: center;
+ display: flex;
+ margin-top: 10px;
+ padding: 5px 20px;
+ }
+
+ ::slotted([slot=controls]) {
+ flex: 1;
+ }
+
+ ::slotted([slot=title]) {
+ -webkit-padding-end: 20px;
+ color: #646464;
+ font-size: 1em;
+ width: 70px;
+ word-break: break-word;
+ }
+
+ :host(.multirow-controls) ::slotted([slot=title]) {
+ align-self: flex-start;
+ padding-top: 7px;
+ }
+ </style>
+ <slot name="title"></slot>
+ <slot name="controls"></slot>
+ </template>
+ <script src="settings_section.js"></script>
+</dom-module>
diff --git a/chromium/chrome/browser/resources/print_preview/new/settings_section.js b/chromium/chrome/browser/resources/print_preview/new/settings_section.js
new file mode 100644
index 00000000000..a28a5054954
--- /dev/null
+++ b/chromium/chrome/browser/resources/print_preview/new/settings_section.js
@@ -0,0 +1,7 @@
+// Copyright 2017 The Chromium 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: 'print-preview-settings-section',
+});
diff --git a/chromium/chrome/browser/resources/print_preview/new/strings.html b/chromium/chrome/browser/resources/print_preview/new/strings.html
new file mode 100644
index 00000000000..3bf66307de1
--- /dev/null
+++ b/chromium/chrome/browser/resources/print_preview/new/strings.html
@@ -0,0 +1,2 @@
+<link rel="import" href="chrome://resources/html/load_time_data.html">
+<script src="../strings.js"></script>
diff --git a/chromium/chrome/browser/resources/print_preview/new/throbber_css.html b/chromium/chrome/browser/resources/print_preview/new/throbber_css.html
new file mode 100644
index 00000000000..747c1667f65
--- /dev/null
+++ b/chromium/chrome/browser/resources/print_preview/new/throbber_css.html
@@ -0,0 +1,15 @@
+<!-- Styles copied from resources/css/throbber.css. -->
+<link rel="import" href="chrome://resources/html/polymer.html">
+
+<dom-module id="throbber">
+ <template>
+ <style>
+ .throbber {
+ background: url(chrome://resources/images/throbber_small.svg) no-repeat;
+ display: inline-block;
+ height: 16px;
+ width: 16px;
+ }
+ </style>
+ </template>
+</dom-module>
diff --git a/chromium/chrome/browser/resources/print_preview/preview_generator.js b/chromium/chrome/browser/resources/print_preview/preview_generator.js
index 8d47ae1275b..93c0c2f083c 100644
--- a/chromium/chrome/browser/resources/print_preview/preview_generator.js
+++ b/chromium/chrome/browser/resources/print_preview/preview_generator.js
@@ -5,166 +5,133 @@
cr.define('print_preview', function() {
'use strict';
- /**
- * Interface to the Chromium print preview generator.
- * @param {!print_preview.DestinationStore} destinationStore Used to get the
- * currently selected destination.
- * @param {!print_preview.PrintTicketStore} printTicketStore Used to read the
- * state of the ticket and write document information.
- * @param {!print_preview.NativeLayer} nativeLayer Used to communicate to
- * Chromium's preview rendering system.
- * @param {!print_preview.DocumentInfo} documentInfo Document data model.
- * @param {!WebUIListenerTracker} listenerTracker Tracker for the WebUI
- * listeners added in the PreviewGenerator constructor.
- * @constructor
- * @extends {cr.EventTarget}
- */
- function PreviewGenerator(
- destinationStore, printTicketStore, nativeLayer, documentInfo,
- listenerTracker) {
- cr.EventTarget.call(this);
-
- /**
- * Used to get the currently selected destination.
- * @type {!print_preview.DestinationStore}
- * @private
- */
- this.destinationStore_ = destinationStore;
-
- /**
- * Used to read the state of the ticket and write document information.
- * @type {!print_preview.PrintTicketStore}
- * @private
- */
- this.printTicketStore_ = printTicketStore;
-
- /**
- * Interface to the Chromium native layer.
- * @type {!print_preview.NativeLayer}
- * @private
- */
- this.nativeLayer_ = nativeLayer;
-
- /**
- * Document data model.
- * @type {!print_preview.DocumentInfo}
- * @private
- */
- this.documentInfo_ = documentInfo;
-
- /**
- * ID of current in-flight request. Requests that do not share this ID will
- * be ignored.
- * @type {number}
- * @private
- */
- this.inFlightRequestId_ = -1;
-
- /**
- * Whether the current in flight request requires generating draft pages for
- * print preview. This is true only for modifiable documents when the print
- * settings has changed sufficiently to require re-rendering.
- * @private {boolean}
- */
- this.generateDraft_ = false;
-
- /**
- * Media size to generate preview with. {@code null} indicates default size.
- * @type {print_preview.ValueType}
- * @private
- */
- this.mediaSize_ = null;
-
+ class PreviewGenerator extends cr.EventTarget {
/**
- * Whether the previews are being generated in landscape mode.
- * @type {boolean}
- * @private
- */
- this.isLandscapeEnabled_ = false;
-
- /**
- * Whether the previews are being generated with a header and footer.
- * @type {boolean}
- * @private
- */
- this.isHeaderFooterEnabled_ = false;
-
- /**
- * Whether the previews are being generated in color.
- * @type {boolean}
- * @private
- */
- this.colorValue_ = false;
-
- /**
- * Whether the document should be fitted to the page.
- * @type {boolean}
- * @private
- */
- this.isFitToPageEnabled_ = false;
-
- /**
- * The scaling factor (in percent) for the document. Ignored if fit to page
- * is true.
- * @type {number}
- * @private
- */
- this.scalingValue_ = 100;
-
- /**
- * Page ranges setting used used to generate the last preview.
- * @type {Array<{from: number, to: number}>}
- * @private
+ * Interface to the Chromium print preview generator.
+ * @param {!print_preview.DestinationStore} destinationStore Used to get the
+ * currently selected destination.
+ * @param {!print_preview.PrintTicketStore} printTicketStore Used to read
+ * the state of the ticket and write document information.
+ * @param {!print_preview.NativeLayer} nativeLayer Used to communicate to
+ * Chromium's preview rendering system.
+ * @param {!print_preview.DocumentInfo} documentInfo Document data model.
+ * @param {!WebUIListenerTracker} listenerTracker Tracker for the WebUI
+ * listeners added in the PreviewGenerator constructor.
*/
- this.pageRanges_ = null;
-
- /**
- * Margins type used to generate the last preview.
- * @type {!print_preview.ticket_items.MarginsTypeValue}
- * @private
- */
- this.marginsType_ = print_preview.ticket_items.MarginsTypeValue.DEFAULT;
-
- /**
- * Whether the document should have element CSS backgrounds printed.
- * @type {boolean}
- * @private
- */
- this.isCssBackgroundEnabled_ = false;
-
- /**
- * Destination that was selected for the last preview.
- * @type {print_preview.Destination}
- * @private
- */
- this.selectedDestination_ = null;
-
- this.addWebUIEventListeners_(listenerTracker);
- }
-
- /**
- * Event types dispatched by the preview generator.
- * @enum {string}
- */
- PreviewGenerator.EventType = {
- // Dispatched when the document can be printed.
- DOCUMENT_READY: 'print_preview.PreviewGenerator.DOCUMENT_READY',
-
- // Dispatched when a page preview is ready. The previewIndex field of the
- // event is the index of the page in the modified document, not the
- // original. So page 4 of the original document might be previewIndex = 0 of
- // the modified document.
- PAGE_READY: 'print_preview.PreviewGenerator.PAGE_READY',
-
- // Dispatched when the document preview starts to be generated.
- PREVIEW_START: 'print_preview.PreviewGenerator.PREVIEW_START',
-
- // Dispatched when the current print preview request fails.
- FAIL: 'print_preview.PreviewGenerator.FAIL'
- };
-
- PreviewGenerator.prototype = {
- __proto__: cr.EventTarget.prototype,
+ constructor(
+ destinationStore, printTicketStore, nativeLayer, documentInfo,
+ listenerTracker) {
+ super();
+
+ /**
+ * Used to get the currently selected destination.
+ * @private {!print_preview.DestinationStore}
+ */
+ this.destinationStore_ = destinationStore;
+
+ /**
+ * Used to read the state of the ticket and write document information.
+ * @private {!print_preview.PrintTicketStore}
+ */
+ this.printTicketStore_ = printTicketStore;
+
+ /**
+ * Interface to the Chromium native layer.
+ * @private {!print_preview.NativeLayer}
+ */
+ this.nativeLayer_ = nativeLayer;
+
+ /**
+ * Document data model.
+ * @private {!print_preview.DocumentInfo}
+ */
+ this.documentInfo_ = documentInfo;
+
+ /**
+ * ID of current in-flight request. Requests that do not share this ID
+ * will be ignored.
+ * @private {number}
+ */
+ this.inFlightRequestId_ = -1;
+
+ /**
+ * Whether the current in flight request requires generating draft pages
+ * for print preview. This is true only for modifiable documents when the
+ * print settings has changed sufficiently to require re-rendering.
+ * @private {boolean}
+ */
+ this.generateDraft_ = false;
+
+ /**
+ * Media size to generate preview with. {@code null} indicates default
+ * size.
+ * @private {print_preview.ValueType}
+ */
+ this.mediaSize_ = null;
+
+ /**
+ * Whether the previews are being generated in landscape mode.
+ * @private {boolean}
+ */
+ this.isLandscapeEnabled_ = false;
+
+ /**
+ * Whether the previews are being generated with a header and footer.
+ * @private {boolean}
+ */
+ this.isHeaderFooterEnabled_ = false;
+
+ /**
+ * Whether the previews are being generated in color.
+ * @private {boolean}
+ */
+ this.colorValue_ = false;
+
+ /**
+ * Whether the document should be fitted to the page.
+ * @private {boolean}
+ */
+ this.isFitToPageEnabled_ = false;
+
+ /**
+ * The scaling factor (in percent) for the document. Ignored if fit to
+ * page is true.
+ * @private {number}
+ */
+ this.scalingValue_ = 100;
+
+ /**
+ * Page ranges setting used used to generate the last preview.
+ * @private {Array<{from: number, to: number}>}
+ */
+ this.pageRanges_ = null;
+
+ /**
+ * Margins type used to generate the last preview.
+ * @private {!print_preview.ticket_items.MarginsTypeValue}
+ */
+ this.marginsType_ = print_preview.ticket_items.MarginsTypeValue.DEFAULT;
+
+ /**
+ * Whether the document should have element CSS backgrounds printed.
+ * @private {boolean}
+ */
+ this.isCssBackgroundEnabled_ = false;
+
+ /**
+ * Whether the document should have only the selected area printed.
+ * @private {boolean}
+ */
+ this.isSelectionOnlyEnabled_ = false;
+
+ /**
+ * Destination that was selected for the last preview.
+ * @private {print_preview.Destination}
+ */
+ this.selectedDestination_ = null;
+
+ this.addWebUIEventListeners_(listenerTracker);
+ }
/**
* Starts listening for relevant WebUI events and adds the listeners to
@@ -173,14 +140,14 @@ cr.define('print_preview', function() {
* @param {!WebUIListenerTracker} listenerTracker
* @private
*/
- addWebUIEventListeners_: function(listenerTracker) {
+ addWebUIEventListeners_(listenerTracker) {
listenerTracker.add(
'page-count-ready', this.onPageCountReady_.bind(this));
listenerTracker.add(
'page-layout-ready', this.onPageLayoutReady_.bind(this));
listenerTracker.add(
'page-preview-ready', this.onPagePreviewReady_.bind(this));
- },
+ }
/**
* Request that new preview be generated. A preview request will not be
@@ -190,13 +157,13 @@ cr.define('print_preview', function() {
* was requested, and a promise that will resolve when the preview is
* complete (null if no preview was actually requested).
*/
- requestPreview: function() {
+ requestPreview() {
if (!this.printTicketStore_.isTicketValidForPreview() ||
!this.printTicketStore_.isInitialized ||
!this.destinationStore_.selectedDestination) {
return {id: -1, request: null};
}
- var previewChanged = this.hasPreviewChanged_();
+ const previewChanged = this.hasPreviewChanged_();
if (!previewChanged && !this.hasPreviewPageRangeChanged_()) {
// Changes to these ticket items might not trigger a new preview, but
// they still need to be recorded.
@@ -226,7 +193,7 @@ cr.define('print_preview', function() {
this.destinationStore_.selectedDestination, this.printTicketStore_,
this.documentInfo_, this.generateDraft_, this.inFlightRequestId_),
};
- },
+ }
/**
* Dispatches a PAGE_READY event to signal that a page preview is ready.
@@ -239,13 +206,13 @@ cr.define('print_preview', function() {
* @param {number} previewUid Unique identifier of the preview.
* @private
*/
- dispatchPageReadyEvent_: function(previewIndex, pageNumber, previewUid) {
- var pageGenEvent = new Event(PreviewGenerator.EventType.PAGE_READY);
+ dispatchPageReadyEvent_(previewIndex, pageNumber, previewUid) {
+ const pageGenEvent = new Event(PreviewGenerator.EventType.PAGE_READY);
pageGenEvent.previewIndex = previewIndex;
pageGenEvent.previewUrl = 'chrome://print/' + previewUid.toString() +
'/' + (pageNumber - 1) + '/print.pdf';
this.dispatchEvent(pageGenEvent);
- },
+ }
/**
* Dispatches a PREVIEW_START event. Signals that the preview should be
@@ -254,8 +221,8 @@ cr.define('print_preview', function() {
* @param {number} index Index of the first page of the preview.
* @private
*/
- dispatchPreviewStartEvent_: function(previewUid, index) {
- var previewStartEvent =
+ dispatchPreviewStartEvent_(previewUid, index) {
+ const previewStartEvent =
new Event(PreviewGenerator.EventType.PREVIEW_START);
if (!this.documentInfo_.isModifiable) {
index = -1;
@@ -263,7 +230,7 @@ cr.define('print_preview', function() {
previewStartEvent.previewUrl = 'chrome://print/' + previewUid.toString() +
'/' + index + '/print.pdf';
this.dispatchEvent(previewStartEvent);
- },
+ }
/**
* @return {boolean} Whether the print ticket, excluding the page range, has
@@ -271,8 +238,8 @@ cr.define('print_preview', function() {
* should be issued.
* @private
*/
- hasPreviewChanged_: function() {
- var ticketStore = this.printTicketStore_;
+ hasPreviewChanged_() {
+ const ticketStore = this.printTicketStore_;
return this.inFlightRequestId_ == -1 ||
!ticketStore.mediaSize.isValueEqual(this.mediaSize_) ||
!ticketStore.landscape.isValueEqual(this.isLandscapeEnabled_) ||
@@ -293,18 +260,18 @@ cr.define('print_preview', function() {
this.isSelectionOnlyEnabled_) ||
(this.selectedDestination_ !=
this.destinationStore_.selectedDestination);
- },
+ }
/**
* @return {boolean} Whether the page range in the print ticket has changed.
* @private
*/
- hasPreviewPageRangeChanged_: function() {
+ hasPreviewPageRangeChanged_() {
return this.pageRanges_ == null ||
!areRangesEqual(
this.printTicketStore_.pageRange.getPageRanges(),
this.pageRanges_);
- },
+ }
/**
* Called when the page layout of the document is ready. Always occurs
@@ -324,22 +291,22 @@ cr.define('print_preview', function() {
* custom page size or style to use.
* @private
*/
- onPageLayoutReady_: function(pageLayout, hasCustomPageSizeStyle) {
+ onPageLayoutReady_(pageLayout, hasCustomPageSizeStyle) {
// NOTE: A request ID is not specified, so assuming its for the current
// in-flight request.
- var origin = new print_preview.Coordinate2d(
+ const origin = new print_preview.Coordinate2d(
pageLayout.printableAreaX, pageLayout.printableAreaY);
- var size = new print_preview.Size(
+ const size = new print_preview.Size(
pageLayout.printableAreaWidth, pageLayout.printableAreaHeight);
- var margins = new print_preview.Margins(
+ const margins = new print_preview.Margins(
Math.round(pageLayout.marginTop), Math.round(pageLayout.marginRight),
Math.round(pageLayout.marginBottom),
Math.round(pageLayout.marginLeft));
- var o = print_preview.ticket_items.CustomMarginsOrientation;
- var pageSize = new print_preview.Size(
+ const o = print_preview.ticket_items.CustomMarginsOrientation;
+ const pageSize = new print_preview.Size(
pageLayout.contentWidth + margins.get(o.LEFT) + margins.get(o.RIGHT),
pageLayout.contentHeight + margins.get(o.TOP) +
margins.get(o.BOTTOM));
@@ -347,7 +314,7 @@ cr.define('print_preview', function() {
this.documentInfo_.updatePageInfo(
new print_preview.PrintableArea(origin, size), pageSize,
hasCustomPageSizeStyle, margins);
- },
+ }
/**
* Called when the document page count is received from the native layer.
@@ -359,14 +326,13 @@ cr.define('print_preview', function() {
* to page (unused).
* @private
*/
- onPageCountReady_: function(
- pageCount, previewResponseId, fitToPageScaling) {
+ onPageCountReady_(pageCount, previewResponseId, fitToPageScaling) {
if (this.inFlightRequestId_ != previewResponseId) {
return; // Ignore old response.
}
this.documentInfo_.updatePageCount(pageCount);
this.pageRanges_ = this.printTicketStore_.pageRange.getPageRanges();
- },
+ }
/**
* Called when a page's preview has been generated. Dispatches a
@@ -377,20 +343,20 @@ cr.define('print_preview', function() {
* preview is a response to.
* @private
*/
- onPagePreviewReady_: function(pageIndex, previewUid, previewResponseId) {
+ onPagePreviewReady_(pageIndex, previewUid, previewResponseId) {
if (this.inFlightRequestId_ != previewResponseId) {
return; // Ignore old response.
}
- var pageNumber = pageIndex + 1;
- var pageNumberSet = this.printTicketStore_.pageRange.getPageNumberSet();
+ const pageNumber = pageIndex + 1;
+ const pageNumberSet = this.printTicketStore_.pageRange.getPageNumberSet();
if (pageNumberSet.hasPageNumber(pageNumber)) {
- var previewIndex = pageNumberSet.getPageNumberIndex(pageNumber);
+ const previewIndex = pageNumberSet.getPageNumberIndex(pageNumber);
if (previewIndex == 0) {
this.dispatchPreviewStartEvent_(previewUid, pageIndex);
}
this.dispatchPageReadyEvent_(previewIndex, pageNumber, previewUid);
}
- },
+ }
/**
* Called when the preview generation is complete. Dispatches a
@@ -398,7 +364,7 @@ cr.define('print_preview', function() {
* @param {number} previewResponseId
* @param {number} previewUid
*/
- onPreviewGenerationDone: function(previewResponseId, previewUid) {
+ onPreviewGenerationDone(previewResponseId, previewUid) {
if (this.inFlightRequestId_ != previewResponseId) {
return; // Ignore old response.
}
@@ -409,17 +375,38 @@ cr.define('print_preview', function() {
this.dispatchPreviewStartEvent_(previewUid, 0);
}
cr.dispatchSimpleEvent(this, PreviewGenerator.EventType.DOCUMENT_READY);
- },
+ }
/**
* Called when the preview generation fails.
* @private
*/
- onPreviewGenerationFail_: function() {
+ onPreviewGenerationFail_() {
// NOTE: No request ID is returned from Chromium so its assumed its the
// current one.
cr.dispatchSimpleEvent(this, PreviewGenerator.EventType.FAIL);
}
+ }
+
+ /**
+ * Event types dispatched by the preview generator.
+ * @enum {string}
+ */
+ PreviewGenerator.EventType = {
+ // Dispatched when the document can be printed.
+ DOCUMENT_READY: 'print_preview.PreviewGenerator.DOCUMENT_READY',
+
+ // Dispatched when a page preview is ready. The previewIndex field of the
+ // event is the index of the page in the modified document, not the
+ // original. So page 4 of the original document might be previewIndex = 0 of
+ // the modified document.
+ PAGE_READY: 'print_preview.PreviewGenerator.PAGE_READY',
+
+ // Dispatched when the document preview starts to be generated.
+ PREVIEW_START: 'print_preview.PreviewGenerator.PREVIEW_START',
+
+ // Dispatched when the current print preview request fails.
+ FAIL: 'print_preview.PreviewGenerator.FAIL'
};
// Export
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 72fe4bca8be..83f9fb86d52 100644
--- a/chromium/chrome/browser/resources/print_preview/previewarea/margin_control.js
+++ b/chromium/chrome/browser/resources/print_preview/previewarea/margin_control.js
@@ -219,10 +219,11 @@ cr.define('print_preview', function() {
*/
setPositionInPts: function(posInPts) {
this.positionInPts_ = posInPts;
- var orientationEnum = print_preview.ticket_items.CustomMarginsOrientation;
- var x = this.translateTransform_.x;
- var y = this.translateTransform_.y;
- var width = null, height = null;
+ const orientationEnum =
+ print_preview.ticket_items.CustomMarginsOrientation;
+ let x = this.translateTransform_.x;
+ let y = this.translateTransform_.y;
+ let width = null, height = null;
if (this.orientation_ == orientationEnum.TOP) {
y = this.scaleTransform_ * posInPts + this.translateTransform_.y -
MarginControl.RADIUS_;
@@ -268,8 +269,9 @@ cr.define('print_preview', function() {
* @return {number} Given value expressed in points.
*/
convertPixelsToPts: function(pixels) {
- var pts;
- var orientationEnum = print_preview.ticket_items.CustomMarginsOrientation;
+ let pts;
+ const orientationEnum =
+ print_preview.ticket_items.CustomMarginsOrientation;
if (this.orientation_ == orientationEnum.TOP) {
pts = pixels - this.translateTransform_.y + MarginControl.RADIUS_;
pts /= this.scaleTransform_;
@@ -352,7 +354,7 @@ cr.define('print_preview', function() {
// and MarginControls are on the single scrollable container.
// crbug.com/601341
if (isFocused) {
- var previewArea = $('preview-area');
+ const previewArea = $('preview-area');
previewArea.scrollTop = 0;
previewArea.scrollLeft = 0;
}
@@ -384,8 +386,8 @@ cr.define('print_preview', function() {
onTransitionEnd_: function(event) {
if (event.propertyName != 'opacity')
return;
- var elStyle = window.getComputedStyle(this.getElement());
- var disabled = parseInt(elStyle.getPropertyValue('opacity'), 10) == 0;
+ const elStyle = window.getComputedStyle(this.getElement());
+ const 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/previewarea/margin_control_container.js b/chromium/chrome/browser/resources/print_preview/previewarea/margin_control_container.js
index 9a6f8042c65..248c6b45086 100644
--- a/chromium/chrome/browser/resources/print_preview/previewarea/margin_control_container.js
+++ b/chromium/chrome/browser/resources/print_preview/previewarea/margin_control_container.js
@@ -68,10 +68,10 @@ cr.define('print_preview', function() {
* @private
*/
this.controls_ = {};
- for (var key in print_preview.ticket_items.CustomMarginsOrientation) {
- var orientation =
+ for (const key in print_preview.ticket_items.CustomMarginsOrientation) {
+ const orientation =
print_preview.ticket_items.CustomMarginsOrientation[key];
- var control = new print_preview.MarginControl(orientation);
+ const control = new print_preview.MarginControl(orientation);
this.controls_[orientation] = control;
this.addChild(control);
}
@@ -145,7 +145,7 @@ cr.define('print_preview', function() {
updateTranslationTransform: function(translateTransform) {
if (!translateTransform.equals(this.translateTransform_)) {
this.translateTransform_ = translateTransform;
- for (var orientation in this.controls_) {
+ for (const orientation in this.controls_) {
this.controls_[orientation].setTranslateTransform(translateTransform);
}
}
@@ -158,7 +158,7 @@ cr.define('print_preview', function() {
updateScaleTransform: function(scaleTransform) {
if (scaleTransform != this.scaleTransform_) {
this.scaleTransform_ = scaleTransform;
- for (var orientation in this.controls_) {
+ for (const orientation in this.controls_) {
this.controls_[orientation].setScaleTransform(scaleTransform);
}
}
@@ -173,8 +173,8 @@ cr.define('print_preview', function() {
return;
}
this.clippingSize_ = clipSize;
- for (var orientation in this.controls_) {
- var el = this.controls_[orientation].getElement();
+ for (const orientation in this.controls_) {
+ const el = this.controls_[orientation].getElement();
el.style.clip = 'rect(' + (-el.offsetTop) + 'px, ' +
(clipSize.width - el.offsetLeft) + 'px, ' +
(clipSize.height - el.offsetTop) + 'px, ' + (-el.offsetLeft) +
@@ -215,7 +215,7 @@ cr.define('print_preview', function() {
print_preview.ticket_items.TicketItem.EventType.CHANGE,
this.onTicketChange_.bind(this));
- for (var orientation in this.controls_) {
+ for (const orientation in this.controls_) {
this.tracker.add(
this.controls_[orientation],
print_preview.MarginControl.EventType.DRAG_START,
@@ -229,7 +229,7 @@ cr.define('print_preview', function() {
/** @override */
decorateInternal: function() {
- for (var orientation in this.controls_) {
+ for (const orientation in this.controls_) {
this.controls_[orientation].render(this.getElement());
}
},
@@ -239,7 +239,7 @@ cr.define('print_preview', function() {
* @private
*/
setIsMarginControlsVisible_: function(isVisible) {
- for (var orientation in this.controls_) {
+ for (const orientation in this.controls_) {
this.controls_[orientation].setIsVisible(isVisible);
}
},
@@ -253,7 +253,7 @@ cr.define('print_preview', function() {
* @private
*/
moveControlWithConstraints_: function(control, posInPixels) {
- var newPosInPts;
+ let newPosInPts;
if (MarginControlContainer.isTopOrBottom_(control.getOrientation())) {
newPosInPts = control.convertPixelsToPts(posInPixels.y);
} else {
@@ -279,14 +279,14 @@ cr.define('print_preview', function() {
if (value.length == 0) {
return null;
}
- var validationRegex = new RegExp(
+ const validationRegex = new RegExp(
'^(^-?)(\\d)+(\\' + this.measurementSystem_.thousandsDelimeter +
'\\d{3})*(\\' + this.measurementSystem_.decimalDelimeter + '\\d*)?' +
'(' + this.measurementSystem_.unitSymbol + ')?$');
if (validationRegex.test(value)) {
// Replacing decimal point with the dot symbol in order to use
// parseFloat() properly.
- var replacementRegex =
+ const replacementRegex =
new RegExp('\\' + this.measurementSystem_.decimalDelimeter + '{1}');
value = value.replace(replacementRegex, '.');
return this.measurementSystem_.convertToPoints(parseFloat(value));
@@ -350,7 +350,7 @@ cr.define('print_preview', function() {
this.getElement().classList.remove(
MarginControlContainer.Classes_.DRAGGING_HORIZONTAL);
if (event) {
- var posInPixels =
+ const posInPixels =
this.draggedControl_.translateMouseToPositionInPixels(
new print_preview.Coordinate2d(event.x, event.y));
this.moveControlWithConstraints_(this.draggedControl_, posInPixels);
@@ -371,7 +371,7 @@ cr.define('print_preview', function() {
* @private
*/
onMouseOver_: function(event) {
- var fromElement = event.fromElement;
+ let fromElement = event.fromElement;
while (fromElement != null) {
if (fromElement == this.getElement()) {
return;
@@ -392,7 +392,7 @@ cr.define('print_preview', function() {
* @private
*/
onMouseOut_: function(event) {
- var toElement = event.toElement;
+ let toElement = event.toElement;
while (toElement != null) {
if (toElement == this.getElement()) {
return;
@@ -402,7 +402,7 @@ cr.define('print_preview', function() {
if (this.draggedControl_ != null) {
return;
}
- for (var orientation in this.controls_) {
+ for (const orientation in this.controls_) {
if (this.controls_[orientation].getIsFocused() ||
this.controls_[orientation].getIsInError()) {
return;
@@ -417,9 +417,9 @@ cr.define('print_preview', function() {
* @private
*/
onTicketChange_: function() {
- var margins = this.customMarginsTicketItem_.getValue();
- for (var orientation in this.controls_) {
- var control = this.controls_[orientation];
+ const margins = this.customMarginsTicketItem_.getValue();
+ for (const orientation in this.controls_) {
+ const control = this.controls_[orientation];
control.setPageSize(this.documentInfo_.pageSize);
control.setTextboxValue(
this.serializeValueFromPts_(margins.get(orientation)));
@@ -442,17 +442,17 @@ cr.define('print_preview', function() {
* @private
*/
onControlTextChange_: function(control) {
- var marginValue = this.parseValueToPts_(control.getTextboxValue());
+ const marginValue = this.parseValueToPts_(control.getTextboxValue());
if (marginValue != null) {
this.customMarginsTicketItem_.updateMargin(
control.getOrientation(), marginValue);
// Enable all controls.
- for (var o in this.controls_) {
+ for (const o in this.controls_) {
this.controls_[o].setIsEnabled(true);
}
control.setIsInError(false);
} else {
- var enableOtherControls;
+ let enableOtherControls;
if (!control.getIsFocused()) {
// If control no longer in focus, revert to previous valid value.
control.setTextboxValue(
@@ -464,7 +464,7 @@ cr.define('print_preview', function() {
enableOtherControls = false;
}
// Enable other controls.
- for (var o in this.controls_) {
+ for (const o in this.controls_) {
if (control.getOrientation() != o) {
this.controls_[o].setIsEnabled(enableOtherControls);
}
diff --git a/chromium/chrome/browser/resources/print_preview/previewarea/preview_area.js b/chromium/chrome/browser/resources/print_preview/previewarea/preview_area.js
index 98e8f1c9add..cde64b46ac0 100644
--- a/chromium/chrome/browser/resources/print_preview/previewarea/preview_area.js
+++ b/chromium/chrome/browser/resources/print_preview/previewarea/preview_area.js
@@ -266,7 +266,7 @@ cr.define('print_preview', function() {
}
// Don't handle the key event for these elements.
- var tagName = document.activeElement.tagName;
+ const tagName = document.activeElement.tagName;
if (arrayContains(['INPUT', 'SELECT', 'EMBED'], tagName)) {
return;
}
@@ -276,7 +276,7 @@ cr.define('print_preview', function() {
// element, and work up the DOM tree to see if any element has a
// scrollbar. If there exists a scrollbar, do not handle the key event
// here.
- var element = e.target;
+ let element = e.target;
while (element) {
if (element.scrollHeight > element.clientHeight ||
element.scrollWidth > element.clientWidth) {
@@ -317,7 +317,7 @@ cr.define('print_preview', function() {
assert(this.openSystemDialogButton_), 'click',
this.onOpenSystemDialogButtonClick_.bind(this));
- var TicketStoreEvent = print_preview.PrintTicketStore.EventType;
+ const TicketStoreEvent = print_preview.PrintTicketStore.EventType;
[TicketStoreEvent.INITIALIZE, TicketStoreEvent.CAPABILITIES_CHANGE,
TicketStoreEvent.DOCUMENT_CHANGE]
.forEach(eventType => {
@@ -386,9 +386,9 @@ cr.define('print_preview', function() {
// TODO(raymes): It's harder to test compatibility of the out of process
// plugin because it's asynchronous. We could do a better job at some
// point.
- var oopCompatObj = this.getElement().getElementsByClassName(
+ const oopCompatObj = this.getElement().getElementsByClassName(
PreviewArea.Classes_.OUT_OF_PROCESS_COMPATIBILITY_OBJECT)[0];
- var isOOPCompatible = oopCompatObj.postMessage;
+ const isOOPCompatible = oopCompatObj.postMessage;
oopCompatObj.parentElement.removeChild(oopCompatObj);
return isOOPCompatible;
@@ -404,25 +404,25 @@ cr.define('print_preview', function() {
*/
showMessage_: function(messageId, opt_message) {
// Hide all messages.
- var messageEls = this.getElement().getElementsByClassName(
+ const messageEls = this.getElement().getElementsByClassName(
PreviewArea.Classes_.MESSAGE);
- for (var i = 0, messageEl; (messageEl = messageEls[i]); i++) {
+ for (let i = 0, messageEl; (messageEl = messageEls[i]); i++) {
setIsVisible(messageEl, false);
}
// Disable jumping animation to conserve cycles.
- var jumpingDotsEl = this.getElement().querySelector(
+ const jumpingDotsEl = this.getElement().querySelector(
'.preview-area-loading-message-jumping-dots');
jumpingDotsEl.classList.remove('jumping-dots');
// Show specific message.
if (messageId == print_preview.PreviewAreaMessageId_.CUSTOM) {
- var customMessageTextEl = this.getElement().getElementsByClassName(
+ const customMessageTextEl = this.getElement().getElementsByClassName(
PreviewArea.Classes_.CUSTOM_MESSAGE_TEXT)[0];
customMessageTextEl.textContent = opt_message;
} else if (messageId == print_preview.PreviewAreaMessageId_.LOADING) {
jumpingDotsEl.classList.add('jumping-dots');
}
- var messageEl = this.getElement().getElementsByClassName(
+ const messageEl = this.getElement().getElementsByClassName(
PreviewArea.MessageIdClassMap_[messageId])[0];
setIsVisible(messageEl, true);
@@ -440,20 +440,20 @@ cr.define('print_preview', function() {
this.overlayEl_.setAttribute('aria-hidden', !visible);
// Hide/show all controls that will overlap when the overlay is visible.
- var marginControls = this.getElement().getElementsByClassName(
+ const marginControls = this.getElement().getElementsByClassName(
PreviewArea.Classes_.MARGIN_CONTROL);
- for (var i = 0; i < marginControls.length; ++i) {
+ for (let i = 0; i < marginControls.length; ++i) {
marginControls[i].setAttribute('aria-hidden', visible);
}
- var previewAreaControls = this.getElement().getElementsByClassName(
+ const previewAreaControls = this.getElement().getElementsByClassName(
PreviewArea.Classes_.PREVIEW_AREA);
- for (var i = 0; i < previewAreaControls.length; ++i) {
+ for (let i = 0; i < previewAreaControls.length; ++i) {
previewAreaControls[i].setAttribute('aria-hidden', visible);
}
if (!visible) {
// Disable jumping animation to conserve cycles.
- var jumpingDotsEl = this.getElement().querySelector(
+ const jumpingDotsEl = this.getElement().querySelector(
'.preview-area-loading-message-jumping-dots');
jumpingDotsEl.classList.remove('jumping-dots');
}
@@ -505,7 +505,7 @@ cr.define('print_preview', function() {
*/
onOpenSystemDialogButtonClick_: function() {
this.openSystemDialogButton_.disabled = true;
- var openSystemDialogThrobber = this.getElement().getElementsByClassName(
+ const openSystemDialogThrobber = this.getElement().getElementsByClassName(
PreviewArea.Classes_.OPEN_SYSTEM_DIALOG_BUTTON_THROBBER)[0];
setIsVisible(openSystemDialogThrobber, true);
cr.dispatchSimpleEvent(
@@ -519,7 +519,7 @@ cr.define('print_preview', function() {
onTicketChange_: function() {
if (!this.previewGenerator_)
return;
- var previewRequest = this.previewGenerator_.requestPreview();
+ const previewRequest = this.previewGenerator_.requestPreview();
if (previewRequest.id <= -1) {
this.marginControlContainer_.showMarginControlsIfNeeded();
return;
diff --git a/chromium/chrome/browser/resources/print_preview/print_header.js b/chromium/chrome/browser/resources/print_preview/print_header.js
index b8f12871fe8..67e445bd70f 100644
--- a/chromium/chrome/browser/resources/print_preview/print_header.js
+++ b/chromium/chrome/browser/resources/print_preview/print_header.js
@@ -80,7 +80,7 @@ cr.define('print_preview', function() {
/** @param {string} message Error message to display in the print header. */
setErrorMessage: function(message) {
- var summaryEl = this.getChildElement('.summary');
+ const summaryEl = this.getChildElement('.summary');
summaryEl.innerHTML = '';
summaryEl.textContent = message;
this.getChildElement('button.print').classList.toggle('loading', false);
@@ -144,24 +144,24 @@ cr.define('print_preview', function() {
return;
}
- var saveToPdfOrDrive = this.destinationStore_.selectedDestination &&
+ const saveToPdfOrDrive = this.destinationStore_.selectedDestination &&
(this.destinationStore_.selectedDestination.id ==
print_preview.Destination.GooglePromotedId.SAVE_AS_PDF ||
this.destinationStore_.selectedDestination.id ==
print_preview.Destination.GooglePromotedId.DOCS);
- var numPages = this.printTicketStore_.pageRange.getPageNumberSet().size;
- var numSheets = numPages;
+ let numPages = this.printTicketStore_.pageRange.getPageNumberSet().size;
+ let numSheets = numPages;
if (!saveToPdfOrDrive && this.printTicketStore_.duplex.getValue()) {
numSheets = Math.ceil(numPages / 2);
}
- var copies = this.printTicketStore_.copies.getValueAsNumber();
+ const copies = this.printTicketStore_.copies.getValueAsNumber();
numSheets *= copies;
numPages *= copies;
- var pagesLabel = loadTimeData.getString('printPreviewPageLabelPlural');
- var summaryLabel;
+ const pagesLabel = loadTimeData.getString('printPreviewPageLabelPlural');
+ let summaryLabel;
if (numSheets > 1) {
summaryLabel = saveToPdfOrDrive ?
pagesLabel :
@@ -172,8 +172,8 @@ cr.define('print_preview', function() {
'printPreviewSheetsLabelSingular');
}
- var html;
- var label;
+ let html;
+ let label;
if (numPages != numSheets) {
html = loadTimeData.getStringF(
'printPreviewSummaryFormatLong',
@@ -196,7 +196,7 @@ cr.define('print_preview', function() {
// Removing extra spaces from within the string.
html = html.replace(/\s{2,}/g, ' ');
- var summary = this.getChildElement('.summary');
+ const summary = this.getChildElement('.summary');
summary.innerHTML = html;
summary.setAttribute('aria-label', label);
},
@@ -211,7 +211,7 @@ cr.define('print_preview', function() {
print_preview.Destination.GooglePromotedId.SAVE_AS_PDF) {
this.getChildElement('button.print').classList.add('loading');
this.getChildElement('button.cancel').classList.add('loading');
- var isSaveLabel =
+ const isSaveLabel =
(this.destinationStore_.selectedDestination.id ==
print_preview.Destination.GooglePromotedId.DOCS);
this.getChildElement('.summary').innerHTML =
@@ -235,7 +235,7 @@ cr.define('print_preview', function() {
* @private
*/
onDestinationSelect_: function() {
- var isSaveLabel = this.destinationStore_.selectedDestination &&
+ const isSaveLabel = this.destinationStore_.selectedDestination &&
(this.destinationStore_.selectedDestination.id ==
print_preview.Destination.GooglePromotedId.SAVE_AS_PDF ||
this.destinationStore_.selectedDestination.id ==
diff --git a/chromium/chrome/browser/resources/print_preview/print_preview.js b/chromium/chrome/browser/resources/print_preview/print_preview.js
index bee9f809d16..2aa5685083f 100644
--- a/chromium/chrome/browser/resources/print_preview/print_preview.js
+++ b/chromium/chrome/browser/resources/print_preview/print_preview.js
@@ -40,7 +40,7 @@ print_preview.PrintAttemptResult_ = {
cr.define('print_preview', function() {
'use strict';
- var PrintPreviewUiState_ = print_preview.PrintPreviewUiState_;
+ const PrintPreviewUiState_ = print_preview.PrintPreviewUiState_;
/**
* Container class for Chromium's print preview.
@@ -229,7 +229,7 @@ cr.define('print_preview', function() {
new print_preview.AdvancedSettings(this.printTicketStore_);
this.addChild(this.advancedSettings_);
- var settingsSections = [
+ const settingsSections = [
this.destinationSettings_, this.pageSettings_, this.copiesSettings_,
this.mediaSizeSettings_, this.layoutSettings_, this.marginSettings_,
this.colorSettings_, this.dpiSettings_, this.scalingSettings_,
@@ -416,12 +416,8 @@ cr.define('print_preview', function() {
this.tracker.add(
this.destinationSearch_,
- print_preview.DestinationSearch.EventType.MANAGE_CLOUD_DESTINATIONS,
- this.onManageCloudDestinationsActivated_.bind(this));
- this.tracker.add(
- this.destinationSearch_,
- print_preview.DestinationSearch.EventType.MANAGE_LOCAL_DESTINATIONS,
- this.onManageLocalDestinationsActivated_.bind(this));
+ print_preview.DestinationSearch.EventType.MANAGE_PRINT_DESTINATIONS,
+ this.onManagePrintDestinationsActivated_.bind(this));
this.tracker.add(
this.destinationSearch_,
print_preview.DestinationSearch.EventType.ADD_ACCOUNT,
@@ -516,7 +512,7 @@ cr.define('print_preview', function() {
}
this.setIsEnabled_(false);
this.printHeader_.isCancelButtonEnabled = true;
- var printAttemptResult = this.printIfReady_();
+ const printAttemptResult = this.printIfReady_();
if (printAttemptResult ==
print_preview.PrintAttemptResult_.READY_WAITING_FOR_PREVIEW) {
if ((this.destinationStore_.selectedDestination.isLocal &&
@@ -538,7 +534,7 @@ cr.define('print_preview', function() {
* @private
*/
printIfReady_: function() {
- var okToPrint =
+ const okToPrint =
(this.uiState_ == PrintPreviewUiState_.PRINTING ||
this.uiState_ == PrintPreviewUiState_.OPENING_PDF_PREVIEW ||
this.uiState_ == PrintPreviewUiState_.FILE_SELECTION ||
@@ -562,10 +558,9 @@ cr.define('print_preview', function() {
print_preview.Metrics.PrintSettingsUiBucket
.PRINT_WITH_SETTINGS_COLLAPSED);
}
- var destination = assert(this.destinationStore_.selectedDestination);
- var whenPrintDone = this.nativeLayer_.print(
- destination, this.printTicketStore_, this.cloudPrintInterface_,
- this.documentInfo_,
+ const destination = assert(this.destinationStore_.selectedDestination);
+ const whenPrintDone = this.nativeLayer_.print(
+ destination, this.printTicketStore_, this.documentInfo_,
this.uiState_ == PrintPreviewUiState_.OPENING_PDF_PREVIEW,
this.showSystemDialogBeforeNextPrint_);
if (this.uiState_ == PrintPreviewUiState_.OPENING_PDF_PREVIEW ||
@@ -575,16 +570,16 @@ cr.define('print_preview', function() {
print_preview.Destination.GooglePromotedId.SAVE_AS_PDF)) {
// Local printers resolve when print is ready to start. Hide the
// dialog. Mac "Open in Preview" is treated as a local printer.
- var boundHideDialog = () => {
+ const boundHideDialog = () => {
this.nativeLayer_.hidePreview();
};
whenPrintDone.then(boundHideDialog, boundHideDialog);
} else if (!destination.isLocal) {
// Cloud print resolves when print data is returned to submit to cloud
- // print, or if setings are invalid.
+ // print, or if print ticket cannot be read, no PDF data is found, or
+ // PDF is oversized.
whenPrintDone.then(
- this.onPrintToCloud_.bind(this),
- this.onSettingsInvalid_.bind(this));
+ this.onPrintToCloud_.bind(this), this.onPrintFailed_.bind(this));
} else if (destination.isPrivet || destination.isExtension) {
// Privet and extension resolve when printing is complete or if there
// is an error printing.
@@ -668,6 +663,7 @@ cr.define('print_preview', function() {
settings.serializedDefaultDestinationSelectionRulesStr);
this.appState_.setInitialized();
+ // This is only visible in the task manager.
$('document-title').innerText = settings.documentTitle;
this.hideSystemDialogLink_ = settings.isInAppKioskMode;
if ($('system-dialog-link')) {
@@ -861,7 +857,7 @@ cr.define('print_preview', function() {
* @private
*/
onCloudPrintRegisterPromoClick_: function(e) {
- var devicesUrl = 'chrome://devices/register?id=' + e.destination.id;
+ const devicesUrl = 'chrome://devices/register?id=' + e.destination.id;
this.nativeLayer_.forceOpenNewTab(devicesUrl);
this.destinationStore_.waitForRegister(e.destination.id);
},
@@ -912,7 +908,7 @@ cr.define('print_preview', function() {
assert(
this.uiState_ == PrintPreviewUiState_.READY,
'Trying to print when not in ready state: ' + this.uiState_);
- var activeElementTag = document.activeElement.tagName.toUpperCase();
+ const activeElementTag = document.activeElement.tagName.toUpperCase();
if (activeElementTag != 'BUTTON' && activeElementTag != 'SELECT' &&
activeElementTag != 'A') {
this.printDocumentOrOpenPdfPreview_(false /*isPdfPreview*/);
@@ -954,7 +950,7 @@ cr.define('print_preview', function() {
*/
onTicketChange_: function() {
this.printHeader_.onTicketChange();
- var disable = !this.printHeader_.isPrintButtonEnabled;
+ const disable = !this.printHeader_.isPrintButtonEnabled;
if (cr.isWindows && $('system-dialog-link'))
$('system-dialog-link').disabled = disable;
if ($('open-pdf-in-preview-link'))
@@ -981,21 +977,12 @@ cr.define('print_preview', function() {
},
/**
- * Called when the destination search dispatches manage cloud destinations
- * event. Calls corresponding native layer method.
- * @private
- */
- onManageCloudDestinationsActivated_: function() {
- this.nativeLayer_.manageCloudPrinters(this.userInfo_.activeUser);
- },
-
- /**
- * Called when the destination search dispatches manage local destinations
- * event. Calls corresponding native layer method.
+ * Called when the destination search dispatches manage all print
+ * destinations event. Calls corresponding native layer method.
* @private
*/
- onManageLocalDestinationsActivated_: function() {
- this.nativeLayer_.manageLocalPrinters();
+ onManagePrintDestinationsActivated_: function() {
+ this.nativeLayer_.managePrinters();
},
/**
@@ -1050,13 +1037,13 @@ cr.define('print_preview', function() {
},
/**
- * Called when printing to a privet or extension printer fails.
+ * Called when printing to a privet, cloud, or extension printer fails.
* @param {*} httpError The HTTP error code, or -1 or a string describing
* the error, if not an HTTP error.
* @private
*/
onPrintFailed_: function(httpError) {
- console.error('Privet printing failed with error code ' + httpError);
+ console.error('Printing failed with error code ' + httpError);
this.printHeader_.setErrorMessage(
loadTimeData.getString('couldNotPrint'));
},
@@ -1109,9 +1096,9 @@ cr.define('print_preview', function() {
return;
}
- var destinations = this.destinationStore_.destinations();
- var pdfDestination = null;
- for (var i = 0; i < destinations.length; i++) {
+ const destinations = this.destinationStore_.destinations();
+ let pdfDestination = null;
+ for (let i = 0; i < destinations.length; i++) {
if (destinations[i].id ==
print_preview.Destination.GooglePromotedId.SAVE_AS_PDF) {
pdfDestination = destinations[i];
@@ -1133,7 +1120,7 @@ cr.define('print_preview', function() {
* @private
*/
setLayoutSettingsForTest_: function(portrait) {
- var combobox = document.querySelector('.layout-settings-select');
+ const combobox = document.querySelector('.layout-settings-select');
if (combobox.value == 'portrait') {
this.nativeLayer_.uiLoadedForTest();
} else {
@@ -1150,7 +1137,7 @@ cr.define('print_preview', function() {
* @private
*/
setPageRangeForTest_: function(pageRange) {
- var textbox = document.querySelector('.page-settings-custom-input');
+ const textbox = document.querySelector('.page-settings-custom-input');
if (textbox.value == pageRange) {
this.nativeLayer_.uiLoadedForTest();
} else {
@@ -1167,7 +1154,7 @@ cr.define('print_preview', function() {
* @private
*/
setHeadersAndFootersForTest_: function(headersAndFooters) {
- var checkbox = document.querySelector('.header-footer-checkbox');
+ const checkbox = document.querySelector('.header-footer-checkbox');
if (headersAndFooters == checkbox.checked)
this.nativeLayer_.uiLoadedForTest();
else
@@ -1182,7 +1169,7 @@ cr.define('print_preview', function() {
* @private
*/
setBackgroundColorsAndImagesForTest_: function(backgroundColorsAndImages) {
- var checkbox = document.querySelector('.css-background-checkbox');
+ const checkbox = document.querySelector('.css-background-checkbox');
if (backgroundColorsAndImages == checkbox.checked)
this.nativeLayer_.uiLoadedForTest();
else
@@ -1197,7 +1184,7 @@ cr.define('print_preview', function() {
* @private
*/
setMarginsForTest_: function(margins) {
- var combobox = document.querySelector('.margin-settings-select');
+ const combobox = document.querySelector('.margin-settings-select');
if (margins == combobox.selectedIndex) {
this.nativeLayer_.uiLoadedForTest();
} else if (margins >= 0 && margins < combobox.length) {
@@ -1218,7 +1205,7 @@ cr.define('print_preview', function() {
return false;
if (!cr.isWindows)
return true;
- var selectedDest = this.destinationStore_.selectedDestination;
+ const selectedDest = this.destinationStore_.selectedDestination;
return !!selectedDest &&
selectedDest.origin == print_preview.DestinationOrigin.LOCAL &&
selectedDest.id !=
@@ -1326,16 +1313,15 @@ cr.define('print_preview', function() {
// <include src="preview_generator.js">
// <include src="search/destination_list.js">
-// <include src="search/cloud_destination_list.js">
// <include src="search/recent_destination_list.js">
// <include src="search/destination_list_item.js">
// <include src="search/destination_search.js">
// <include src="search/provisional_destination_resolver.js">
window.addEventListener('DOMContentLoaded', function() {
- var previewWindow = /** @type {{isTest: boolean}} */ (window);
+ const previewWindow = /** @type {{isTest: boolean}} */ (window);
if (!previewWindow.isTest) {
- var printPreview = new print_preview.PrintPreview();
+ const printPreview = new print_preview.PrintPreview();
printPreview.initialize();
}
});
diff --git a/chromium/chrome/browser/resources/print_preview/print_preview_animations.js b/chromium/chrome/browser/resources/print_preview/print_preview_animations.js
index 86ead3a16b1..f2d9f0f5c5b 100644
--- a/chromium/chrome/browser/resources/print_preview/print_preview_animations.js
+++ b/chromium/chrome/browser/resources/print_preview/print_preview_animations.js
@@ -3,15 +3,16 @@
// found in the LICENSE file.
// Counter used to give animations unique names.
-var animationCounter = 0;
+let animationCounter = 0;
-var animationEventTracker = new EventTracker();
+const animationEventTracker = new EventTracker();
function addAnimation(code) {
- var name = 'anim' + animationCounter;
+ const name = 'anim' + animationCounter;
animationCounter++;
- var rules = document.createTextNode('@keyframes ' + name + ' {' + code + '}');
- var el = document.createElement('style');
+ const rules =
+ document.createTextNode('@keyframes ' + name + ' {' + code + '}');
+ const el = document.createElement('style');
el.type = 'text/css';
el.appendChild(rules);
el.setAttribute('id', name);
@@ -46,13 +47,13 @@ function fadeInElement(el, opt_justShow) {
el.hidden = false;
el.setAttribute('aria-hidden', 'false');
el.style.height = 'auto';
- var height = el.offsetHeight;
+ const height = el.offsetHeight;
if (opt_justShow) {
el.style.height = '';
el.style.opacity = '';
} else {
el.style.height = height + 'px';
- var animName = addAnimation(getFadeInAnimationCode(height));
+ const animName = addAnimation(getFadeInAnimationCode(height));
animationEventTracker.add(
el, 'animationend', onFadeInAnimationEnd.bind(el), false);
el.style.animationName = animName;
@@ -70,7 +71,7 @@ function fadeOutElement(el) {
return;
fadeInAnimationCleanup(el);
el.style.height = 'auto';
- var height = el.offsetHeight;
+ const height = el.offsetHeight;
el.style.height = height + 'px';
/** @suppress {suspiciousCode} */
el.offsetHeight; // Should force an update of the computed style.
@@ -109,7 +110,7 @@ function onFadeInAnimationEnd(event) {
*/
function fadeInAnimationCleanup(element) {
if (element.style.animationName) {
- var animEl = $(element.style.animationName);
+ const animEl = $(element.style.animationName);
if (animEl)
animEl.parentNode.removeChild(animEl);
element.style.animationName = '';
@@ -129,15 +130,15 @@ function fadeInOption(el, opt_justShow) {
// To make the option visible during the first fade in.
el.hidden = false;
- var leftColumn =
+ const leftColumn =
assertInstanceof(el.querySelector('.left-column'), HTMLElement);
wrapContentsInDiv(leftColumn, ['invisible']);
- var rightColumn =
+ const rightColumn =
assertInstanceof(el.querySelector('.right-column'), HTMLElement);
wrapContentsInDiv(rightColumn, ['invisible']);
- var toAnimate = el.querySelectorAll('.collapsible');
- for (var i = 0; i < toAnimate.length; i++)
+ const toAnimate = el.querySelectorAll('.collapsible');
+ for (let i = 0; i < toAnimate.length; i++)
fadeInElement(assertInstanceof(toAnimate[i], HTMLElement), opt_justShow);
el.classList.add('visible');
}
@@ -152,16 +153,16 @@ function fadeOutOption(el, opt_justHide) {
if (!el.classList.contains('visible'))
return;
- var leftColumn =
+ const leftColumn =
assertInstanceof(el.querySelector('.left-column'), HTMLElement);
wrapContentsInDiv(leftColumn, ['visible']);
- var rightColumn =
+ const rightColumn =
assertInstanceof(el.querySelector('.right-column'), HTMLElement);
if (rightColumn)
wrapContentsInDiv(rightColumn, ['visible']);
- var toAnimate = el.querySelectorAll('.collapsible');
- for (var i = 0; i < toAnimate.length; i++) {
+ const toAnimate = el.querySelectorAll('.collapsible');
+ for (let i = 0; i < toAnimate.length; i++) {
if (opt_justHide) {
toAnimate[i].hidden = true;
toAnimate[i].classList.add('closing');
@@ -181,7 +182,7 @@ function fadeOutOption(el, opt_justHide) {
* @param {!Array} classes The css classes to add.
*/
function wrapContentsInDiv(el, classes) {
- var div = el.querySelector('div');
+ let div = el.querySelector('div');
if (!div || !div.classList.contains('collapsible')) {
div = document.createElement('div');
while (el.childNodes.length > 0)
@@ -191,6 +192,6 @@ function wrapContentsInDiv(el, classes) {
div.className = '';
div.classList.add('collapsible');
- for (var i = 0; i < classes.length; i++)
+ for (let i = 0; i < classes.length; i++)
div.classList.add(classes[i]);
}
diff --git a/chromium/chrome/browser/resources/print_preview/print_preview_focus_manager.js b/chromium/chrome/browser/resources/print_preview/print_preview_focus_manager.js
index 47bb04b81d1..e8ee6ce4366 100644
--- a/chromium/chrome/browser/resources/print_preview/print_preview_focus_manager.js
+++ b/chromium/chrome/browser/resources/print_preview/print_preview_focus_manager.js
@@ -20,8 +20,8 @@ cr.define('print_preview', function() {
/** @override */
getFocusParent: function() {
- var el = document.body;
- var newEl = null;
+ let el = document.body;
+ let newEl = null;
while (newEl = el.querySelector('.overlay:not([hidden])'))
el = newEl;
return el;
diff --git a/chromium/chrome/browser/resources/print_preview/print_preview_new.html b/chromium/chrome/browser/resources/print_preview/print_preview_new.html
new file mode 100644
index 00000000000..303438ada23
--- /dev/null
+++ b/chromium/chrome/browser/resources/print_preview/print_preview_new.html
@@ -0,0 +1,21 @@
+<!doctype html>
+<html dir="$i18n{textdirection}" lang="$i18n{language}">
+<head>
+<meta charset="utf-8">
+ <title></title>
+</head>
+<body>
+ <style>
+ html,
+ body {
+ height: 100%;
+ margin: 0;
+ overflow: hidden;
+ width: 100%;
+ }
+ </style>
+ <print-preview-app></print-preview-app>
+ <link rel="stylesheet" href="chrome://resources/css/text_defaults.css">
+ <link rel="import" href="new/app.html">
+</body>
+</html>
diff --git a/chromium/chrome/browser/resources/print_preview/print_preview_resources.grd b/chromium/chrome/browser/resources/print_preview/print_preview_resources.grd
new file mode 100644
index 00000000000..9066a7ea12c
--- /dev/null
+++ b/chromium/chrome/browser/resources/print_preview/print_preview_resources.grd
@@ -0,0 +1,185 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<grit latest_public_release="0" current_release="1" output_all_resource_defines="false">
+ <outputs>
+ <output filename="grit/print_preview_resources.h" type="rc_header">
+ <emit emit_type='prepend'></emit>
+ </output>
+ <output filename="grit/print_preview_resources_map.cc"
+ type="resource_file_map_source" />
+ <output filename="grit/print_preview_resources_map.h"
+ type="resource_map_header" />
+ <output filename="print_preview_resources.pak" type="data_package" />
+ </outputs>
+ <release seq="1">
+ <structures>
+ <structure name="IDR_PRINT_PREVIEW_NEW_HTML"
+ file="print_preview_new.html"
+ flattenhtml="true"
+ allowexternalscript="true"
+ type="chrome_html" />
+ <structure name="IDR_PRINT_PREVIEW_NEW_APP_HTML"
+ file="new/app.html"
+ type="chrome_html" />
+ <structure name="IDR_PRINT_PREVIEW_NEW_APP_JS"
+ file="new/app.js"
+ type="chrome_html" />
+ <structure name="IDR_PRINT_PREVIEW_NEW_MODEL_HTML"
+ file="new/model.html"
+ type="chrome_html" />
+ <structure name="IDR_PRINT_PREVIEW_NEW_MODEL_JS"
+ file="new/model.js"
+ type="chrome_html" />
+ <structure name="IDR_PRINT_PREVIEW_DATA_DESTINATION_HTML"
+ file="data/destination.html"
+ type="chrome_html" />
+ <structure name="IDR_PRINT_PREVIEW_DATA_DESTINATION_JS"
+ file="data/destination.js"
+ type="chrome_html" />
+ <structure name="IDR_PRINT_PREVIEW_PRINT_PREVIEW_UTILS_HTML"
+ file="print_preview_utils.html"
+ type="chrome_html" />
+ <structure name="IDR_PRINT_PREVIEW_PRINT_PREVIEW_UTILS_JS"
+ file="print_preview_utils.js"
+ type="chrome_html" />
+ <structure name="IDR_PRINT_PREVIEW_DATA_DOCUMENT_INFO_HTML"
+ file="data/document_info.html"
+ type="chrome_html" />
+ <structure name="IDR_PRINT_PREVIEW_DATA_DOCUMENT_INFO_JS"
+ file="data/document_info.js"
+ type="chrome_html" />
+ <structure name="IDR_PRINT_PREVIEW_DATA_SIZE_HTML"
+ file="data/size.html"
+ type="chrome_html" />
+ <structure name="IDR_PRINT_PREVIEW_DATA_SIZE_JS"
+ file="data/size.js"
+ type="chrome_html" />
+ <structure name="IDR_PRINT_PREVIEW_DATA_COORDINATE2D_HTML"
+ file="data/coordinate2d.html"
+ type="chrome_html" />
+ <structure name="IDR_PRINT_PREVIEW_DATA_COORDINATE2D_JS"
+ file="data/coordinate2d.js"
+ type="chrome_html" />
+ <structure name="IDR_PRINT_PREVIEW_DATA_PRINTABLE_AREA_HTML"
+ file="data/printable_area.html"
+ type="chrome_html" />
+ <structure name="IDR_PRINT_PREVIEW_DATA_PRINTABLE_AREA_JS"
+ file="data/printable_area.js"
+ type="chrome_html" />
+ <structure name="IDR_PRINT_PREVIEW_NEW_HEADER_HTML"
+ file="new/header.html"
+ type="chrome_html" />
+ <structure name="IDR_PRINT_PREVIEW_NEW_HEADER_JS"
+ file="new/header.js"
+ type="chrome_html" />
+ <structure name="IDR_PRINT_PREVIEW_NEW_SETTINGS_BEHAVIOR_HTML"
+ file="new/settings_behavior.html"
+ type="chrome_html" />
+ <structure name="IDR_PRINT_PREVIEW_NEW_SETTINGS_BEHAVIOR_JS"
+ file="new/settings_behavior.js"
+ type="chrome_html" />
+ <structure name="IDR_PRINT_PREVIEW_NEW_SETTINGS_SECTION_HTML"
+ file="new/settings_section.html"
+ type="chrome_html" />
+ <structure name="IDR_PRINT_PREVIEW_NEW_SETTINGS_SECTION_JS"
+ file="new/settings_section.js"
+ type="chrome_html" />
+ <structure name="IDR_PRINT_PREVIEW_NEW_DESTINATION_SETTINGS_HTML"
+ file="new/destination_settings.html"
+ type="chrome_html" />
+ <structure name="IDR_PRINT_PREVIEW_NEW_DESTINATION_SETTINGS_JS"
+ file="new/destination_settings.js"
+ type="chrome_html" />
+ <structure name="IDR_PRINT_PREVIEW_NEW_PAGES_SETTINGS_HTML"
+ file="new/pages_settings.html"
+ type="chrome_html" />
+ <structure name="IDR_PRINT_PREVIEW_NEW_PAGES_SETTINGS_JS"
+ file="new/pages_settings.js"
+ type="chrome_html" />
+ <structure name="IDR_PRINT_PREVIEW_NEW_COPIES_SETTINGS_HTML"
+ file="new/copies_settings.html"
+ type="chrome_html" />
+ <structure name="IDR_PRINT_PREVIEW_NEW_COPIES_SETTINGS_JS"
+ file="new/copies_settings.js"
+ type="chrome_html" />
+ <structure name="IDR_PRINT_PREVIEW_NEW_LAYOUT_SETTINGS_HTML"
+ file="new/layout_settings.html"
+ type="chrome_html" />
+ <structure name="IDR_PRINT_PREVIEW_NEW_LAYOUT_SETTINGS_JS"
+ file="new/layout_settings.js"
+ type="chrome_html" />
+ <structure name="IDR_PRINT_PREVIEW_NEW_COLOR_SETTINGS_HTML"
+ file="new/color_settings.html"
+ type="chrome_html" />
+ <structure name="IDR_PRINT_PREVIEW_NEW_COLOR_SETTINGS_JS"
+ file="new/color_settings.js"
+ type="chrome_html" />
+ <structure name="IDR_PRINT_PREVIEW_NEW_MEDIA_SIZE_SETTINGS_HTML"
+ file="new/media_size_settings.html"
+ type="chrome_html" />
+ <structure name="IDR_PRINT_PREVIEW_NEW_MEDIA_SIZE_SETTINGS_JS"
+ file="new/media_size_settings.js"
+ type="chrome_html" />
+ <structure name="IDR_PRINT_PREVIEW_NEW_MARGINS_SETTINGS_HTML"
+ file="new/margins_settings.html"
+ type="chrome_html" />
+ <structure name="IDR_PRINT_PREVIEW_NEW_MARGINS_SETTINGS_JS"
+ file="new/margins_settings.js"
+ type="chrome_html" />
+ <structure name="IDR_PRINT_PREVIEW_NEW_DPI_SETTINGS_HTML"
+ file="new/dpi_settings.html"
+ type="chrome_html" />
+ <structure name="IDR_PRINT_PREVIEW_NEW_DPI_SETTINGS_JS"
+ file="new/dpi_settings.js"
+ type="chrome_html" />
+ <structure name="IDR_PRINT_PREVIEW_NEW_SCALING_SETTINGS_HTML"
+ file="new/scaling_settings.html"
+ type="chrome_html" />
+ <structure name="IDR_PRINT_PREVIEW_NEW_SCALING_SETTINGS_JS"
+ file="new/scaling_settings.js"
+ type="chrome_html" />
+ <structure name="IDR_PRINT_PREVIEW_NEW_OTHER_OPTIONS_SETTINGS_HTML"
+ file="new/other_options_settings.html"
+ type="chrome_html" />
+ <structure name="IDR_PRINT_PREVIEW_NEW_OTHER_OPTIONS_SETTINGS_JS"
+ file="new/other_options_settings.js"
+ type="chrome_html" />
+ <structure name="IDR_PRINT_PREVIEW_NEW_ADVANCED_OPTIONS_SETTINGS_HTML"
+ file="new/advanced_options_settings.html"
+ type="chrome_html" />
+ <structure name="IDR_PRINT_PREVIEW_NEW_ADVANCED_OPTIONS_SETTINGS_JS"
+ file="new/advanced_options_settings.js"
+ type="chrome_html" />
+ <structure name="IDR_PRINT_PREVIEW_NEW_NUMBER_SETTINGS_SECTION_HTML"
+ file="new/number_settings_section.html"
+ type="chrome_html" />
+ <structure name="IDR_PRINT_PREVIEW_NEW_NUMBER_SETTINGS_SECTION_JS"
+ file="new/number_settings_section.js"
+ type="chrome_html" />
+ <structure name="IDR_PRINT_PREVIEW_NEW_PRINT_PREVIEW_SHARED_CSS_HTML"
+ file="new/print_preview_shared_css.html"
+ type="chrome_html"
+ preprocess="true" />
+ <structure name="IDR_PRINT_PREVIEW_NEW_BUTTON_CSS_HTML"
+ file="new/button_css.html"
+ type="chrome_html"
+ preprocess="true"/>
+ <structure name="IDR_PRINT_PREVIEW_NEW_SELECT_CSS_HTML"
+ file="new/select_css.html"
+ type="chrome_html"
+ preprocess="true"/>
+ <structure name="IDR_PRINT_PREVIEW_NEW_CHECKBOX_RADIO_CSS_HTML"
+ file="new/checkbox_radio_css.html"
+ type="chrome_html"
+ preprocess="true"/>
+ <structure name="IDR_PRINT_PREVIEW_NEW_INPUT_CSS_HTML"
+ file="new/input_css.html"
+ type="chrome_html"/>
+ <structure name="IDR_PRINT_PREVIEW_NEW_THROBBER_CSS_HTML"
+ file="new/throbber_css.html"
+ type="chrome_html"/>
+ <structure name="IDR_PRINT_PREVIEW_NEW_STRINGS_HTML"
+ file="new/strings.html"
+ type="chrome_html" />
+ </structures>
+ </release>
+</grit>
diff --git a/chromium/chrome/browser/resources/print_preview/print_preview_utils.html b/chromium/chrome/browser/resources/print_preview/print_preview_utils.html
new file mode 100644
index 00000000000..6c28ddc323d
--- /dev/null
+++ b/chromium/chrome/browser/resources/print_preview/print_preview_utils.html
@@ -0,0 +1,3 @@
+<link rel="import" href="chrome://resources/html/cr.html">
+
+<script src="print_preview_utils.js"></script>
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 bfd199c3801..cd931980ba4 100644
--- a/chromium/chrome/browser/resources/print_preview/print_preview_utils.js
+++ b/chromium/chrome/browser/resources/print_preview/print_preview_utils.js
@@ -8,7 +8,7 @@
* whitespace is allowed.
*/
function isInteger(toTest) {
- var numericExp = /^\s*[0-9]+\s*$/;
+ const numericExp = /^\s*[0-9]+\s*$/;
return numericExp.test(toTest);
}
@@ -30,7 +30,7 @@ function isPositiveInteger(value) {
function areArraysEqual(array1, array2) {
if (array1.length != array2.length)
return false;
- for (var i = 0; i < array1.length; i++)
+ for (let i = 0; i < array1.length; i++)
if (array1[i] !== array2[i])
return false;
return true;
@@ -45,7 +45,7 @@ function areArraysEqual(array1, array2) {
function areRangesEqual(array1, array2) {
if (array1.length != array2.length)
return false;
- for (var i = 0; i < array1.length; i++)
+ for (let i = 0; i < array1.length; i++)
if (array1[i].from != array2[i].from || array1[i].to != array2[i].to) {
return false;
}
@@ -59,20 +59,24 @@ function areRangesEqual(array1, array2) {
* @return {!Array<number>} The array after processing.
*/
function removeDuplicates(inArray) {
- var out = [];
+ const out = [];
if (inArray.length == 0)
return out;
out.push(inArray[0]);
- for (var i = 1; i < inArray.length; ++i)
+ for (let i = 1; i < inArray.length; ++i)
if (inArray[i] != inArray[i - 1])
out.push(inArray[i]);
return out;
}
/** @enum {number} */
-var PageRangeStatus = {NO_ERROR: 0, SYNTAX_ERROR: -1, LIMIT_ERROR: -2};
+const PageRangeStatus = {
+ NO_ERROR: 0,
+ SYNTAX_ERROR: -1,
+ LIMIT_ERROR: -2
+};
/**
* Returns a list of ranges in |pageRangeText|. The ranges are
@@ -105,23 +109,23 @@ function pageRangeTextToPageRanges(pageRangeText, opt_totalPageCount) {
return [];
}
- var MAX_PAGE_NUMBER = 1000000000;
- var totalPageCount =
+ const MAX_PAGE_NUMBER = 1000000000;
+ const totalPageCount =
opt_totalPageCount ? opt_totalPageCount : MAX_PAGE_NUMBER;
- var regex = /^\s*([0-9]*)\s*-\s*([0-9]*)\s*$/;
- var parts = pageRangeText.split(/,/);
+ const regex = /^\s*([0-9]*)\s*-\s*([0-9]*)\s*$/;
+ const parts = pageRangeText.split(/,/);
- var pageRanges = [];
- for (var i = 0; i < parts.length; ++i) {
- var match = parts[i].match(regex);
+ const pageRanges = [];
+ for (let i = 0; i < parts.length; ++i) {
+ const match = parts[i].match(regex);
if (match) {
if (!isPositiveInteger(match[1]) && match[1] !== '')
return PageRangeStatus.SYNTAX_ERROR;
if (!isPositiveInteger(match[2]) && match[2] !== '')
return PageRangeStatus.SYNTAX_ERROR;
- var from = match[1] ? parseInt(match[1], 10) : 1;
- var to = match[2] ? parseInt(match[2], 10) : totalPageCount;
+ const from = match[1] ? parseInt(match[1], 10) : 1;
+ const to = match[2] ? parseInt(match[2], 10) : totalPageCount;
if (from > to)
return PageRangeStatus.SYNTAX_ERROR;
if (to > totalPageCount)
@@ -130,7 +134,7 @@ function pageRangeTextToPageRanges(pageRangeText, opt_totalPageCount) {
} else {
if (!isPositiveInteger(parts[i]))
return PageRangeStatus.SYNTAX_ERROR;
- var singlePageNumber = parseInt(parts[i], 10);
+ const singlePageNumber = parseInt(parts[i], 10);
if (singlePageNumber > totalPageCount)
return PageRangeStatus.LIMIT_ERROR;
pageRanges.push({'from': singlePageNumber, 'to': singlePageNumber});
@@ -150,18 +154,18 @@ function pageRangeTextToPageRanges(pageRangeText, opt_totalPageCount) {
* @return {!Array<number>} A list of all pages.
*/
function pageRangeTextToPageList(pageRangeText, totalPageCount) {
- var pageRanges = pageRangeTextToPageRanges(pageRangeText, totalPageCount);
- var pageList = [];
+ const pageRanges = pageRangeTextToPageRanges(pageRangeText, totalPageCount);
+ const pageList = [];
if (Array.isArray(pageRanges)) {
- for (var i = 0; i < pageRanges.length; ++i) {
- for (var j = pageRanges[i].from;
+ for (let i = 0; i < pageRanges.length; ++i) {
+ for (let j = pageRanges[i].from;
j <= Math.min(pageRanges[i].to, totalPageCount); ++j) {
pageList.push(j);
}
}
}
if (pageList.length == 0) {
- for (var j = 1; j <= totalPageCount; ++j)
+ for (let j = 1; j <= totalPageCount; ++j)
pageList.push(j);
}
return pageList;
@@ -173,7 +177,7 @@ function pageRangeTextToPageList(pageRangeText, totalPageCount) {
* without any duplicates. |pageList| is not affected.
*/
function pageListToPageSet(pageList) {
- var pageSet = [];
+ let pageSet = [];
if (pageList.length == 0)
return pageSet;
pageSet = pageList.slice(0);
@@ -219,7 +223,7 @@ function arrayContains(array, item) {
*/
function getStringForLocale(localizedStrings, locale) {
locale = locale.toLowerCase();
- for (var i = 0; i < localizedStrings.length; i++) {
+ for (let i = 0; i < localizedStrings.length; i++) {
if (localizedStrings[i].locale.toLowerCase() == locale)
return localizedStrings[i].value;
}
diff --git a/chromium/chrome/browser/resources/print_preview/search/cloud_destination_list.js b/chromium/chrome/browser/resources/print_preview/search/cloud_destination_list.js
deleted file mode 100644
index 7f0bcdd353d..00000000000
--- a/chromium/chrome/browser/resources/print_preview/search/cloud_destination_list.js
+++ /dev/null
@@ -1,39 +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.
-
-cr.define('print_preview', function() {
- 'use strict';
-
- /**
- * Sub-class of a destination list that shows cloud-based destinations.
- * @param {!cr.EventTarget} eventTarget Event target to pass to destination
- * items for dispatching SELECT events.
- * @constructor
- * @extends {print_preview.DestinationList}
- */
- function CloudDestinationList(eventTarget) {
- print_preview.DestinationList.call(
- this, eventTarget, loadTimeData.getString('cloudDestinationsTitle'),
- loadTimeData.getString('manage'));
- }
-
- CloudDestinationList.prototype = {
- __proto__: print_preview.DestinationList.prototype,
-
- /** @override */
- updateDestinations: function(destinations) {
- // Change the action link from "Manage..." to "Setup..." if user only has
- // the Docs printer.
- var docsId = print_preview.Destination.GooglePromotedId.DOCS;
- this.setActionLinkTextInternal(loadTimeData.getString(
- destinations.length == 1 && destinations[0].id == docsId ?
- 'setupCloudPrinters' :
- 'manage'));
- print_preview.DestinationList.prototype.updateDestinations.call(
- this, destinations);
- }
- };
-
- return {CloudDestinationList: CloudDestinationList};
-});
diff --git a/chromium/chrome/browser/resources/print_preview/search/destination_list.js b/chromium/chrome/browser/resources/print_preview/search/destination_list.js
index 9c1a2ef0144..c809f3e7c5c 100644
--- a/chromium/chrome/browser/resources/print_preview/search/destination_list.js
+++ b/chromium/chrome/browser/resources/print_preview/search/destination_list.js
@@ -143,7 +143,7 @@ cr.define('print_preview', function() {
*/
getEstimatedHeightInPixels: function(numItems) {
numItems = Math.min(numItems, this.destinations_.length);
- var headerHeight =
+ const headerHeight =
this.getChildElement('.destination-list > header').offsetHeight;
return headerHeight +
(numItems > 0 ? numItems * DestinationList.HEIGHT_OF_ITEM_ :
@@ -185,7 +185,7 @@ cr.define('print_preview', function() {
this.cloneTemplateInternal('destination-list-template'));
this.getChildElement('.title').textContent = this.title_;
if (this.actionLinkLabel_) {
- var actionLinkEl = this.getChildElement('.action-link');
+ const actionLinkEl = this.getChildElement('.action-link');
actionLinkEl.textContent = this.actionLinkLabel_;
setIsVisible(actionLinkEl, true);
}
@@ -260,7 +260,7 @@ cr.define('print_preview', function() {
if (!this.query_) {
this.renderDestinationsList_(this.destinations_);
} else {
- var filteredDests = this.destinations_.filter(function(destination) {
+ const filteredDests = this.destinations_.filter(function(destination) {
return destination.matches(assert(this.query_));
}, this);
this.renderDestinationsList_(filteredDests);
@@ -279,7 +279,7 @@ cr.define('print_preview', function() {
this.getChildElement('.no-destinations-message'),
destinations.length == 0);
setIsVisible(this.getChildElement('.destination-list > footer'), false);
- var numItems = destinations.length;
+ let numItems = destinations.length;
if (destinations.length > this.shortListSize_ && !this.isShowAll_) {
numItems = this.shortListSize_ - 1;
this.getChildElement('.total').textContent =
@@ -288,32 +288,33 @@ cr.define('print_preview', function() {
}
// Remove obsolete list items (those with no corresponding destinations).
this.listItems_ = this.listItems_.filter(item => {
- var isValid = this.destinationIds_.hasOwnProperty(item.destination.id);
+ const isValid =
+ this.destinationIds_.hasOwnProperty(item.destination.id);
if (!isValid)
this.removeChild(item);
return isValid;
});
// Prepare id -> list item cache for visible destinations.
- var visibleListItems = {};
- for (var i = 0; i < numItems; i++)
+ const visibleListItems = {};
+ for (let i = 0; i < numItems; i++)
visibleListItems[destinations[i].id] = null;
// Update visibility for all existing list items.
this.listItems_.forEach(function(item) {
- var isVisible = visibleListItems.hasOwnProperty(item.destination.id);
+ const isVisible = visibleListItems.hasOwnProperty(item.destination.id);
setIsVisible(item.getElement(), isVisible);
if (isVisible)
visibleListItems[item.destination.id] = item;
});
// Update the existing items, add the new ones (preserve the focused one).
- var listEl = this.getChildElement('.destination-list > ul');
+ const listEl = this.getChildElement('.destination-list > ul');
// We need to use activeElement instead of :focus selector, which doesn't
// work in an inactive page. See crbug.com/723579.
- var focusedEl = listEl.contains(document.activeElement) ?
+ const focusedEl = listEl.contains(document.activeElement) ?
document.activeElement :
null;
- for (var i = 0; i < numItems; i++) {
- var destination = assert(destinations[i]);
- var listItem = visibleListItems[destination.id];
+ for (let i = 0; i < numItems; i++) {
+ const destination = assert(destinations[i]);
+ const listItem = visibleListItems[destination.id];
if (listItem) {
// Destination ID is the same, but it can be registered to a different
// user account, hence passing it to the item update.
@@ -334,9 +335,9 @@ cr.define('print_preview', function() {
updateListItem_: function(listEl, listItem, focusedEl, destination) {
listItem.update(destination, this.query_);
- var itemEl = listItem.getElement();
+ const itemEl = listItem.getElement();
// Preserve focused inner element, if there's one.
- var focusedInnerEl =
+ const focusedInnerEl =
focusedEl && itemEl.contains(focusedEl) ? focusedEl : null;
if (focusedEl)
itemEl.classList.add('moving');
@@ -356,7 +357,7 @@ cr.define('print_preview', function() {
* @private
*/
renderListItem_: function(listEl, destination) {
- var listItem = new print_preview.DestinationListItem(
+ const listItem = new print_preview.DestinationListItem(
this.eventTarget_, destination, this.query_);
this.addChild(listItem);
listItem.render(assert(listEl));
diff --git a/chromium/chrome/browser/resources/print_preview/search/destination_list_item.js b/chromium/chrome/browser/resources/print_preview/search/destination_list_item.js
index b52b4938cbd..f85e0af253a 100644
--- a/chromium/chrome/browser/resources/print_preview/search/destination_list_item.js
+++ b/chromium/chrome/browser/resources/print_preview/search/destination_list_item.js
@@ -138,12 +138,12 @@ cr.define('print_preview', function() {
* @private
*/
updateUi_: function() {
- var iconImg = this.getChildElement('.destination-list-item-icon');
+ const iconImg = this.getChildElement('.destination-list-item-icon');
iconImg.src = this.destination_.iconUrl;
iconImg.srcset = this.destination_.srcSet;
- var nameEl = this.getChildElement('.destination-list-item-name');
- var textContent = this.destination_.displayName;
+ const nameEl = this.getChildElement('.destination-list-item-name');
+ let textContent = this.destination_.displayName;
if (this.query_) {
nameEl.textContent = '';
// When search query is specified, make it obvious why this particular
@@ -153,7 +153,7 @@ cr.define('print_preview', function() {
// Show the first matching property.
this.destination_.extraPropertiesToMatch.some(function(property) {
if (property.match(this.query_)) {
- var hintSpan = document.createElement('span');
+ const hintSpan = document.createElement('span');
hintSpan.className = 'search-hint';
nameEl.appendChild(hintSpan);
this.addTextWithHighlight_(hintSpan, property);
@@ -169,8 +169,8 @@ cr.define('print_preview', function() {
nameEl.title = textContent;
if (this.destination_.isExtension) {
- var extensionNameEl = this.getChildElement('.extension-name');
- var extensionName = this.destination_.extensionName;
+ const extensionNameEl = this.getChildElement('.extension-name');
+ const extensionName = this.destination_.extensionName;
extensionNameEl.title = this.destination_.extensionName;
if (this.query_) {
extensionNameEl.textContent = '';
@@ -179,7 +179,7 @@ cr.define('print_preview', function() {
extensionNameEl.textContent = this.destination_.extensionName;
}
- var extensionIconEl = this.getChildElement('.extension-icon');
+ const extensionIconEl = this.getChildElement('.extension-icon');
extensionIconEl.style.backgroundImage = '-webkit-image-set(' +
'url(chrome://extension-icon/' + this.destination_.extensionId +
'/24/1) 1x,' +
@@ -192,13 +192,13 @@ cr.define('print_preview', function() {
this.onExtensionIconKeyDown_.bind(this));
}
- var extensionIndicatorEl =
+ const extensionIndicatorEl =
this.getChildElement('.extension-controlled-indicator');
setIsVisible(extensionIndicatorEl, this.destination_.isExtension);
// Initialize the element which renders the destination's offline status.
this.getElement().classList.toggle('stale', this.destination_.isOffline);
- var offlineStatusEl = this.getChildElement('.offline-status');
+ const offlineStatusEl = this.getChildElement('.offline-status');
offlineStatusEl.textContent = this.destination_.offlineStatusText;
setIsVisible(offlineStatusEl, this.destination_.isOffline);
@@ -223,12 +223,12 @@ cr.define('print_preview', function() {
* @private
*/
addTextWithHighlight_: function(parent, text) {
- var sections = text.split(this.query_);
- for (var i = 0; i < sections.length; ++i) {
+ const sections = text.split(this.query_);
+ for (let i = 0; i < sections.length; ++i) {
if (i % 2 == 0) {
parent.appendChild(document.createTextNode(sections[i]));
} else {
- var span = document.createElement('span');
+ const span = document.createElement('span');
span.className = 'destination-list-item-query-highlight';
span.textContent = sections[i];
parent.appendChild(span);
@@ -261,7 +261,7 @@ cr.define('print_preview', function() {
// Check if the printer needs configuration before using. The user is only
// allowed to set up one printer at one time.
- var configureEvent = new CustomEvent(
+ const configureEvent = new CustomEvent(
DestinationListItem.EventType.CONFIGURE_REQUEST,
{detail: {destination: this.destination_}});
this.eventTarget_.dispatchEvent(configureEvent);
@@ -275,7 +275,7 @@ cr.define('print_preview', function() {
onDestinationActivated_: function() {
if (this.destination_.connectionStatus !=
print_preview.DestinationConnectionStatus.UNREGISTERED) {
- var selectEvt = new Event(DestinationListItem.EventType.SELECT);
+ const selectEvt = new Event(DestinationListItem.EventType.SELECT);
selectEvt.destination = this.destination_;
this.eventTarget_.dispatchEvent(selectEvt);
}
@@ -290,7 +290,7 @@ cr.define('print_preview', function() {
onKeyDown_: function(e) {
if (!hasKeyModifiers(e)) {
if (e.keyCode == 13) {
- var activeElementTag = document.activeElement ?
+ const activeElementTag = document.activeElement ?
document.activeElement.tagName.toUpperCase() :
'';
if (activeElementTag == 'LI') {
@@ -307,7 +307,7 @@ cr.define('print_preview', function() {
* @private
*/
onRegisterPromoClicked_: function() {
- var promoClickedEvent =
+ const promoClickedEvent =
new Event(DestinationListItem.EventType.REGISTER_PROMO_CLICKED);
promoClickedEvent.destination = this.destination_;
this.eventTarget_.dispatchEvent(promoClickedEvent);
diff --git a/chromium/chrome/browser/resources/print_preview/search/destination_search.html b/chromium/chrome/browser/resources/print_preview/search/destination_search.html
index 8be4042ddb0..7d3c4c325e0 100644
--- a/chromium/chrome/browser/resources/print_preview/search/destination_search.html
+++ b/chromium/chrome/browser/resources/print_preview/search/destination_search.html
@@ -9,8 +9,7 @@
<div class="search-box-container"></div>
<div class="lists">
<div class="recent-list"></div>
- <div class="local-list"></div>
- <div class="cloud-list" hidden></div>
+ <div class="print-list"></div>
</div>
<div class="action-area">
<div class="button-strip">
diff --git a/chromium/chrome/browser/resources/print_preview/search/destination_search.js b/chromium/chrome/browser/resources/print_preview/search/destination_search.js
index 7876776fc9a..8aa3456d3cb 100644
--- a/chromium/chrome/browser/resources/print_preview/search/destination_search.js
+++ b/chromium/chrome/browser/resources/print_preview/search/destination_search.js
@@ -41,12 +41,6 @@ cr.define('print_preview', function() {
this.userInfo_ = userInfo;
/**
- * Instance of native layer used to send metrics to C++ metrics handler.
- * @private {!print_preview.NativeLayer}
- */
- this.nativeLayer_ = print_preview.NativeLayer.getInstance();
-
- /**
* Currently displayed printer sharing invitation.
* @private {print_preview.Invitation}
*/
@@ -95,22 +89,13 @@ cr.define('print_preview', function() {
this.addChild(this.recentList_);
/**
- * Destination list containing local destinations.
- * @private {!print_preview.DestinationList}
- */
- this.localList_ = new print_preview.DestinationList(
- this, loadTimeData.getString('localDestinationsTitle'),
- loadTimeData.getBoolean('showLocalManageButton') ?
- loadTimeData.getString('manage') :
- null);
- this.addChild(this.localList_);
-
- /**
- * Destination list containing cloud destinations.
+ * Destination list containing all print destinations.
* @private {!print_preview.DestinationList}
*/
- this.cloudList_ = new print_preview.CloudDestinationList(this);
- this.addChild(this.cloudList_);
+ this.printList_ = new print_preview.DestinationList(
+ this, loadTimeData.getString('printDestinationsTitle'),
+ loadTimeData.getString('manage'));
+ this.addChild(this.printList_);
}
/**
@@ -121,13 +106,9 @@ cr.define('print_preview', function() {
// Dispatched when user requests to sign-in into another Google account.
ADD_ACCOUNT: 'print_preview.DestinationSearch.ADD_ACCOUNT',
- // Dispatched when the user requests to manage their cloud destinations.
- MANAGE_CLOUD_DESTINATIONS:
- 'print_preview.DestinationSearch.MANAGE_CLOUD_DESTINATIONS',
-
- // Dispatched when the user requests to manage their local destinations.
- MANAGE_LOCAL_DESTINATIONS:
- 'print_preview.DestinationSearch.MANAGE_LOCAL_DESTINATIONS',
+ // Dispatched when the user requests to manage their print destinations.
+ MANAGE_PRINT_DESTINATIONS:
+ 'print_preview.DestinationSearch.MANAGE_PRINT_DESTINATIONS',
// Dispatched when the user requests to sign-in to their Google account.
SIGN_IN: 'print_preview.DestinationSearch.SIGN_IN'
@@ -151,7 +132,6 @@ cr.define('print_preview', function() {
if (getIsVisible(this.getChildElement('.cloudprint-promo'))) {
this.metrics_.record(
print_preview.Metrics.DestinationSearchBucket.SIGNIN_PROMPT);
- this.nativeLayer_.recordAction('Signin_Impression_FromCloudPrint');
}
if (this.userInfo_.initialized)
this.onUsersChanged_();
@@ -163,8 +143,7 @@ cr.define('print_preview', function() {
this.invitationStore_.startLoadingInvitations();
} else {
// Collapse all destination lists
- this.localList_.setIsShowAll(false);
- this.cloudList_.setIsShowAll(false);
+ this.printList_.setIsShowAll(false);
if (this.provisionalDestinationResolver_)
this.provisionalDestinationResolver_.cancel();
this.resetSearch_();
@@ -179,11 +158,14 @@ cr.define('print_preview', function() {
/** Shows the Google Cloud Print promotion banner. */
showCloudPrintPromo: function() {
- setIsVisible(this.getChildElement('.cloudprint-promo'), true);
+ const cloudPrintPromoElement = this.getChildElement('.cloudprint-promo');
+ if (getIsVisible(cloudPrintPromoElement))
+ return;
+
+ setIsVisible(cloudPrintPromoElement, true);
if (this.getIsVisible()) {
this.metrics_.record(
print_preview.Metrics.DestinationSearchBucket.SIGNIN_PROMPT);
- this.nativeLayer_.recordAction('Signin_Impression_FromCloudPrint');
}
this.reflowLists_();
},
@@ -259,13 +241,9 @@ cr.define('print_preview', function() {
this.updateInvitations_.bind(this));
this.tracker.add(
- this.localList_,
+ this.printList_,
print_preview.DestinationList.EventType.ACTION_LINK_ACTIVATED,
- this.onManageLocalDestinationsActivated_.bind(this));
- this.tracker.add(
- this.cloudList_,
- print_preview.DestinationList.EventType.ACTION_LINK_ACTIVATED,
- this.onManageCloudDestinationsActivated_.bind(this));
+ this.onManagePrintDestinationsActivated_.bind(this));
this.tracker.add(
this.userInfo_, print_preview.UserInfo.EventType.USERS_CHANGED,
@@ -287,8 +265,7 @@ cr.define('print_preview', function() {
decorateInternal: function() {
this.searchBox_.render(this.getChildElement('.search-box-container'));
this.recentList_.render(this.getChildElement('.recent-list'));
- this.localList_.render(this.getChildElement('.local-list'));
- this.cloudList_.render(this.getChildElement('.cloud-list'));
+ this.printList_.render(this.getChildElement('.print-list'));
this.getChildElement('.promo-text').innerHTML = loadTimeData.getStringF(
'cloudPrintPromotion', '<a is="action-link" class="sign-in">',
'</a>');
@@ -301,7 +278,7 @@ cr.define('print_preview', function() {
* @private
*/
getAvailableListsHeight_: function() {
- var elStyle = window.getComputedStyle(this.getElement());
+ const elStyle = window.getComputedStyle(this.getElement());
return this.getElement().offsetHeight -
parseInt(elStyle.getPropertyValue('padding-top'), 10) -
parseInt(elStyle.getPropertyValue('padding-bottom'), 10) -
@@ -318,8 +295,7 @@ cr.define('print_preview', function() {
*/
filterLists_: function(query) {
this.recentList_.updateSearchQuery(query);
- this.localList_.updateSearchQuery(query);
- this.cloudList_.updateSearchQuery(query);
+ this.printList_.updateSearchQuery(query);
},
/**
@@ -336,17 +312,15 @@ cr.define('print_preview', function() {
* @private
*/
renderDestinations_: function() {
- var recentDestinations = [];
- var localDestinations = [];
- var cloudDestinations = [];
- var unregisteredCloudDestinations = [];
+ const recentDestinations = this.destinationStore_.getRecentDestinations(
+ this.userInfo_.activeUser);
+ const localDestinations = [];
+ const cloudDestinations = [];
+ const unregisteredCloudDestinations = [];
- var destinations =
+ const destinations =
this.destinationStore_.destinations(this.userInfo_.activeUser);
destinations.forEach(function(destination) {
- if (destination.isRecent) {
- recentDestinations.push(destination);
- }
if (destination.isLocal ||
destination.origin == print_preview.DestinationOrigin.DEVICE) {
localDestinations.push(destination);
@@ -367,17 +341,18 @@ cr.define('print_preview', function() {
this.registerPromoShownMetricRecorded_ = true;
}
- var finalCloudDestinations =
+ const finalCloudDestinations =
unregisteredCloudDestinations
.slice(0, DestinationSearch.MAX_PROMOTED_UNREGISTERED_PRINTERS_)
.concat(
cloudDestinations,
unregisteredCloudDestinations.slice(
DestinationSearch.MAX_PROMOTED_UNREGISTERED_PRINTERS_));
+ const finalPrintDestinations =
+ localDestinations.concat(finalCloudDestinations);
this.recentList_.updateDestinations(recentDestinations);
- this.localList_.updateDestinations(localDestinations);
- this.cloudList_.updateDestinations(finalCloudDestinations);
+ this.printList_.updateDestinations(finalPrintDestinations);
},
/**
@@ -389,42 +364,39 @@ cr.define('print_preview', function() {
return;
}
- var hasCloudList = getIsVisible(this.getChildElement('.cloud-list'));
- var lists = [this.recentList_, this.localList_];
- if (hasCloudList) {
- lists.push(this.cloudList_);
- }
-
- var getListsTotalHeight = function(lists, counts) {
+ const lists = [this.recentList_, this.printList_];
+ const getListsTotalHeight = function(lists, counts) {
return lists.reduce(function(sum, list, index) {
- var container = list.getContainerElement();
+ const container = list.getContainerElement();
return sum + list.getEstimatedHeightInPixels(counts[index]) +
parseInt(window.getComputedStyle(container).paddingBottom, 10);
}, 0);
};
- var getCounts = function(lists, count) {
+ const getCounts = function(lists, count) {
return lists.map(function(list) {
return count;
});
};
- var availableHeight = this.getAvailableListsHeight_();
- var listsEl = this.getChildElement('.lists');
+ const availableHeight = this.getAvailableListsHeight_();
+ const listsEl = this.getChildElement('.lists');
listsEl.style.maxHeight = availableHeight + 'px';
- var maxListLength = lists.reduce(function(prevCount, list) {
+ const maxListLength = lists.reduce(function(prevCount, list) {
return Math.max(prevCount, list.getDestinationsCount());
}, 0);
- for (var i = 1; i <= maxListLength; i++) {
+
+ let i = 1;
+ for (; i <= maxListLength; i++) {
if (getListsTotalHeight(lists, getCounts(lists, i)) > availableHeight) {
i--;
break;
}
}
- var counts = getCounts(lists, i);
+ const counts = getCounts(lists, i);
// Fill up the possible n-1 free slots left by the previous loop.
if (getListsTotalHeight(lists, counts) < availableHeight) {
- for (var countIndex = 0; countIndex < counts.length; countIndex++) {
+ for (let countIndex = 0; countIndex < counts.length; countIndex++) {
counts[countIndex]++;
if (getListsTotalHeight(lists, counts) > availableHeight) {
counts[countIndex]--;
@@ -439,10 +411,10 @@ cr.define('print_preview', function() {
// Set height of the list manually so that search filter doesn't change
// lists height.
- var listsHeight = getListsTotalHeight(lists, counts) + 'px';
+ const listsHeight = getListsTotalHeight(lists, counts) + 'px';
if (listsHeight != listsEl.style.height) {
// Try to close account select if there's a possibility it's open now.
- var accountSelectEl = this.getChildElement('.account-select');
+ const accountSelectEl = this.getChildElement('.account-select');
if (!accountSelectEl.disabled) {
accountSelectEl.disabled = true;
accountSelectEl.disabled = false;
@@ -457,13 +429,10 @@ cr.define('print_preview', function() {
* @private
*/
updateThrobbers_: function() {
- this.localList_.setIsThrobberVisible(
- this.destinationStore_.isLocalDestinationSearchInProgress);
- this.cloudList_.setIsThrobberVisible(
- this.destinationStore_.isCloudDestinationSearchInProgress);
+ this.printList_.setIsThrobberVisible(
+ this.destinationStore_.isPrintDestinationSearchInProgress);
this.recentList_.setIsThrobberVisible(
- this.destinationStore_.isLocalDestinationSearchInProgress &&
- this.destinationStore_.isCloudDestinationSearchInProgress);
+ this.destinationStore_.isPrintDestinationSearchInProgress);
this.reflowLists_();
},
@@ -472,7 +441,7 @@ cr.define('print_preview', function() {
* @private
*/
updateInvitations_: function() {
- var invitations = this.userInfo_.activeUser ?
+ const invitations = this.userInfo_.activeUser ?
this.invitationStore_.invitations(this.userInfo_.activeUser) :
[];
if (invitations.length > 0) {
@@ -495,7 +464,7 @@ cr.define('print_preview', function() {
* @private
*/
showInvitation_: function(invitation) {
- var invitationText = '';
+ let invitationText = '';
if (invitation.asGroupManager) {
invitationText = loadTimeData.getStringF(
'groupPrinterSharingInviteText', HTMLEscape(invitation.sender),
@@ -508,7 +477,7 @@ cr.define('print_preview', function() {
}
this.getChildElement('.invitation-text').innerHTML = invitationText;
- var acceptButton = this.getChildElement('.invitation-accept-button');
+ const acceptButton = this.getChildElement('.invitation-accept-button');
acceptButton.textContent = loadTimeData.getString(
invitation.asGroupManager ? 'acceptForGroup' : 'accept');
acceptButton.disabled = !!this.invitationStore_.invitationInProgress;
@@ -524,17 +493,17 @@ cr.define('print_preview', function() {
* @private
*/
onUsersChanged_: function() {
- var loggedIn = this.userInfo_.loggedIn;
+ const loggedIn = this.userInfo_.loggedIn;
if (loggedIn) {
- var accountSelectEl = this.getChildElement('.account-select');
+ const accountSelectEl = this.getChildElement('.account-select');
accountSelectEl.innerHTML = '';
this.userInfo_.users.forEach(function(account) {
- var option = document.createElement('option');
+ const option = document.createElement('option');
option.text = account;
option.value = account;
accountSelectEl.add(option);
});
- var option = document.createElement('option');
+ const option = document.createElement('option');
option.text = loadTimeData.getString('addAccountTitle');
option.value = '';
accountSelectEl.add(option);
@@ -545,7 +514,6 @@ cr.define('print_preview', function() {
}
setIsVisible(this.getChildElement('.user-info'), loggedIn);
- setIsVisible(this.getChildElement('.cloud-list'), loggedIn);
setIsVisible(this.getChildElement('.cloudprint-promo'), !loggedIn);
this.updateInvitations_();
},
@@ -569,15 +537,9 @@ cr.define('print_preview', function() {
* @private
*/
onDestinationConfigureRequest_: function(event) {
- var destination = event.detail.destination;
- // Cloud Print Device printers are stored in the local list
- // crbug.com/713831.
- // TODO(crbug.com/416701): Upon resolution, update this.
- var destinationItem =
- (destination.isLocal ||
- destination.origin == print_preview.DestinationOrigin.DEVICE) ?
- this.localList_.getDestinationItem(destination.id) :
- this.cloudList_.getDestinationItem(destination.id);
+ const destination = event.detail.destination;
+ const destinationItem =
+ this.printList_.getDestinationItem(destination.id);
assert(
destinationItem != null,
'User does not select a valid destination item.');
@@ -610,12 +572,12 @@ cr.define('print_preview', function() {
.then(
response => {
this.destinationInConfiguring_ = null;
- this.localList_.getDestinationItem(destination.id)
+ this.printList_.getDestinationItem(destination.id)
.onConfigureResolved(response);
},
() => {
this.destinationInConfiguring_ = null;
- this.localList_.getDestinationItem(destination.id)
+ this.printList_.getDestinationItem(destination.id)
.onConfigureResolved(
{printerId: destination.id, success: false});
});
@@ -650,7 +612,7 @@ cr.define('print_preview', function() {
!!this.provisionalDestinationResolver_,
'Unable to create provisional destination resolver');
- var lastFocusedElement = document.activeElement;
+ const lastFocusedElement = document.activeElement;
this.addChild(this.provisionalDestinationResolver_);
this.provisionalDestinationResolver_.run(this.getElement())
.then(resolvedDestination => {
@@ -688,14 +650,8 @@ cr.define('print_preview', function() {
* @private
*/
onDestinationStoreSelect_: function() {
- var destinations =
- this.destinationStore_.destinations(this.userInfo_.activeUser);
- var recentDestinations = [];
- destinations.forEach(function(destination) {
- if (destination.isRecent) {
- recentDestinations.push(destination);
- }
- });
+ const recentDestinations = this.destinationStore_.getRecentDestinations(
+ this.userInfo_.activeUser);
this.recentList_.updateDestinations(recentDestinations);
this.reflowLists_();
},
@@ -725,23 +681,13 @@ cr.define('print_preview', function() {
},
/**
- * Called when the manage cloud printers action is activated.
- * @private
- */
- onManageCloudDestinationsActivated_: function() {
- cr.dispatchSimpleEvent(
- this,
- print_preview.DestinationSearch.EventType.MANAGE_CLOUD_DESTINATIONS);
- },
-
- /**
- * Called when the manage local printers action is activated.
+ * Called when the manage all printers action is activated.
* @private
*/
- onManageLocalDestinationsActivated_: function() {
+ onManagePrintDestinationsActivated_: function() {
cr.dispatchSimpleEvent(
this,
- print_preview.DestinationSearch.EventType.MANAGE_LOCAL_DESTINATIONS);
+ print_preview.DestinationSearch.EventType.MANAGE_PRINT_DESTINATIONS);
},
/**
@@ -761,8 +707,8 @@ cr.define('print_preview', function() {
* @private
*/
onAccountChange_: function() {
- var accountSelectEl = this.getChildElement('.account-select');
- var account =
+ const accountSelectEl = this.getChildElement('.account-select');
+ const account =
accountSelectEl.options[accountSelectEl.selectedIndex].value;
if (account) {
this.userInfo_.activeUser = account;
@@ -773,7 +719,7 @@ cr.define('print_preview', function() {
} else {
cr.dispatchSimpleEvent(this, DestinationSearch.EventType.ADD_ACCOUNT);
// Set selection back to the active user.
- for (var i = 0; i < accountSelectEl.options.length; i++) {
+ for (let i = 0; i < accountSelectEl.options.length; i++) {
if (accountSelectEl.options[i].value == this.userInfo_.activeUser) {
accountSelectEl.selectedIndex = i;
break;
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 29dc741bcee..e60eecccf15 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
@@ -111,11 +111,11 @@ cr.define('print_preview', function() {
this.setElementInternal(
this.cloneTemplateInternal('extension-usb-resolver'));
- var extNameEl = this.getChildElement('.usb-permission-extension-name');
+ const extNameEl = this.getChildElement('.usb-permission-extension-name');
extNameEl.title = this.destination_.extensionName;
extNameEl.textContent = this.destination_.extensionName;
- var extIconEl = this.getChildElement('.usb-permission-extension-icon');
+ const extIconEl = this.getChildElement('.usb-permission-extension-icon');
extIconEl.style.backgroundImage = '-webkit-image-set(' +
'url(chrome://extension-icon/' + this.destination_.extensionId +
'/24/1) 1x,' +
diff --git a/chromium/chrome/browser/resources/print_preview/settings/advanced_settings/advanced_settings.js b/chromium/chrome/browser/resources/print_preview/settings/advanced_settings/advanced_settings.js
index 799f206980a..601da25b01c 100644
--- a/chromium/chrome/browser/resources/print_preview/settings/advanced_settings/advanced_settings.js
+++ b/chromium/chrome/browser/resources/print_preview/settings/advanced_settings/advanced_settings.js
@@ -107,7 +107,7 @@ cr.define('print_preview', function() {
/** @override */
onEnterPressedInternal: function() {
- var doneButton = this.getChildElement('.button-strip .done-button');
+ const doneButton = this.getChildElement('.button-strip .done-button');
if (!doneButton.disabled)
doneButton.click();
return !doneButton.disabled;
@@ -118,7 +118,7 @@ cr.define('print_preview', function() {
* @private
*/
getAvailableContentHeight_: function() {
- var elStyle = window.getComputedStyle(this.getElement());
+ const elStyle = window.getComputedStyle(this.getElement());
return this.getElement().offsetHeight -
parseInt(elStyle.getPropertyValue('padding-top'), 10) -
parseInt(elStyle.getPropertyValue('padding-bottom'), 10) -
@@ -132,8 +132,8 @@ cr.define('print_preview', function() {
* @private
*/
filterLists_: function(query) {
- var atLeastOneMatch = false;
- var lastVisibleItemWithBubble = null;
+ let atLeastOneMatch = false;
+ let lastVisibleItemWithBubble = null;
this.items_.forEach(function(item) {
item.updateSearchQuery(query);
if (getIsVisible(item.getElement()))
@@ -168,29 +168,29 @@ cr.define('print_preview', function() {
});
this.items_ = [];
- var extraPadding = this.element_.querySelector(
+ let extraPadding = this.element_.querySelector(
'.' + AdvancedSettings.Classes_.EXTRA_PADDING);
if (extraPadding)
extraPadding.parentNode.removeChild(extraPadding);
- var vendorCapabilities = this.printTicketStore_.vendorItems.capability;
+ const vendorCapabilities = this.printTicketStore_.vendorItems.capability;
if (!vendorCapabilities)
return;
- var availableHeight = this.getAvailableContentHeight_();
- var containerEl = this.getChildElement('.settings-area');
+ const availableHeight = this.getAvailableContentHeight_();
+ const containerEl = this.getChildElement('.settings-area');
containerEl.style.maxHeight = availableHeight + 'px';
- var settingsEl = this.getChildElement('.settings');
+ const settingsEl = this.getChildElement('.settings');
vendorCapabilities.forEach(capability => {
- var item = new print_preview.AdvancedSettingsItem(
+ const item = new print_preview.AdvancedSettingsItem(
this.printTicketStore_, capability);
this.addChild(item);
item.render(settingsEl);
this.items_.push(item);
});
- var searchBoxArea = this.getChildElement('.search-box-area');
+ const searchBoxArea = this.getChildElement('.search-box-area');
if (this.items_.length <= 1) {
setIsVisible(searchBoxArea, false);
} else {
@@ -221,7 +221,7 @@ cr.define('print_preview', function() {
onApplySettings_: function(evt) {
this.setIsVisible(false);
- var values = {};
+ const values = {};
this.items_.forEach(item => {
if (item.isModified())
values[item.id] = item.selectedValue;
diff --git a/chromium/chrome/browser/resources/print_preview/settings/advanced_settings/advanced_settings_item.js b/chromium/chrome/browser/resources/print_preview/settings/advanced_settings/advanced_settings_item.js
index 40e4be31452..b5ce64999e5 100644
--- a/chromium/chrome/browser/resources/print_preview/settings/advanced_settings/advanced_settings_item.js
+++ b/chromium/chrome/browser/resources/print_preview/settings/advanced_settings/advanced_settings_item.js
@@ -155,7 +155,7 @@ cr.define('print_preview', function() {
this.selectedValue_ = this.text_.value || null;
if (this.query_) {
- var optionMatches = (this.selectedValue_ || '').match(this.query_);
+ const optionMatches = (this.selectedValue_ || '').match(this.query_);
// Even if there's no match anymore, keep the item visible to do not
// surprise user. Even if there's a match, do not show the bubble, user
// is already aware that this option is visible and matches the search.
@@ -173,7 +173,7 @@ cr.define('print_preview', function() {
* @private
*/
getEntityDisplayName_: function(entity) {
- var displayName = entity.display_name;
+ let displayName = entity.display_name;
if (!displayName && entity.display_name_localized)
displayName = getStringForCurrentLocale(entity.display_name_localized);
return displayName || '';
@@ -184,22 +184,22 @@ cr.define('print_preview', function() {
* @private
*/
renderCapability_: function() {
- var textContent = this.getEntityDisplayName_(this.capability_);
+ const textContent = this.getEntityDisplayName_(this.capability_);
// Whether capability name matches the query.
- var nameMatches = this.query_ ? !!textContent.match(this.query_) : true;
+ const nameMatches = this.query_ ? !!textContent.match(this.query_) : true;
// An array of text segments of the capability value matching the query.
- var optionMatches = null;
+ let optionMatches = null;
if (this.query_) {
if (this.capability_.type == 'SELECT') {
// Look for the first option that matches the query.
- for (var i = 0; i < this.select_.length && !optionMatches; i++)
+ for (let i = 0; i < this.select_.length && !optionMatches; i++)
optionMatches = this.select_.options[i].text.match(this.query_);
} else {
optionMatches = (this.text_.value || this.text_.placeholder ||
'').match(this.query_);
}
}
- var matches = nameMatches || !!optionMatches;
+ const matches = nameMatches || !!optionMatches;
if (!optionMatches)
this.hideSearchBubble_();
@@ -208,7 +208,7 @@ cr.define('print_preview', function() {
if (!matches)
return;
- var nameEl = this.getChildElement('.advanced-settings-item-label');
+ const nameEl = this.getChildElement('.advanced-settings-item-label');
if (this.query_) {
nameEl.textContent = '';
this.addTextWithHighlight_(nameEl, textContent);
@@ -227,7 +227,7 @@ cr.define('print_preview', function() {
* @private
*/
showSearchBubble_: function(text) {
- var element =
+ const element =
this.capability_.type == 'SELECT' ? this.select_ : this.text_;
if (!this.searchBubble_) {
this.searchBubble_ = new print_preview.SearchBubble(text);
@@ -270,17 +270,17 @@ cr.define('print_preview', function() {
setIsVisible(
assert(this.getChildElement('.advanced-settings-item-value-select')),
true);
- var selectEl = this.select_;
- var indexToSelect = 0;
+ const selectEl = this.select_;
+ let indexToSelect = 0;
this.capability_.select_cap.option.forEach(function(option, index) {
- var item = document.createElement('option');
+ const item = document.createElement('option');
item.text = this.getEntityDisplayName_(option);
item.value = option.value;
if (option.is_default)
indexToSelect = index;
selectEl.appendChild(item);
}, this);
- for (var i = 0, option; (option = selectEl.options[i]); i++) {
+ for (let i = 0, option; (option = selectEl.options[i]); i++) {
if (option.value == this.selectedValue_) {
indexToSelect = i;
break;
@@ -298,7 +298,7 @@ cr.define('print_preview', function() {
assert(this.getChildElement('.advanced-settings-item-value-text')),
true);
- var defaultValue = null;
+ let defaultValue = null;
if (this.capability_.type == 'TYPED_VALUE' &&
this.capability_.typed_value_cap) {
defaultValue = this.capability_.typed_value_cap.default || null;
@@ -324,7 +324,7 @@ cr.define('print_preview', function() {
if (i % 2 == 0) {
parent.appendChild(document.createTextNode(section));
} else {
- var span = document.createElement('span');
+ const span = document.createElement('span');
span.className = 'advanced-settings-item-query-highlight';
span.textContent = section;
parent.appendChild(span);
diff --git a/chromium/chrome/browser/resources/print_preview/settings/color_settings.js b/chromium/chrome/browser/resources/print_preview/settings/color_settings.js
index c2df674dfc6..bb9e7d0eed9 100644
--- a/chromium/chrome/browser/resources/print_preview/settings/color_settings.js
+++ b/chromium/chrome/browser/resources/print_preview/settings/color_settings.js
@@ -58,8 +58,8 @@ cr.define('print_preview', function() {
* @private
*/
onSelectChange_: function() {
- var select = this.select_;
- var isColor = select.options[select.selectedIndex].value == 'color';
+ const select = this.select_;
+ const isColor = select.options[select.selectedIndex].value == 'color';
this.colorTicketItem_.updateValue(isColor);
},
@@ -78,9 +78,9 @@ cr.define('print_preview', function() {
*/
updateState_: function() {
if (this.isAvailable()) {
- var select = this.select_;
- var valueToSelect = this.colorTicketItem_.getValue() ? 'color' : 'bw';
- for (var i = 0; i < select.options.length; i++) {
+ const select = this.select_;
+ const valueToSelect = this.colorTicketItem_.getValue() ? 'color' : 'bw';
+ for (let i = 0; i < select.options.length; i++) {
if (select.options[i].value == valueToSelect) {
select.selectedIndex = i;
break;
diff --git a/chromium/chrome/browser/resources/print_preview/settings/copies_settings.js b/chromium/chrome/browser/resources/print_preview/settings/copies_settings.js
index 1dbcc74d6ba..0079fb529c6 100644
--- a/chromium/chrome/browser/resources/print_preview/settings/copies_settings.js
+++ b/chromium/chrome/browser/resources/print_preview/settings/copies_settings.js
@@ -139,7 +139,7 @@ cr.define('print_preview', function() {
*/
onTextfieldTimeout_: function() {
this.textfieldTimeout_ = null;
- var newValue =
+ const newValue =
(this.inputField_.validity.valid && this.inputField_.value != '') ?
this.inputField_.valueAsNumber.toString() :
'';
diff --git a/chromium/chrome/browser/resources/print_preview/settings/destination_settings.js b/chromium/chrome/browser/resources/print_preview/settings/destination_settings.js
index 54d1994e9c8..631df0d33df 100644
--- a/chromium/chrome/browser/resources/print_preview/settings/destination_settings.js
+++ b/chromium/chrome/browser/resources/print_preview/settings/destination_settings.js
@@ -80,7 +80,7 @@ cr.define('print_preview', function() {
/** @override */
set isEnabled(isEnabled) {
- var changeButton = this.getElement().getElementsByClassName(
+ const changeButton = this.getElement().getElementsByClassName(
print_preview.DestinationSettingsClasses_.CHANGE_BUTTON)[0];
changeButton.disabled = !isEnabled;
},
@@ -88,7 +88,7 @@ cr.define('print_preview', function() {
/** @override */
enterDocument: function() {
print_preview.SettingsSection.prototype.enterDocument.call(this);
- var changeButton = this.getElement().getElementsByClassName(
+ const changeButton = this.getElement().getElementsByClassName(
print_preview.DestinationSettingsClasses_.CHANGE_BUTTON)[0];
this.tracker.add(
changeButton, 'click', this.onChangeButtonClick_.bind(this));
@@ -118,34 +118,34 @@ cr.define('print_preview', function() {
* @private
*/
onDestinationSelect_: function() {
- var destinationSettingsBoxEl =
+ const destinationSettingsBoxEl =
this.getChildElement('.destination-settings-box');
- var destination = this.destinationStore_.selectedDestination;
+ const destination = this.destinationStore_.selectedDestination;
if (destination != null) {
- var nameEl = this.getElement().getElementsByClassName(
+ const nameEl = this.getElement().getElementsByClassName(
print_preview.DestinationSettingsClasses_.NAME)[0];
nameEl.textContent = destination.displayName;
nameEl.title = destination.displayName;
- var iconEl = this.getElement().getElementsByClassName(
+ const iconEl = this.getElement().getElementsByClassName(
print_preview.DestinationSettingsClasses_.ICON)[0];
iconEl.src = destination.iconUrl;
iconEl.srcset = destination.srcSet;
- var hint = destination.hint;
- var locationEl = this.getElement().getElementsByClassName(
+ const hint = destination.hint;
+ const locationEl = this.getElement().getElementsByClassName(
print_preview.DestinationSettingsClasses_.LOCATION)[0];
locationEl.textContent = hint;
locationEl.title = hint;
- var offlineStatusText = destination.offlineStatusText;
- var offlineStatusEl =
+ const offlineStatusText = destination.offlineStatusText;
+ const offlineStatusEl =
this.getChildElement('.destination-settings-offline-status');
offlineStatusEl.textContent = offlineStatusText;
offlineStatusEl.title = offlineStatusText;
- var isOffline = destination.isOffline;
+ const isOffline = destination.isOffline;
destinationSettingsBoxEl.classList.toggle(
print_preview.DestinationSettingsClasses_.STALE, isOffline);
setIsVisible(locationEl, !isOffline);
@@ -159,9 +159,9 @@ cr.define('print_preview', function() {
},
onSelectedDestinationNameSet_: function() {
- var destinationName =
+ const destinationName =
this.destinationStore_.selectedDestination.displayName;
- var nameEl = this.getElement().getElementsByClassName(
+ const nameEl = this.getElement().getElementsByClassName(
print_preview.DestinationSettingsClasses_.THOBBER_NAME)[0];
nameEl.textContent = destinationName;
nameEl.title = destinationName;
diff --git a/chromium/chrome/browser/resources/print_preview/settings/dpi_settings.js b/chromium/chrome/browser/resources/print_preview/settings/dpi_settings.js
index 4e44a50198e..4d2823d89bf 100644
--- a/chromium/chrome/browser/resources/print_preview/settings/dpi_settings.js
+++ b/chromium/chrome/browser/resources/print_preview/settings/dpi_settings.js
@@ -21,8 +21,8 @@ cr.define('print_preview', function() {
/** @override */
getDefaultDisplayName_: function(option) {
- var hDpi = option.horizontal_dpi || 0;
- var vDpi = option.vertical_dpi || 0;
+ const hDpi = option.horizontal_dpi || 0;
+ const vDpi = option.vertical_dpi || 0;
if (hDpi > 0 && vDpi > 0 && hDpi != vDpi) {
return loadTimeData.getStringF(
'nonIsotropicDpiItemLabel', hDpi.toLocaleString(),
diff --git a/chromium/chrome/browser/resources/print_preview/settings/layout_settings.js b/chromium/chrome/browser/resources/print_preview/settings/layout_settings.js
index acb018e86f0..ec423d22f94 100644
--- a/chromium/chrome/browser/resources/print_preview/settings/layout_settings.js
+++ b/chromium/chrome/browser/resources/print_preview/settings/layout_settings.js
@@ -58,8 +58,8 @@ cr.define('print_preview', function() {
* @private
*/
onSelectChange_: function() {
- var select = this.select_;
- var isLandscape =
+ const select = this.select_;
+ const isLandscape =
select.options[select.selectedIndex].value == 'landscape';
this.landscapeTicketItem_.updateValue(isLandscape);
},
@@ -81,10 +81,10 @@ cr.define('print_preview', function() {
*/
onLandscapeTicketItemChange_: function() {
if (this.isAvailable()) {
- var select = this.select_;
- var valueToSelect =
+ const select = this.select_;
+ const valueToSelect =
this.landscapeTicketItem_.getValue() ? 'landscape' : 'portrait';
- for (var i = 0; i < select.options.length; i++) {
+ for (let i = 0; i < select.options.length; i++) {
if (select.options[i].value == valueToSelect) {
select.selectedIndex = i;
break;
diff --git a/chromium/chrome/browser/resources/print_preview/settings/margin_settings.js b/chromium/chrome/browser/resources/print_preview/settings/margin_settings.js
index f99b3de2fa8..4e8168d90a6 100644
--- a/chromium/chrome/browser/resources/print_preview/settings/margin_settings.js
+++ b/chromium/chrome/browser/resources/print_preview/settings/margin_settings.js
@@ -75,8 +75,8 @@ cr.define('print_preview', function() {
* @private
*/
onSelectChange_: function() {
- var select = this.select_;
- var marginsType =
+ const select = this.select_;
+ const marginsType =
/** @type {!print_preview.ticket_items.MarginsTypeValue} */ (
select.selectedIndex);
this.marginsTypeTicketItem_.updateValue(marginsType);
@@ -89,11 +89,11 @@ cr.define('print_preview', function() {
*/
onMarginsTypeTicketItemChange_: function() {
if (this.isAvailable()) {
- var select = this.select_;
- var marginsType =
+ const select = this.select_;
+ const marginsType =
/** @type {!print_preview.ticket_items.MarginsTypeValue} */ (
this.marginsTypeTicketItem_.getValue());
- var selectedMarginsType =
+ const selectedMarginsType =
/** @type {!print_preview.ticket_items.MarginsTypeValue} */ (
select.selectedIndex);
if (marginsType != selectedMarginsType) {
diff --git a/chromium/chrome/browser/resources/print_preview/settings/more_settings.js b/chromium/chrome/browser/resources/print_preview/settings/more_settings.js
index 3c044fd4efc..5648df8a97b 100644
--- a/chromium/chrome/browser/resources/print_preview/settings/more_settings.js
+++ b/chromium/chrome/browser/resources/print_preview/settings/more_settings.js
@@ -124,18 +124,18 @@ cr.define('print_preview', function() {
this.getChildElement('.more-settings-label').textContent =
loadTimeData.getString(
this.isExpanded ? 'lessOptionsLabel' : 'moreOptionsLabel');
- var iconEl = this.getChildElement('.more-settings-icon');
+ const iconEl = this.getChildElement('.more-settings-icon');
iconEl.classList.toggle('more-settings-icon-plus', !this.isExpanded);
iconEl.classList.toggle('more-settings-icon-minus', this.isExpanded);
- var availableSections =
+ const availableSections =
this.settingsSections_.reduce(function(count, section) {
return count + (section.isAvailable() ? 1 : 0);
}, 0);
// Magic 6 is chosen as the number of sections when it still feels like
// manageable and not too crowded.
- var hasSectionsToToggle = availableSections > 6 &&
+ const hasSectionsToToggle = availableSections > 6 &&
this.settingsSections_.some(function(section) {
return section.hasCollapsibleContent();
});
@@ -145,7 +145,7 @@ cr.define('print_preview', function() {
else
fadeOutElement(this.getElement());
- var collapseContent = !this.isExpanded && hasSectionsToToggle;
+ const collapseContent = !this.isExpanded && hasSectionsToToggle;
this.settingsSections_.forEach(function(section) {
section.setCollapseContent(collapseContent, noAnimation);
});
diff --git a/chromium/chrome/browser/resources/print_preview/settings/other_options_settings.js b/chromium/chrome/browser/resources/print_preview/settings/other_options_settings.js
index 56c10e26bd8..ec3d88b7a63 100644
--- a/chromium/chrome/browser/resources/print_preview/settings/other_options_settings.js
+++ b/chromium/chrome/browser/resources/print_preview/settings/other_options_settings.js
@@ -186,7 +186,7 @@ cr.define('print_preview', function() {
* element, as this checkbox is enabled based on whether the user has
* selected something in the page, which is different logic from the
* other elements. */
- for (var i = 0; i < this.elements_.length - 1; i++)
+ for (let i = 0; i < this.elements_.length - 1; i++)
this.elements_[i].checkbox.disabled = !isEnabled;
},
@@ -207,13 +207,13 @@ cr.define('print_preview', function() {
/** @override */
exitDocument: function() {
print_preview.SettingsSection.prototype.exitDocument.call(this);
- for (var i = 0; i < this.elements_.length; i++)
+ for (let i = 0; i < this.elements_.length; i++)
this.elements_[i].exitDocument();
},
/** @override */
decorateInternal: function() {
- for (var i = 0; i < this.elements_.length; i++)
+ for (let i = 0; i < this.elements_.length; i++)
this.elements_[i].decorate();
$('rasterize-container').hidden = !this.rasterizeEnabled_;
},
@@ -221,7 +221,7 @@ cr.define('print_preview', function() {
/** @override */
updateUiStateInternal: function() {
if (this.isAvailable()) {
- for (var i = 0; i < this.elements_.length; i++)
+ for (let i = 0; i < this.elements_.length; i++)
this.elements_[i].setVisibility(this.collapseContent);
}
print_preview.SettingsSection.prototype.updateUiStateInternal.call(this);
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 edbd64c3e23..da8d5db78dd 100644
--- a/chromium/chrome/browser/resources/print_preview/settings/page_settings.js
+++ b/chromium/chrome/browser/resources/print_preview/settings/page_settings.js
@@ -109,7 +109,7 @@ cr.define('print_preview', function() {
/** @override */
enterDocument: function() {
print_preview.SettingsSection.prototype.enterDocument.call(this);
- var customInput = assert(this.customInput_);
+ const customInput = assert(this.customInput_);
this.tracker.add(
assert(this.allRadio_), 'click', this.onAllRadioClick_.bind(this));
this.tracker.add(
@@ -164,7 +164,7 @@ cr.define('print_preview', function() {
fadeOutElement(this.customHintEl_);
return;
}
- var message;
+ let message;
if (validity === PageRangeStatus.LIMIT_ERROR) {
if (this.pageRangeTicketItem_.getDocumentNumPages()) {
message = loadTimeData.getStringF(
@@ -277,7 +277,7 @@ cr.define('print_preview', function() {
*/
onPageRangeTicketItemChange_: function() {
if (this.isAvailable()) {
- var pageRangeStr = this.pageRangeTicketItem_.getValue();
+ const pageRangeStr = this.pageRangeTicketItem_.getValue();
if (pageRangeStr || this.customRadio_.checked) {
if (!document.hasFocus() ||
document.activeElement != this.customInput_) {
diff --git a/chromium/chrome/browser/resources/print_preview/settings/scaling_settings.js b/chromium/chrome/browser/resources/print_preview/settings/scaling_settings.js
index 2b12f418253..a4174049a4c 100644
--- a/chromium/chrome/browser/resources/print_preview/settings/scaling_settings.js
+++ b/chromium/chrome/browser/resources/print_preview/settings/scaling_settings.js
@@ -227,7 +227,7 @@ cr.define('print_preview', function() {
return;
// Convert value to a valid number or ''. The scaling ticket item assumes
// the only invalid value is ''.
- var value =
+ const value =
(this.inputField_.validity.valid && this.inputField_.value != '') ?
this.inputField_.valueAsNumber.toString() :
'';
diff --git a/chromium/chrome/browser/resources/print_preview/settings/settings_section.js b/chromium/chrome/browser/resources/print_preview/settings/settings_section.js
index 6deb0aa3393..e3b89b32e68 100644
--- a/chromium/chrome/browser/resources/print_preview/settings/settings_section.js
+++ b/chromium/chrome/browser/resources/print_preview/settings/settings_section.js
@@ -91,8 +91,9 @@ cr.define('print_preview', function() {
* @protected
*/
updateUiStateInternal: function(opt_noAnimation) {
- var hasCollapsibleContent = this.hasCollapsibleContent();
- var changed = this.hasCollapsibleContentCached_ != hasCollapsibleContent;
+ const hasCollapsibleContent = this.hasCollapsibleContent();
+ const changed =
+ this.hasCollapsibleContentCached_ != hasCollapsibleContent;
this.hasCollapsibleContentCached_ = hasCollapsibleContent;
if (this.isSectionVisibleInternal())
diff --git a/chromium/chrome/browser/resources/print_preview/settings/settings_section_select.js b/chromium/chrome/browser/resources/print_preview/settings/settings_section_select.js
index ab8b1d59fc0..fb20c2d7e06 100644
--- a/chromium/chrome/browser/resources/print_preview/settings/settings_section_select.js
+++ b/chromium/chrome/browser/resources/print_preview/settings/settings_section_select.js
@@ -69,22 +69,22 @@ cr.define('print_preview', function() {
* @private
*/
updateSelect_: function() {
- var select = this.select_;
+ const select = this.select_;
if (!this.isAvailable()) {
select.innerHTML = '';
return;
}
// Should the select content be updated?
- var sameContent =
+ const sameContent =
this.ticketItem_.capability.option.length == select.length &&
this.ticketItem_.capability.option.every(function(option, index) {
return select.options[index].value == JSON.stringify(option);
});
- var indexToSelect = select.selectedIndex;
+ let indexToSelect = select.selectedIndex;
if (!sameContent) {
select.innerHTML = '';
this.ticketItem_.capability.option.forEach(function(option, index) {
- var selectOption = document.createElement('option');
+ const selectOption = document.createElement('option');
selectOption.text = this.getCustomDisplayName_(option) ||
this.getDefaultDisplayName_(option);
selectOption.value = JSON.stringify(option);
@@ -94,8 +94,8 @@ cr.define('print_preview', function() {
}, this);
}
// Try to select current ticket item.
- var valueToSelect = JSON.stringify(this.ticketItem_.getValue());
- for (var i = 0, option; (option = select.options[i]); i++) {
+ const valueToSelect = JSON.stringify(this.ticketItem_.getValue());
+ for (let i = 0, option; (option = select.options[i]); i++) {
if (option.value == valueToSelect) {
indexToSelect = i;
break;
@@ -111,7 +111,7 @@ cr.define('print_preview', function() {
* @private
*/
getCustomDisplayName_: function(option) {
- var displayName = option.custom_display_name;
+ let displayName = option.custom_display_name;
if (!displayName && option.custom_display_name_localized) {
displayName =
getStringForCurrentLocale(option.custom_display_name_localized);
@@ -133,7 +133,7 @@ cr.define('print_preview', function() {
* @private
*/
onSelectChange_: function() {
- var select = this.select_;
+ const select = this.select_;
this.ticketItem_.updateValue(
JSON.parse(select.options[select.selectedIndex].value));
},
diff --git a/chromium/chrome/browser/resources/safe_browsing/download_file_types.asciipb b/chromium/chrome/browser/resources/safe_browsing/download_file_types.asciipb
index 4fd285afc89..04a91c17835 100644
--- a/chromium/chrome/browser/resources/safe_browsing/download_file_types.asciipb
+++ b/chromium/chrome/browser/resources/safe_browsing/download_file_types.asciipb
@@ -8,8 +8,9 @@
##
## Top level settings
##
-version_id: 13
+version_id: 15
sampled_ping_probability: 0.01
+max_archived_binaries_to_report: 10
default_file_type {
uma_value: 18
ping_setting: SAMPLED_PING
@@ -786,6 +787,41 @@ file_types {
uma_value: 23
ping_setting: FULL_PING
}
+file_types {
+ # Opened by uTorrent and Transmission (can be a renamed .torrent)
+ # Added crbug.com/767502
+ extension: "btapp"
+ uma_value: 298
+ ping_setting: FULL_PING
+}
+file_types {
+ # Opened by uTorrent and Transmission (can be a renamed .torrent)
+ # Added crbug.com/767502
+ extension: "btbtskin"
+ uma_value: 299
+ ping_setting: FULL_PING
+}
+file_types {
+ # Opened by uTorrent and Transmission (can be a renamed .torrent)
+ # Added crbug.com/767502
+ extension: "btinstall"
+ uma_value: 300
+ ping_setting: FULL_PING
+}
+file_types {
+ # Opened by uTorrent and Transmission (can be a renamed .torrent)
+ # Added crbug.com/767502
+ extension: "btkey"
+ uma_value: 301
+ ping_setting: FULL_PING
+}
+file_types {
+ # Opened by uTorrent and Transmission (can be a renamed .torrent)
+ # Added crbug.com/767502
+ extension: "btsearch"
+ uma_value: 302
+ ping_setting: FULL_PING
+}
##
## Windows-specific files
@@ -1529,7 +1565,7 @@ file_types {
}
}
-# Other Windows files
+# Other Windows files (some cross-platform too)
file_types {
extension: "ad"
uma_value: 262
@@ -1695,6 +1731,30 @@ file_types {
}
}
file_types {
+ # HTML-like file. This extension can be abused by UwS campaigns to evade
+ # referrer attribution via a two-level download scheme. crbug.com/719784
+ # Added in https://crbug.com/762702
+ extension: "dhtml"
+ uma_value: 303
+ ping_setting: FULL_PING
+}
+file_types {
+ # HTML-like file. This extension can be abused by UwS campaigns to evade
+ # referrer attribution via a two-level download scheme. crbug.com/719784
+ # Added in https://crbug.com/762702
+ extension: "dhtm"
+ uma_value: 304
+ ping_setting: FULL_PING
+}
+file_types {
+ # HTML-like file. This extension can be abused by UwS campaigns to evade
+ # referrer attribution via a two-level download scheme. crbug.com/719784
+ # Added in https://crbug.com/762702
+ extension: "dht"
+ uma_value: 305
+ ping_setting: FULL_PING
+}
+file_types {
# Windows executable. It can gain control of an executable launched from the
# same directory, so it can do bad things without ever being clicked on.
extension: "dll"
@@ -1814,10 +1874,6 @@ file_types {
extension: "htm"
uma_value: 284
ping_setting: FULL_PING
- platform_settings {
- danger_level: NOT_DANGEROUS
- auto_open_hint: ALLOW_AUTO_OPEN
- }
}
file_types {
# HTML file. This extension is abused by UwS campaigns to evade referrer
@@ -1825,10 +1881,6 @@ file_types {
extension: "html"
uma_value: 285
ping_setting: FULL_PING
- platform_settings {
- danger_level: NOT_DANGEROUS
- auto_open_hint: ALLOW_AUTO_OPEN
- }
}
file_types {
# Hypertext Template File. See https://support.microsoft.com/kb/181689.
@@ -2131,6 +2183,30 @@ file_types {
}
}
file_types {
+ # HTML-like file. This extension can be abused by UwS campaigns to evade
+ # referrer attribution via a two-level download scheme. crbug.com/719784
+ # Added in https://crbug.com/762702
+ extension: "shtml"
+ uma_value: 306
+ ping_setting: FULL_PING
+}
+file_types {
+ # HTML-like file. This extension can be abused by UwS campaigns to evade
+ # referrer attribution via a two-level download scheme. crbug.com/719784
+ # Added in https://crbug.com/762702
+ extension: "shtm"
+ uma_value: 307
+ ping_setting: FULL_PING
+}
+file_types {
+ # HTML-like file. This extension can be abused by UwS campaigns to evade
+ # referrer attribution via a two-level download scheme. crbug.com/719784
+ # Added in https://crbug.com/762702
+ extension: "sht"
+ uma_value: 308
+ ping_setting: FULL_PING
+}
+file_types {
# System executable. Windows tries hard to prevent you from opening these
# types of files.
extension: "sys"
@@ -2154,6 +2230,112 @@ file_types {
}
}
file_types {
+ # A Visio file type. Added in https://crbug.com/771469
+ extension: "vdx"
+ uma_value: 289
+ ping_setting: FULL_PING
+ platform_settings {
+ platform: PLATFORM_WINDOWS
+ danger_level: ALLOW_ON_USER_GESTURE
+ auto_open_hint: ALLOW_AUTO_OPEN
+ }
+}
+file_types {
+ # A Visio file type. Added in https://crbug.com/771469
+ extension: "vsx"
+ uma_value: 290
+ ping_setting: FULL_PING
+ platform_settings {
+ platform: PLATFORM_WINDOWS
+ danger_level: ALLOW_ON_USER_GESTURE
+ auto_open_hint: ALLOW_AUTO_OPEN
+ }
+}
+file_types {
+ # A Visio file type. Added in https://crbug.com/771469
+ extension: "vtx"
+ uma_value: 291
+ ping_setting: FULL_PING
+ platform_settings {
+ platform: PLATFORM_WINDOWS
+ danger_level: ALLOW_ON_USER_GESTURE
+ auto_open_hint: ALLOW_AUTO_OPEN
+ }
+}
+file_types {
+ # A Visio file type. Added in https://crbug.com/771469
+ extension: "vsdx"
+ uma_value: 292
+ ping_setting: FULL_PING
+ platform_settings {
+ platform: PLATFORM_WINDOWS
+ danger_level: ALLOW_ON_USER_GESTURE
+ auto_open_hint: ALLOW_AUTO_OPEN
+ }
+ # TODO(nparker): Unpack these as ZIP files. https://crbug.com/628796
+}
+file_types {
+ # A Visio file type. Added in https://crbug.com/771469
+ extension: "vssx"
+ uma_value: 293
+ ping_setting: FULL_PING
+ platform_settings {
+ platform: PLATFORM_WINDOWS
+ danger_level: ALLOW_ON_USER_GESTURE
+ auto_open_hint: ALLOW_AUTO_OPEN
+ }
+ # TODO(nparker): Unpack these as ZIP files. https://crbug.com/628796
+}
+file_types {
+ # A Visio file type. Added in https://crbug.com/771469
+ extension: "vstx"
+ uma_value: 294
+ ping_setting: FULL_PING
+ platform_settings {
+ platform: PLATFORM_WINDOWS
+ danger_level: ALLOW_ON_USER_GESTURE
+ auto_open_hint: ALLOW_AUTO_OPEN
+ }
+ # TODO(nparker): Unpack these as ZIP files. https://crbug.com/628796
+}
+file_types {
+ # A Visio file type. Added in https://crbug.com/771469
+ extension: "vsdm"
+ uma_value: 295
+ ping_setting: FULL_PING
+ platform_settings {
+ platform: PLATFORM_WINDOWS
+ danger_level: ALLOW_ON_USER_GESTURE
+ auto_open_hint: ALLOW_AUTO_OPEN
+ }
+ # TODO(nparker): Unpack these as ZIP files. https://crbug.com/628796
+}
+file_types {
+ # A Visio file type. Added in https://crbug.com/771469
+ extension: "vssm"
+ uma_value: 296
+ ping_setting: FULL_PING
+ platform_settings {
+ platform: PLATFORM_WINDOWS
+ danger_level: ALLOW_ON_USER_GESTURE
+ auto_open_hint: ALLOW_AUTO_OPEN
+ }
+ # TODO(nparker): Unpack these as ZIP files. https://crbug.com/628796
+}
+file_types {
+ # A Visio file type. Added in https://crbug.com/771469
+ extension: "vstm"
+ uma_value: 297
+ ping_setting: FULL_PING
+ platform_settings {
+ platform: PLATFORM_WINDOWS
+ danger_level: ALLOW_ON_USER_GESTURE
+ auto_open_hint: ALLOW_AUTO_OPEN
+ }
+ # TODO(nparker): Unpack these as ZIP files. https://crbug.com/628796
+}
+file_types {
+ # An older Visio file type. See https://crbug.com/771469
extension: "vsd"
uma_value: 118
ping_setting: FULL_PING
@@ -2175,6 +2357,7 @@ file_types {
}
}
file_types {
+ # An older Visio file type. See https://crbug.com/771469
extension: "vss"
uma_value: 120
ping_setting: FULL_PING
@@ -2185,6 +2368,7 @@ file_types {
}
}
file_types {
+ # An older Visio file type. See https://crbug.com/771469
extension: "vst"
uma_value: 121
ping_setting: FULL_PING
@@ -2221,30 +2405,18 @@ file_types {
extension: "xht"
uma_value: 286
ping_setting: FULL_PING
- platform_settings {
- danger_level: NOT_DANGEROUS
- auto_open_hint: ALLOW_AUTO_OPEN
- }
}
file_types {
# Similar to "html". Added for https://crbug.com/762702
extension: "xhtm"
uma_value: 287
ping_setting: FULL_PING
- platform_settings {
- danger_level: NOT_DANGEROUS
- auto_open_hint: ALLOW_AUTO_OPEN
- }
}
file_types {
# Similar to "html". Added for https://crbug.com/762702
extension: "xhtml"
uma_value: 288
ping_setting: FULL_PING
- platform_settings {
- danger_level: NOT_DANGEROUS
- auto_open_hint: ALLOW_AUTO_OPEN
- }
}
file_types {
# Microsoft Exchange Public Folder Shortcut
diff --git a/chromium/chrome/browser/resources/settings/about_page/about_page.html b/chromium/chrome/browser/resources/settings/about_page/about_page.html
index bc42399d48f..42a110c6acf 100644
--- a/chromium/chrome/browser/resources/settings/about_page/about_page.html
+++ b/chromium/chrome/browser/resources/settings/about_page/about_page.html
@@ -104,7 +104,8 @@
src="[[getIconSrc_(obsoleteSystemInfo_, currentUpdateStatusEvent_)]]">
</iron-icon>
<div class="start padded">
- <div id="updateStatusMessage" hidden="[[!showUpdateStatus_]]"
+ <div id="updateStatusMessage" hidden="[[!showUpdateStatus_]]">
+ <div
<if expr="not chromeos">
inner-h-t-m-l="[[getUpdateStatusMessage_(
currentUpdateStatusEvent_)]]">
@@ -113,6 +114,12 @@
inner-h-t-m-l="[[getUpdateStatusMessage_(
currentUpdateStatusEvent_, targetChannel_)]]">
</if>
+ </div>
+ <a hidden$="[[!shouldShowLearnMoreLink_(
+ currentUpdateStatusEvent_)]]" target="_blank"
+ href="https://support.google.com/chrome?p=update_error">
+ $i18n{learnMore}
+ </a>
</div>
<span id="deprecationWarning"
hidden="[[!obsoleteSystemInfo_.obsolete]]">
diff --git a/chromium/chrome/browser/resources/settings/about_page/about_page.js b/chromium/chrome/browser/resources/settings/about_page/about_page.js
index 5ddfb82ce1f..0ed1b715a19 100644
--- a/chromium/chrome/browser/resources/settings/about_page/about_page.js
+++ b/chromium/chrome/browser/resources/settings/about_page/about_page.js
@@ -283,6 +283,14 @@ Polymer({
},
/**
+ * @return {boolean}
+ * @private
+ */
+ shouldShowLearnMoreLink_: function() {
+ return this.currentUpdateStatusEvent_.status == UpdateStatus.FAILED;
+ },
+
+ /**
* @return {string}
* @private
*/
diff --git a/chromium/chrome/browser/resources/settings/android_apps_page/android_apps_page.html b/chromium/chrome/browser/resources/settings/android_apps_page/android_apps_page.html
index 0fed226e58a..a59514198c0 100644
--- a/chromium/chrome/browser/resources/settings/android_apps_page/android_apps_page.html
+++ b/chromium/chrome/browser/resources/settings/android_apps_page/android_apps_page.html
@@ -21,7 +21,8 @@
focus-config="[[focusConfig_]]">
<neon-animatable route-path="default">
<template is="dom-if" if="[[havePlayStoreApp]]" restamp>
- <div id="android-apps" class="settings-box two-line first" actionable
+ <div id="android-apps" class="settings-box two-line first"
+ actionable$="[[androidAppsInfo.playStoreEnabled]]"
on-tap="onSubpageTap_">
<div class="start">
$i18n{androidAppsPageLabel}
diff --git a/chromium/chrome/browser/resources/settings/android_apps_page/android_apps_subpage.js b/chromium/chrome/browser/resources/settings/android_apps_page/android_apps_subpage.js
index a0699eace97..9dee9d3149d 100644
--- a/chromium/chrome/browser/resources/settings/android_apps_page/android_apps_subpage.js
+++ b/chromium/chrome/browser/resources/settings/android_apps_page/android_apps_subpage.js
@@ -74,7 +74,7 @@ Polymer({
onConfirmDisableDialogConfirm_: function() {
this.setPrefValue('arc.enabled', false);
this.$.confirmDisableDialog.close();
- settings.navigateToPreviousRoute();
+ // Sub-page will be closed in onAndroidAppsInfoUpdate_ call.
},
/**
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 cb5157281cf..94029ec4769 100644
--- a/chromium/chrome/browser/resources/settings/basic_page/basic_page.html
+++ b/chromium/chrome/browser/resources/settings/basic_page/basic_page.html
@@ -27,7 +27,7 @@
<link rel="import" href="../default_browser_page/default_browser_page.html">
</if>
-<if expr="is_win">
+<if expr="_google_chrome and is_win">
<link rel="import" href="../chrome_cleanup_page/chrome_cleanup_page.html">
</if>
@@ -124,7 +124,7 @@
</settings-section>
</template>
</if>
-<if expr="is_win">
+<if expr="_google_chrome and is_win">
<template is="dom-if" if="[[showChromeCleanup]]" restamp>
<settings-section section="chromeCleanup">
<settings-chrome-cleanup-page></settings-chrome-cleanup-page>
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 36b2b7f6423..8207b5b3880 100644
--- a/chromium/chrome/browser/resources/settings/basic_page/basic_page.js
+++ b/chromium/chrome/browser/resources/settings/basic_page/basic_page.js
@@ -29,13 +29,15 @@ Polymer({
/** @type {!AndroidAppsInfo|undefined} */
androidAppsInfo: Object,
+ // <if expr="_google_chrome and is_win">
showChromeCleanup: {
type: Boolean,
value: function() {
- return loadTimeData.valueExists('chromeCleanupEnabled') &&
- loadTimeData.getBoolean('chromeCleanupEnabled');
+ return loadTimeData.getBoolean('chromeCleanupEnabled') &&
+ !loadTimeData.getBoolean('userInitiatedCleanupsEnabled');
},
},
+ // </if>
showChangePassword: {
type: Boolean,
@@ -108,7 +110,7 @@ Polymer({
attached: function() {
this.currentRoute_ = settings.getCurrentRoute();
- // <if expr="is_win">
+ // <if expr="_google_chrome and is_win">
this.addEventListener('chrome-cleanup-dismissed', () => {
this.showChromeCleanup = false;
});
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 dd816a8810d..2a6445caf7c 100644
--- a/chromium/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.js
+++ b/chromium/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.js
@@ -206,10 +206,10 @@ Polymer({
this.bluetoothToggleDisabled_ = true;
this.bluetoothPrivate.setAdapterState(
{powered: this.bluetoothToggleState_}, () => {
- if (chrome.runtime.lastError) {
- console.error(
- 'Error enabling bluetooth: ' +
- chrome.runtime.lastError.message);
+ var error = chrome.runtime.lastError;
+ if (error && error != 'Error setting adapter properties: powered') {
+ console.error('Error enabling bluetooth: ' + error.message);
+ return;
}
this.setPrefValue(
'ash.user.bluetooth.adapter_enabled',
diff --git a/chromium/chrome/browser/resources/settings/bluetooth_page/bluetooth_subpage.html b/chromium/chrome/browser/resources/settings/bluetooth_page/bluetooth_subpage.html
index 7a782eeb0e5..e3fc960d500 100644
--- a/chromium/chrome/browser/resources/settings/bluetooth_page/bluetooth_subpage.html
+++ b/chromium/chrome/browser/resources/settings/bluetooth_page/bluetooth_subpage.html
@@ -39,7 +39,7 @@
}
</style>
- <div class="settings-box first">
+ <div class="settings-box first" actionable on-tap="onEnableTap_">
<div id="onOff" class="start" on$="[[bluetoothToggleState]]">
[[getOnOffString_(bluetoothToggleState,
'$i18nPolymer{deviceOn}', '$i18nPolymer{deviceOff}')]]
@@ -47,7 +47,8 @@
<paper-toggle-button id="enableBluetooth"
checked="{{bluetoothToggleState}}"
disabled$="[[bluetoothToggleDisabled]]"
- aria-label="$i18n{bluetoothToggleA11yLabel}">
+ aria-label="$i18n{bluetoothToggleA11yLabel}"
+ on-tap="stopTap_">
</paper-toggle-button>
</div>
@@ -62,13 +63,12 @@
<div id="pairedContainer" class="container"
scrollable on-device-event="onDeviceEvent_"
hidden="[[!showDevices_(bluetoothToggleState, pairedDeviceList_)]]">
- <iron-list id="pairedDevices" class="vertical-list" preserve-focus
- items="[[pairedDeviceList_]]"
+ <iron-list id="pairedDevices" preserve-focus items="[[pairedDeviceList_]]"
selection-enabled selected-item="{{selectedPairedItem_}}"
- scroll-target="pairedContainer">
+ scroll-target="pairedContainer" class="cr-separators">
<template>
<bluetooth-device-list-item actionable device="[[item]]"
- tabindex$="[[tabIndex]]">
+ first$="[[!index]]" tabindex$="[[tabIndex]]">
</bluetooth-device-list-item>
</template>
</iron-list>
@@ -87,13 +87,13 @@
<div id="unpairedContainer" class="container"
scrollable on-device-event="onDeviceEvent_"
hidden="[[!showDevices_(bluetoothToggleState, unpairedDeviceList_)]]">
- <iron-list id="unpairedDevices" class="vertical-list" preserve-focus
+ <iron-list id="unpairedDevices" class="cr-separators" preserve-focus
items="[[unpairedDeviceList_]]"
selection-enabled selected-item="{{selectedUnpairedItem_}}"
scroll-target="unpairedContainer">
<template>
<bluetooth-device-list-item actionable device="[[item]]"
- tabindex$="[[tabIndex]]">
+ first$="[[!index]]" tabindex$="[[tabIndex]]">
</bluetooth-device-list-item>
</template>
</iron-list>
@@ -102,7 +102,7 @@
<bluetooth-dialog id="deviceDialog"
bluetooth="[[bluetooth]]"
bluetooth-private="[[bluetoothPrivate]]"
- title="$i18n{bluetoothPairDevicePageTitle}"
+ dialog-title="$i18n{bluetoothPairDevicePageTitle}"
on-close="onDialogClose_"
pairing-device="[[pairingDevice_]]">
</bluetooth-dialog>
diff --git a/chromium/chrome/browser/resources/settings/bluetooth_page/bluetooth_subpage.js b/chromium/chrome/browser/resources/settings/bluetooth_page/bluetooth_subpage.js
index 54876622ff1..89131bed6c2 100644
--- a/chromium/chrome/browser/resources/settings/bluetooth_page/bluetooth_subpage.js
+++ b/chromium/chrome/browser/resources/settings/bluetooth_page/bluetooth_subpage.js
@@ -3,6 +3,12 @@
// found in the LICENSE file.
/**
+ * Maximum number of bluetooth devices shown in bluetooth subpage.
+ * @const {number}
+ */
+var MAX_NUMBER_DEVICE_SHOWN = 50;
+
+/**
* @fileoverview
* 'settings-bluetooth-subpage' is the settings subpage for managing bluetooth
* properties and devices.
@@ -128,6 +134,15 @@ Polymer({
type: Object,
value: chrome.bluetoothPrivate,
},
+
+ /**
+ * Update frequency of the bluetooth list.
+ * @type {number}
+ */
+ listUpdateFrequencyMs: {
+ type: Number,
+ value: 1000,
+ },
},
observers: [
@@ -136,13 +151,27 @@ Polymer({
],
/**
- * Listener for chrome.bluetooth.onBluetoothDeviceAdded/Changed events.
+ * Timer ID for bluetooth list update.
+ * @type {number|undefined}
+ * @private
+ */
+ updateTimerId_: undefined,
+
+ /**
+ * Listener for chrome.bluetooth.onBluetoothDeviceChanged events.
* @type {?function(!chrome.bluetooth.Device)}
* @private
*/
bluetoothDeviceUpdatedListener_: null,
/**
+ * Listener for chrome.bluetooth.onBluetoothDeviceAdded events.
+ * @type {?function(!chrome.bluetooth.Device)}
+ * @private
+ */
+ bluetoothDeviceAddedListener_: null,
+
+ /**
* Listener for chrome.bluetooth.onBluetoothDeviceRemoved events.
* @type {?function(!chrome.bluetooth.Device)}
* @private
@@ -154,11 +183,14 @@ Polymer({
this.bluetoothDeviceUpdatedListener_ =
this.bluetoothDeviceUpdatedListener_ ||
this.onBluetoothDeviceUpdated_.bind(this);
- this.bluetooth.onDeviceAdded.addListener(
- this.bluetoothDeviceUpdatedListener_);
this.bluetooth.onDeviceChanged.addListener(
this.bluetoothDeviceUpdatedListener_);
+ this.bluetoothDeviceAddedListener_ = this.bluetoothDeviceAddedListener_ ||
+ this.onBluetoothDeviceAdded_.bind(this);
+ this.bluetooth.onDeviceAdded.addListener(
+ this.bluetoothDeviceAddedListener_);
+
this.bluetoothDeviceRemovedListener_ =
this.bluetoothDeviceRemovedListener_ ||
this.onBluetoothDeviceRemoved_.bind(this);
@@ -169,7 +201,7 @@ Polymer({
/** @override */
detached: function() {
this.bluetooth.onDeviceAdded.removeListener(
- assert(this.bluetoothDeviceUpdatedListener_));
+ assert(this.bluetoothDeviceAddedListener_));
this.bluetooth.onDeviceChanged.removeListener(
assert(this.bluetoothDeviceUpdatedListener_));
this.bluetooth.onDeviceRemoved.removeListener(
@@ -204,7 +236,7 @@ Polymer({
return !!device.paired || !!device.connecting;
});
this.unpairedDeviceList_ = this.deviceList_.filter(function(device) {
- return !device.paired;
+ return !device.paired && !device.connecting;
});
this.updateScrollableContents();
this.restoreScroll(this.$.unpairedDevices);
@@ -243,13 +275,11 @@ Polymer({
this.deviceList_ = [];
return;
}
- this.bluetooth.getDevices(devices => {
- this.deviceList_ = devices;
- });
+ this.requestListUpdate_();
},
/**
- * Process bluetooth.onDeviceAdded and onDeviceChanged events.
+ * Process onDeviceChanged events.
* @param {!chrome.bluetooth.Device} device
* @private
*/
@@ -262,11 +292,17 @@ Polymer({
var index = this.deviceList_.findIndex(function(device) {
return device.address == address;
});
- if (index >= 0) {
+ if (index >= 0)
this.set('deviceList_.' + index, device);
- return;
- }
- this.push('deviceList_', device);
+ },
+
+ /**
+ * Process bluetooth.onDeviceAdded events.
+ * @param {!chrome.bluetooth.Device} device
+ * @private
+ */
+ onBluetoothDeviceAdded_: function(device) {
+ this.requestListUpdate_();
},
/**
@@ -331,6 +367,23 @@ Polymer({
},
/**
+ * @param {!Event} event
+ * @private
+ */
+ stopTap_: function(event) {
+ event.stopPropagation();
+ },
+
+ /**
+ * @param {!Event} event
+ * @private
+ */
+ onEnableTap_: function(event) {
+ this.bluetoothToggleState = !this.bluetoothToggleState;
+ event.stopPropagation();
+ },
+
+ /**
* @param {boolean} enabled
* @param {string} onstr
* @param {string} offstr
@@ -436,4 +489,77 @@ Polymer({
if (device)
device.focus();
},
+
+ /**
+ * Requests update for bluetooth list.
+ * @private
+ */
+ requestListUpdate_: function() {
+ if (this.deviceList_.length == 0) {
+ // Update immediately for the initial device list.
+ this.bluetooth.getDevices(devices => {
+ this.populateDeviceList_(devices);
+ });
+ return;
+ }
+
+ // Return here because an update is already queued.
+ if (this.updateTimerId_ !== undefined)
+ return;
+
+ // Call bluetooth.getDevices once per listUpdateFrequencyMs.
+ this.updateTimerId_ = window.setTimeout(() => {
+ if (settings.getCurrentRoute() != settings.routes.BLUETOOTH_DEVICES) {
+ this.stopListUpdate_();
+ return;
+ }
+
+ this.bluetooth.getDevices(devices => {
+ this.populateDeviceList_(devices);
+ });
+ this.updateTimerId_ = undefined;
+ }, this.listUpdateFrequencyMs);
+ },
+
+ /**
+ * Stops update for bluetooth list.
+ * @private
+ */
+ stopListUpdate_: function() {
+ if (this.updateTimerId_ !== undefined) {
+ window.clearTimeout(this.updateTimerId_);
+ this.updateTimerId_ = undefined;
+ }
+ },
+
+ /**
+ * Populate the device list from chrome.bluetooth.getDevices
+ * Limit the device number to MAX_NUMBER_DEVICE_SHOWN and
+ * prioritize paired/connecting devices over other devices.
+ * @param {!Array<!chrome.bluetooth.Device|undefined>} devices
+ * @private
+ */
+ populateDeviceList_: function(devices) {
+ var tempList = [];
+ var i;
+ for (i = 0; i < devices.length; i++) {
+ if (tempList.length == MAX_NUMBER_DEVICE_SHOWN)
+ break;
+
+ if (!!devices[i].paired || !!devices[i].connecting) {
+ tempList.push(devices[i]);
+ devices[i] = undefined;
+ }
+ }
+
+ for (i = 0; i < devices.length; i++) {
+ if (tempList.length == MAX_NUMBER_DEVICE_SHOWN)
+ break;
+
+ if (devices[i] !== undefined)
+ tempList.push(devices[i]);
+ }
+
+ this.deviceList_ = tempList;
+ },
});
diff --git a/chromium/chrome/browser/resources/settings/chrome_cleanup_page/chrome_cleanup_page.html b/chromium/chrome/browser/resources/settings/chrome_cleanup_page/chrome_cleanup_page.html
index d2c2fc0ae4f..955204ac45c 100644
--- a/chromium/chrome/browser/resources/settings/chrome_cleanup_page/chrome_cleanup_page.html
+++ b/chromium/chrome/browser/resources/settings/chrome_cleanup_page/chrome_cleanup_page.html
@@ -98,11 +98,12 @@
<span>[[title_]]</span>
<template is="dom-if" if="[[showDetails_]]">
<!-- Force line break to display learn-more inlined with
- chromeCleanupExplanation or with the title_ (if showDetails_ is
- false) despite these two elements being on different lines. -->
+ chromeCleanupExplanationRemove or with the title_ (if
+ showDetails_ is false) despite these two elements being on
+ different lines. -->
<div></div>
<span class="secondary">
- $i18n{chromeCleanupExplanation}
+ $i18n{chromeCleanupExplanationRemove}
</span>
</template>
<a id="learn-more" href="$i18n{chromeCleanupLearnMoreUrl}"
diff --git a/chromium/chrome/browser/resources/settings/clear_browsing_data_dialog/clear_browsing_data_dialog_tabs.html b/chromium/chrome/browser/resources/settings/clear_browsing_data_dialog/clear_browsing_data_dialog_tabs.html
index 502eac00064..d0b12514e16 100644
--- a/chromium/chrome/browser/resources/settings/clear_browsing_data_dialog/clear_browsing_data_dialog_tabs.html
+++ b/chromium/chrome/browser/resources/settings/clear_browsing_data_dialog/clear_browsing_data_dialog_tabs.html
@@ -104,7 +104,6 @@
}
.time-range-select {
- -webkit-margin-start: 0.5em;
/* Adjust for md-select-underline and 1px additional bottom padding
* to keep md-select's text (without the underline) aligned with
* neighboring text that does not have an underline. */
diff --git a/chromium/chrome/browser/resources/settings/controls/compiled_resources2.gyp b/chromium/chrome/browser/resources/settings/controls/compiled_resources2.gyp
index 518172c836e..32dadfbdef9 100644
--- a/chromium/chrome/browser/resources/settings/controls/compiled_resources2.gyp
+++ b/chromium/chrome/browser/resources/settings/controls/compiled_resources2.gyp
@@ -101,6 +101,7 @@
{
'target_name': 'settings_toggle_button',
'dependencies': [
+ '<(DEPTH)/ui/webui/resources/cr_elements/cr_toggle/compiled_resources2.gyp:cr_toggle',
'settings_boolean_control_behavior',
],
'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
diff --git a/chromium/chrome/browser/resources/settings/controls/settings_toggle_button.html b/chromium/chrome/browser/resources/settings/controls/settings_toggle_button.html
index 3e6a81d6d48..7cdb86fdff3 100644
--- a/chromium/chrome/browser/resources/settings/controls/settings_toggle_button.html
+++ b/chromium/chrome/browser/resources/settings/controls/settings_toggle_button.html
@@ -1,7 +1,7 @@
<link rel="import" href="chrome://resources/html/polymer.html">
+<link rel="import" href="chrome://resources/cr_elements/cr_toggle/cr_toggle.html">
<link rel="import" href="chrome://resources/cr_elements/policy/cr_policy_pref_indicator.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/paper-toggle-button/paper-toggle-button.html">
<link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/iron-flex-layout-classes.html">
<link rel="import" href="settings_boolean_control_behavior.html">
<link rel="import" href="../settings_shared_css.html">
@@ -62,13 +62,12 @@
<cr-policy-pref-indicator pref="[[pref]]" icon-aria-label="[[label]]">
</cr-policy-pref-indicator>
</template>
- <paper-toggle-button id="control" checked="{{checked}}"
- on-change="notifyChangedByUserInteraction"
+ <cr-toggle id="control" checked="{{checked}}"
+ on-change="onChange_"
aria-label$="[[getAriaLabel_(label, ariaLabel)]]"
- aria-describedby="subLabel" on-up="resetTrackLock_"
- disabled="[[controlDisabled_(disabled, pref)]]"
- on-tap="onToggleTap_">
- </paper-toggle-button>
+ aria-describedby="subLabel"
+ disabled="[[controlDisabled_(disabled, pref)]]">
+ </cr-toggle>
</div>
</template>
<script src="settings_toggle_button.js"></script>
diff --git a/chromium/chrome/browser/resources/settings/controls/settings_toggle_button.js b/chromium/chrome/browser/resources/settings/controls/settings_toggle_button.js
index 96c789995a9..b4e7c83d4b3 100644
--- a/chromium/chrome/browser/resources/settings/controls/settings_toggle_button.js
+++ b/chromium/chrome/browser/resources/settings/controls/settings_toggle_button.js
@@ -58,17 +58,6 @@ Polymer({
return this.label || this.ariaLabel;
},
- /**
- * Handle taps directly on the toggle (see: onLabelWrapperTap_ for non-toggle
- * taps).
- * @param {!Event} e
- * @private
- */
- onToggleTap_: function(e) {
- // Stop the event from propagating to avoid firing two 'changed' events.
- e.stopPropagation();
- },
-
/** @private */
onDisableOrPrefChange_: function() {
if (this.controlDisabled_()) {
@@ -79,28 +68,34 @@ Polymer({
},
/**
- * Handle non-toggle button taps (see: onToggleTap_ for toggle taps).
+ * Handles non cr-toggle button taps (cr-toggle handles its own tap events
+ * which don't bubble).
* @param {!Event} e
* @private
*/
onHostTap_: function(e) {
- // Stop the event from propagating to avoid firing two 'changed' events.
e.stopPropagation();
if (this.controlDisabled_())
return;
+ // Ignore this |tap| event, if the interaction sequence
+ // (pointerdown+pointerup) began within the cr-toggle itself.
+ if (/** @type {!CrToggleElement} */ (this.$.control)
+ .shouldIgnoreHostTap(e)) {
+ return;
+ }
+
this.checked = !this.checked;
this.notifyChangedByUserInteraction();
this.fire('change');
},
/**
- * TODO(scottchen): temporary fix until polymer gesture bug resolved. See:
- * https://github.com/PolymerElements/paper-slider/issues/186
+ * @param {!CustomEvent} e
* @private
*/
- resetTrackLock_: function() {
- // Run tap.reset in next run-loop to avoid reversing the current tap event.
- setTimeout(() => Polymer.Gestures.gestures.tap.reset());
+ onChange_: function(e) {
+ this.checked = /** @type {boolean} */ (e.detail);
+ this.notifyChangedByUserInteraction();
},
});
diff --git a/chromium/chrome/browser/resources/settings/date_time_page/compiled_resources2.gyp b/chromium/chrome/browser/resources/settings/date_time_page/compiled_resources2.gyp
index 0da9b331bfe..ad752f8f355 100644
--- a/chromium/chrome/browser/resources/settings/date_time_page/compiled_resources2.gyp
+++ b/chromium/chrome/browser/resources/settings/date_time_page/compiled_resources2.gyp
@@ -6,13 +6,46 @@
{
'target_name': 'date_time_page',
'dependencies': [
- '../controls/compiled_resources2.gyp:settings_dropdown_menu',
+ '../compiled_resources2.gyp:route',
'../prefs/compiled_resources2.gyp:prefs_behavior',
'../prefs/compiled_resources2.gyp:prefs_types',
'<(DEPTH)/ui/webui/resources/cr_elements/policy/compiled_resources2.gyp:cr_policy_indicator_behavior',
'<(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',
'<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:web_ui_listener_behavior',
+ 'date_time_types',
+ 'timezone_selector',
+ 'timezone_subpage',
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'date_time_types',
+ 'dependencies': [
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'timezone_selector',
+ 'dependencies': [
+ '../controls/compiled_resources2.gyp:settings_dropdown_menu',
+ '../prefs/compiled_resources2.gyp:prefs_behavior',
+ '../prefs/compiled_resources2.gyp:prefs_types',
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:i18n_behavior',
+ 'date_time_types',
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'timezone_subpage',
+ 'dependencies': [
+ '../prefs/compiled_resources2.gyp:prefs_behavior',
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
+ 'date_time_types',
+ 'timezone_selector',
],
'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
},
diff --git a/chromium/chrome/browser/resources/settings/date_time_page/date_time_page.html b/chromium/chrome/browser/resources/settings/date_time_page/date_time_page.html
index 0b573e387a1..d946c09c440 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,16 +1,21 @@
<link rel="import" href="chrome://resources/html/polymer.html">
+<link rel="import" href="chrome://resources/cr_elements/cr_toggle/cr_toggle.html">
+<link rel="import" href="chrome://resources/cr_elements/policy/cr_policy_indicator.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/web_ui_listener_behavior.html">
-<link rel="import" href="chrome://resources/cr_elements/policy/cr_policy_indicator.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button-light.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/paper-toggle-button/paper-toggle-button.html">
-<link rel="import" href="../controls/settings_dropdown_menu.html">
<link rel="import" href="../controls/settings_toggle_button.html">
<link rel="import" href="../i18n_setup.html">
<link rel="import" href="../prefs/prefs_behavior.html">
<link rel="import" href="../prefs/prefs_types.html">
+<link rel="import" href="../route.html">
+<link rel="import" href="../settings_page/settings_subpage.html">
<link rel="import" href="../settings_shared_css.html">
+<link rel="import" href="date_time_types.html">
+<link rel="import" href="timezone_selector.html">
+<link rel="import" href="timezone_subpage.html">
<dom-module id="settings-date-time-page">
<template>
@@ -19,11 +24,14 @@
padding: 0;
}
- settings-dropdown-menu {
- --md-select-width: 400px;
+ #timeZoneButton {
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ width: 100%;
}
- paper-toggle-button {
+ cr-toggle {
-webkit-margin-start: var(--settings-control-label-spacing);
}
@@ -31,76 +39,90 @@
-webkit-margin-start: var(--settings-controlled-by-spacing);
}
</style>
- <div class="settings-box first">
- <div id="timezoneGeolocateToggleLabel" class="start">
- $i18n{timeZoneGeolocation}
- </div>
- <template is="dom-if" restamp
- if="[[!prefs.cros.flags.per_user_timezone_enabled.value]]">
- <template is="dom-if" if="[[hasTimeZoneAutoDetectPolicy_]]" restamp>
- <cr-policy-indicator indicator-type="devicePolicy"
- icon-aria-label="$i18n{timeZoneGeolocation}">
- </cr-policy-indicator>
- </template>
- <paper-toggle-button
- id="timeZoneAutoDetect"
- aria-labelledby="timezoneGeolocateToggleLabel"
- checked="[[timeZoneAutoDetect_]]"
- disabled="[[hasTimeZoneAutoDetectPolicy_]]"
- on-change="onTimeZoneAutoDetectChange_">
- </paper-toggle-button>
- </template>
- <template is="dom-if" restamp
- if="[[prefs.cros.flags.per_user_timezone_enabled.value]]">
- <settings-toggle-button class="first"
- pref="{{prefs.settings.resolve_timezone_by_geolocation}}"
- id="timeZoneAutoDetect"
- aria-label="$i18n{timeZoneGeolocation}">
- </settings-toggle-button>
- </template>
- </div>
- <div class="settings-box continuation embedded">
- <template is="dom-if" restamp
- if="[[!prefs.cros.flags.per_user_timezone_enabled.value]]">
- <settings-dropdown-menu pref="{{prefs.cros.system.timezone}}"
- label="$i18n{timeZone}"
- menu-options="[[timeZoneList_]]"
- disabled="[[timeZoneAutoDetect_]]">
- </settings-dropdown-menu>
- </template>
- <template is="dom-if" restamp
- if="[[prefs.cros.flags.per_user_timezone_enabled.value]]">
- <template is="dom-if" if="[[!isUserTimeZoneSelectorHidden_(
- prefs.settings.timezone,
- prefs.settings.resolve_timezone_by_geolocation.value)]]" restamp>
- <settings-dropdown-menu id="userTimeZoneSelector"
- pref="{{prefs.settings.timezone}}"
- label="$i18n{timeZone}"
- menu-options="[[timeZoneList_]]">
- </settings-dropdown-menu>
+ <settings-animated-pages id="pages" section="dateTime"
+ focus-config="[[focusConfig_]]">
+ <neon-animatable id="main" route-path="default">
+ <template is="dom-if"
+ if="[[!prefs.cros.flags.fine_grained_time_zone_detection_enabled.value]]"
+ restamp>
+ <div class="settings-box first">
+ <div id="timezoneGeolocateToggleLabel" class="start">
+ $i18n{timeZoneGeolocation}
+ </div>
+ <template is="dom-if"
+ if="[[hasTimeZoneAutoDetectPolicyRestriction_]]" restamp>
+ <cr-policy-indicator indicator-type="devicePolicy"
+ icon-aria-label="$i18n{timeZoneGeolocation}">
+ </cr-policy-indicator>
+ </template>
+ <cr-toggle
+ id="timeZoneAutoDetect"
+ aria-label="$i18n{timeZoneGeolocation}"
+ checked="[[timeZoneAutoDetect_]]"
+ disabled="[[hasTimeZoneAutoDetectPolicyRestriction_]]"
+ on-change="onTimeZoneAutoDetectChange_">
+ </cr-toggle>
+ </div>
</template>
- <template is="dom-if" if="[[isUserTimeZoneSelectorHidden_(
- prefs.settings.timezone,
- prefs.settings.resolve_timezone_by_geolocation.value)]]" restamp>
- <settings-dropdown-menu id="systemTimezoneSelector"
- pref="{{prefs.cros.system.timezone}}"
- label="$i18n{timeZone}"
- menu-options="[[timeZoneList_]]"
- disabled>
- </settings-dropdown-menu>
+ <template is="dom-if"
+ if="[[prefs.cros.flags.fine_grained_time_zone_detection_enabled.value]]"
+ restamp>
+ <div id="timeZoneSettingsTrigger" class="settings-box first"
+ on-tap="onTimeZoneSettings_" actionable>
+ <div id="timeZoneButton" class="two-line">
+ $i18n{timeZoneButton}
+ <div class="secondary">
+ <div hidden="[[timeZoneAutoDetect_]]">
+ [[activeTimeZoneDisplayName]]
+ </div>
+ <div hidden="[[!timeZoneAutoDetect_]]">
+ [[getTimeZoneAutoDetectMethodDisplayName_(
+ timeZoneAutoDetectMethod_)]]
+ </div>
+ </div>
+ </div>
+ <template is="dom-if"
+ if="[[hasTimeZoneAutoDetectPolicyRestriction_]]" restamp>
+ <cr-policy-indicator indicator-type="devicePolicy"
+ icon-aria-label="$i18n{timeZoneGeolocation}"
+ hidden="[[!hasTimeZoneAutoDetectPolicyRestriction_]]">
+ </cr-policy-indicator>
+ </template>
+ <button class="subpage-arrow"
+ disabled="[[hasTimeZoneAutoDetectPolicyRestriction_]]"
+ is="paper-icon-button-light"
+ aria-label="$i18n{timeZoneButton}"></button>
+ </div>
</template>
+ <div class="settings-box continuation embedded"
+ hidden="[[prefs.cros.flags.fine_grained_time_zone_detection_enabled.value]]">
+ <timezone-selector prefs="{{prefs}}"
+ time-zone-auto-detect="[[timeZoneAutoDetect_]]"
+ active-time-zone-display-name="{{activeTimeZoneDisplayName}}">
+ </timezone-selector>
+ </div>
+ <settings-toggle-button
+ pref="{{prefs.settings.clock.use_24hour_clock}}"
+ label="$i18n{use24HourClock}">
+ </settings-toggle-button>
+ <div class="settings-box" id="setDateTime" actionable
+ on-tap="onSetDateTimeTap_" hidden$="[[!canSetDateTime_]]">
+ <div class="start">$i18n{setDateTime}</div>
+ <button class="subpage-arrow" is="paper-icon-button-light"
+ aria-label="$i18n{setDateTime}"></button>
+ </div>
+ </neon-animatable>
+ <template is="dom-if" route-path="/dateTime/timeZone">
+ <settings-subpage data-route="DATETIME_TIMEZONE_SUBPAGE"
+ associated-control="[[$$('#timeZoneSettingsTrigger')]]"
+ page-title="$i18n{timeZoneSubpageTitle}">
+ <timezone-subpage id="timezoneSubpage" prefs="{{prefs}}"
+ time-zone-auto-detect="[[timeZoneAutoDetect_]]"
+ active-time-zone-display-name="{{activeTimeZoneDisplayName}}">
+ </timezone-subpage>
+ </settings-subpage>
</template>
- </div>
- <settings-toggle-button
- pref="{{prefs.settings.clock.use_24hour_clock}}"
- label="$i18n{use24HourClock}">
- </settings-toggle-button>
- <div class="settings-box" id="setDateTime" actionable
- on-tap="onSetDateTimeTap_" hidden$="[[!canSetDateTime_]]">
- <div class="start">$i18n{setDateTime}</div>
- <button class="subpage-arrow" is="paper-icon-button-light"
- aria-label="$i18n{setDateTime}"></button>
- </div>
+ </settings-animated-pages>
</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 ef378947636..09badd25ad5 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
@@ -8,36 +8,24 @@
* settings.
*/
-cr.exportPath('settings');
-
-/**
- * Describes the status of the auto-detect policy.
- * @enum {number}
- */
-settings.TimeZoneAutoDetectPolicy = {
- NONE: 0,
- FORCED_ON: 1,
- FORCED_OFF: 2,
-};
-
Polymer({
is: 'settings-date-time-page',
- behaviors: [PrefsBehavior, WebUIListenerBehavior],
+ behaviors: [I18nBehavior, PrefsBehavior, WebUIListenerBehavior],
properties: {
/**
- * The time zone auto-detect policy.
- * @private {settings.TimeZoneAutoDetectPolicy}
+ * The effective policy restriction on time zone automatic detection.
+ * @private {settings.TimeZoneAutoDetectPolicyRestriction}
*/
- timeZoneAutoDetectPolicy_: {
- type: Boolean,
+ timeZoneAutoDetectPolicyRestriction_: {
+ type: Number,
value: function() {
if (!loadTimeData.valueExists('timeZoneAutoDetectValueFromPolicy'))
- return settings.TimeZoneAutoDetectPolicy.NONE;
+ return settings.TimeZoneAutoDetectPolicyRestriction.NONE;
return loadTimeData.getBoolean('timeZoneAutoDetectValueFromPolicy') ?
- settings.TimeZoneAutoDetectPolicy.FORCED_ON :
- settings.TimeZoneAutoDetectPolicy.FORCED_OFF;
+ settings.TimeZoneAutoDetectPolicyRestriction.FORCED_ON :
+ settings.TimeZoneAutoDetectPolicyRestriction.FORCED_OFF;
},
},
@@ -45,37 +33,32 @@ Polymer({
* Whether a policy controls the time zone auto-detect setting.
* @private
*/
- hasTimeZoneAutoDetectPolicy_: {
+ hasTimeZoneAutoDetectPolicyRestriction_: {
type: Boolean,
- computed:
- 'computeHasTimeZoneAutoDetectPolicy_(timeZoneAutoDetectPolicy_)',
+ computed: 'computeHasTimeZoneAutoDetectPolicy_(' +
+ 'timeZoneAutoDetectPolicyRestriction_)',
},
/**
- * The effective time zone auto-detect setting.
+ * The effective time zone auto-detect enabled/disabled status.
* @private
*/
timeZoneAutoDetect_: {
type: Boolean,
computed: 'computeTimeZoneAutoDetect_(' +
- 'timeZoneAutoDetectPolicy_,' +
- 'prefs.settings.resolve_timezone_by_geolocation.value)',
+ 'timeZoneAutoDetectPolicyRestriction_,' +
+ 'prefs.settings.resolve_timezone_by_geolocation_method.value)',
},
/**
- * Initialized with the current time zone so the menu displays the
- * correct value. The full option list is fetched lazily if necessary by
- * maybeGetTimeZoneList_.
- * @private {!DropdownMenuOptionList}
+ * The effective time zone auto-detect method.
+ * @private {settings.TimeZoneAutoDetectMethod}
*/
- timeZoneList_: {
- type: Array,
- value: function() {
- return [{
- name: loadTimeData.getString('timeZoneName'),
- value: loadTimeData.getString('timeZoneID'),
- }];
- },
+ timeZoneAutoDetectMethod_: {
+ type: Number,
+ computed: 'computeTimeZoneAutoDetectMethod_(' +
+ 'hasTimeZoneAutoDetectPolicyRestriction_,' +
+ 'prefs.settings.resolve_timezone_by_geolocation_method.value)',
},
/**
@@ -87,14 +70,29 @@ Polymer({
type: Boolean,
value: false,
},
- },
- observers: [
- 'maybeGetTimeZoneListPerUser_(' +
- 'prefs.settings.timezone.value, timeZoneAutoDetect_)',
- 'maybeGetTimeZoneListPerSystem_(' +
- 'prefs.cros.system.timezone.value, timeZoneAutoDetect_)',
- ],
+ /**
+ * This is used to get current time zone display name from
+ * <timezone-selector> via bi-directional binding.
+ */
+ activeTimeZoneDisplayName: {
+ type: String,
+ value: loadTimeData.getString('timeZoneName'),
+ },
+
+ /** @private {!Map<string, string>} */
+ focusConfig_: {
+ type: Object,
+ value: function() {
+ var map = new Map();
+ if (settings.routes.DATETIME_TIMEZONE_SUBPAGE)
+ map.set(
+ settings.routes.DATETIME_TIMEZONE_SUBPAGE.path,
+ '#timeZoneSettingsTrigger .subpage-arrow');
+ return map;
+ },
+ },
+ },
/** @override */
attached: function() {
@@ -105,7 +103,6 @@ Polymer({
'can-set-date-time-changed', this.onCanSetDateTimeChanged_.bind(this));
chrome.send('dateTimePageReady');
- this.maybeGetTimeZoneList_();
},
/**
@@ -116,11 +113,12 @@ Polymer({
*/
onTimeZoneAutoDetectPolicyChanged_: function(managed, valueFromPolicy) {
if (managed) {
- this.timeZoneAutoDetectPolicy_ = valueFromPolicy ?
- settings.TimeZoneAutoDetectPolicy.FORCED_ON :
- settings.TimeZoneAutoDetectPolicy.FORCED_OFF;
+ this.timeZoneAutoDetectPolicyRestriction_ = valueFromPolicy ?
+ settings.TimeZoneAutoDetectPolicyRestriction.FORCED_ON :
+ settings.TimeZoneAutoDetectPolicyRestriction.FORCED_OFF;
} else {
- this.timeZoneAutoDetectPolicy_ = settings.TimeZoneAutoDetectPolicy.NONE;
+ this.timeZoneAutoDetectPolicyRestriction_ =
+ settings.TimeZoneAutoDetectPolicyRestriction.NONE;
}
},
@@ -138,7 +136,9 @@ Polymer({
*/
onTimeZoneAutoDetectChange_: function(e) {
this.setPrefValue(
- 'settings.resolve_timezone_by_geolocation', e.target.checked);
+ 'settings.resolve_timezone_by_geolocation_method',
+ e.target.checked ? settings.TimeZoneAutoDetectMethod.IP_ONLY :
+ settings.TimeZoneAutoDetectMethod.DISABLED);
},
/** @private */
@@ -147,106 +147,100 @@ Polymer({
},
/**
- * @param {settings.TimeZoneAutoDetectPolicy} timeZoneAutoDetectPolicy
+ * @param {settings.TimeZoneAutoDetectPolicyRestriction} policyValue
* @return {boolean}
* @private
*/
- computeHasTimeZoneAutoDetectPolicy_: function(timeZoneAutoDetectPolicy) {
- return timeZoneAutoDetectPolicy != settings.TimeZoneAutoDetectPolicy.NONE;
+ computeHasTimeZoneAutoDetectPolicy_: function(policyValue) {
+ return policyValue != settings.TimeZoneAutoDetectPolicyRestriction.NONE;
},
/**
- * @param {settings.TimeZoneAutoDetectPolicy} timeZoneAutoDetectPolicy
- * @param {boolean} prefValue Value of the geolocation pref.
+ * @param {settings.TimeZoneAutoDetectPolicyRestriction} policyValue
+ * @param {settings.TimeZoneAutoDetectMethod} prefValue
+ * prefs.settings.resolve_timezone_by_geolocation_method.value
* @return {boolean} Whether time zone auto-detect is enabled.
* @private
*/
- computeTimeZoneAutoDetect_: function(timeZoneAutoDetectPolicy, prefValue) {
- switch (timeZoneAutoDetectPolicy) {
- case settings.TimeZoneAutoDetectPolicy.NONE:
- return prefValue;
- case settings.TimeZoneAutoDetectPolicy.FORCED_ON:
+ computeTimeZoneAutoDetect_: function(policyValue, prefValue) {
+ switch (policyValue) {
+ case settings.TimeZoneAutoDetectPolicyRestriction.NONE:
+ return prefValue != settings.TimeZoneAutoDetectMethod.DISABLED;
+ case settings.TimeZoneAutoDetectPolicyRestriction.FORCED_ON:
return true;
- case settings.TimeZoneAutoDetectPolicy.FORCED_OFF:
+ case settings.TimeZoneAutoDetectPolicyRestriction.FORCED_OFF:
return false;
default:
- assertNotReached();
+ console.error('Unknown policy value "' + policyValue + '".');
+ return false;
}
},
/**
- * Fetches the list of time zones if necessary.
- * @param {boolean=} perUserTimeZoneMode Expected value of per-user time zone.
+ * Computes effective time zone detection method.
+ * @param {Boolean} hasTimeZoneAutoDetectPolicyRestriction
+ * this.hasTimeZoneAutoDetectPolicyRestriction_
+ * @param {settings.TimeZoneAutoDetectMethod} prefResolveValue
+ * prefs.settings.resolve_timezone_by_geolocation_method.value
+ * @return {settings.TimeZoneAutoDetectMethod}
* @private
*/
- maybeGetTimeZoneList_: function(perUserTimeZoneMode) {
- if (typeof(perUserTimeZoneMode) !== 'undefined') {
- /* This method is called as observer. Skip if if current mode does not
- * match expected.
- */
- if (perUserTimeZoneMode !=
- this.getPref('cros.flags.per_user_timezone_enabled').value) {
- return;
+ computeTimeZoneAutoDetectMethod_: function(
+ hasTimeZoneAutoDetectPolicyRestriction, prefResolveValue) {
+ if (hasTimeZoneAutoDetectPolicyRestriction) {
+ // timeZoneAutoDetectPolicyRestriction_ actually depends on several time
+ // policies and chrome flags. So we ignore real policy value if it is
+ // disabled.
+ if (this.timeZoneAutoDetectPolicyRestriction_ ==
+ settings.TimeZoneAutoDetectPolicyRestriction.FORCED_OFF) {
+ return settings.TimeZoneAutoDetectMethod.DISABLED;
}
- }
- // Only fetch the list once.
- if (this.timeZoneList_.length > 1 || !CrSettingsPrefs.isInitialized)
- return;
-
- // If auto-detect is enabled, we only need the current time zone.
- if (this.timeZoneAutoDetect_) {
- var isPerUserTimezone =
- this.getPref('cros.flags.per_user_timezone_enabled').value;
- if (this.timeZoneList_[0].value ==
- (isPerUserTimezone ? this.getPref('settings.timezone').value :
- this.getPref('cros.system.timezone').value)) {
- return;
+
+ var policyValue = /** @type{settings.SystemTimezoneProto} */ (
+ this.getPref('settings.resolve_device_timezone_by_geolocation_policy')
+ .value);
+
+ switch (policyValue) {
+ case settings.SystemTimezoneProto.USERS_DECIDE:
+ console.error('Unexpected policy value "' + policyValue + '".');
+ return settings.TimeZoneAutoDetectMethod.DISABLED;
+ case settings.SystemTimezoneProto.DISABLED:
+ return settings.TimeZoneAutoDetectMethod.DISABLED;
+ case settings.SystemTimezoneProto.IP_ONLY:
+ return settings.TimeZoneAutoDetectMethod.IP_ONLY;
+ case settings.SystemTimezoneProto.SEND_WIFI_ACCESS_POINTS:
+ return settings.TimeZoneAutoDetectMethod.SEND_WIFI_ACCESS_POINTS;
+ case settings.SystemTimezoneProto.SEND_ALL_LOCATION_INFO:
+ return settings.TimeZoneAutoDetectMethod.SEND_ALL_LOCATION_INFO;
+ default:
+ return settings.TimeZoneAutoDetectMethod.DISABLED;
}
}
-
- cr.sendWithPromise('getTimeZones').then(this.setTimeZoneList_.bind(this));
- },
-
- /**
- * Prefs observer for Per-user time zone enabled mode.
- * @private
- */
- maybeGetTimeZoneListPerUser_: function() {
- this.maybeGetTimeZoneList_(true);
+ return prefResolveValue;
},
/**
- * Prefs observer for Per-user time zone disabled mode.
+ * Returns display name of the given time zone detection method.
+ * @param {settings.TimeZoneAutoDetectMethod} method
+ * this.timeZoneAutoDetectMethod_ value.
+ * @return {string}
* @private
*/
- maybeGetTimeZoneListPerSystem_: function() {
- this.maybeGetTimeZoneList_(false);
+ getTimeZoneAutoDetectMethodDisplayName_: function(method) {
+ var id = ([
+ 'setTimeZoneAutomaticallyDisabled',
+ 'setTimeZoneAutomaticallyIpOnlyDefault',
+ 'setTimeZoneAutomaticallyWithWiFiAccessPointsData',
+ 'setTimeZoneAutomaticallyWithAllLocationInfo'
+ ])[method];
+ if (id)
+ return this.i18n(id);
+
+ return '';
},
- /**
- * Converts the C++ response into an array of menu options.
- * @param {!Array<!Array<string>>} timeZones C++ time zones response.
- * @private
- */
- setTimeZoneList_: function(timeZones) {
- this.timeZoneList_ = timeZones.map(function(timeZonePair) {
- return {
- name: timeZonePair[1],
- value: timeZonePair[0],
- };
- });
- },
-
- /**
- * Computes visibility of user timezone preference.
- * @param {?chrome.settingsPrivate.PrefObject} prefUserTimezone
- * pref.settings.timezone
- * @param {boolean} prefResolveValue
- * prefs.settings.resolve_timezone_by_geolocation.value
- * @private
- */
- isUserTimeZoneSelectorHidden_: function(prefUserTimezone, prefResolveValue) {
- return (prefUserTimezone && prefUserTimezone.controlledBy != null) ||
- prefResolveValue;
+ onTimeZoneSettings_: function() {
+ // TODO(alemate): revise this once UI mocks are finished.
+ settings.navigateTo(settings.routes.DATETIME_TIMEZONE_SUBPAGE);
},
});
diff --git a/chromium/chrome/browser/resources/settings/date_time_page/date_time_types.html b/chromium/chrome/browser/resources/settings/date_time_page/date_time_types.html
new file mode 100644
index 00000000000..b3ecb802c52
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/date_time_page/date_time_types.html
@@ -0,0 +1,2 @@
+<link rel="import" href="chrome://resources/html/cr.html">
+<script src="date_time_types.js"></script>
diff --git a/chromium/chrome/browser/resources/settings/date_time_page/date_time_types.js b/chromium/chrome/browser/resources/settings/date_time_page/date_time_types.js
new file mode 100644
index 00000000000..241d9b21e0c
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/date_time_page/date_time_types.js
@@ -0,0 +1,48 @@
+// Copyright 2017 The Chromium 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 defines some types for settings-date-time-page.
+ */
+
+cr.exportPath('settings');
+
+/**
+ * Describes the effective policy restriction on time zone automatic detection.
+ * @enum {number}
+ */
+settings.TimeZoneAutoDetectPolicyRestriction = {
+ NONE: 0,
+ FORCED_ON: 1,
+ FORCED_OFF: 2,
+};
+
+/**
+ * Describes values of prefs.settings.resolve_timezone_by_geolocation_method.
+ * Must be kept in sync with TimeZoneResolverManager::TimeZoneResolveMethod
+ * enum.
+ * @enum {number}
+ */
+settings.TimeZoneAutoDetectMethod = {
+ DISABLED: 0,
+ IP_ONLY: 1,
+ SEND_WIFI_ACCESS_POINTS: 2,
+ SEND_ALL_LOCATION_INFO: 3
+};
+
+/**
+ * Describes values of prefs.settings.
+ * resolve_device_timezone_by_geolocation_policy
+ * Must be kept in sync with enterprise_management::SystemTimezoneProto
+ * enum.
+ * @enum {number}
+ */
+settings.SystemTimezoneProto = {
+ USERS_DECIDE: 0,
+ DISABLED: 1,
+ IP_ONLY: 2,
+ SEND_WIFI_ACCESS_POINTS: 3,
+ SEND_ALL_LOCATION_INFO: 4,
+};
diff --git a/chromium/chrome/browser/resources/settings/date_time_page/timezone_selector.html b/chromium/chrome/browser/resources/settings/date_time_page/timezone_selector.html
new file mode 100644
index 00000000000..10e03126f46
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/date_time_page/timezone_selector.html
@@ -0,0 +1,52 @@
+<link rel="import" href="chrome://resources/html/polymer.html">
+
+<link rel="import" href="chrome://resources/html/i18n_behavior.html">
+<link rel="import" href="../controls/settings_dropdown_menu.html">
+<link rel="import" href="../i18n_setup.html">
+<link rel="import" href="../prefs/prefs_behavior.html">
+<link rel="import" href="../prefs/prefs_types.html">
+<link rel="import" href="../settings_shared_css.html">
+<link rel="import" href="date_time_types.html">
+
+<dom-module id="timezone-selector">
+ <template>
+ <style include="settings-shared">
+ settings-dropdown-menu {
+ --md-select-width: 400px;
+ }
+ </style>
+ <template is="dom-if" restamp
+ if="[[!prefs.cros.flags.per_user_timezone_enabled.value]]">
+ <settings-dropdown-menu pref="{{prefs.cros.system.timezone}}"
+ label="$i18n{timeZoneColon}"
+ menu-options="[[timeZoneList_]]"
+ disabled="[[timeZoneAutoDetect]]">
+ </settings-dropdown-menu>
+ </template>
+ <template is="dom-if" restamp
+ if="[[prefs.cros.flags.per_user_timezone_enabled.value]]">
+ <template is="dom-if" if="[[!isUserTimeZoneSelectorHidden_(
+ prefs.settings.timezone,
+ prefs.settings.resolve_timezone_by_geolocation_method.value)]]"
+ restamp>
+ <settings-dropdown-menu id="userTimeZoneSelector"
+ pref="{{prefs.settings.timezone}}"
+ label="$i18n{timeZoneColon}"
+ menu-options="[[timeZoneList_]]">
+ </settings-dropdown-menu>
+ </template>
+ <template is="dom-if" if="[[isUserTimeZoneSelectorHidden_(
+ prefs.settings.timezone,
+ prefs.settings.resolve_timezone_by_geolocation_method.value)]]"
+ restamp>
+ <settings-dropdown-menu id="systemTimezoneSelector"
+ pref="{{prefs.cros.system.timezone}}"
+ label="$i18n{timeZoneColon}"
+ menu-options="[[timeZoneList_]]"
+ disabled>
+ </settings-dropdown-menu>
+ </template>
+ </template>
+ </template>
+ <script src="timezone_selector.js"></script>
+</dom-module>
diff --git a/chromium/chrome/browser/resources/settings/date_time_page/timezone_selector.js b/chromium/chrome/browser/resources/settings/date_time_page/timezone_selector.js
new file mode 100644
index 00000000000..e6559db6fbd
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/date_time_page/timezone_selector.js
@@ -0,0 +1,153 @@
+// Copyright 2017 The Chromium 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 'timezone-selector' is the time zone selector dropdown.
+ */
+(function() {
+'use strict';
+
+Polymer({
+ is: 'timezone-selector',
+
+ behaviors: [I18nBehavior, PrefsBehavior],
+
+ properties: {
+ /**
+ * If time zone auto detectoin is enabled.
+ */
+ timeZoneAutoDetect: Boolean,
+
+ /**
+ * This stores active time zone display name to be used in other UI
+ * via bi-directional binding.
+ */
+ activeTimeZoneDisplayName: {
+ type: String,
+ notify: true,
+ },
+
+ /**
+ * Initialized with the current time zone so the menu displays the
+ * correct value. The full option list is fetched lazily if necessary by
+ * maybeGetTimeZoneList_.
+ * @private {!DropdownMenuOptionList}
+ */
+ timeZoneList_: {
+ type: Array,
+ value: function() {
+ return [{
+ name: loadTimeData.getString('timeZoneName'),
+ value: loadTimeData.getString('timeZoneID'),
+ }];
+ },
+ },
+ },
+
+ observers: [
+ 'maybeGetTimeZoneListPerUser_(' +
+ 'prefs.settings.timezone.value, timeZoneAutoDetect)',
+ 'maybeGetTimeZoneListPerSystem_(' +
+ 'prefs.cros.system.timezone.value, timeZoneAutoDetect)',
+ 'updateActiveTimeZoneName_(prefs.cros.system.timezone.value)',
+ ],
+
+ /** @override */
+ attached: function() {
+ this.maybeGetTimeZoneList_();
+ },
+
+ /**
+ * Fetches the list of time zones if necessary.
+ * @param {boolean=} perUserTimeZoneMode Expected value of per-user time zone.
+ * @private
+ */
+ maybeGetTimeZoneList_: function(perUserTimeZoneMode) {
+ if (typeof(perUserTimeZoneMode) !== 'undefined') {
+ /* This method is called as observer. Skip if if current mode does not
+ * match expected.
+ */
+ if (perUserTimeZoneMode !=
+ this.getPref('cros.flags.per_user_timezone_enabled').value) {
+ return;
+ }
+ }
+ // Only fetch the list once.
+ if (this.timeZoneList_.length > 1 || !CrSettingsPrefs.isInitialized)
+ return;
+
+ // If auto-detect is enabled, we only need the current time zone.
+ if (this.timeZoneAutoDetect) {
+ var isPerUserTimezone =
+ this.getPref('cros.flags.per_user_timezone_enabled').value;
+ if (this.timeZoneList_[0].value ==
+ (isPerUserTimezone ? this.getPref('settings.timezone').value :
+ this.getPref('cros.system.timezone').value)) {
+ return;
+ }
+ }
+
+ cr.sendWithPromise('getTimeZones').then(this.setTimeZoneList_.bind(this));
+ },
+
+ /**
+ * Prefs observer for Per-user time zone enabled mode.
+ * @private
+ */
+ maybeGetTimeZoneListPerUser_: function() {
+ this.maybeGetTimeZoneList_(true);
+ },
+
+ /**
+ * Prefs observer for Per-user time zone disabled mode.
+ * @private
+ */
+ maybeGetTimeZoneListPerSystem_: function() {
+ this.maybeGetTimeZoneList_(false);
+ },
+
+ /**
+ * Converts the C++ response into an array of menu options.
+ * @param {!Array<!Array<string>>} timeZones C++ time zones response.
+ * @private
+ */
+ setTimeZoneList_: function(timeZones) {
+ this.timeZoneList_ = timeZones.map(function(timeZonePair) {
+ return {
+ name: timeZonePair[1],
+ value: timeZonePair[0],
+ };
+ });
+ this.updateActiveTimeZoneName_(
+ /** @type {!String} */ (this.getPref('cros.system.timezone').value));
+ },
+
+ /**
+ * Updates active time zone display name when changed.
+ * @param {!String} activeTimeZoneId value of cros.system.timezone preference.
+ * @private
+ */
+ updateActiveTimeZoneName_: function(activeTimeZoneId) {
+ var activeTimeZone = this.timeZoneList_.find(
+ (timeZone) => timeZone.value == activeTimeZoneId);
+ if (activeTimeZone)
+ this.activeTimeZoneDisplayName = activeTimeZone.name;
+ },
+
+
+ /**
+ * Computes visibility of user timezone preference.
+ * @param {?chrome.settingsPrivate.PrefObject} prefUserTimezone
+ * pref.settings.timezone
+ * @param {settings.TimeZoneAutoDetectMethod} prefResolveValue
+ * prefs.settings.resolve_timezone_by_geolocation_method.value
+ * @return {boolean}
+ * @private
+ */
+ isUserTimeZoneSelectorHidden_: function(prefUserTimezone, prefResolveValue) {
+ return (prefUserTimezone && prefUserTimezone.controlledBy != null) ||
+ prefResolveValue != settings.TimeZoneAutoDetectMethod.DISABLED;
+ },
+});
+})();
diff --git a/chromium/chrome/browser/resources/settings/date_time_page/timezone_subpage.html b/chromium/chrome/browser/resources/settings/date_time_page/timezone_subpage.html
new file mode 100644
index 00000000000..200f175ffed
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/date_time_page/timezone_subpage.html
@@ -0,0 +1,54 @@
+<link rel="import" href="chrome://resources/html/polymer.html">
+
+<link rel="import" href="../controls/controlled_radio_button.html">
+<link rel="import" href="../controls/settings_radio_group.html">
+<link rel="import" href="../prefs/prefs.html">
+<link rel="import" href="../prefs/prefs_behavior.html">
+<link rel="import" href="../settings_shared_css.html">
+<link rel="import" href="date_time_types.html">
+
+<dom-module id="timezone-subpage">
+ <template>
+ <style include="settings-shared">
+ .block {
+ display: block;
+ }
+ </style>
+ <div class="settings-box block first">
+ <settings-radio-group id="timeZoneRadioGroup"
+ pref="{{prefs.settings.resolve_timezone_by_geolocation_method}}">
+ <controlled-radio-button
+ name="[[timezoneAutodetectMethodValues_.IP_ONLY]]"
+ pref="[[prefs.settings.resolve_timezone_by_geolocation_method]]"
+ label="$i18n{setTimeZoneAutomaticallyIpOnlyDefault}"
+ no-extension-indicator>
+ <div class="secondary">
+ $i18n{setTimeZoneAutomaticallyIpOnlyDefaultDescription}
+ </div>
+ </controlled-radio-button>
+ <controlled-radio-button
+ name="[[timezoneAutodetectMethodValues_.SEND_ALL_LOCATION_INFO]]"
+ pref="[[prefs.settings.resolve_timezone_by_geolocation_method]]"
+ label="$i18n{setTimeZoneAutomaticallyWithAllLocationInfo}"
+ no-extension-indicator>
+ <div class="secondary">
+ $i18n{setTimeZoneAutomaticallyWithAllLocationInfoDescription}
+ </div>
+ </controlled-radio-button>
+ <controlled-radio-button
+ name="[[timezoneAutodetectMethodValues_.DISABLED]]"
+ pref="[[prefs.settings.resolve_timezone_by_geolocation_method]]"
+ label="$i18n{selectYourTimeZone}"
+ no-extension-indicator>
+ </controlled-radio-button>
+ </settings-radio-group>
+ </div>
+ <div class="settings-box block">
+ <timezone-selector prefs="{{prefs}}"
+ time-zone-auto-detect="[[timeZoneAutoDetect]]"
+ active-time-zone-display-name="{{activeTimeZoneDisplayName}}">
+ </timezone-selector>
+ </div>
+ </template>
+ <script src="timezone_subpage.js"></script>
+</dom-module>
diff --git a/chromium/chrome/browser/resources/settings/date_time_page/timezone_subpage.js b/chromium/chrome/browser/resources/settings/date_time_page/timezone_subpage.js
new file mode 100644
index 00000000000..96109be8c76
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/date_time_page/timezone_subpage.js
@@ -0,0 +1,43 @@
+// Copyright 2017 The Chromium 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 'timezone-subpage' is the collapsible section containing
+ * time zone settings.
+ */
+(function() {
+'use strict';
+
+Polymer({
+ is: 'timezone-subpage',
+
+ behaviors: [PrefsBehavior],
+
+ properties: {
+ /**
+ * This is <timezone-selector> parameter.
+ */
+ activeTimeZoneDisplayName: {
+ type: String,
+ notify: true,
+ },
+
+ /**
+ * The effective time zone auto-detect enabled/disabled status.
+ */
+ timeZoneAutoDetect: Boolean,
+
+ /**
+ * settings.TimeZoneAutoDetectMethod values.
+ * @private {!Object<settings.TimeZoneAutoDetectMethod, number>}
+ */
+ timezoneAutodetectMethodValues_: Object,
+
+ },
+
+ attached: function() {
+ this.timezoneAutodetectMethodValues_ = settings.TimeZoneAutoDetectMethod;
+ },
+});
+})();
diff --git a/chromium/chrome/browser/resources/settings/device_page/display.html b/chromium/chrome/browser/resources/settings/device_page/display.html
index 0602de00131..b3e57b250ca 100644
--- a/chromium/chrome/browser/resources/settings/device_page/display.html
+++ b/chromium/chrome/browser/resources/settings/device_page/display.html
@@ -1,6 +1,7 @@
<link rel="import" href="chrome://resources/html/polymer.html">
<link rel="import" href="chrome://resources/cr_elements/cr_link_row/cr_link_row.html">
+<link rel="import" href="chrome://resources/cr_elements/cr_toggle/cr_toggle.html">
<link rel="import" href="chrome://resources/html/assert.html">
<link rel="import" href="chrome://resources/html/cr/ui/focus_without_ink.html">
<link rel="import" href="chrome://resources/html/i18n_behavior.html">
@@ -9,7 +10,6 @@
<link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button-light.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-tabs/paper-tabs.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/paper-toggle-button/paper-toggle-button.html">
<link rel="import" href="display_layout.html">
<link rel="import" href="display_overscan_dialog.html">
<link rel="import" href="night_light_slider.html">
@@ -28,6 +28,11 @@
padding: 0;
}
+ #nightLightTemperatureDiv[disabled] {
+ opacity: 0.38;
+ pointer-events: none;
+ }
+
.display-tabs {
width: 100%;
}
@@ -72,6 +77,18 @@
selected-display="[[selectedDisplay]]"
on-select-display="onSelectDisplay_">
</display-layout>
+
+ <template is="dom-if" if="[[showMirror_(unifiedDesktopMode_, displays)]]"
+ restamp>
+ <div class="secondary self-start">
+ <paper-checkbox checked="[[isMirrored_(displays)]]"
+ on-tap="onMirroredTap_"
+ aria-label="[[getDisplayMirrorText_(displays)]]">
+ <div class="text-area">[[getDisplayMirrorText_(displays)]]</div>
+ </paper-checkbox>
+ </div>
+ </template>
+
</div>
<div hidden="[[!hasMultipleDisplays_(displays)]]" class="settings-box">
<paper-tabs noink selected="[[selectedDisplay.id]]" class="display-tabs"
@@ -86,21 +103,6 @@
<div id="controlsDiv" class="settings-box layout vertical first">
<h2>[[selectedDisplay.name]]</h2>
-
- <template is="dom-if" if="[[showMirror_(unifiedDesktopMode_, displays)]]"
- restamp>
- <div class="settings-box indented two-line">
- <div class="start">
- <div id="displayMirrorCheckboxLabel">$i18n{displayMirror}</div>
- <div class="secondary">[[getDisplayMirrorText_(displays)]]</div>
- </div>
- <paper-toggle-button checked="[[isMirrored_(displays)]]"
- on-tap="onMirroredTap_"
- aria-labelledby="displayMirrorCheckboxLabel">
- </paper-toggle-button>
- </div>
- </template>
-
<template is="dom-if" if="[[showUnifiedDesktop_(unifiedDesktopAvailable_,
unifiedDesktopMode_, displays)]]" restamp>
<div class="settings-box indented two-line">
@@ -112,10 +114,10 @@
[[getUnifiedDesktopText_(unifiedDesktopMode_)]]
</div>
</div>
- <paper-toggle-button checked="[[unifiedDesktopMode_]]"
+ <cr-toggle checked="[[unifiedDesktopMode_]]"
on-tap="onUnifiedDesktopTap_"
aria-labelledby="displayUnifiedDesktopCheckboxLabel">
- </paper-toggle-button>
+ </cr-toggle>
</div>
</template>
@@ -208,7 +210,9 @@
<div id="nightLightSettingsDiv"
class="settings-box continuation start layout vertical">
<!-- Color temperature slider -->
- <div class="settings-box indented continuation">
+ <div id="nightLightTemperatureDiv"
+ class="settings-box indented continuation"
+ disabled$="[[!prefs.ash.night_light.enabled.value]]">
<div class="start text-area" id="colorTemperatureLabel">
$i18n{displayNightLightTemperatureLabel}
</div>
@@ -216,7 +220,8 @@
aria-labelledby="colorTemperatureLabel" min="0" max="100"
scale="100" label-min="$i18n{displayNightLightTempSliderMinLabel}"
label-max="$i18n{displayNightLightTempSliderMaxLabel}"
- pref="{{prefs.ash.night_light.color_temperature}}">
+ pref="{{prefs.ash.night_light.color_temperature}}"
+ disabled$="[[!prefs.ash.night_light.enabled.value]]">
</settings-slider>
</div>
<!-- Schedule settings -->
diff --git a/chromium/chrome/browser/resources/settings/device_page/display.js b/chromium/chrome/browser/resources/settings/device_page/display.js
index a29d2615c60..1a35186287c 100644
--- a/chromium/chrome/browser/resources/settings/device_page/display.js
+++ b/chromium/chrome/browser/resources/settings/device_page/display.js
@@ -80,6 +80,9 @@ Polymer({
notify: true,
},
+ /** Ids for mirroring destination displays. */
+ mirroringDestinationIds: Array,
+
/** @private {!Array<number>} Mode index values for slider. */
modeValues_: Array,
@@ -92,6 +95,14 @@ Polymer({
},
/** @private */
+ multiMirroringAvailable_: {
+ type: Boolean,
+ value: function() {
+ return loadTimeData.getBoolean('multiMirroringAvailable');
+ }
+ },
+
+ /** @private */
nightLightFeatureEnabled_: {
type: Boolean,
value: function() {
@@ -205,6 +216,10 @@ Polymer({
return;
settings.display.systemDisplayApi.getDisplayLayout(
this.displayLayoutFetched_.bind(this, displays));
+ if (this.isMirrored_(displays))
+ this.mirroringDestinationIds = displays[0].mirroringDestinationIds;
+ else
+ this.mirroringDestinationIds = [];
},
/**
@@ -256,16 +271,17 @@ Polymer({
},
/**
- * Returns true if the given display has touch support and is not an internal
- * display. If the feature is not enabled via the switch, this will return
- * false.
+ * Returns true if external touch devices are connected and the current
+ * display is not an internal display. If the feature is not enabled via the
+ * switch, this will return false.
* @param {!chrome.system.display.DisplayUnitInfo} display Display being
* checked for touch support.
* @return {boolean}
* @private
*/
showTouchCalibrationSetting_: function(display) {
- return !display.isInternal && display.hasTouchSupport &&
+ return !display.isInternal &&
+ loadTimeData.getBoolean('hasExternalTouchDevice') &&
loadTimeData.getBoolean('enableTouchCalibrationSetting');
},
@@ -310,7 +326,7 @@ Polymer({
* @private
*/
getDisplayMirrorText_: function(displays) {
- return this.i18n(this.isMirrored_(displays) ? 'toggleOn' : 'toggleOff');
+ return this.i18n('displayMirror', displays[0].name);
},
/**
@@ -344,7 +360,9 @@ Polymer({
*/
showMirror_: function(unifiedDesktopMode, displays) {
return this.isMirrored_(displays) ||
- (!unifiedDesktopMode && displays.length == 2);
+ (!unifiedDesktopMode &&
+ ((this.multiMirroringAvailable_ && displays.length > 1) ||
+ displays.length == 2));
},
/**
@@ -496,7 +514,10 @@ Polymer({
},
/** @private */
- onMirroredTap_: function() {
+ onMirroredTap_: function(event) {
+ // Blur the control so that when the transition animation completes and the
+ // UI is focused, the control does not receive focus. crbug.com/785070
+ event.target.blur();
var id = '';
/** @type {!chrome.system.display.DisplayProperties} */ var properties = {};
if (this.isMirrored_(this.displays)) {
@@ -565,7 +586,8 @@ Polymer({
this.unifiedDesktopMode_ = !!primaryDisplay && primaryDisplay.isUnified;
- this.$.displayLayout.updateDisplays(this.displays, this.layouts);
+ this.$.displayLayout.updateDisplays(
+ this.displays, this.layouts, this.mirroringDestinationIds);
},
/** @private */
diff --git a/chromium/chrome/browser/resources/settings/device_page/display_layout.html b/chromium/chrome/browser/resources/settings/device_page/display_layout.html
index d5a610f0db7..289ebf9c8f2 100644
--- a/chromium/chrome/browser/resources/settings/device_page/display_layout.html
+++ b/chromium/chrome/browser/resources/settings/device_page/display_layout.html
@@ -58,10 +58,11 @@
}
</style>
<div id="displayArea" on-iron-resize="calculateVisualScale_">
- <template is="dom-repeat" items="[[displays]]">
- <div id="_mirror_[[item.id]]" class="display mirror"
+ <template is="dom-repeat" items="[[mirroringDestinationIds_]]">
+ <div id="_mirror_[[item]]" class="display mirror"
hidden$="[[!mirroring]]"
- style$="[[getMirrorDivStyle_(item.id, item.bounds, visualScale)]]">
+ style$="[[getMirrorDivStyle_(index, mirroringDestinationIds_.length,
+ displays, visualScale)]]">
</div>
</template>
<template is="dom-repeat" items="[[displays]]">
@@ -69,7 +70,12 @@
draggable="[[dragEnabled]]" on-tap="onSelectDisplayTap_"
style$="[[getDivStyle_(item.id, item.bounds, visualScale)]]"
selected$="[[isSelected_(item, selectedDisplay)]]">
- [[item.name]]
+ <div hidden$="[[mirroring]]">
+ [[item.name]]
+ </div>
+ <div hidden$="[[!mirroring]]">
+ $i18n{displayMirrorDisplayName}
+ </div>
</div>
</template>
</div>
diff --git a/chromium/chrome/browser/resources/settings/device_page/display_layout.js b/chromium/chrome/browser/resources/settings/device_page/display_layout.js
index 7063a7c0a80..c5ef6d6491d 100644
--- a/chromium/chrome/browser/resources/settings/device_page/display_layout.js
+++ b/chromium/chrome/browser/resources/settings/device_page/display_layout.js
@@ -36,6 +36,13 @@ Polymer({
* @type {number}
*/
visualScale: 1,
+
+ /**
+ * Ids for mirroring destination displays.
+ * @type {!Array<string>|undefined}
+ * @private
+ */
+ mirroringDestinationIds_: Array,
},
/** @private {!{left: number, top: number}} */
@@ -51,10 +58,12 @@ Polymer({
* have been fetched from chrome.
* @param {!Array<!chrome.system.display.DisplayUnitInfo>} displays
* @param {!Array<!chrome.system.display.DisplayLayout>} layouts
+ * @param {!Array<string>} mirroringDestinationIds
*/
- updateDisplays: function(displays, layouts) {
+ updateDisplays: function(displays, layouts, mirroringDestinationIds) {
this.displays = displays;
this.layouts = layouts;
+ this.mirroringDestinationIds_ = mirroringDestinationIds;
this.initializeDisplayLayout(displays, layouts);
@@ -137,15 +146,15 @@ Polymer({
* @param {string} id
* @param {!chrome.system.display.Bounds} displayBounds
* @param {number} visualScale
- * @param {boolean=} opt_mirrored
+ * @param {number=} opt_offset
* @return {string} The style string for the div.
* @private
*/
- getDivStyle_: function(id, displayBounds, visualScale, opt_mirrored) {
+ getDivStyle_: function(id, displayBounds, visualScale, opt_offset) {
// This matches the size of the box-shadow or border in CSS.
/** @const {number} */ var BORDER = 1;
/** @const {number} */ var MARGIN = 4;
- /** @const {number} */ var OFFSET = opt_mirrored ? -4 : 0;
+ /** @const {number} */ var OFFSET = opt_offset || 0;
/** @const {number} */ var PADDING = 3;
var bounds = this.getCalculatedDisplayBounds(id, true /* notest */);
if (!bounds)
@@ -163,14 +172,22 @@ Polymer({
},
/**
- * @param {string} id
- * @param {!chrome.system.display.Bounds} displayBounds
+ * @param {number} mirroringDestinationIndex
+ * @param {number} mirroringDestinationDisplayNum
+ * @param {!Array<!chrome.system.display.DisplayUnitInfo>} displays
* @param {number} visualScale
* @return {string} The style string for the mirror div.
* @private
*/
- getMirrorDivStyle_: function(id, displayBounds, visualScale) {
- return this.getDivStyle_(id, displayBounds, visualScale, true);
+ getMirrorDivStyle_: function(
+ mirroringDestinationIndex, mirroringDestinationDisplayNum, displays,
+ visualScale) {
+ // All destination displays have the same bounds as the mirroring source
+ // display, but we add a little offset to each destination display's bounds
+ // so that they can be distinguished from each other in the layout.
+ return this.getDivStyle_(
+ displays[0].id, displays[0].bounds, visualScale,
+ (mirroringDestinationDisplayNum - mirroringDestinationIndex) * -4);
},
/**
diff --git a/chromium/chrome/browser/resources/settings/device_page/stylus.html b/chromium/chrome/browser/resources/settings/device_page/stylus.html
index 4c50c21298c..6a0dad02d98 100644
--- a/chromium/chrome/browser/resources/settings/device_page/stylus.html
+++ b/chromium/chrome/browser/resources/settings/device_page/stylus.html
@@ -1,5 +1,6 @@
<link rel="import" href="chrome://resources/html/polymer.html">
+<link rel="import" href="chrome://resources/cr_elements/cr_toggle/cr_toggle.html">
<link rel="import" href="chrome://resources/html/action_link.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button-light.html">
<link rel="import" href="../controls/settings_toggle_button.html">
@@ -29,13 +30,15 @@
}
</style>
- <settings-toggle-button class="continuation"
+ <settings-toggle-button id="enableStylusToolsToggle"
+ class="continuation"
pref="{{prefs.settings.enable_stylus_tools}}"
label="$i18n{stylusEnableStylusTools}">
</settings-toggle-button>
<template is="dom-if" if="[[hasInternalStylus_]]">
<settings-toggle-button
+ id ="launchPaletteOnEjectEventToggle"
pref="{{prefs.settings.launch_palette_on_eject_event}}"
label="$i18n{stylusAutoOpenStylusTools}"
disabled="[[!prefs.settings.enable_stylus_tools.value]]">
@@ -103,12 +106,12 @@
indicator-type="[[userPolicyIndicator_]]">
</cr-policy-indicator>
</template>
- <paper-toggle-button id="enable-app-on-lock-screen-toggle"
+ <cr-toggle id="enable-app-on-lock-screen-toggle"
aria-labelledby="lock-screen-toggle-label"
disabled="[[disallowedOnLockScreenByPolicy_(selectedApp_)]]"
checked="[[lockScreenSupportEnabled_(selectedApp_)]]"
on-change="toggleLockScreenSupport_">
- </paper-toggle-button>
+ </cr-toggle>
</div>
<template is="dom-if" if="[[lockScreenSupportEnabled_(selectedApp_)]]">
diff --git a/chromium/chrome/browser/resources/settings/icons.html b/chromium/chrome/browser/resources/settings/icons.html
index 61224dceb7b..07119529659 100644
--- a/chromium/chrome/browser/resources/settings/icons.html
+++ b/chromium/chrome/browser/resources/settings/icons.html
@@ -54,6 +54,7 @@ List icons here rather than importing large sets of (e.g. Polymer) icons.
<if expr="chromeos">
<g id="chevron-left"><path d="M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z"</path></g>
</if>
+ <g id="clipboard"><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="cloud"><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.96z"></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="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>
@@ -64,7 +65,6 @@ List icons here rather than importing large sets of (e.g. Polymer) icons.
</if>
<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="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>
<if expr="chromeos">
<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="gamepad"><path d="M15 7.5V2H9v5.5l3 3 3-3zM7.5 9H2v6h5.5l3-3-3-3zM9 16.5V22h6v-5.5l-3-3-3 3zM16.5 9l-3 3 3 3H22V9h-5.5z"></path></g>
@@ -72,6 +72,7 @@ List icons here rather than importing large sets of (e.g. Polymer) icons.
</if>
<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="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>
<if expr="chromeos">
<g id="keyboard"><path d="M20 5H4c-1.1 0-1.99.9-1.99 2L2 17c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm-9 3h2v2h-2V8zm0 3h2v2h-2v-2zM8 8h2v2H8V8zm0 3h2v2H8v-2zm-1 2H5v-2h2v2zm0-3H5V8h2v2zm9 7H8v-2h8v2zm0-4h-2v-2h2v2zm0-3h-2V8h2v2zm3 3h-2v-2h2v2zm0-3h-2V8h2v2z"></path></g>
</if>
@@ -81,9 +82,6 @@ List icons here rather than importing large sets of (e.g. Polymer) icons.
</if>
<g id="list"><path d="M3 13h2v-2H3v2zm0 4h2v-2H3v2zm0-8h2V7H3v2zm4 4h14v-2H7v2zm0 4h14v-2H7v2zM7 7v2h14V7H7z"></path></g>
<g id="location-on"><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>
-<if expr="chromeos">
- <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>
-</if>
<g id="mic"><path d="M12 14c1.66 0 2.99-1.34 2.99-3L15 5c0-1.66-1.34-3-3-3S9 3.34 9 5v6c0 1.66 1.34 3 3 3zm5.3-3c0 3-2.54 5.1-5.3 5.1S6.7 14 6.7 11H5c0 3.41 2.72 6.23 6 6.72V21h2v-3.28c3.28-.48 6-3.3 6-6.72h-1.7z"></path></g>
<g id="midi"><path d="M21,19.1H3V5h18V19.1z M21,3H3C1.9,3,1,3.9,1,5v14c0,1.1,0.9,2,2,2h18c1.1,0,2-0.9,2-2V5C23,3.9,22.1,3,21,3z"></path><path fill="none" d="M21,19.1H3V5h18V19.1z M21,3H3C1.9,3,1,3.9,1,5v14c0,1.1,0.9,2,2,2h18c1.1,0,2-0.9,2-2V5C23,3.9,22.1,3,21,3z"></path><path d="M14,5h3v8h-3V5z"></path><path d="M15,12h1v8h-1V12z"></path><path fill="none" d="M0,0h24v24H0V0z"></path><rect x="7" y="5" width="3" height="8"></rect><rect x="8" y="12" width="1" height="8"></rect></g>
<if expr="chromeos">
@@ -109,7 +107,6 @@ List icons here rather than importing large sets of (e.g. Polymer) icons.
<g id="signal-cellular-2-bar"><path fill-opacity=".3" d="M2 22h20V2z"></path><path d="M14 10L2 22h12z"></path></g>
<g id="signal-cellular-3-bar"><path fill-opacity=".3" d="M2 22h20V2z"></path><path d="M17 7L2 22h15z"></path></g>
<g id="signal-cellular-4-bar"><path d="M2 22h20V2z"></path></g>
- <g id="sim-card-alert"><path d="M18 2h-8L4.02 8 4 20c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm-5 15h-2v-2h2v2zm0-4h-2V8h2v5z"></path></g>
<g id="smartphone"><path d="M17 1.01L7 1c-1.1 0-2 .9-2 2v18c0 1.1.9 2 2 2h10c1.1 0 2-.9 2-2V3c0-1.1-.9-1.99-2-1.99zM17 19H7V5h10v14z"></path></g>
</if>
<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>
diff --git a/chromium/chrome/browser/resources/settings/internet_page/compiled_resources2.gyp b/chromium/chrome/browser/resources/settings/internet_page/compiled_resources2.gyp
index 18f9191b2ff..7ffb7c767f7 100644
--- a/chromium/chrome/browser/resources/settings/internet_page/compiled_resources2.gyp
+++ b/chromium/chrome/browser/resources/settings/internet_page/compiled_resources2.gyp
@@ -11,10 +11,20 @@
'<(DEPTH)/ui/webui/resources/cr_elements/chromeos/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',
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:web_ui_listener_behavior',
'<(EXTERNS_GYP):chrome_send',
'<(EXTERNS_GYP):management',
'<(EXTERNS_GYP):networking_private',
'<(INTERFACES_GYP):networking_private_interface',
+ 'internet_config',
+ 'internet_page_browser_proxy',
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'internet_page_browser_proxy',
+ 'dependencies': [
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
],
'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
},
@@ -24,6 +34,7 @@
'../compiled_resources2.gyp:route',
'<(DEPTH)/ui/webui/resources/cr_components/chromeos/network/compiled_resources2.gyp:network_config',
'<(DEPTH)/ui/webui/resources/cr_elements/chromeos/network/compiled_resources2.gyp:cr_onc_types',
+ '<(DEPTH)/ui/webui/resources/cr_elements/cr_dialog/compiled_resources2.gyp:cr_dialog',
'<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:assert',
'<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:i18n_behavior',
'<(EXTERNS_GYP):networking_private',
@@ -43,6 +54,7 @@
'<(EXTERNS_GYP):networking_private',
'<(INTERFACES_GYP):networking_private_interface',
'tether_connection_dialog',
+ 'internet_page_browser_proxy',
],
'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
},
@@ -68,6 +80,7 @@
'<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:i18n_behavior',
'<(EXTERNS_GYP):networking_private',
'<(INTERFACES_GYP):networking_private_interface',
+ 'internet_page_browser_proxy',
],
'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
},
@@ -86,17 +99,6 @@
'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
},
{
- 'target_name': 'network_siminfo',
- 'dependencies': [
- '<(DEPTH)/third_party/polymer/v1_0/components-chromium/paper-input/compiled_resources2.gyp:paper-input-extracted',
- '<(DEPTH)/ui/webui/resources/cr_elements/chromeos/network/compiled_resources2.gyp:cr_onc_types',
- '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:assert',
- '<(DEPTH)/ui/webui/resources/js/cr/ui/compiled_resources2.gyp:focus_without_ink',
- '<(INTERFACES_GYP):networking_private_interface',
- ],
- 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
- },
- {
'target_name': 'network_summary',
'dependencies': [
'<(DEPTH)/ui/webui/resources/cr_elements/chromeos/network/compiled_resources2.gyp:cr_onc_types',
diff --git a/chromium/chrome/browser/resources/settings/internet_page/internet_config.html b/chromium/chrome/browser/resources/settings/internet_page/internet_config.html
index fd8d716df89..c909581bc60 100644
--- a/chromium/chrome/browser/resources/settings/internet_page/internet_config.html
+++ b/chromium/chrome/browser/resources/settings/internet_page/internet_config.html
@@ -1,52 +1,47 @@
<link rel="import" href="chrome://resources/html/polymer.html">
<link rel="import" href="chrome://resources/cr_components/chromeos/network/network_config.html">
-<link rel="import" href="chrome://resources/cr_elements/chromeos/network/cr_network_icon.html">
<link rel="import" href="chrome://resources/cr_elements/chromeos/network/cr_onc_types.html">
+<link rel="import" href="chrome://resources/cr_elements/cr_dialog/cr_dialog.html">
<link rel="import" href="chrome://resources/html/i18n_behavior.html">
<link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/iron-flex-layout-classes.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html">
<link rel="import" href="internet_shared_css.html">
-<dom-module id="settings-internet-config">
+<dom-module id="internet-config">
<template>
<style include="internet-shared iron-flex">
+ dialog {
+ width: 460px;
+ }
</style>
- <!-- Title section: Icon + name. -->
- <div class="settings-box first">
- <div class="start layout horizontal center">
- <cr-network-icon network-state="[[networkProperties_]]" is-list-item>
- </cr-network-icon>
- <div class="title">[[getTitle_(networkProperties_.*)]]</div>
+ <dialog is="cr-dialog" id="dialog" close-text="$i18n{close}">
+ <div slot="title">[[getDialogTitle_(networkProperties_)]]</div>
+ <div slot="body">
+ <network-config id="networkConfig" class="flex"
+ networking-private="[[networkingPrivate]]"
+ global-policy="[[globalPolicy]]"
+ network-properties="{{networkProperties_}}"
+ enable-connect="{{enableConnect_}}" enable-save="{{enableSave_}}"
+ share-allow-enable="[[shareAllowEnable_]]"
+ share-default="[[shareDefault_]]"
+ on-close="close">
+ </network-config>
</div>
- <div id="buttonDiv">
- <paper-button class="secondary-button" on-tap="onCancelTap_">
+
+ <div slot="button-container">
+ <paper-button class="cancel-button" on-tap="onCancelTap_">
$i18n{cancel}
</paper-button>
- <template is="dom-if" if="[[guid_]]">
- <paper-button class="primary-button" on-tap="onSaveTap_"
- disabled="[[!enableSave_]]">
- $i18n{save}
- </paper-button>
- </template>
- <template is="dom-if" if="[[!guid_]]">
- <paper-button class="primary-button" on-tap="onConnectTap_"
- disabled="[[!enableConnect_]]">
- $i18n{networkButtonConnect}
- </paper-button>
- </template>
+ <paper-button class="action-button" on-tap="onSaveOrConnectTap_"
+ disabled="[[!getSaveOrConnectEnabled_(
+ guid, networkProperties_, enableSave_, enableConnect_)]]">
+ [[getSaveOrConnectLabel_(guid, networkProperties_)]]
+ </paper-button>
</div>
- </div>
- <div class="settings-box">
- <network-config id="networkConfig" class="flex"
- networking-private="[[networkingPrivate]]"
- network-properties="{{networkProperties_}}"
- enable-connect="{{enableConnect_}}" enable-save="{{enableSave_}}"
- on-close="close_">
- </network-config>
- </div>
+ </dialog>
</template>
<script src="internet_config.js"></script>
</dom-module>
diff --git a/chromium/chrome/browser/resources/settings/internet_page/internet_config.js b/chromium/chrome/browser/resources/settings/internet_page/internet_config.js
index a74aa471f2e..38b8d8961d5 100644
--- a/chromium/chrome/browser/resources/settings/internet_page/internet_config.js
+++ b/chromium/chrome/browser/resources/settings/internet_page/internet_config.js
@@ -4,12 +4,12 @@
/**
* @fileoverview
- * 'settings-internet-config' is a Settings wrapper for network-config.
+ * 'internet-config' is a Settings dialog wrapper for network-config.
*/
Polymer({
- is: 'settings-internet-config',
+ is: 'internet-config',
- behaviors: [settings.RouteObserverBehavior, I18nBehavior],
+ behaviors: [I18nBehavior],
properties: {
/**
@@ -18,18 +18,49 @@ Polymer({
*/
networkingPrivate: Object,
+ /** @type {!chrome.networkingPrivate.GlobalPolicy|undefined} */
+ globalPolicy: Object,
+
+ /** @private */
+ shareAllowEnable_: {
+ type: Boolean,
+ value: function() {
+ return loadTimeData.getBoolean('shareNetworkAllowEnable');
+ }
+ },
+
+ /** @private */
+ shareDefault_: {
+ type: Boolean,
+ value: function() {
+ return loadTimeData.getBoolean('shareNetworkDefault');
+ }
+ },
+
/**
* The GUID when an existing network is being configured. This will be
* empty when configuring a new network.
* @private
*/
- guid_: String,
+ guid: String,
+
+ /**
+ * The type of network to be configured.
+ * @private {!chrome.networkingPrivate.NetworkType}
+ */
+ type: String,
+
+ /**
+ * The name of network (for display while the network details are fetched).
+ * @private
+ */
+ name: String,
/** @private */
- enableConnect_: String,
+ enableConnect_: Boolean,
/** @private */
- enableSave_: String,
+ enableSave_: Boolean,
/**
* The current properties if an existing network is being configured, or
@@ -40,69 +71,72 @@ Polymer({
networkProperties_: Object,
},
- /**
- * settings.RouteObserverBehavior
- * @param {!settings.Route} route
- * @protected
- */
- currentRouteChanged: function(route) {
- if (route != settings.routes.NETWORK_CONFIG)
- return;
-
- var queryParams = settings.getQueryParameters();
- this.guid_ = queryParams.get('guid') || '';
+ open: function() {
+ var dialog = /** @type {!CrDialogElement} */ (this.$.dialog);
+ if (!dialog.open)
+ dialog.showModal();
// Set networkProperties for new configurations and for existing
// configurations until the current properties are loaded.
- var name = queryParams.get('name') || '';
- var typeParam = queryParams.get('type');
- var type = (typeParam && CrOnc.getValidType(typeParam)) || CrOnc.Type.WI_FI;
- assert(type && type != CrOnc.Type.ALL);
+ assert(this.type && this.type != CrOnc.Type.ALL);
this.networkProperties_ = {
- GUID: this.guid_,
- Name: name,
- Type: type,
+ GUID: this.guid,
+ Name: this.name,
+ Type: this.type,
};
-
- // First focus this page (which will focus a button), then init the config
- // element which will focus an enabled element if any.
- this.focus();
this.$.networkConfig.init();
},
- focus() {
- var e = this.$$('paper-button:not([disabled])');
- assert(e); // The 'cancel' button should never be disabled.
- e.focus();
+ close: function() {
+ var dialog = /** @type {!CrDialogElement} */ (this.$.dialog);
+ if (dialog.open)
+ dialog.close();
},
- /** @private */
- close_: function() {
- if (settings.getCurrentRoute() == settings.routes.NETWORK_CONFIG)
- settings.navigateToPreviousRoute();
+ /**
+ * @return {string}
+ * @private
+ */
+ getDialogTitle_: function() {
+ var name = this.networkProperties_.Name;
+ if (name)
+ return this.i18n('internetConfigName', name);
+ var type = this.i18n('OncType' + this.networkProperties_.Type);
+ return this.i18n('internetJoinType', type);
+ },
+
+ /**
+ * @return {boolean}
+ * @private
+ */
+ isConfigured_: function() {
+ var source = this.networkProperties_.Source;
+ return !!this.guid && !!source && source != CrOnc.Source.NONE;
},
/**
* @return {string}
* @private
*/
- getTitle_: function() {
- return this.networkProperties_.Name ||
- this.i18n('OncType' + this.networkProperties_.Type);
+ getSaveOrConnectLabel_: function() {
+ return this.i18n(this.isConfigured_() ? 'save' : 'networkButtonConnect');
},
- /** @private */
- onCancelTap_: function() {
- this.close_();
+ /**
+ * @return {boolean}
+ * @private
+ */
+ getSaveOrConnectEnabled_: function() {
+ return this.isConfigured_() ? this.enableSave_ : this.enableConnect_;
},
/** @private */
- onSaveTap_: function() {
- this.$.networkConfig.saveOrConnect();
+ onCancelTap_: function() {
+ this.close();
},
/** @private */
- onConnectTap_: function() {
+ onSaveOrConnectTap_: function() {
this.$.networkConfig.saveOrConnect();
},
});
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 ac1652041e5..67fa0ae5221 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
@@ -5,6 +5,7 @@
<link rel="import" href="chrome://resources/cr_components/chromeos/network/network_ip_config.html">
<link rel="import" href="chrome://resources/cr_components/chromeos/network/network_nameservers.html">
<link rel="import" href="chrome://resources/cr_components/chromeos/network/network_property_list.html">
+<link rel="import" href="chrome://resources/cr_components/chromeos/network/network_siminfo.html">
<link rel="import" href="chrome://resources/cr_elements/chromeos/network/cr_network_icon.html">
<link rel="import" href="chrome://resources/cr_elements/chromeos/network/cr_onc_types.html">
<link rel="import" href="chrome://resources/cr_elements/cr_expand_button/cr_expand_button.html">
@@ -23,7 +24,6 @@
<link rel="import" href="../route.html">
<link rel="import" href="internet_shared_css.html">
<link rel="import" href="network_proxy_section.html">
-<link rel="import" href="network_siminfo.html">
<link rel="import" href="tether_connection_dialog.html">
<dom-module id="settings-internet-detail-page">
@@ -96,7 +96,7 @@
<paper-button class="primary-button" on-tap="onConnectTap_"
hidden$="[[!showConnect_(networkProperties, globalPolicy)]]"
disabled="[[!enableConnect_(networkProperties, defaultNetwork,
- globalPolicy)]]">
+ globalPolicy, networkPropertiesReceived_)]]">
$i18n{networkButtonConnect}
</paper-button>
<paper-button class="primary-button" on-tap="onDisconnectTap_"
@@ -158,15 +158,6 @@
</paper-toggle-button>
</div>
</template>
- <!-- Choose Mobile Network (Cellular only). -->
- <template is="dom-if"
- if="[[showCellularChooseNetwork_(networkProperties)]]">
- <div class="settings-box single-column stretch">
- <network-choose-mobile networking-private="[[networkingPrivate]]"
- network-properties="[[networkProperties]]">
- </network-choose-mobile>
- </div>
- </template>
<!-- Data roaming (Cellular only). -->
<template is="dom-if" if="[[isCellular_(networkProperties)]]">
<settings-toggle-button id="allowDataRoaming"
@@ -245,6 +236,15 @@
<iron-collapse opened="[[networkExpanded_]]">
<div class="settings-box single-column stretch indented">
+ <!-- Choose Mobile Network (Cellular only). -->
+ <template is="dom-if"
+ if="[[showCellularChooseNetwork_(networkProperties)]]">
+ <network-choose-mobile
+ networking-private="[[networkingPrivate]]"
+ network-properties="[[networkProperties]]">
+ </network-choose-mobile>
+ </template>
+
<!-- APN -->
<template is="dom-if" if="[[isCellular_(networkProperties)]]">
<network-apnlist editable on-apn-change="onNetworkPropertyChange_"
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 03ebf640485..24b95396a3a 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
@@ -120,12 +120,10 @@ Polymer({
proxyExpanded_: Boolean,
},
- /**
- * Listener function for chrome.networkingPrivate.onNetworksChanged event.
- * @type {?function(!Array<string>)}
- * @private
- */
- networksChangedListener_: null,
+ listeners: {
+ 'network-list-changed': 'checkNetworkExists_',
+ 'networks-changed': 'updateNetworkDetails_',
+ },
/** @private {boolean} */
didSetFocus_: false,
@@ -133,6 +131,8 @@ Polymer({
/**
* Set to true to once the initial properties have been received. This
* prevents setProperties from being called when setting default properties.
+ * This will also be set to false if the network no longer exists in the
+ * list of networks (e.g. it goes out of range).
* @private {boolean}
*/
networkPropertiesReceived_: false,
@@ -145,6 +145,14 @@ Polymer({
*/
shouldShowConfigureWhenNetworkLoaded_: false,
+ /** @private {settings.InternetPageBrowserProxy} */
+ browserProxy_: null,
+
+ /** @override */
+ created: function() {
+ this.browserProxy_ = settings.InternetPageBrowserProxyImpl.getInstance();
+ },
+
/**
* settings.RouteObserverBehavior
* @param {!settings.Route} route
@@ -152,19 +160,9 @@ Polymer({
* @protected
*/
currentRouteChanged: function(route, oldRoute) {
- if (route != settings.routes.NETWORK_DETAIL) {
- if (this.networksChangedListener_) {
- this.networkingPrivate.onNetworksChanged.removeListener(
- this.networksChangedListener_);
- this.networksChangedListener_ = null;
- }
+ if (route != settings.routes.NETWORK_DETAIL)
return;
- }
- if (!this.networksChangedListener_) {
- this.networksChangedListener_ = this.onNetworksChangedEvent_.bind(this);
- this.networkingPrivate.onNetworksChanged.addListener(
- this.networksChangedListener_);
- }
+
var queryParams = settings.getQueryParameters();
this.guid = queryParams.get('guid') || '';
if (!this.guid) {
@@ -193,10 +191,9 @@ Polymer({
/** @private */
close_: function() {
+ this.guid = '';
// Delay navigating to allow other subpages to load first.
- requestAnimationFrame(function() {
- settings.navigateToPreviousRoute();
- });
+ requestAnimationFrame(() => settings.navigateToPreviousRoute());
},
/** @private */
@@ -263,11 +260,20 @@ Polymer({
},
/**
- * networkingPrivate.onNetworksChanged event callback.
- * @param {!Array<string>} networkIds The list of changed network GUIDs.
+ * @param {{detail: !Array<string>}} event
+ * @private
+ */
+ checkNetworkExists_: function(event) {
+ var networkIds = event.detail;
+ this.networkPropertiesReceived_ = networkIds.indexOf(this.guid) != -1;
+ },
+
+ /**
+ * @param {{detail: !Array<string>}} event
* @private
*/
- onNetworksChangedEvent_: function(networkIds) {
+ updateNetworkDetails_: function(event) {
+ var networkIds = event.detail;
if (networkIds.indexOf(this.guid) != -1)
this.getNetworkDetails_();
},
@@ -305,11 +311,23 @@ Polymer({
this.close_();
return;
}
+
+ // Details page was closed while request was in progress, ignore the result.
+ if (!this.guid)
+ return;
+
if (!properties) {
console.error('No properties for: ' + this.guid);
this.close_();
return;
}
+
+ // Detail page should not be shown when Arc VPN is not connected.
+ if (this.isArcVpn_(properties) && !this.isConnectedState_(properties)) {
+ this.guid = '';
+ this.close_();
+ }
+
this.networkProperties = properties;
this.networkPropertiesReceived_ = true;
},
@@ -435,6 +453,11 @@ Polymer({
showConnect_: function(networkProperties, globalPolicy) {
if (this.connectNotAllowed_(networkProperties, globalPolicy))
return false;
+ // TODO(lgcheng@) support connect Arc VPN from UI once Android support API
+ // to initiate a VPN session.
+ if (this.isArcVpn_(networkProperties))
+ return false;
+
return networkProperties.Type != CrOnc.Type.ETHERNET &&
networkProperties.ConnectionState ==
CrOnc.ConnectionState.NOT_CONNECTED;
@@ -460,6 +483,8 @@ Polymer({
var type = networkProperties.Type;
if (type != CrOnc.Type.WI_FI && type != CrOnc.Type.VPN)
return false;
+ if (this.isArcVpn_(networkProperties))
+ return false;
return !this.isPolicySource(networkProperties.Source) &&
this.isRemembered_(networkProperties);
},
@@ -494,6 +519,10 @@ Polymer({
CrOnc.ConnectionState.NOT_CONNECTED) {
return false;
}
+ if (this.isArcVpn_(networkProperties) &&
+ !this.isConnectedState_(networkProperties)) {
+ return false;
+ }
return true;
},
@@ -535,12 +564,17 @@ Polymer({
* @param {!CrOnc.NetworkProperties} networkProperties
* @param {?CrOnc.NetworkStateProperties} defaultNetwork
* @param {!chrome.networkingPrivate.GlobalPolicy} globalPolicy
+ * @param {boolean} networkPropertiesReceived
* @return {boolean} Whether or not to enable the network connect button.
* @private
*/
- enableConnect_: function(networkProperties, defaultNetwork, globalPolicy) {
+ enableConnect_: function(
+ networkProperties, defaultNetwork, globalPolicy,
+ networkPropertiesReceived) {
if (!this.showConnect_(networkProperties, globalPolicy))
return false;
+ if (!networkPropertiesReceived)
+ return false;
if ((networkProperties.Type == CrOnc.Type.CELLULAR) &&
(CrOnc.isSimLocked(networkProperties) ||
this.get('Cellular.Scanning', networkProperties))) {
@@ -597,6 +631,11 @@ Polymer({
/** @private */
onConfigureTap_: function() {
+ if (this.networkProperties && this.isArcVpn_(this.networkProperties)) {
+ this.browserProxy_.showNetworkConfigure(this.guid);
+ return;
+ }
+
if (loadTimeData.getBoolean('networkSettingsConfig'))
this.fire('show-config', this.networkProperties);
else
@@ -788,7 +827,8 @@ Polymer({
*/
showAutoConnect_: function(networkProperties) {
return networkProperties.Type != CrOnc.Type.ETHERNET &&
- this.isRemembered_(networkProperties);
+ this.isRemembered_(networkProperties) &&
+ !this.isArcVpn_(networkProperties);
},
/**
@@ -824,7 +864,8 @@ Polymer({
showPreferNetwork_: function(networkProperties) {
// TODO(stevenjb): Resolve whether or not we want to allow "preferred" for
// networkProperties.Type == CrOnc.Type.ETHERNET.
- return this.isRemembered_(networkProperties);
+ return this.isRemembered_(networkProperties) &&
+ !this.isArcVpn_(networkProperties);
},
/**
@@ -868,6 +909,8 @@ Polymer({
var vpnType = CrOnc.getActiveValue(this.networkProperties.VPN.Type);
if (vpnType == 'ThirdPartyVPN') {
fields.push('VPN.ThirdPartyVPN.ProviderName');
+ } else if (vpnType == 'ARCVPN') {
+ fields.push('VPN.Type');
} else {
fields.push('VPN.Host', 'VPN.Type');
if (vpnType == 'OpenVPN')
@@ -952,7 +995,8 @@ Polymer({
return false;
}
return this.hasAdvancedFields_() || this.hasDeviceFields_() ||
- this.isRememberedOrConnected_(networkProperties);
+ (networkProperties.Type != CrOnc.Type.VPN &&
+ this.isRememberedOrConnected_(networkProperties));
},
/**
@@ -1019,12 +1063,29 @@ Polymer({
},
/**
+ * @param {!CrOnc.NetworkProperties} networkProperties
+ * @return {boolean}
+ * @private
+ */
+ isArcVpn_: function(networkProperties) {
+ return !!networkProperties.VPN &&
+ CrOnc.getActiveValue(networkProperties.VPN.Type) == 'ARCVPN';
+ },
+
+ /**
* @param {string} ipAddress
* @param {!CrOnc.NetworkProperties} networkProperties
* @return {boolean}
* @private
*/
showIpAddress_: function(ipAddress, networkProperties) {
+ // Arc Vpn does not currently pass IP configuration to ChromeOS. IP address
+ // property holds an internal IP address Android uses to talk to ChromeOS.
+ // TODO(lgcheng@) Show correct IP address when we implement IP configuration
+ // correclty.
+ if (this.isArcVpn_(networkProperties))
+ return false;
+
return !!ipAddress && this.isConnectedState_(networkProperties);
},
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 5ec39d7469b..b1dc5e6e712 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
@@ -54,44 +54,17 @@ Polymer({
enableForget_: Boolean,
},
+ listeners: {'network-list-changed': 'refreshNetworks_'},
+
/** @private {string} */
selectedGuid_: '',
- /**
- * Listener function for chrome.networkingPrivate.onNetworksChanged event.
- * @type {function(!Array<string>)}
- * @private
- */
- networksChangedListener_: function() {},
-
- /** @override */
- attached: function() {
- this.networksChangedListener_ = this.onNetworksChangedEvent_.bind(this);
- this.networkingPrivate.onNetworksChanged.addListener(
- this.networksChangedListener_);
- },
-
- /** @override */
- detached: function() {
- this.networkingPrivate.onNetworksChanged.removeListener(
- this.networksChangedListener_);
- },
-
/** @private */
networkTypeChanged_: function() {
this.refreshNetworks_();
},
/**
- * networkingPrivate.onNetworksChanged event callback.
- * @param {!Array<string>} networkIds The list of changed network GUIDs.
- * @private
- */
- onNetworksChangedEvent_: function(networkIds) {
- this.refreshNetworks_();
- },
-
- /**
* Requests the list of network states from Chrome. Updates networkStates
* once the results are returned from Chrome.
* @private
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 f77ea978261..cd6b2afbadb 100644
--- a/chromium/chrome/browser/resources/settings/internet_page/internet_page.html
+++ b/chromium/chrome/browser/resources/settings/internet_page/internet_page.html
@@ -4,6 +4,7 @@
<link rel="import" href="chrome://resources/cr_elements/cr_expand_button/cr_expand_button.html">
<link rel="import" href="chrome://resources/cr_elements/icons.html">
<link rel="import" href="chrome://resources/html/i18n_behavior.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/neon-animation/neon-animatable.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button-light.html">
@@ -73,6 +74,15 @@
</button>
</div>
</template>
+ <template is="dom-if" if="[[arcVpnProviders_.length]]">
+ <div actionable class="list-item" id="addArcVpn"
+ on-tap="onAddArcVpnTap_">
+ <div class="start">$i18n{internetAddArcVPN}</div>
+ <button class="icon-external" is="paper-icon-button-light"
+ aria-label$="$i18n{internetAddArcVPN}">
+ </button>
+ </div>
+ </template>
</div>
</template>
</template>
@@ -84,14 +94,7 @@
</template>
</neon-animatable>
- <template is="dom-if" route-path="/networkConfig" no-search>
- <settings-subpage page-title="$i18n{internetConfigTitle}">
- <settings-internet-config networking-private="[[networkingPrivate]]">
- </settings-internet-config>
- </settings-subpage>
- </template>
-
- <template is="dom-if" route-path="/networkDetail" no-search>
+ <template is="dom-if" route-path="/networkDetail" no-search restamp>
<settings-subpage page-title="$i18n{internetDetailPageTitle}">
<settings-internet-detail-page prefs="{{prefs}}"
default-network="[[defaultNetwork]]"
@@ -101,7 +104,7 @@
</settings-subpage>
</template>
- <template is="dom-if" route-path="/knownNetworks" no-search>
+ <template is="dom-if" route-path="/knownNetworks" no-search restamp>
<settings-subpage page-title="$i18n{internetKnownNetworksPageTitle}">
<settings-internet-known-networks-page
network-type="[[knownNetworksType_]]"
@@ -110,7 +113,7 @@
</settings-subpage>
</template>
- <template is="dom-if" route-path="/networks" no-search>
+ <template is="dom-if" route-path="/networks" no-search restamp>
<settings-subpage page-title="[[getNetworksPageTitle_(subpageType_)]]"
show-spinner="[[showSpinner_]]">
<settings-internet-subpage
@@ -119,6 +122,7 @@
tether-device-state="[[get('Tether', deviceStates)]]"
global-policy="[[globalPolicy_]]"
third-party-vpn-providers="[[thirdPartyVpnProviders_]]"
+ arc-vpn-providers="[[arcVpnProviders_]]"
networking-private="[[networkingPrivate]]"
show-spinner="{{showSpinner_}}">
</settings-bluetooth-subpage>
@@ -126,6 +130,12 @@
</template>
</settings-animated-pages>
+
+ <internet-config id="configDialog"
+ networking-private="[[networkingPrivate]]"
+ global-policy="[[globalPolicy_]]">
+ </internet-config>
+
</template>
<script src="internet_page.js"></script>
</dom-module>
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 85c7a78c1c8..8e935fa68cf 100644
--- a/chromium/chrome/browser/resources/settings/internet_page/internet_page.js
+++ b/chromium/chrome/browser/resources/settings/internet_page/internet_page.js
@@ -10,7 +10,8 @@
Polymer({
is: 'settings-internet-page',
- behaviors: [I18nBehavior, settings.RouteObserverBehavior],
+ behaviors:
+ [I18nBehavior, settings.RouteObserverBehavior, WebUIListenerBehavior],
properties: {
/**
@@ -89,6 +90,18 @@ Polymer({
}
},
+ /**
+ * List of Arc VPN providers.
+ * @type {!Array<!settings.ArcVpnProvider>}
+ * @private
+ */
+ arcVpnProviders_: {
+ type: Array,
+ value: function() {
+ return [];
+ }
+ },
+
/** @private {!Map<string, string>} */
focusConfig_: {
type: Object,
@@ -112,6 +125,13 @@ Polymer({
},
// chrome.networkingPrivate listeners
+ /** @private {?function(!Array<string>)} */
+ networkListChangedListener_: null,
+
+ /** @private {?function(!Array<string>)} */
+ networksChangedListener_: null,
+
+ // chrome.management listeners
/** @private {Function} */
onExtensionAddedListener_: null,
@@ -121,8 +141,33 @@ Polymer({
/** @private {Function} */
onExtensionDisabledListener_: null,
+ /** @private {settings.InternetPageBrowserProxy} */
+ browserProxy_: null,
+
+ /** @override */
+ created: function() {
+ this.browserProxy_ = settings.InternetPageBrowserProxyImpl.getInstance();
+ },
+
+ /** @override */
+ ready: function() {
+ this.browserProxy_.setUpdateArcVpnProvidersCallback(
+ this.onArcVpnProvidersReceived_.bind(this));
+ this.browserProxy_.requestArcVpnProviders();
+ },
+
/** @override */
attached: function() {
+ this.networkListChangedListener_ = this.networkListChangedListener_ ||
+ this.onNetworkListChanged_.bind(this);
+ this.networkingPrivate.onNetworkListChanged.addListener(
+ this.networkListChangedListener_);
+
+ this.networksChangedListener_ =
+ this.networksChangedListener_ || this.onNetworksChanged_.bind(this);
+ this.networkingPrivate.onNetworksChanged.addListener(
+ this.networksChangedListener_);
+
this.onExtensionAddedListener_ =
this.onExtensionAddedListener_ || this.onExtensionAdded_.bind(this);
chrome.management.onInstalled.addListener(this.onExtensionAddedListener_);
@@ -146,6 +191,11 @@ Polymer({
/** @override */
detached: function() {
+ this.networkingPrivate.onNetworkListChanged.removeListener(
+ assert(this.networkListChangedListener_));
+ this.networkingPrivate.onNetworksChanged.removeListener(
+ assert(this.networksChangedListener_));
+
chrome.management.onInstalled.removeListener(
assert(this.onExtensionAddedListener_));
chrome.management.onEnabled.removeListener(
@@ -233,13 +283,13 @@ Polymer({
* @private
*/
showConfig_: function(type, guid, name) {
- var params = new URLSearchParams;
- params.append('type', type);
- if (guid)
- params.append('guid', guid);
- if (name)
- params.append('name', name);
- settings.navigateTo(settings.routes.NETWORK_CONFIG, params);
+ var configDialog =
+ /** @type {!InternetConfigElement} */ (this.$.configDialog);
+ configDialog.type =
+ /** @type {chrome.networkingPrivate.NetworkType} */ (type);
+ configDialog.guid = guid || '';
+ configDialog.name = name || '';
+ configDialog.open();
},
/**
@@ -261,11 +311,7 @@ Polymer({
* @private
*/
onShowNetworks_: function(event) {
- this.detailType_ = event.detail.Type;
- var params = new URLSearchParams;
- params.append('type', event.detail.Type);
- this.subpageType_ = event.detail.Type;
- settings.navigateTo(settings.routes.INTERNET_NETWORKS, params);
+ this.showNetworksSubpage_(event.detail.Type);
},
/**
@@ -353,7 +399,24 @@ Polymer({
*/
onAddThirdPartyVpnTap_: function(event) {
var provider = event.model.item;
- chrome.send('addNetwork', [CrOnc.Type.VPN, provider.ExtensionID]);
+ this.browserProxy_.addThirdPartyVpn(CrOnc.Type.VPN, provider.ExtensionID);
+ },
+
+ /** @private */
+ onAddArcVpnTap_: function() {
+ this.showNetworksSubpage_(CrOnc.Type.VPN);
+ },
+
+ /**
+ * @param {string} type
+ * @private
+ */
+ showNetworksSubpage_: function(type) {
+ this.detailType_ = type;
+ var params = new URLSearchParams;
+ params.append('type', type);
+ this.subpageType_ = type;
+ settings.navigateTo(settings.routes.INTERNET_NETWORKS, params);
},
/**
@@ -393,6 +456,45 @@ Polymer({
},
/**
+ * This event is triggered when the list of networks changes.
+ * |networkIds| contains the ids for all visible or configured networks.
+ * networkingPrivate.onNetworkListChanged event callback.
+ * @param {!Array<string>} networkIds
+ * @private
+ */
+ onNetworkListChanged_: function(networkIds) {
+ var event = new CustomEvent('network-list-changed', {detail: networkIds});
+ this.maybeDispatchEvent_('network-summary', event);
+ this.maybeDispatchEvent_('settings-internet-detail-page', event);
+ this.maybeDispatchEvent_('settings-internet-known-networks-page', event);
+ this.maybeDispatchEvent_('settings-internet-subpage', event);
+ },
+
+ /**
+ * This event is triggered when interesting properties of a network change.
+ * |networkIds| contains the ids for networks whose properties have changed.
+ * networkingPrivate.onNetworksChanged event callback.
+ * @param {!Array<string>} networkIds
+ * @private
+ */
+ onNetworksChanged_: function(networkIds) {
+ var event = new CustomEvent('networks-changed', {detail: networkIds});
+ this.maybeDispatchEvent_('network-summary', event);
+ this.maybeDispatchEvent_('settings-internet-detail-page', event);
+ },
+
+ /**
+ * @param {!Event} event
+ * @private
+ */
+ maybeDispatchEvent_: function(identifier, event) {
+ var element = this.$$(identifier);
+ if (!element)
+ return;
+ element.dispatchEvent(event);
+ },
+
+ /**
* chrome.management.onInstalled or onEnabled event.
* @param {!chrome.management.ExtensionInfo} extension
* @private
@@ -417,6 +519,29 @@ Polymer({
},
/**
+ * Compares Arc VPN Providers based on LastlauchTime
+ * @param {!settings.ArcVpnProvider} arcVpnProvider1
+ * @param {!settings.ArcVpnProvider} arcVpnProvider2
+ * @private
+ */
+ compareArcVpnProviders_: function(arcVpnProvider1, arcVpnProvider2) {
+ if (arcVpnProvider1.LastLaunchTime > arcVpnProvider2.LastLaunchTime)
+ return -1;
+ if (arcVpnProvider1.LastLaunchTime < arcVpnProvider2.LastLaunchTime)
+ return 1;
+ return 0;
+ },
+
+ /**
+ * @param {?Array<!settings.ArcVpnProvider>} arcVpnProviders
+ * @private
+ */
+ onArcVpnProvidersReceived_: function(arcVpnProviders) {
+ arcVpnProviders.sort(this.compareArcVpnProviders_);
+ this.arcVpnProviders_ = arcVpnProviders;
+ },
+
+ /**
* chrome.management.onDisabled event.
* @param {{id: string}} extension
* @private
diff --git a/chromium/chrome/browser/resources/settings/internet_page/internet_page_browser_proxy.html b/chromium/chrome/browser/resources/settings/internet_page/internet_page_browser_proxy.html
new file mode 100644
index 00000000000..5989a2fed95
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/internet_page/internet_page_browser_proxy.html
@@ -0,0 +1,2 @@
+<link rel="import" href="chrome://resources/html/cr.html">
+<script src="internet_page_browser_proxy.js"></script>
diff --git a/chromium/chrome/browser/resources/settings/internet_page/internet_page_browser_proxy.js b/chromium/chrome/browser/resources/settings/internet_page/internet_page_browser_proxy.js
new file mode 100644
index 00000000000..80cce5c9341
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/internet_page/internet_page_browser_proxy.js
@@ -0,0 +1,78 @@
+// Copyright 2017 The Chromium 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 for Internet page. */
+cr.exportPath('settings');
+
+/**
+ * @typedef {{
+ * PackageName: string,
+ * ProviderName: string,
+ * AppID: string,
+ * LastLaunchTime: number,
+ * }}
+ */
+settings.ArcVpnProvider;
+
+cr.define('settings', function() {
+ /** @interface */
+ class InternetPageBrowserProxy {
+ /**
+ * Shows configuration of connnected external VPN network.
+ * @param {string} guid
+ */
+ showNetworkConfigure(guid) {}
+
+ /**
+ * Sends add VPN request to external VPN provider.
+ * @param {string} networkType
+ * @param {string} appId
+ */
+ addThirdPartyVpn(networkType, appId) {}
+
+ /**
+ * Requests Chrome to send list of Arc VPN providers.
+ */
+ requestArcVpnProviders() {}
+
+ /**
+ * |callback| is run when there is update of Arc VPN providers.
+ * Available after |requestArcVpnProviders| has been called.
+ * @param {function(?Array<settings.ArcVpnProvider>):void} callback
+ */
+ setUpdateArcVpnProvidersCallback(callback) {}
+ }
+
+ /**
+ * @implements {settings.InternetPageBrowserProxy}
+ */
+ class InternetPageBrowserProxyImpl {
+ /** @override */
+ showNetworkConfigure(guid) {
+ chrome.send('configureNetwork', [guid]);
+ }
+
+ /** @override */
+ addThirdPartyVpn(networkType, appId) {
+ chrome.send('addNetwork', [networkType, appId]);
+ }
+
+ /** @override */
+ requestArcVpnProviders() {
+ chrome.send('requestArcVpnProviders');
+ }
+
+ /** @override */
+ setUpdateArcVpnProvidersCallback(callback) {
+ cr.addWebUIListener('sendArcVpnProviders', callback);
+ }
+ }
+
+ cr.addSingletonGetter(InternetPageBrowserProxyImpl);
+
+ return {
+ InternetPageBrowserProxy: InternetPageBrowserProxy,
+ InternetPageBrowserProxyImpl: InternetPageBrowserProxyImpl,
+ };
+});
diff --git a/chromium/chrome/browser/resources/settings/internet_page/internet_shared_css.html b/chromium/chrome/browser/resources/settings/internet_page/internet_shared_css.html
index 1d60703ee2c..3b367ab31c3 100644
--- a/chromium/chrome/browser/resources/settings/internet_page/internet_shared_css.html
+++ b/chromium/chrome/browser/resources/settings/internet_page/internet_shared_css.html
@@ -1,4 +1,5 @@
<link rel="import" href="../settings_shared_css.html">
+<link rel="import" href="internet_page_browser_proxy.html">
<!-- Common styles for Internet settings. -->
<dom-module id="internet-shared">
diff --git a/chromium/chrome/browser/resources/settings/internet_page/internet_subpage.html b/chromium/chrome/browser/resources/settings/internet_page/internet_subpage.html
index 3d0116aba06..892b52e6555 100644
--- a/chromium/chrome/browser/resources/settings/internet_page/internet_subpage.html
+++ b/chromium/chrome/browser/resources/settings/internet_page/internet_subpage.html
@@ -102,8 +102,8 @@
class="no-networks">
</div>
- <!-- Third party VPNs. -->
<template is="dom-if" if="[[isEqual_('VPN', deviceState.Type)]]">
+ <!-- Third party VPNs. -->
<template is="dom-repeat" items="[[thirdPartyVpnProviders]]">
<div id="[[item.ProviderName]]"
class="vpn-header layout horizontal center">
@@ -123,6 +123,26 @@
$i18n{internetNoNetworks}
</div>
</template>
+ <!-- Arc VPNs. -->
+ <template is="dom-repeat" items="[[arcVpnProviders]]">
+ <div id="[[item.ProviderName]]"
+ class="vpn-header layout horizontal center">
+ <div class="flex">[[item.ProviderName]]</div>
+ <button is="paper-icon-button-light" class="icon-add-circle"
+ aria-label$="[[getAddArcVpnAllyString_(item)]]"
+ on-tap="onAddArcVpnTap_" tabindex$="[[tabindex]]">
+ </button>
+ </div>
+ <cr-network-list show-buttons
+ hidden$="[[!haveArcVpnNetwork_(arcVpns_, item)]]"
+ networks="[[getArcVpnNetworks_(arcVpns_, item)]]"
+ on-selected="onNetworkSelected_">
+ </cr-network-list>
+ <div hidden$="[[haveArcVpnNetwork_(arcVpns_, item)]]"
+ class="no-networks">
+ $i18n{internetNoNetworks}
+ </div>
+ </template>
</template>
</div>
diff --git a/chromium/chrome/browser/resources/settings/internet_page/internet_subpage.js b/chromium/chrome/browser/resources/settings/internet_page/internet_subpage.js
index 0434b0e14c0..69592e2c91b 100644
--- a/chromium/chrome/browser/resources/settings/internet_page/internet_subpage.js
+++ b/chromium/chrome/browser/resources/settings/internet_page/internet_subpage.js
@@ -50,6 +50,12 @@ Polymer({
thirdPartyVpnProviders: Array,
/**
+ * List of Arc VPN providers.
+ * @type {!Array<!settings.ArcVpnProvider>|undefined}
+ */
+ arcVpnProviders: Array,
+
+ /**
* Interface for networkingPrivate calls, passed from internet_page.
* @type {!NetworkingPrivate}
*/
@@ -82,33 +88,37 @@ Polymer({
return {};
},
},
+
+ /**
+ * Dictionary of lists of network states for Arc VPNs.
+ * @private {!Object<!Array<!CrOnc.NetworkStateProperties>>}
+ */
+ arcVpns_: {
+ type: Object,
+ value: function() {
+ return {};
+ }
+ }
},
+ listeners: {'network-list-changed': 'getNetworkStateList_'},
+
observers: ['deviceStateChanged_(networkingPrivate, deviceState)'],
/** @private {number|null} */
scanIntervalId_: null,
- /**
- * Listener function for chrome.networkingPrivate.onNetworkListChanged event.
- * @type {?function(!Array<string>)}
- * @private
- */
- networkListChangedListener_: null,
+ /** @private {settings.InternetPageBrowserProxy} */
+ browserProxy_: null,
- /** override */
- attached: function() {
- this.networkListChangedListener_ = this.networkListChangedListener_ ||
- this.onNetworkListChangedEvent_.bind(this);
- this.networkingPrivate.onNetworkListChanged.addListener(
- this.networkListChangedListener_);
+ /** @override */
+ created: function() {
+ this.browserProxy_ = settings.InternetPageBrowserProxyImpl.getInstance();
},
/** override */
detached: function() {
this.stopScanning_();
- this.networkingPrivate.onNetworkListChanged.removeListener(
- assert(this.networkListChangedListener_));
},
/**
@@ -124,6 +134,7 @@ Polymer({
// Clear any stale data.
this.networkStateList_ = [];
this.thirdPartyVpns_ = {};
+ this.arcVpns_ = {};
// Request the list of networks and start scanning if necessary.
this.getNetworkStateList_();
this.updateScanning_();
@@ -195,14 +206,6 @@ Polymer({
this.scanIntervalId_ = null;
},
- /**
- * networkingPrivate.onNetworkListChanged event callback.
- * @private
- */
- onNetworkListChangedEvent_: function() {
- this.getNetworkStateList_();
- },
-
/** @private */
getNetworkStateList_: function() {
if (!this.deviceState)
@@ -237,23 +240,30 @@ Polymer({
return;
}
- // For VPNs, separate out third party VPNs.
+ // For VPNs, separate out third party VPNs and Arc VPNs.
if (this.deviceState.Type == CrOnc.Type.VPN) {
var builtinNetworkStates = [];
var thirdPartyVpns = {};
+ var arcVpns = {};
for (var i = 0; i < networkStates.length; ++i) {
var state = networkStates[i];
- var providerType = state.VPN && state.VPN.ThirdPartyVPN &&
- state.VPN.ThirdPartyVPN.ProviderName;
+ var providerType = this.get('VPN.ThirdPartyVPN.ProviderName', state);
if (providerType) {
thirdPartyVpns[providerType] = thirdPartyVpns[providerType] || [];
thirdPartyVpns[providerType].push(state);
+ } else if (this.get('VPN.Type', state) == 'ARCVPN') {
+ var arcProviderName = this.get('VPN.Host', state);
+ if (state.ConnectionState != CrOnc.ConnectionState.CONNECTED)
+ continue;
+ arcVpns[arcProviderName] = arcVpns[arcProviderName] || [];
+ arcVpns[arcProviderName].push(state);
} else {
builtinNetworkStates.push(state);
}
}
networkStates = builtinNetworkStates;
this.thirdPartyVpns_ = thirdPartyVpns;
+ this.arcVpns_ = arcVpns;
}
this.networkStateList_ = networkStates;
@@ -329,6 +339,15 @@ Polymer({
},
/**
+ * @param {!settings.ArcVpnProvider} arcVpn
+ * @return {string}
+ * @private
+ */
+ getAddArcVpnAllyString_: function(arcVpn) {
+ return this.i18n('internetAddArcVPNProvider', arcVpn.ProviderName);
+ },
+
+ /**
* @param {!chrome.networkingPrivate.GlobalPolicy} globalPolicy
* @return {boolean}
* @private
@@ -370,7 +389,19 @@ Polymer({
*/
onAddThirdPartyVpnTap_: function(event) {
var provider = event.model.item;
- chrome.send('addNetwork', [CrOnc.Type.VPN, provider.ExtensionID]);
+ this.browserProxy_.addThirdPartyVpn(CrOnc.Type.VPN, provider.ExtensionID);
+ },
+
+ /**
+ * @param {!{model:
+ * !{item: !settings.ArcVpnProvider},
+ * }} event
+ * @private
+ */
+ onAddArcVpnTap_: function(event) {
+ var provider = event.model.item;
+ settings.InternetPageBrowserProxyImpl.getInstance().addThirdPartyVpn(
+ CrOnc.Type.VPN, provider.AppID);
},
/**
@@ -428,6 +459,27 @@ Polymer({
},
/**
+ * @param {!Object<!Array<!CrOnc.NetworkStateProperties>>} arcVpns
+ * @param {!settings.ArcVpnProvider} arcVpnProvider
+ * @return {!Array<!CrOnc.NetworkStateProperties>}
+ * @private
+ */
+ getArcVpnNetworks_: function(arcVpns, arcVpnProvider) {
+ return arcVpns[arcVpnProvider.PackageName] || [];
+ },
+
+ /**
+ * @param {!Object<!Array<!CrOnc.NetworkStateProperties>>} arcVpns
+ * @param {!settings.ArcVpnProvider} arcVpnProvider
+ * @return {boolean}
+ * @private
+ */
+ haveArcVpnNetwork_: function(arcVpns, arcVpnProvider) {
+ var list = this.getArcVpnNetworks_(arcVpns, arcVpnProvider);
+ return !!list.length;
+ },
+
+ /**
* Event triggered when a network list item is selected.
* @param {!{target: HTMLElement, detail: !CrOnc.NetworkStateProperties}} e
* @private
diff --git a/chromium/chrome/browser/resources/settings/internet_page/network_siminfo.html b/chromium/chrome/browser/resources/settings/internet_page/network_siminfo.html
deleted file mode 100644
index 8f4df0be364..00000000000
--- a/chromium/chrome/browser/resources/settings/internet_page/network_siminfo.html
+++ /dev/null
@@ -1,199 +0,0 @@
-<link rel="import" href="chrome://resources/html/polymer.html">
-
-<link rel="import" href="chrome://resources/cr_elements/chromeos/network/cr_onc_types.html">
-<link rel="import" href="chrome://resources/cr_elements/cr_dialog/cr_dialog.html">
-<link rel="import" href="chrome://resources/html/assert.html">
-<link rel="import" href="chrome://resources/html/cr/ui/focus_without_ink.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-flex-layout/iron-flex-layout-classes.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-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-toggle-button/paper-toggle-button.html">
-<link rel="import" href="../icons.html">
-<link rel="import" href="internet_shared_css.html">
-
-<dom-module id="network-siminfo">
- <template>
- <style include="settings-shared internet-shared iron-flex">
- iron-icon {
- -webkit-margin-end: 10px;
- }
-
- .dialog-error {
- color: red;
- font-size: 125%;
- font-weight: 500;
- margin-top: 10px;
- }
-
- .error {
- color: red;
- font-weight: 500;
- }
-
- .pin {
- min-width: 100px;
- }
-
- .puk {
- min-width: 200px;
- }
-
- /* Siminfo is embedded; remove the padding. */
- .settings-box {
- padding: 0;
- }
-
- .settings-box:first-of-type {
- border-top: none;
- }
-
- paper-toggle-button {
- -webkit-margin-start: var(--settings-control-label-spacing);
- }
- </style>
-
- <!-- SIM missing UI -->
- <div class="settings-box two-line"
- hidden$="[[networkProperties.Cellular.SIMPresent]]">
- <div class="start layout horizontal center">
- <iron-icon icon="settings:sim-card-alert"></iron-icon>
- <div class="error">$i18n{networkSimCardMissing}</div>
- </div>
- </div>
-
- <!-- SIM locked -->
- <div class="settings-box two-line"
- hidden$="[[!showSimLocked_(networkProperties)]]">
- <div class="start layout horizontal center">
- <iron-icon icon="settings:lock"></iron-icon>
- <div class="error">$i18n{networkSimCardLocked}</div>
- </div>
- <div class="separator"></div>
- <paper-button id="unlockPinButton" on-tap="onUnlockPinTap_">
- $i18n{networkSimUnlock}
- </paper-button>
- </div>
-
- <!-- SIM unlocked -->
- <div class="settings-box two-line"
- hidden$="[[!showSimUnlocked_(networkProperties)]]">
- <div id="simLockToggleLabel" class="start">
- $i18n{networkSimLockEnable}
- </div>
- <paper-button id="changePinButton" on-tap="onChangePinTap_"
- hidden$="[[!networkProperties.Cellular.SIMLockStatus.LockEnabled]]">
- $i18n{networkSimChangePin}
- </paper-button>
- <paper-toggle-button id="simLockButton"
- on-change="onSimLockEnabledChange_" checked="{{lockEnabled_}}"
- aria-labelledby="simLockToggleLabel">
- </paper-toggle-button>
- </div>
-
- <!-- Enter PIN dialog -->
- <dialog is="cr-dialog" id="enterPinDialog" close-text="$i18n{close}"
- on-cancel="onEnterPinDialogCancel_"
- on-close="onEnterPinDialogClose_">
- <div slot="title">$i18n{networkSimEnterPinTitle}</div>
- <div slot="body">
- <paper-input id="enterPin" class="pin" no-label-float autofocus
- label="$i18n{networkSimEnterPin}">
- <iron-a11y-keys keys="enter" on-keys-pressed="sendEnterPin_">
- </iron-a11y-keys>
- </paper-input>
- <div class="dialog-error">
- [[getErrorMsg_(error_, networkProperties)]]
- </div>
- </div>
- <div slot="button-container">
- <paper-button on-tap="sendEnterPin_">
- $i18n{networkSimEnter}
- </paper-button>
- </div>
- </dialog>
-
- <!-- Change PIN dialog -->
- <dialog is="cr-dialog" id="changePinDialog" close-text="$i18n{close}"
- on-close="onChangePinDialogClose_">
- <div slot="title">$i18n{networkSimChangePinTitle}</div>
- <div slot="body">
- <paper-input id="changePinOld" class="pin" no-label-float autofocus
- label="$i18n{networkSimEnterOldPin}">
- </paper-input>
- <paper-input id="changePinNew1" class="pin" no-label-float
- label="$i18n{networkSimEnterNewPin}">
- </paper-input>
- <paper-input id="changePinNew2" class="pin" no-label-float
- label="$i18n{networkSimReEnterNewPin}">
- <iron-a11y-keys keys="enter" on-keys-pressed="sendChangePin_">
- </iron-a11y-keys>
- </paper-input>
- <div class="dialog-error">
- [[getErrorMsg_(error_, networkProperties)]]
- </div>
- </div>
- <div slot="button-container">
- <paper-button on-tap="sendChangePin_">
- $i18n{networkSimChange}
- </paper-button>
- </div>
- </dialog>
-
- <!-- Unlock PIN dialog -->
- <dialog is="cr-dialog" id="unlockPinDialog" close-text="$i18n{close}"
- on-close="onUnlockPinDialogClose_">
- <div slot="title">$i18n{networkSimLockedTitle}</div>
- <div slot="body">
- <paper-input id="unlockPin" class="pin" no-label-float autofocus
- label="$i18n{networkSimEnterPin}">
- <iron-a11y-keys keys="enter" on-keys-pressed="sendUnlockPin_">
- </iron-a11y-keys>
- </paper-input>
- <div class="dialog-error">
- [[getErrorMsg_(error_, networkProperties)]]
- </div>
- </div>
- <div slot="button-container">
- <paper-button on-tap="sendUnlockPin_">
- $i18n{networkSimUnlock}
- </paper-button>
- </div>
- </dialog>
-
- <!-- Unlock PUK dialog -->
- <dialog is="cr-dialog" id="unlockPukDialog" close-text="$i18n{close}"
- on-close="onUnlockPinDialogClose_">
- <div slot="title">$i18n{networkSimLockedTitle}</div>
- <div slot="body">
- <div>
- Enter the 8-digit PIN Unblocking Key provided by your carrier
- </div>
- <paper-input id="unlockPuk" class="puk" no-label-float autofocus
- label="$i18n{networkSimEnterPuk}">
- </paper-input>
- <paper-input id="unlockPin1" class="pin" no-label-float
- label="$i18n{networkSimEnterNewPin}">
- </paper-input>
- <paper-input id="unlockPin2" class="pin" no-label-float
- label="$i18n{networkSimReEnterNewPin}">
- <iron-a11y-keys keys="enter" on-keys-pressed="sendUnlockPuk_">
- </iron-a11y-keys>
- </paper-input>
- <div class="dialog-error">
- $i18n{networkSimLockedWarning}
- </div>
- <div class="dialog-error">
- [[getErrorMsg_(error_, networkProperties)]]
- </div>
- </div>
- <div slot="button-container">
- <paper-button on-tap="sendUnlockPuk_">
- $i18n{networkSimUnlock}
- </paper-button>
- </div>
- </dialog>
- </template>
- <script src="network_siminfo.js"></script>
-</dom-module>
diff --git a/chromium/chrome/browser/resources/settings/internet_page/network_siminfo.js b/chromium/chrome/browser/resources/settings/internet_page/network_siminfo.js
deleted file mode 100644
index 2ea134f2069..00000000000
--- a/chromium/chrome/browser/resources/settings/internet_page/network_siminfo.js
+++ /dev/null
@@ -1,402 +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 Polymer element for displaying and modifying cellular sim info.
- */
-(function() {
-
-/** @enum {string} */
-var ErrorType = {
- NONE: 'none',
- INCORRECT_PIN: 'incorrect-pin',
- INCORRECT_PUK: 'incorrect-puk',
- MISMATCHED_PIN: 'mismatched-pin',
- INVALID_PIN: 'invalid-pin',
- INVALID_PUK: 'invalid-puk'
-};
-
-var PIN_MIN_LENGTH = 4;
-var PUK_MIN_LENGTH = 8;
-
-Polymer({
- is: 'network-siminfo',
-
- properties: {
- /**
- * The network properties associated with the element.
- * @type {!CrOnc.NetworkProperties|undefined}
- */
- networkProperties: {
- type: Object,
- observer: 'networkPropertiesChanged_',
- },
-
- /**
- * Interface for networkingPrivate calls, passed from internet_page.
- * @type {NetworkingPrivate}
- */
- networkingPrivate: Object,
-
- /**
- * Reflects networkProperties.Cellular.SIMLockStatus.LockEnabled for the
- * toggle button.
- * @private
- */
- lockEnabled_: {
- type: Boolean,
- value: false,
- },
-
- /**
- * Set to true when a PUK is required to unlock the SIM.
- * @private
- */
- pukRequired_: {
- type: Boolean,
- value: false,
- observer: 'pukRequiredChanged_',
- },
-
- /**
- * Set to an ErrorType value after an incorrect PIN or PUK entry.
- * @private {ErrorType}
- */
- error_: {
- type: Object,
- value: ErrorType.NONE,
- },
- },
-
- sendSimLockEnabled_: false,
-
- /** @override */
- detached: function() {
- if (this.$.enterPinDialog.open)
- this.$.enterPinDialog.close();
- if (this.$.changePinDialog.open)
- this.$.changePinDialog.close();
- if (this.$.unlockPinDialog.open)
- this.$.unlockPinDialog.close();
- if (this.$.unlockPukDialog.open)
- this.$.unlockPukDialog.close();
- },
-
- /** @private */
- networkPropertiesChanged_: function() {
- if (!this.networkProperties || !this.networkProperties.Cellular)
- return;
- var simLockStatus = this.networkProperties.Cellular.SIMLockStatus;
- this.pukRequired_ =
- !!simLockStatus && simLockStatus.LockType == CrOnc.LockType.PUK;
- this.lockEnabled_ = !!simLockStatus && simLockStatus.LockEnabled;
- },
-
- /** @private */
- pukRequiredChanged_: function() {
- if (this.$.unlockPukDialog.open) {
- if (this.pukRequired_)
- this.$.unlockPuk.focus();
- else
- this.$.unlockPukDialog.close();
- return;
- }
-
- if (!this.pukRequired_)
- return;
-
- // If the PUK was activated while attempting to enter or change a pin,
- // close the dialog and open the unlock PUK dialog.
- var showUnlockPuk = false;
- if (this.$.enterPinDialog.open) {
- this.$.enterPinDialog.close();
- showUnlockPuk = true;
- }
- if (this.$.changePinDialog.open) {
- this.$.changePinDialog.close();
- showUnlockPuk = true;
- }
- if (this.$.unlockPinDialog.open) {
- this.$.unlockPinDialog.close();
- showUnlockPuk = true;
- }
- if (!showUnlockPuk)
- return;
-
- this.showUnlockPukDialog_();
- },
-
- /**
- * Opens the pin dialog when the sim lock enabled state changes.
- * @param {!Event} event
- * @private
- */
- onSimLockEnabledChange_: function(event) {
- if (!this.networkProperties || !this.networkProperties.Cellular)
- return;
- this.sendSimLockEnabled_ = event.target.checked;
- this.error_ = ErrorType.NONE;
- this.$.enterPin.value = '';
- this.$.enterPinDialog.showModal();
- },
-
- /**
- * Sends the PIN value from the Enter PIN dialog.
- * @param {!Event} event
- * @private
- */
- sendEnterPin_: function(event) {
- event.stopPropagation();
- var guid = (this.networkProperties && this.networkProperties.GUID) || '';
- var pin = this.$.enterPin.value;
- if (!this.validatePin_(pin)) {
- this.onEnterPinDialogCancel_();
- return;
- }
- var simState = /** @type {!CrOnc.CellularSimState} */ ({
- currentPin: pin,
- requirePin: this.sendSimLockEnabled_,
- });
- this.networkingPrivate.setCellularSimState(guid, simState, () => {
- if (chrome.runtime.lastError) {
- this.error_ = ErrorType.INCORRECT_PIN;
- this.$.enterPin.inputElement.select();
- } else {
- this.error_ = ErrorType.NONE;
- this.$.enterPinDialog.close();
- }
- });
- },
-
- /**
- * Opens the Change PIN dialog.
- * @param {!Event} event
- * @private
- */
- onChangePinTap_: function(event) {
- event.stopPropagation();
- if (!this.networkProperties || !this.networkProperties.Cellular)
- return;
- this.error_ = ErrorType.NONE;
- this.$.changePinOld.value = '';
- this.$.changePinNew1.value = '';
- this.$.changePinNew2.value = '';
- this.$.changePinDialog.showModal();
- },
-
- /**
- * Sends the old and new PIN values from the Change PIN dialog.
- * @param {!Event} event
- * @private
- */
- sendChangePin_: function(event) {
- event.stopPropagation();
- var guid = (this.networkProperties && this.networkProperties.GUID) || '';
- var newPin = this.$.changePinNew1.value;
- if (!this.validatePin_(newPin, this.$.changePinNew2.value))
- return;
-
- var simState = /** @type {!CrOnc.CellularSimState} */ ({
- requirePin: true,
- currentPin: this.$.changePinOld.value,
- newPin: newPin
- });
- this.networkingPrivate.setCellularSimState(guid, simState, () => {
- if (chrome.runtime.lastError) {
- this.error_ = ErrorType.INCORRECT_PIN;
- this.$.changePinOld.inputElement.select();
- } else {
- this.error_ = ErrorType.NONE;
- this.$.changePinDialog.close();
- }
- });
- },
-
- /**
- * Opens the Unlock PIN / PUK dialog.
- * @param {!Event} event
- * @private
- */
- onUnlockPinTap_: function(event) {
- event.stopPropagation();
- if (this.pukRequired_) {
- this.showUnlockPukDialog_();
- } else {
- this.showUnlockPinDialog_();
- }
- },
-
- /**
- * Sends the PIN value from the Unlock PIN dialog.
- * @param {!Event} event
- * @private
- */
- sendUnlockPin_: function(event) {
- event.stopPropagation();
- var guid = (this.networkProperties && this.networkProperties.GUID) || '';
- var pin = this.$.unlockPin.value;
- if (!this.validatePin_(pin))
- return;
-
- this.networkingPrivate.unlockCellularSim(guid, pin, '', () => {
- if (chrome.runtime.lastError) {
- this.error_ = ErrorType.INCORRECT_PIN;
- this.$.unlockPin.inputElement.select();
- } else {
- this.error_ = ErrorType.NONE;
- this.$.unlockPinDialog.close();
- }
- });
- },
-
- /** @private */
- showUnlockPinDialog_: function() {
- this.error_ = ErrorType.NONE;
- this.$.unlockPin.value = '';
- this.$.unlockPinDialog.showModal();
- },
-
- /** @private */
- showUnlockPukDialog_: function() {
- this.error_ = ErrorType.NONE;
- this.$.unlockPuk.value = '';
- this.$.unlockPin1.value = '';
- this.$.unlockPin2.value = '';
- this.$.unlockPukDialog.showModal();
- },
-
- /**
- * Sends the PUK value and new PIN value from the Unblock PUK dialog.
- * @param {!Event} event
- * @private
- */
- sendUnlockPuk_: function(event) {
- event.stopPropagation();
- var guid = (this.networkProperties && this.networkProperties.GUID) || '';
- var puk = this.$.unlockPuk.value;
- if (!this.validatePuk_(puk))
- return;
- var pin = this.$.unlockPin1.value;
- if (!this.validatePin_(pin, this.$.unlockPin2.value))
- return;
-
- this.networkingPrivate.unlockCellularSim(guid, pin, puk, () => {
- if (chrome.runtime.lastError) {
- this.error_ = ErrorType.INCORRECT_PUK;
- this.$.unlockPuk.inputElement.select();
- } else {
- this.error_ = ErrorType.NONE;
- this.$.unlockPukDialog.close();
- }
- });
- },
-
- /**
- * @return {boolean}
- * @private
- */
- showSimLocked_: function() {
- if (!this.networkProperties || !this.networkProperties.Cellular ||
- !this.networkProperties.Cellular.SIMPresent) {
- return false;
- }
- return CrOnc.isSimLocked(this.networkProperties);
- },
-
- /**
- * @return {boolean}
- * @private
- */
- showSimUnlocked_: function() {
- if (!this.networkProperties || !this.networkProperties.Cellular ||
- !this.networkProperties.Cellular.SIMPresent) {
- return false;
- }
- return !CrOnc.isSimLocked(this.networkProperties);
- },
-
- /** @private */
- getErrorMsg_: function() {
- if (this.error_ == ErrorType.NONE)
- return '';
- // TODO(stevenjb): Translate
- var msg;
- if (this.error_ == ErrorType.INCORRECT_PIN)
- msg = 'Incorrect PIN.';
- else if (this.error_ == ErrorType.INCORRECT_PUK)
- msg = 'Incorrect PUK.';
- else if (this.error_ == ErrorType.MISMATCHED_PIN)
- msg = 'PIN values do not match.';
- else if (this.error_ == ErrorType.INVALID_PIN)
- msg = 'Invalid PIN.';
- else if (this.error_ == ErrorType.INVALID_PUK)
- msg = 'Invalid PUK.';
- else
- return 'UNKNOWN ERROR';
- var retriesLeft =
- this.get('Cellular.SIMLockStatus.RetriesLeft', this.networkProperties);
- if (retriesLeft) {
- msg += ' Retries left: ' + retriesLeft.toString();
- }
- return msg;
- },
-
- /**
- * Checks whether |pin1| is of the proper length and if opt_pin2 is not
- * undefined, whether pin1 and opt_pin2 match. On any failure, sets
- * |this.error_| and returns false.
- * @param {string} pin1
- * @param {string=} opt_pin2
- * @return {boolean} True if the pins match and are of minimum length.
- * @private
- */
- validatePin_: function(pin1, opt_pin2) {
- if (pin1.length < PIN_MIN_LENGTH) {
- this.error_ = ErrorType.INVALID_PIN;
- return false;
- }
- if (opt_pin2 != undefined && pin1 != opt_pin2) {
- this.error_ = ErrorType.MISMATCHED_PIN;
- return false;
- }
- return true;
- },
-
- /**
- * Checks whether |puk| is of the proper length. If not, sets |this.error_|
- * and returns false.
- * @param {string} puk
- * @return {boolean} True if the puk is of minimum length.
- * @private
- */
- validatePuk_: function(puk) {
- if (puk.length < PUK_MIN_LENGTH) {
- this.error_ = ErrorType.INVALID_PUK;
- return false;
- }
- return true;
- },
-
- /** @private */
- onEnterPinDialogCancel_: function() {
- this.lockEnabled_ =
- this.networkProperties.Cellular.SIMLockStatus.LockEnabled;
- },
-
- /** @private */
- onEnterPinDialogClose_: function() {
- cr.ui.focusWithoutInk(assert(this.$$('#simLockButton')));
- },
-
- /** @private */
- onChangePinDialogClose_: function() {
- cr.ui.focusWithoutInk(assert(this.$$('#changePinButton')));
- },
-
- /** @private */
- onUnlockPinDialogClose_: function() {
- cr.ui.focusWithoutInk(assert(this.$$('#unlockPinButton')));
- },
-});
-})();
diff --git a/chromium/chrome/browser/resources/settings/internet_page/network_summary.js b/chromium/chrome/browser/resources/settings/internet_page/network_summary.js
index a1c6dea2665..a755721b3c4 100644
--- a/chromium/chrome/browser/resources/settings/internet_page/network_summary.js
+++ b/chromium/chrome/browser/resources/settings/internet_page/network_summary.js
@@ -91,11 +91,10 @@ Polymer({
},
},
- /**
- * Listener function for chrome.networkingPrivate.onNetworkListChanged event.
- * @private {?function(!Array<string>)}
- */
- networkListChangedListener_: null,
+ listeners: {
+ 'network-list-changed': 'getNetworkLists_',
+ 'networks-changed': 'updateActiveNetworks_',
+ },
/**
* Listener function for chrome.networkingPrivate.onDeviceStateListChanged
@@ -105,12 +104,6 @@ Polymer({
deviceStateListChangedListener_: null,
/**
- * Listener function for chrome.networkingPrivate.onNetworksChanged event.
- * @private {?function(!Array<string>)}
- */
- networksChangedListener_: null,
-
- /**
* Set of GUIDs identifying active networks, one for each type.
* @private {?Set<string>}
*/
@@ -120,41 +113,17 @@ Polymer({
attached: function() {
this.getNetworkLists_();
- this.networkListChangedListener_ = this.networkListChangedListener_ ||
- this.onNetworkListChangedEvent_.bind(this);
- this.networkingPrivate.onNetworkListChanged.addListener(
- this.networkListChangedListener_);
-
this.deviceStateListChangedListener_ =
this.deviceStateListChangedListener_ ||
this.onDeviceStateListChangedEvent_.bind(this);
this.networkingPrivate.onDeviceStateListChanged.addListener(
this.deviceStateListChangedListener_);
-
- this.networksChangedListener_ = this.networksChangedListener_ ||
- this.onNetworksChangedEvent_.bind(this);
- this.networkingPrivate.onNetworksChanged.addListener(
- this.networksChangedListener_);
},
/** @override */
detached: function() {
- this.networkingPrivate.onNetworkListChanged.removeListener(
- assert(this.networkListChangedListener_));
-
this.networkingPrivate.onDeviceStateListChanged.removeListener(
assert(this.deviceStateListChangedListener_));
-
- this.networkingPrivate.onNetworksChanged.removeListener(
- assert(this.networksChangedListener_));
- },
-
- /**
- * networkingPrivate.onNetworkListChanged event callback.
- * @private
- */
- onNetworkListChangedEvent_: function() {
- this.getNetworkLists_();
},
/**
@@ -166,13 +135,13 @@ Polymer({
},
/**
- * networkingPrivate.onNetworksChanged event callback.
- * @param {!Array<string>} networkIds The list of changed network GUIDs.
+ * @param {{detail: !Array<string>}} event
* @private
*/
- onNetworksChangedEvent_: function(networkIds) {
+ updateActiveNetworks_: function(event) {
if (!this.activeNetworkIds_)
return; // Initial list of networks not received yet.
+ var networkIds = event.detail;
networkIds.forEach(function(id) {
if (this.activeNetworkIds_.has(id)) {
this.networkingPrivate.getState(
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 b1a730a7e82..812bf51fff9 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,5 +1,6 @@
<link rel="import" href="chrome://resources/html/polymer.html">
+<link rel="import" href="chrome://resources/cr_components/chromeos/network/network_siminfo.html">
<link rel="import" href="chrome://resources/cr_elements/chromeos/network/cr_network_icon.html">
<link rel="import" href="chrome://resources/cr_elements/policy/cr_policy_indicator.html">
<link rel="import" href="chrome://resources/html/i18n_behavior.html">
@@ -8,7 +9,6 @@
<link rel="import" href="chrome://resources/polymer/v1_0/paper-toggle-button/paper-toggle-button.html">
<link rel="import" href="../settings_page/settings_subpage.html">
<link rel="import" href="../settings_shared_css.html">
-<link rel="import" href="network_siminfo.html">
<dom-module id="network-summary-item">
<template>
diff --git a/chromium/chrome/browser/resources/settings/internet_page/network_summary_item.js b/chromium/chrome/browser/resources/settings/internet_page/network_summary_item.js
index 9555d961bd8..1171557295f 100644
--- a/chromium/chrome/browser/resources/settings/internet_page/network_summary_item.js
+++ b/chromium/chrome/browser/resources/settings/internet_page/network_summary_item.js
@@ -130,17 +130,24 @@ Polymer({
},
/**
- * Show the <network-siminfo> element if this is a disabled and locked
- * cellular device.
* @param {!CrOnc.DeviceStateProperties|undefined} deviceState
* @return {boolean}
* @private
*/
showSimInfo_: function(deviceState) {
- if (!deviceState || deviceState.Type != CrOnc.Type.CELLULAR ||
- this.deviceIsEnabled_(deviceState)) {
+ if (!deviceState || deviceState.Type != CrOnc.Type.CELLULAR)
+ return false;
+ return this.simLockedOrAbsent_(deviceState);
+ },
+
+ /**
+ * @param {!CrOnc.DeviceStateProperties} deviceState
+ * @return {boolean}
+ * @private
+ */
+ simLockedOrAbsent_: function(deviceState) {
+ if (this.deviceIsEnabled_(deviceState))
return false;
- }
if (deviceState.SIMPresent === false)
return true;
var simLockType =
@@ -184,10 +191,23 @@ Polymer({
* @private
*/
enableToggleIsVisible_: function(deviceState) {
- return !!deviceState && deviceState.Type != CrOnc.Type.ETHERNET &&
- deviceState.Type != CrOnc.Type.VPN &&
- (deviceState.Type == CrOnc.Type.TETHER ||
- deviceState.State != CrOnc.DeviceState.UNINITIALIZED);
+ if (!deviceState)
+ return false;
+ switch (deviceState.Type) {
+ case CrOnc.Type.ETHERNET:
+ case CrOnc.Type.VPN:
+ return false;
+ case CrOnc.Type.TETHER:
+ return true;
+ case CrOnc.Type.WI_FI:
+ case CrOnc.Type.WI_MAX:
+ return deviceState.State != CrOnc.DeviceState.UNINITIALIZED;
+ case CrOnc.Type.CELLULAR:
+ return deviceState.State != CrOnc.DeviceState.UNINITIALIZED &&
+ !this.simLockedOrAbsent_(deviceState);
+ }
+ assertNotReached();
+ return false;
},
/**
diff --git a/chromium/chrome/browser/resources/settings/internet_page/tether_connection_dialog.html b/chromium/chrome/browser/resources/settings/internet_page/tether_connection_dialog.html
index 67d7e60dba4..e22b64676bd 100644
--- a/chromium/chrome/browser/resources/settings/internet_page/tether_connection_dialog.html
+++ b/chromium/chrome/browser/resources/settings/internet_page/tether_connection_dialog.html
@@ -1,6 +1,7 @@
<link rel="import" href="chrome://resources/html/polymer.html">
<link rel="import" href="chrome://resources/cr_elements/chromeos/network/cr_network_icon.html">
<link rel="import" href="chrome://resources/cr_elements/chromeos/network/cr_onc_types.html">
+<link rel="import" href="chrome://resources/cr_elements/cr_dialog/cr_dialog.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="../icons.html">
diff --git a/chromium/chrome/browser/resources/settings/languages_page/languages.js b/chromium/chrome/browser/resources/settings/languages_page/languages.js
index 47a7568bf09..d90b775393c 100644
--- a/chromium/chrome/browser/resources/settings/languages_page/languages.js
+++ b/chromium/chrome/browser/resources/settings/languages_page/languages.js
@@ -15,6 +15,8 @@
cr.exportPath('settings');
+var MoveType = chrome.languageSettingsPrivate.MoveType;
+
// Translate server treats some language codes the same.
// See also: components/translate/core/common/translate_util.cc.
var kLanguageCodeToTranslateCode = {
@@ -610,38 +612,22 @@ Polymer({
},
/**
- * Moves the language in the list of enabled languages by the given offset.
+ * Moves the language in the list of enabled languages either up (toward the
+ * front of the list) or down (toward the back).
* @param {string} languageCode
- * @param {number} offset Negative offset moves the language toward the front
- * of the list. A Positive one moves the language toward the back.
+ * @param {boolean} upDirection True if we need to move up, false if we
+ * need to move down
*/
- moveLanguage: function(languageCode, offset) {
+ moveLanguage: function(languageCode, upDirection) {
if (!CrSettingsPrefs.isInitialized)
return;
- var languageCodes =
- this.getPref(preferredLanguagesPrefName).value.split(',');
-
- var originalIndex = languageCodes.indexOf(languageCode);
- var newIndex = originalIndex;
- var direction = Math.sign(offset);
- var distance = Math.abs(offset);
-
- // Step over the distance to find the target index.
- while (distance > 0) {
- newIndex += direction;
- if (newIndex < 0 || newIndex >= languageCodes.length)
- return;
-
- // Skip over non-enabled languages, since they don't appear in the list
- // (but we don't want to remove them).
- if (this.enabledLanguageSet_.has(languageCodes[newIndex]))
- distance--;
+ if (upDirection) {
+ this.languageSettingsPrivate_.moveLanguage(languageCode, MoveType.UP);
+ } else {
+ this.languageSettingsPrivate_.moveLanguage(languageCode, MoveType.DOWN);
}
- languageCodes[originalIndex] = languageCodes[newIndex];
- languageCodes[newIndex] = languageCode;
- this.setPrefValue(preferredLanguagesPrefName, languageCodes.join(','));
},
/**
@@ -652,15 +638,7 @@ Polymer({
if (!CrSettingsPrefs.isInitialized)
return;
- var languageCodes =
- this.getPref(preferredLanguagesPrefName).value.split(',');
- var originalIndex = languageCodes.indexOf(languageCode);
- assert(originalIndex != -1);
-
- languageCodes.splice(originalIndex, 1);
- languageCodes.unshift(languageCode);
-
- this.setPrefValue(preferredLanguagesPrefName, languageCodes.join(','));
+ this.languageSettingsPrivate_.moveLanguage(languageCode, MoveType.TOP);
},
/**
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 cfa11d4a722..76bec8e924e 100644
--- a/chromium/chrome/browser/resources/settings/languages_page/languages_page.html
+++ b/chromium/chrome/browser/resources/settings/languages_page/languages_page.html
@@ -9,10 +9,10 @@
<link rel="import" href="chrome://resources/polymer/v1_0/neon-animation/neon-animatable.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-checkbox/paper-checkbox.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button-light.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/paper-toggle-button/paper-toggle-button.html">
<link rel="import" href="chrome://resources/cr_elements/cr_action_menu/cr_action_menu.html">
<link rel="import" href="chrome://resources/cr_elements/cr_expand_button/cr_expand_button.html">
<link rel="import" href="chrome://resources/cr_elements/cr_lazy_render/cr_lazy_render.html">
+<link rel="import" href="chrome://resources/cr_elements/cr_toggle/cr_toggle.html">
<link rel="import" href="chrome://resources/cr_elements/icons.html">
<link rel="import" href="add_languages_dialog.html">
<link rel="import" href="languages.html">
@@ -222,11 +222,11 @@
actionable$="[[item.language.supportsSpellcheck]]">
[[item.language.displayName]]
</div>
- <paper-toggle-button on-change="onSpellCheckChange_"
+ <cr-toggle on-change="onSpellCheckChange_"
disabled="[[!item.language.supportsSpellcheck]]"
checked="[[item.spellCheckEnabled]]"
aria-label$="[[item.language.displayName]]">
- </paper-toggle-button>
+ </cr-toggle>
</div>
</template>
<div class="list-item" on-tap="onEditDictionaryTap_" actionable>
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 4c0782d2f48..eef8e646f89 100644
--- a/chromium/chrome/browser/resources/settings/languages_page/languages_page.js
+++ b/chromium/chrome/browser/resources/settings/languages_page/languages_page.js
@@ -342,7 +342,8 @@ Polymer({
*/
onMoveUpTap_: function() {
/** @type {!CrActionMenuElement} */ (this.$.menu.get()).close();
- this.languageHelper.moveLanguage(this.detailLanguage_.language.code, -1);
+ this.languageHelper.moveLanguage(
+ this.detailLanguage_.language.code, true /* upDirection */);
},
/**
@@ -351,7 +352,8 @@ Polymer({
*/
onMoveDownTap_: function() {
/** @type {!CrActionMenuElement} */ (this.$.menu.get()).close();
- this.languageHelper.moveLanguage(this.detailLanguage_.language.code, 1);
+ this.languageHelper.moveLanguage(
+ this.detailLanguage_.language.code, false /* upDirection */);
},
/**
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 af76c645853..8d0833feb41 100644
--- a/chromium/chrome/browser/resources/settings/languages_page/languages_types.js
+++ b/chromium/chrome/browser/resources/settings/languages_page/languages_types.js
@@ -106,8 +106,8 @@ LanguageHelper.prototype = {
/**
* Moves the language in the list of enabled languages by the given offset.
* @param {string} languageCode
- * @param {number} offset Negative offset moves the language toward the front
- * of the list. A Positive one moves the language toward the back.
+ * @param {boolean} upDirection True if we need to move toward the front,
+ * false if we need to move toward the back.
*/
moveLanguage: assertNotReached,
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 0fc0746165b..02b87b2093a 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
@@ -17,25 +17,29 @@
<dom-module id="settings-startup-urls-page">
<template>
<style include="settings-shared action-link iron-flex">
- #outer {
+ .list-frame {
@apply(--settings-list-frame-padding);
- max-height: 395px; /** Enough height to show six entries. */
}
- #container iron-list > settings-startup-url-entry:not(:first-of-type) {
- border-top: var(--settings-separator-line);
+ .list-frame > div {
+ border-top: var(--cr-separator-line);
+ }
+
+ #outer {
+ @apply(--settings-list-frame-padding);
+ max-height: 355px; /** Enough height to show six entries. */
}
#container settings-startup-url-entry {
cursor: default;
}
</style>
- <div id="outer" class="layout vertical flex vertical-list">
+ <div id="outer" class="layout vertical flex">
<div id="container" class="scroll-container" scrollable>
<iron-list items="[[startupPages_]]" scroll-target="container"
- preserve-focus risk-selection>
+ preserve-focus risk-selection class="cr-separators">
<template>
- <settings-startup-url-entry model="[[item]]"
+ <settings-startup-url-entry model="[[item]]" first$="[[!index]]"
tabindex$="[[tabIndex]]" iron-list-tab-index="[[tabIndex]]"
last-focused="{{lastFocused_}}"
editable="[[shouldAllowUrlsEdit_(
@@ -44,6 +48,8 @@
</template>
</iron-list>
</div>
+ </div>
+ <div class="list-frame">
<template is="dom-if" if="[[shouldAllowUrlsEdit_(
prefs.session.startup_urls.enforcement)]]" restamp>
<div class="list-item" id="addPage">
diff --git a/chromium/chrome/browser/resources/settings/passwords_and_forms_page/autofill_section.html b/chromium/chrome/browser/resources/settings/passwords_and_forms_page/autofill_section.html
index f6e65e7231b..4da90c016dc 100644
--- a/chromium/chrome/browser/resources/settings/passwords_and_forms_page/autofill_section.html
+++ b/chromium/chrome/browser/resources/settings/passwords_and_forms_page/autofill_section.html
@@ -1,6 +1,7 @@
<link rel="import" href="chrome://resources/html/polymer.html">
<link rel="import" href="chrome://resources/cr_elements/cr_action_menu/cr_action_menu.html">
+<link rel="import" href="chrome://resources/cr_elements/policy/cr_policy_indicator.html">
<link rel="import" href="chrome://resources/html/action_link.html">
<link rel="import" href="chrome://resources/html/action_link_css.html">
<link rel="import" href="chrome://resources/html/assert.html">
@@ -57,6 +58,11 @@
text-overflow: ellipsis;
white-space: nowrap;
}
+
+ cr-policy-indicator {
+ padding-right: 20px;
+ width: 20px;
+ }
</style>
<settings-toggle-button id="autofillToggle"
class="first primary-toggle"
@@ -133,51 +139,62 @@
<h2 class="start">$i18n{creditCards}</h2>
<paper-button id="addCreditCard"
class="secondary-button header-aligned-button"
- on-tap="onAddCreditCardTap_">
+ on-tap="onAddCreditCardTap_"
+ hidden$="[[isDisabled_(prefs.autofill.credit_card_enabled)]]">
$i18n{add}
</paper-button>
</div>
<div class="list-frame">
- <div id="creditCardsHeading" class="list-item column-header"
- hidden$="[[!hasSome_(creditCards)]]">
- <div class="type-column">$i18n{creditCardType}</div>
- <div class="expiration-column">$i18n{creditCardExpiration}</div>
- </div>
- <div id="creditCardList" class="vertical-list list-with-header">
- <template is="dom-repeat" items="[[creditCards]]">
- <div class="list-item">
- <div class="type-column">
- <span id="creditCardLabel">[[item.metadata.summaryLabel]]</span>
- <span class="payments-label" hidden$="[[item.metadata.isLocal]]">
- <span hidden$="[[item.metadata.isCached]]">
- $i18n{googlePayments}
- </span>
- <span hidden$="[[!item.metadata.isCached]]">
- $i18n{googlePaymentsCached}
+ <template is="dom-if"
+ if="[[!isDisabled_(prefs.autofill.credit_card_enabled)]]">
+ <div id="creditCardsHeading" class="list-item column-header"
+ hidden$="[[!hasSome_(creditCards)]]">
+ <div class="type-column">$i18n{creditCardType}</div>
+ <div class="expiration-column">$i18n{creditCardExpiration}</div>
+ </div>
+ <div id="creditCardList" class="vertical-list list-with-header">
+ <template is="dom-repeat" items="[[creditCards]]">
+ <div class="list-item">
+ <div class="type-column">
+ <span id="creditCardLabel">[[item.metadata.summaryLabel]]</span>
+ <span class="payments-label"
+ hidden$="[[item.metadata.isLocal]]">
+ <span hidden$="[[item.metadata.isCached]]">
+ $i18n{googlePayments}
+ </span>
+ <span hidden$="[[!item.metadata.isCached]]">
+ $i18n{googlePaymentsCached}
+ </span>
</span>
- </span>
- </div>
- <div class="expiration-column">
- <div id="creditCardExpiration"
- class="expiration-date">[[expiration_(item)]]</div>
- <template is="dom-if" if="[[showDots_(item.metadata)]]">
- <button is="paper-icon-button-light" id="creditCardMenu"
- class="icon-more-vert" title="$i18n{moreActions}"
- on-tap="onCreditCardMenuTap_">
- </button>
- </template>
- <template is="dom-if" if="[[!showDots_(item.metadata)]]">
- <button is="paper-icon-button-light" id="remoteCreditCardLink"
- class="icon-external"
- on-tap="onRemoteEditCreditCardTap_" actionable></button>
- </template>
+ </div>
+ <div class="expiration-column">
+ <div id="creditCardExpiration"
+ class="expiration-date">[[expiration_(item)]]</div>
+ <template is="dom-if" if="[[showDots_(item.metadata)]]">
+ <button is="paper-icon-button-light" id="creditCardMenu"
+ class="icon-more-vert" title="$i18n{moreActions}"
+ on-tap="onCreditCardMenuTap_">
+ </button>
+ </template>
+ <template is="dom-if" if="[[!showDots_(item.metadata)]]">
+ <button is="paper-icon-button-light" id="remoteCreditCardLink"
+ class="icon-external"
+ on-tap="onRemoteEditCreditCardTap_" actionable></button>
+ </template>
+ </div>
</div>
- </div>
- </template>
- </div>
- <div id="noCreditCardsLabel" class="list-item"
- hidden$="[[hasSome_(creditCards)]]">
- $i18n{noCreditCardsFound}
+ </template>
+ </div>
+ <div id="noCreditCardsLabel" class="list-item"
+ hidden$="[[hasSome_(creditCards)]]">
+ $i18n{noCreditCardsFound}
+ </div>
+ </template>
+ <div id="CreditCardsDisabledLabel" class="list-item"
+ hidden$="[[!isDisabled_(prefs.autofill.credit_card_enabled)]]">
+ <cr-policy-indicator indicator-type="userPolicy"
+ icon-aria-label="$i18n{noCreditCardsPolicy}"></cr-policy-indicator>
+ $i18n{noCreditCardsPolicy}
</div>
</div>
<dialog is="cr-action-menu" id="creditCardSharedMenu">
diff --git a/chromium/chrome/browser/resources/settings/passwords_and_forms_page/autofill_section.js b/chromium/chrome/browser/resources/settings/passwords_and_forms_page/autofill_section.js
index ffad7d4c01e..95a22ca7e25 100644
--- a/chromium/chrome/browser/resources/settings/passwords_and_forms_page/autofill_section.js
+++ b/chromium/chrome/browser/resources/settings/passwords_and_forms_page/autofill_section.js
@@ -435,6 +435,17 @@ Polymer({
},
/**
+ * Returns true if the pref has been explicitly disabled.
+ * @param {Object} pref
+ * @return {boolean}
+ * @private
+ */
+ isDisabled_: function(pref) {
+ return !!pref && (pref.value === false);
+ },
+
+
+ /**
* Listens for the save-address event, and calls the private API.
* @param {!Event} event
* @private
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
index 28f9cec9ad3..c637647b887 100644
--- 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
@@ -44,25 +44,25 @@
<div slot="title">$i18n{passwordDetailsTitle}</div>
<div slot="body">
<paper-input id="websiteInput" label="$i18n{editPasswordWebsiteLabel}"
- value="[[item.loginPair.urls.link]]" readonly always-float-label
- on-tap="onReadonlyInputTap_">
+ value="[[item.entry.loginPair.urls.link]]" readonly
+ always-float-label on-tap="onReadonlyInputTap_">
</paper-input>
<paper-input id="usernameInput" label="$i18n{editPasswordUsernameLabel}"
- value="[[item.loginPair.username]]" readonly always-float-label
- on-tap="onReadonlyInputTap_">
+ value="[[item.entry.loginPair.username]]" readonly
+ always-float-label on-tap="onReadonlyInputTap_">
</paper-input>
<div id="passwordGroup">
<paper-input id="passwordInput" always-float-label
label="$i18n{editPasswordPasswordLabel}"
- type="[[getPasswordInputType_(item, password)]]"
- value="[[getPassword_(item, password)]]" readonly
+ type="[[getPasswordInputType_(item.password)]]"
+ value="[[getPassword_(item.password)]]" readonly
on-tap="onReadonlyInputTap_">
</paper-input>
<button is="paper-icon-button-light" id="showPasswordButton"
- class$="[[getIconClass_(item, password)]]"
- hidden$="[[item.federationText]]"
+ class$="[[getIconClass_(item.password)]]"
+ hidden$="[[item.entry.federationText]]"
on-tap="onShowPasswordButtonTap_"
- title="[[showPasswordTitle_(password,
+ title="[[showPasswordTitle_(item.password,
'$i18nPolymer{hidePassword}','$i18nPolymer{showPassword}')]]">
</button>
</div>
diff --git a/chromium/chrome/browser/resources/settings/passwords_and_forms_page/password_list_item.html b/chromium/chrome/browser/resources/settings/passwords_and_forms_page/password_list_item.html
index 1d11c507149..85dda982896 100644
--- a/chromium/chrome/browser/resources/settings/passwords_and_forms_page/password_list_item.html
+++ b/chromium/chrome/browser/resources/settings/passwords_and_forms_page/password_list_item.html
@@ -31,37 +31,37 @@
</style>
<div class="list-item" focus-row-container>
<div class="website-column no-min-width"
- title="[[item.loginPair.urls.link]]">
+ title="[[item.entry.loginPair.urls.link]]">
<a id="originUrl" target="_blank" class="no-min-width"
- href="[[item.loginPair.urls.link]]"
+ href="[[item.entry.loginPair.urls.link]]"
focus-row-control focus-type="originUrl">
<span class="text-elide">
<!-- This bdo tag is necessary to fix the display of domains
starting with numbers. -->
- <bdo dir="ltr">[[item.loginPair.urls.shown]]</bdo>
+ <bdo dir="ltr">[[item.entry.loginPair.urls.shown]]</bdo>
</span>
</a>
</div>
<div class="username-column text-elide"
- id="username">[[item.loginPair.username]]</div>
+ id="username">[[item.entry.loginPair.username]]</div>
<div class="password-column">
- <template is="dom-if" if="[[!item.federationText]]">
+ <template is="dom-if" if="[[!item.entry.federationText]]">
<input id="password" aria-label=$i18n{editPasswordPasswordLabel}
- type="[[getPasswordInputType_(item, password)]]"
+ type="[[getPasswordInputType_(item.password)]]"
on-tap="onReadonlyInputTap_" class="password-field" readonly
- disabled$="[[!password]]"
- value="[[getPassword_(item, password)]]">
+ disabled$="[[!item.password]]"
+ value="[[getPassword_(item.password)]]">
<button is="paper-icon-button-light" id="showPasswordButton"
- class$="[[getIconClass_(item, password)]]"
+ class$="[[getIconClass_(item.password)]]"
on-tap="onShowPasswordButtonTap_"
- title="[[showPasswordTitle_(password,
+ title="[[showPasswordTitle_(item.password,
'$i18nPolymer{hidePassword}','$i18nPolymer{showPassword}')]]"
focus-row-control focus-type="showPassword">
</button>
</template>
- <template is="dom-if" if="[[item.federationText]]">
+ <template is="dom-if" if="[[item.entry.federationText]]">
<span class="password-field text-elide" id="federated">
- [[item.federationText]]
+ [[item.entry.federationText]]
</span>
</template>
</div>
diff --git a/chromium/chrome/browser/resources/settings/passwords_and_forms_page/password_list_item.js b/chromium/chrome/browser/resources/settings/passwords_and_forms_page/password_list_item.js
index 1ade2576b1b..8b2b619fec5 100644
--- a/chromium/chrome/browser/resources/settings/passwords_and_forms_page/password_list_item.js
+++ b/chromium/chrome/browser/resources/settings/passwords_and_forms_page/password_list_item.js
@@ -27,6 +27,6 @@ Polymer({
*/
onPasswordMenuTap_: function() {
this.fire(
- 'password-menu-tap', {target: this.$.passwordMenu, item: this.item});
+ 'password-menu-tap', {target: this.$.passwordMenu, listItem: this});
},
});
diff --git a/chromium/chrome/browser/resources/settings/passwords_and_forms_page/passwords_export_dialog.html b/chromium/chrome/browser/resources/settings/passwords_and_forms_page/passwords_export_dialog.html
new file mode 100644
index 00000000000..6da824f6159
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/passwords_and_forms_page/passwords_export_dialog.html
@@ -0,0 +1,37 @@
+<link rel="import" href="chrome://resources/html/polymer.html">
+
+<link rel="import" href="chrome://resources/cr_elements/cr_dialog/cr_dialog.html">
+<link rel="import" href="chrome://resources/cr_elements/cr_icons_css.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/iron-flex-layout-classes.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html">
+<link rel="import" href="../settings_shared_css.html">
+
+<dom-module id="passwords-export-dialog">
+ <template>
+ <style include="settings-shared iron-flex">
+ #info-icon {
+ padding-right: 15px;
+ }
+ </style>
+ <dialog is="cr-dialog" id="dialog" close-text="$i18n{close}">
+ <div slot="title">$i18n{exportPasswordsTitle}</div>
+ <div slot="body">
+ <div class="layout horizontal center">
+ <iron-icon icon="settings:info-outline" id="info-icon"></iron-icon>
+ <div>$i18n{exportPasswordsDescription}</div>
+ </div>
+ </div>
+ <div slot="button-container">
+ <paper-button class="secondary-button header-aligned-button"
+ on-tap="onCancelButtonTap_">
+ $i18n{cancel}
+ </paper-button>
+ <paper-button class="action-button header-aligned-button"
+ on-tap="onExportTap_" id="exportPasswordsButton">
+ $i18n{exportPasswords}
+ </paper-button>
+ </div>
+ </dialog>
+ </template>
+ <script src="passwords_export_dialog.js"></script>
+</dom-module> \ No newline at end of file
diff --git a/chromium/chrome/browser/resources/settings/passwords_and_forms_page/passwords_export_dialog.js b/chromium/chrome/browser/resources/settings/passwords_and_forms_page/passwords_export_dialog.js
new file mode 100644
index 00000000000..da06563ff1c
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/passwords_and_forms_page/passwords_export_dialog.js
@@ -0,0 +1,52 @@
+// Copyright 2017 The Chromium 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 'passwords-export-dialog' is the dialog that allows exporting
+ * passwords.
+ */
+
+(function() {
+'use strict';
+
+Polymer({
+ is: 'passwords-export-dialog',
+
+ /**
+ * The interface for callbacks to the browser.
+ * Defined in passwords_section.js
+ * @type {PasswordManager}
+ * @private
+ */
+ passwordManager_: null,
+
+ /** @override */
+ attached: function() {
+ this.$.dialog.showModal();
+
+ this.passwordManager_ = PasswordManagerImpl.getInstance();
+ },
+
+ /** Closes the dialog. */
+ close: function() {
+ this.$.dialog.close();
+ },
+
+ /**
+ * Fires an event that should trigger the password export process.
+ * @private
+ */
+ onExportTap_: function() {
+ this.passwordManager_.exportPasswords();
+ },
+
+ /**
+ * Handler for tapping the 'cancel' button. Should just dismiss the dialog.
+ * @private
+ */
+ onCancelButtonTap_: function() {
+ this.close();
+ },
+});
+})(); \ No newline at end of file
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 fd2f647da10..5c82c295d86 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
@@ -15,6 +15,7 @@
<link rel="import" href="../prefs/prefs.html">
<link rel="import" href="../settings_shared_css.html">
<link rel="import" href="password_edit_dialog.html">
+<link rel="import" href="passwords_export_dialog.html">
<link rel="import" href="passwords_shared_css.html">
<link rel="import" href="password_list_item.html">
@@ -84,16 +85,13 @@
</div>
<div class="settings-box first">
<h2 class="start">$i18n{savedPasswordsHeading}</h2>
- <template is="dom-if" if="[[showImportExportPasswords_]]">
- <paper-button class="secondary-button header-aligned-button"
- on-tap="onImportTap_" id="import">
- $i18n{import}
- </paper-button>
- <paper-button class="secondary-button header-aligned-button"
- on-tap="onExportTap_" id="export"
- disabled$="[[!hasSome_(savedPasswords)]]">
- $i18n{export}
- </paper-button>
+ <template is="dom-if"
+ if="[[showImportOrExportPasswords_(
+ showExportPasswords_, showImportPasswords_)]]">
+ <button is="paper-icon-button-light" id="exportImportMenuButton"
+ class="icon-more-vert" on-tap="onImportExportMenuTap_"
+ title="$i18n{moreActions}" focus-type="exportImportMenuButton">
+ </button>
</template>
</div>
<div class="list-frame">
@@ -109,11 +107,11 @@
</div>
<iron-list id="passwordList" preserve-focus
items="[[getFilteredPasswords_(savedPasswords, filter)]]"
- class="vertical-list list-with-header"
+ class="cr-separators list-with-header"
scroll-target="[[subpageScrollTarget]]" risk-selection>
<template>
<password-list-item item="[[item]]" tabindex$="[[tabIndex]]"
- iron-list-tab-index="[[tabIndex]]"
+ first$="[[!index]]" iron-list-tab-index="[[tabIndex]]"
last-focused="{{lastFocused_}}">
<password-list-item>
</template>
@@ -129,9 +127,23 @@
<button id="menuRemovePassword" class="dropdown-item"
on-tap="onMenuRemovePasswordTap_">$i18n{removePassword}</button>
</dialog>
+ <dialog is="cr-action-menu" id="exportImportMenu">
+ <template is="dom-if" if="[[showImportPasswords_]]">
+ <button id="menuImportPassword" class="dropdown-item"
+ on-tap="onImportTap_">$i18n{import}</button>
+ </template>
+ <template is="dom-if" if="[[showExportPasswords_]]">
+ <button id="menuExportPassword" class="dropdown-item"
+ on-tap="onExportTap_">$i18n{export}</button>
+ </template>
+ </dialog>
+ <template is="dom-if" if="[[showPasswordsExportDialog_]]" restamp>
+ <passwords-export-dialog on-close="onPasswordsExportDialogClosed_">
+ </passwords-export-dialog>
+ </template>
<template is="dom-if" if="[[showPasswordEditDialog_]]" restamp>
<password-edit-dialog on-close="onPasswordEditDialogClosed_"
- item="[[activePassword]]">
+ item="[[activePassword.item]]">
</password-edit-dialog>
</template>
<cr-toast id="undoToast" duration="[[toastDuration_]]">
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 9e5b23059c2..16c02d14e1f 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
@@ -100,6 +100,9 @@ PasswordManager.ExceptionEntry;
/** @typedef {chrome.passwordsPrivate.PlaintextPasswordEventParameters} */
PasswordManager.PlaintextPasswordEvent;
+/** @typedef {{ entry: !PasswordManager.PasswordUiEntry, password: string }} */
+PasswordManager.UiEntryWithPassword;
+
/**
* Implementation that accesses the private API.
* @implements {PasswordManager}
@@ -234,7 +237,7 @@ Polymer({
/**
* The model for any password related action menus or dialogs.
- * @private {?chrome.passwordsPrivate.PasswordUiEntry}
+ * @private {?PasswordListItemElement}
*/
activePassword: Object,
@@ -246,11 +249,20 @@ Polymer({
},
/** @private */
- showImportExportPasswords_: {
+ showExportPasswords_: {
+ type: Boolean,
+ value: function() {
+ return loadTimeData.valueExists('showExportPasswords') &&
+ loadTimeData.getBoolean('showExportPasswords');
+ }
+ },
+
+ /** @private */
+ showImportPasswords_: {
type: Boolean,
value: function() {
- return loadTimeData.valueExists('showImportExportPasswords') &&
- loadTimeData.getBoolean('showImportExportPasswords');
+ return loadTimeData.valueExists('showImportPasswords') &&
+ loadTimeData.getBoolean('showImportPasswords');
}
},
@@ -270,6 +282,7 @@ Polymer({
listeners: {
'show-password': 'showPassword_',
'password-menu-tap': 'onPasswordMenuTap_',
+ 'export-passwords': 'onExportPasswords_',
},
keyBindings: {
@@ -310,7 +323,12 @@ Polymer({
attached: function() {
// Create listener functions.
var setSavedPasswordsListener = list => {
- this.savedPasswords = list;
+ this.savedPasswords = list.map(entry => {
+ return {
+ entry: entry,
+ password: '',
+ };
+ });
};
var setPasswordExceptionsListener = list => {
@@ -346,6 +364,9 @@ Polymer({
this.passwordManager_.removeExceptionListChangedListener(
/** @type {function(!Array<PasswordManager.ExceptionEntry>):void} */ (
this.setPasswordExceptionsListener_));
+
+ if (this.$.undoToast.open)
+ this.$.undoToast.hide();
},
/**
@@ -364,12 +385,16 @@ Polymer({
this.showPasswordEditDialog_ = false;
cr.ui.focusWithoutInk(assert(this.activeDialogAnchor_));
this.activeDialogAnchor_ = null;
+
+ // Trigger a re-evaluation of the activePassword as the visibility state of
+ // the password might have changed.
+ this.activePassword.notifyPath('item.password');
},
/**
- * @param {!Array<!chrome.passwordsPrivate.PasswordUiEntry>} savedPasswords
+ * @param {!Array<!PasswordManager.UiEntryWithPassword>} savedPasswords
* @param {string} filter
- * @return {!Array<!chrome.passwordsPrivate.PasswordUiEntry>}
+ * @return {!Array<!PasswordManager.UiEntryWithPassword>}
* @private
*/
getFilteredPasswords_: function(savedPasswords, filter) {
@@ -377,7 +402,7 @@ Polymer({
return savedPasswords;
return savedPasswords.filter(p => {
- return [p.loginPair.urls.shown, p.loginPair.username].some(
+ return [p.entry.loginPair.urls.shown, p.entry.loginPair.username].some(
term => term.toLowerCase().includes(filter.toLowerCase()));
});
},
@@ -398,7 +423,8 @@ Polymer({
* @private
*/
onMenuRemovePasswordTap_: function() {
- this.passwordManager_.removeSavedPassword(this.activePassword.index);
+ this.passwordManager_.removeSavedPassword(
+ this.activePassword.item.entry.index);
this.fire('iron-announce', {text: this.$.undoLabel.textContent});
this.$.undoToast.show();
/** @type {CrActionMenuElement} */ (this.$.menu).close();
@@ -435,8 +461,20 @@ Polymer({
var target = /** @type {!HTMLElement} */ (event.detail.target);
this.activePassword =
- /** @type {!chrome.passwordsPrivate.PasswordUiEntry} */ (
- event.detail.item);
+ /** @type {!PasswordListItemElement} */ (event.detail.listItem);
+ menu.showAt(target);
+ this.activeDialogAnchor_ = target;
+ },
+
+ /**
+ * Opens the export/import action menu.
+ * @private
+ */
+ onImportExportMenuTap_: function() {
+ var menu = /** @type {!CrActionMenuElement} */ (this.$.exportImportMenu);
+ var target =
+ /** @type {!HTMLElement} */ (this.$$('#exportImportMenuButton'));
+
menu.showAt(target);
this.activeDialogAnchor_ = target;
},
@@ -454,11 +492,17 @@ Polymer({
},
/**
- * Fires an event that should trigger the password export process.
+ * Opens the export passwords dialog.
* @private
*/
onExportTap_: function() {
- this.passwordManager_.exportPasswords();
+ this.showPasswordsExportDialog_ = true;
+ this.$.exportImportMenu.close();
+ },
+
+ /** @private */
+ onPasswordsExportDialogClosed_: function() {
+ this.showPasswordsExportDialog_ = false;
},
/**
@@ -478,8 +522,8 @@ Polymer({
*/
showPassword_: function(event) {
this.passwordManager_.getPlaintextPassword(
- /** @type {!number} */ (event.detail.item.index), item => {
- event.detail.password = item.plaintextPassword;
+ /** @type {!number} */ (event.detail.item.entry.index), item => {
+ event.detail.set('item.password', item.plaintextPassword);
});
},
@@ -490,6 +534,17 @@ Polymer({
*/
getOnOffLabel_: function(toggleValue) {
return toggleValue ? this.i18n('toggleOn') : this.i18n('toggleOff');
+ },
+
+ /**
+ * @private
+ * @param {boolean} showExportPasswords
+ * @param {boolean} showImportPasswords
+ * @return {boolean}
+ */
+ showImportOrExportPasswords_: function(
+ showExportPasswords, showImportPasswords) {
+ return showExportPasswords || showImportPasswords;
}
});
})();
diff --git a/chromium/chrome/browser/resources/settings/passwords_and_forms_page/show_password_behavior.js b/chromium/chrome/browser/resources/settings/passwords_and_forms_page/show_password_behavior.js
index 8c4a54bf5b0..52c7fcf8338 100644
--- a/chromium/chrome/browser/resources/settings/passwords_and_forms_page/show_password_behavior.js
+++ b/chromium/chrome/browser/resources/settings/passwords_and_forms_page/show_password_behavior.js
@@ -13,19 +13,9 @@ var ShowPasswordBehavior = {
properties: {
/**
* The password that is being displayed.
- * @type {!chrome.passwordsPrivate.PasswordUiEntry}
+ * @type {!ShowPasswordBehavior.UiEntryWithPassword}
*/
item: Object,
-
- /**
- * Holds the plaintext password when requested.
- * Initializing it to the empty string is necessary to indicate that the
- * password hasn't been fetched yet.
- */
- password: {
- type: String,
- value: '',
- },
},
/**
@@ -34,7 +24,8 @@ var ShowPasswordBehavior = {
* @private
*/
getPasswordInputType_: function() {
- return this.password || this.item.federationText ? 'text' : 'password';
+ return this.item.password || this.item.entry.federationText ? 'text' :
+ 'password';
},
/**
@@ -54,7 +45,7 @@ var ShowPasswordBehavior = {
* @private
*/
getIconClass_: function() {
- return this.password ? 'icon-visibility-off' : 'icon-visibility';
+ return this.item.password ? 'icon-visibility-off' : 'icon-visibility';
},
/**
@@ -66,9 +57,8 @@ var ShowPasswordBehavior = {
getPassword_: function() {
if (!this.item)
return '';
-
- return this.item.federationText || this.password ||
- ' '.repeat(this.item.numCharactersInPassword);
+ return this.item.entry.federationText || this.item.password ||
+ ' '.repeat(this.item.entry.numCharactersInPassword);
},
/**
@@ -77,9 +67,16 @@ var ShowPasswordBehavior = {
* @private
*/
onShowPasswordButtonTap_: function() {
- if (this.password)
- this.password = '';
+ if (this.item.password)
+ this.set('item.password', '');
else
this.fire('show-password', this); // Request the password.
},
};
+
+/** @typedef {{
+ * entry: !chrome.passwordsPrivate.PasswordUiEntry,
+ * password: string
+ * }}
+ */
+ShowPasswordBehavior.UiEntryWithPassword;
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 82cbc58d44a..87ec0b1917d 100644
--- a/chromium/chrome/browser/resources/settings/people_page/change_picture.html
+++ b/chromium/chrome/browser/resources/settings/people_page/change_picture.html
@@ -84,7 +84,10 @@
discard-image-label="$i18n{discardPhoto}"
preview-alt-text="$i18n{previewAltText}"
take-photo-label="$i18n{takePhoto}"
- switch-mode-label="$i18n{switchMode}">
+ capture-video-label="$i18n{captureVideo}"
+ switch-mode-to-camera-label="$i18n{switchModeToCamera}"
+ switch-mode-to-video-label="$i18n{switchModeToVideo}"
+ camera-video-mode-enabled="[[cameraVideoModeEnabled_]]">
</cr-picture-pane>
<div id="authorCredit"
hidden="[[!isAuthorCreditShown_(selectedItem_)]]">
@@ -103,8 +106,8 @@
choose-file-label="$i18n{chooseFile}"
old-image-label="$i18n{oldPhoto}"
profile-image-label="$i18n{profilePhoto}"
- take-photo-label="$i18n{takePhoto}"
- switch-mode-label="$i18n{switchMode}">
+ take-photo-label="$i18n{takePhoto}">
+ capture-video-label="$i18n{captureVideo}">
</cr-picture-list>
</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 702225517b3..0703e896395 100644
--- a/chromium/chrome/browser/resources/settings/people_page/change_picture.js
+++ b/chromium/chrome/browser/resources/settings/people_page/change_picture.js
@@ -53,6 +53,15 @@ Polymer({
* @private
*/
firstDefaultImageIndex_: Number,
+
+ /**
+ * True when camera video mode is enabled.
+ * @private {boolean}
+ */
+ cameraVideoModeEnabled_: {
+ type: Boolean,
+ value: false,
+ },
},
listeners: {
@@ -173,7 +182,7 @@ Polymer({
case CrPicture.SelectionTypes.OLD:
var imageIndex = image.dataset.imageIndex;
if (imageIndex !== undefined && imageIndex >= 0 && image.src)
- this.browserProxy_.selectDefaultImage(image.src);
+ this.browserProxy_.selectDefaultImage(image.dataset.url);
else
this.browserProxy_.selectOldImage();
break;
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 656400bd7c9..fbc49f4ef9d 100644
--- a/chromium/chrome/browser/resources/settings/people_page/manage_profile.html
+++ b/chromium/chrome/browser/resources/settings/people_page/manage_profile.html
@@ -1,10 +1,10 @@
<link rel="import" href="chrome://resources/html/polymer.html">
<link rel="import" href="chrome://resources/cr_elements/cr_profile_avatar_selector/cr_profile_avatar_selector.html">
+<link rel="import" href="chrome://resources/cr_elements/cr_toggle/cr_toggle.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-styles/shadow.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/paper-toggle-button/paper-toggle-button.html">
<link rel="import" href="../i18n_setup.html">
<link rel="import" href="manage_profile_browser_proxy.html">
<link rel="import" href="../route.html">
@@ -27,11 +27,11 @@
<template is="dom-if" if="[[isProfileShortcutSettingVisible_]]">
<div class="settings-box first">
<div id="showShortcutLabel" class="start">$i18n{showShortcutLabel}</div>
- <paper-toggle-button id="hasShortcutToggle"
+ <cr-toggle id="hasShortcutToggle"
checked="{{hasProfileShortcut_}}"
on-change="onHasProfileShortcutChange_"
aria-labelledby="showShortcutLabel">
- </paper-toggle-button>
+ </cr-toggle>
</div>
</template>
<cr-profile-avatar-selector id="selector" avatars="[[availableIcons]]"
diff --git a/chromium/chrome/browser/resources/settings/people_page/password_prompt_dialog.js b/chromium/chrome/browser/resources/settings/people_page/password_prompt_dialog.js
index 2d3035ada0d..5115c11f17b 100644
--- a/chromium/chrome/browser/resources/settings/people_page/password_prompt_dialog.js
+++ b/chromium/chrome/browser/resources/settings/people_page/password_prompt_dialog.js
@@ -136,6 +136,12 @@ Polymer({
// The password might have been cleared during the duration of the
// getActiveModes call.
this.passwordInvalid_ = !valid && !!this.password_;
+ // Return focus to the password input if it lost focus while being checked
+ // (user pressed confirm button).
+ if (this.passwordInvalid_ &&
+ this.shadowRoot.activeElement != this.$.passwordInput) {
+ this.$.passwordInput.focus();
+ }
if (valid) {
// Create the |this.setModes| closure and automatically clear it after
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 cec6369f63b..4ab0dfcd81f 100644
--- a/chromium/chrome/browser/resources/settings/people_page/people_page.html
+++ b/chromium/chrome/browser/resources/settings/people_page/people_page.html
@@ -274,7 +274,11 @@
<settings-subpage
associated-control="[[$$('#manage-other-people-subpage-trigger')]]"
page-title="$i18n{manageOtherPeople}">
- <settings-users-page prefs="{{prefs}}"></settings-users-page>
+ <settings-users-page
+ prefs="{{prefs}}"
+ profile-manages-supervised-users=
+ "[[profileManagesSupervisedUsers_]]">
+ </settings-users-page>
</settings-subpage>
</template>
<template is="dom-if" route-path="/changePicture">
diff --git a/chromium/chrome/browser/resources/settings/people_page/setup_pin_dialog.html b/chromium/chrome/browser/resources/settings/people_page/setup_pin_dialog.html
index bdee32b9efe..d7a74e2a102 100644
--- a/chromium/chrome/browser/resources/settings/people_page/setup_pin_dialog.html
+++ b/chromium/chrome/browser/resources/settings/people_page/setup_pin_dialog.html
@@ -1,10 +1,10 @@
+<link rel="import" href="chrome://resources/cr_elements/icons.html">
<link rel="import" href="chrome://resources/html/polymer.html">
<link rel="import" href="chrome://resources/html/assert.html">
<link rel="import" href="chrome://resources/html/i18n_behavior.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html">
<link rel="import" href="../i18n_setup.html">
-<link rel="import" href="../icons.html">
<link rel="import" href="lock_screen_constants.html">
<link rel="import" href="pin_keyboard.html">
<link rel="import" href="../settings_shared_css.html">
@@ -55,7 +55,7 @@
<!-- Warning/error; only shown if title is hidden. -->
<div id="problemDiv" class$="[[problemClass_]]"
hidden="[[!problemMessage_]]" problem>
- <iron-icon icon="settings:error-outline"></iron-icon>
+ <iron-icon icon="cr:error-outline"></iron-icon>
<span id="problemMessage">[[problemMessage_]]</span>
</div>
</pin-keyboard>
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 9d6fba87a42..07ae46a0bac 100644
--- a/chromium/chrome/browser/resources/settings/people_page/sync_page.html
+++ b/chromium/chrome/browser/resources/settings/people_page/sync_page.html
@@ -3,9 +3,9 @@
<link rel="import" href="chrome://resources/html/i18n_behavior.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/cr_elements/cr_toggle/cr_toggle.html">
<link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/iron-flex-layout-classes.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-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/polymer/v1_0/paper-input/paper-input.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-radio-button/paper-radio-button.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-radio-group/paper-radio-group.html">
@@ -103,23 +103,23 @@
<div id="syncEverythingCheckboxLabel" class="start">
$i18n{syncEverythingCheckboxLabel}
</div>
- <paper-toggle-button id="syncAllDataTypesControl"
+ <cr-toggle id="syncAllDataTypesControl"
checked="{{syncPrefs.syncAllDataTypes}}"
on-change="onSyncAllDataTypesChanged_"
aria-labelledby="syncEverythingCheckboxLabel">
- </paper-toggle-button>
+ </cr-toggle>
</div>
<div class="list-frame" id="sync-data-types">
<div class="layout horizontal list-item"
hidden="[[!syncPrefs.appsRegistered]]">
<div id="appCheckboxLabel" class="flex">$i18n{appCheckboxLabel}</div>
- <paper-toggle-button checked="{{syncPrefs.appsSynced}}"
+ <cr-toggle checked="{{syncPrefs.appsSynced}}"
on-change="onSingleSyncDataTypeChanged_"
disabled="[[shouldSyncCheckboxBeDisabled_(
syncPrefs.syncAllDataTypes, syncPrefs.appsEnforced)]]"
aria-labelledby="appCheckboxLabel">
- </paper-toggle-button>
+ </cr-toggle>
</div>
<div class="layout horizontal list-item"
@@ -129,12 +129,12 @@
</div>
<!-- Autofill has a special on-change handler to deal with
Payments integriation. -->
- <paper-toggle-button checked="{{syncPrefs.autofillSynced}}"
+ <cr-toggle checked="{{syncPrefs.autofillSynced}}"
on-change="onAutofillDataTypeChanged_"
disabled="[[shouldSyncCheckboxBeDisabled_(
syncPrefs.syncAllDataTypes, syncPrefs.autofillEnforced)]]"
aria-labelledby="autofillCheckboxLabel">
- </paper-toggle-button>
+ </cr-toggle>
</div>
<div class="layout horizontal list-item"
@@ -142,12 +142,12 @@
<div id="bookmarksCheckboxLabel" class="flex">
$i18n{bookmarksCheckboxLabel}
</div>
- <paper-toggle-button checked="{{syncPrefs.bookmarksSynced}}"
+ <cr-toggle checked="{{syncPrefs.bookmarksSynced}}"
on-change="onSingleSyncDataTypeChanged_"
disabled="[[shouldSyncCheckboxBeDisabled_(
syncPrefs.syncAllDataTypes, syncPrefs.bookmarksEnforced)]]"
aria-labelledby="bookmarksCheckboxLabel">
- </paper-toggle-button>
+ </cr-toggle>
</div>
<div class="layout horizontal list-item"
@@ -155,12 +155,12 @@
<div id="extensionsCheckboxLabel" class="flex">
$i18n{extensionsCheckboxLabel}
</div>
- <paper-toggle-button checked="{{syncPrefs.extensionsSynced}}"
+ <cr-toggle checked="{{syncPrefs.extensionsSynced}}"
on-change="onSingleSyncDataTypeChanged_"
disabled="[[shouldSyncCheckboxBeDisabled_(
syncPrefs.syncAllDataTypes, syncPrefs.extensionsEnforced)]]"
aria-labelledby="extensionsCheckboxLabel">
- </paper-toggle-button>
+ </cr-toggle>
</div>
<div class="layout horizontal list-item"
@@ -168,12 +168,12 @@
<div id="historyCheckboxLabel" class="flex">
$i18n{historyCheckboxLabel}
</div>
- <paper-toggle-button checked="{{syncPrefs.typedUrlsSynced}}"
+ <cr-toggle checked="{{syncPrefs.typedUrlsSynced}}"
on-change="onSingleSyncDataTypeChanged_"
disabled="[[shouldSyncCheckboxBeDisabled_(
syncPrefs.syncAllDataTypes, syncPrefs.typedUrlsEnforced)]]"
aria-labelledby="historyCheckboxLabel">
- </paper-toggle-button>
+ </cr-toggle>
</div>
<div class="layout horizontal list-item"
@@ -181,12 +181,12 @@
<div id="passwordsCheckboxLabel" class="flex">
$i18n{passwordsCheckboxLabel}
</div>
- <paper-toggle-button checked="{{syncPrefs.passwordsSynced}}"
+ <cr-toggle checked="{{syncPrefs.passwordsSynced}}"
on-change="onSingleSyncDataTypeChanged_"
disabled="[[shouldSyncCheckboxBeDisabled_(
syncPrefs.syncAllDataTypes, syncPrefs.passwordsEnforced)]]"
aria-labelledby="passwordsCheckboxLabel">
- </paper-toggle-button>
+ </cr-toggle>
</div>
<div class="layout horizontal list-item"
@@ -194,12 +194,12 @@
<div id="settingsCheckboxLabel" class="flex">
$i18n{settingsCheckboxLabel}
</div>
- <paper-toggle-button checked="{{syncPrefs.preferencesSynced}}"
+ <cr-toggle checked="{{syncPrefs.preferencesSynced}}"
on-change="onSingleSyncDataTypeChanged_"
disabled="[[shouldSyncCheckboxBeDisabled_(
syncPrefs.syncAllDataTypes, syncPrefs.preferencesEnforced)]]"
aria-labelledby="settingsCheckboxLabel">
- </paper-toggle-button>
+ </cr-toggle>
</div>
<div class="layout horizontal list-item"
@@ -207,12 +207,12 @@
<div id="themesAndWallpapersCheckboxLabel" class="flex">
$i18n{themesAndWallpapersCheckboxLabel}
</div>
- <paper-toggle-button checked="{{syncPrefs.themesSynced}}"
+ <cr-toggle checked="{{syncPrefs.themesSynced}}"
on-change="onSingleSyncDataTypeChanged_"
disabled="[[shouldSyncCheckboxBeDisabled_(
syncPrefs.syncAllDataTypes, syncPrefs.themesEnforced)]]"
aria-labelledby="themesAndWallpapersCheckboxLabel">
- </paper-toggle-button>
+ </cr-toggle>
</div>
<div class="layout horizontal list-item"
@@ -220,12 +220,12 @@
<div id="openTabsCheckboxLabel" class="flex">
$i18n{openTabsCheckboxLabel}
</div>
- <paper-toggle-button checked="{{syncPrefs.tabsSynced}}"
+ <cr-toggle checked="{{syncPrefs.tabsSynced}}"
on-change="onSingleSyncDataTypeChanged_"
disabled="[[shouldSyncCheckboxBeDisabled_(
syncPrefs.syncAllDataTypes, syncPrefs.tabsEnforced)]]"
aria-labelledby="openTabsCheckboxLabel">
- </paper-toggle-button>
+ </cr-toggle>
</div>
<div class="layout horizontal list-item"
@@ -239,13 +239,13 @@
$i18n{learnMore}
</a>
</div>
- <paper-toggle-button
+ <cr-toggle
checked="{{syncPrefs.paymentsIntegrationEnabled}}"
on-change="onSingleSyncDataTypeChanged_"
disabled="[[shouldPaymentsCheckboxBeDisabled_(
syncPrefs.syncAllDataTypes, syncPrefs.autofillSynced)]]"
aria-label="$i18n{enablePaymentsIntegrationCheckboxLabel}">
- </paper-toggle-button>
+ </cr-toggle>
</div>
</div>
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 a2fea7f100f..ac720c8628e 100644
--- a/chromium/chrome/browser/resources/settings/people_page/users_page.html
+++ b/chromium/chrome/browser/resources/settings/people_page/users_page.html
@@ -39,11 +39,13 @@
label="$i18n{guestBrowsingLabel}"
disabled="[[isEditingDisabled_(isOwner_, isWhitelistManaged_)]]">
</settings-toggle-button>
- <settings-toggle-button class="continuation"
- pref="{{prefs.cros.accounts.supervisedUsersEnabled}}"
- label="$i18n{supervisedUsersLabel}"
- disabled="[[isEditingDisabled_(isOwner_, isWhitelistManaged_)]]">
- </settings-toggle-button>
+ <template is="dom-if" if="[[profileManagesSupervisedUsers]]">
+ <settings-toggle-button class="continuation"
+ pref="{{prefs.cros.accounts.supervisedUsersEnabled}}"
+ label="$i18n{supervisedUsersLabel}"
+ disabled="[[isEditingDisabled_(isOwner_, isWhitelistManaged_)]]">
+ </settings-toggle-button>
+ </template>
<settings-toggle-button class="continuation"
pref="{{prefs.cros.accounts.showUserNamesOnSignIn}}"
label="$i18n{showOnSigninLabel}"
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 2d14833a0dc..762fb6763f8 100644
--- a/chromium/chrome/browser/resources/settings/people_page/users_page.js
+++ b/chromium/chrome/browser/resources/settings/people_page/users_page.js
@@ -19,6 +19,15 @@ Polymer({
notify: true,
},
+ /**
+ * True if the current profile manages supervised users.
+ * Set in people-page.
+ */
+ profileManagesSupervisedUsers: {
+ type: Boolean,
+ value: false,
+ },
+
/** @private */
isOwner_: {
type: Boolean,
diff --git a/chromium/chrome/browser/resources/settings/printing_page/compiled_resources2.gyp b/chromium/chrome/browser/resources/settings/printing_page/compiled_resources2.gyp
index 6a3b5f8fddf..cc0e0003a42 100644
--- a/chromium/chrome/browser/resources/settings/printing_page/compiled_resources2.gyp
+++ b/chromium/chrome/browser/resources/settings/printing_page/compiled_resources2.gyp
@@ -72,6 +72,13 @@
'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
},
{
+ 'target_name': 'printing_browser_proxy',
+ 'dependencies': [
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
'target_name': 'printing_page',
'dependencies': [
'<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:assert',
@@ -79,6 +86,7 @@
'../compiled_resources2.gyp:route',
'../settings_page/compiled_resources2.gyp:settings_animated_pages',
'cups_printers_browser_proxy',
+ 'printing_browser_proxy',
],
'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
},
diff --git a/chromium/chrome/browser/resources/settings/printing_page/cups_add_printer_dialog.html b/chromium/chrome/browser/resources/settings/printing_page/cups_add_printer_dialog.html
index 5ca6f7e45de..5f697cc8706 100644
--- a/chromium/chrome/browser/resources/settings/printing_page/cups_add_printer_dialog.html
+++ b/chromium/chrome/browser/resources/settings/printing_page/cups_add_printer_dialog.html
@@ -61,7 +61,7 @@
$i18n{cancelButtonText}
</paper-button>
<paper-button class="action-button" id="addPrinterButton"
- disabled="[[!selectedPrinter]]"
+ disabled="[[!canAddPrinter_(selectedPrinter)]]"
on-tap="switchToConfiguringDialog_">
$i18n{addPrinterButtonText}
</paper-button>
diff --git a/chromium/chrome/browser/resources/settings/printing_page/cups_add_printer_dialog.js b/chromium/chrome/browser/resources/settings/printing_page/cups_add_printer_dialog.js
index 6ebd338e294..ccd0c66fcdf 100644
--- a/chromium/chrome/browser/resources/settings/printing_page/cups_add_printer_dialog.js
+++ b/chromium/chrome/browser/resources/settings/printing_page/cups_add_printer_dialog.js
@@ -143,6 +143,15 @@ Polymer({
this.close();
this.fire('open-configuring-printer-dialog');
},
+
+ /**
+ * @param {?CupsPrinterInfo} selectedPrinter
+ * @return {boolean} Whether the add printer button is enabled.
+ * @private
+ */
+ canAddPrinter_: function(selectedPrinter) {
+ return !!selectedPrinter && !!selectedPrinter.printerName;
+ },
});
Polymer({
diff --git a/chromium/chrome/browser/resources/settings/printing_page/cups_printers.js b/chromium/chrome/browser/resources/settings/printing_page/cups_printers.js
index 0957580006d..727755f4a89 100644
--- a/chromium/chrome/browser/resources/settings/printing_page/cups_printers.js
+++ b/chromium/chrome/browser/resources/settings/printing_page/cups_printers.js
@@ -115,7 +115,7 @@ Polymer({
break;
case PrinterSetupResult.PRINTER_UNREACHABLE:
messageText.textContent =
- loadTimeData.getString('printerAddedPrinterUnreachableMessage');
+ loadTimeData.getString('printerAddedUnreachableMessage');
break;
case PrinterSetupResult.DBUS_ERROR:
// Simply display a generic error message as this error should only
diff --git a/chromium/chrome/browser/resources/settings/printing_page/cups_printers_browser_proxy.js b/chromium/chrome/browser/resources/settings/printing_page/cups_printers_browser_proxy.js
index 6cc0b682015..a1804172813 100644
--- a/chromium/chrome/browser/resources/settings/printing_page/cups_printers_browser_proxy.js
+++ b/chromium/chrome/browser/resources/settings/printing_page/cups_printers_browser_proxy.js
@@ -4,7 +4,7 @@
/**
* @fileoverview A helper object used from the "CUPS printing" section to
- * interact with the browser.
+ * interact with the browser. Used only on Chrome OS.
*/
/**
diff --git a/chromium/chrome/browser/resources/settings/printing_page/printing_browser_proxy.html b/chromium/chrome/browser/resources/settings/printing_page/printing_browser_proxy.html
new file mode 100644
index 00000000000..8e6d297ef56
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/printing_page/printing_browser_proxy.html
@@ -0,0 +1,2 @@
+<link rel="import" href="chrome://resources/html/cr.html">
+<script src="printing_browser_proxy.js"></script>
diff --git a/chromium/chrome/browser/resources/settings/printing_page/printing_browser_proxy.js b/chromium/chrome/browser/resources/settings/printing_page/printing_browser_proxy.js
new file mode 100644
index 00000000000..83b8536e836
--- /dev/null
+++ b/chromium/chrome/browser/resources/settings/printing_page/printing_browser_proxy.js
@@ -0,0 +1,35 @@
+// Copyright 2017 The Chromium 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 Chrome printing section to
+ * interact with the browser. Used on operating system that is not Chrome OS.
+ */
+
+cr.define('settings', function() {
+ /** @interface */
+ class PrintingBrowserProxy {
+ /**
+ * Open the native print system dialog.
+ */
+ openSystemPrintDialog() {}
+ }
+
+ /**
+ * @implements {settings.PrintingBrowserProxy}
+ */
+ class PrintingBrowserProxyImpl {
+ /** @override */
+ openSystemPrintDialog() {
+ chrome.send('openSystemPrintDialog');
+ }
+ }
+
+ cr.addSingletonGetter(PrintingBrowserProxyImpl);
+
+ return {
+ PrintingBrowserProxy: PrintingBrowserProxy,
+ PrintingBrowserProxyImpl: PrintingBrowserProxyImpl,
+ };
+});
diff --git a/chromium/chrome/browser/resources/settings/printing_page/printing_page.html b/chromium/chrome/browser/resources/settings/printing_page/printing_page.html
index 77eddcbbdfc..90e18fbb2e5 100644
--- a/chromium/chrome/browser/resources/settings/printing_page/printing_page.html
+++ b/chromium/chrome/browser/resources/settings/printing_page/printing_page.html
@@ -10,6 +10,9 @@
<if expr="chromeos">
<link rel="import" href="cups_printers.html">
</if>
+<if expr="not chromeos">
+<link rel="import" href="printing_browser_proxy.html">
+</if>
<dom-module id="settings-printing-page">
<template>
@@ -25,6 +28,14 @@
aria-label="$i18n{cupsPrintersTitle}"></button>
</div>
</if>
+<if expr="not chromeos">
+ <div class="settings-box first"
+ on-tap="onTapLocalPrinters_" actionable>
+ <div class="start">$i18n{localPrintersTitle}</div>
+ <button class="subpage-arrow" is="paper-icon-button-light"
+ aria-label="$i18n{localPrintersTitle}"></button>
+ </div>
+</if>
<div id="cloudPrinters" class="settings-box"
on-tap="onTapCloudPrinters_" actionable>
<div class="start">$i18n{cloudPrintersTitle}</div>
diff --git a/chromium/chrome/browser/resources/settings/printing_page/printing_page.js b/chromium/chrome/browser/resources/settings/printing_page/printing_page.js
index 8c8e14b2934..79a7be19b24 100644
--- a/chromium/chrome/browser/resources/settings/printing_page/printing_page.js
+++ b/chromium/chrome/browser/resources/settings/printing_page/printing_page.js
@@ -45,6 +45,12 @@ Polymer({
},
// </if>
+ // <if expr="not chromeos">
+ onTapLocalPrinters_: function() {
+ settings.PrintingBrowserProxyImpl.getInstance().openSystemPrintDialog();
+ },
+ // </if>
+
/** @private */
onTapCloudPrinters_: function() {
settings.navigateTo(settings.routes.CLOUD_PRINTERS);
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 52fff4a8457..1ba4c86e60b 100644
--- a/chromium/chrome/browser/resources/settings/privacy_page/privacy_page.html
+++ b/chromium/chrome/browser/resources/settings/privacy_page/privacy_page.html
@@ -349,8 +349,8 @@
<template is="dom-if" route-path="/content/sound" no-search>
<settings-subpage page-title="$i18n{siteSettingsSound}">
<category-default-setting
- toggle-off-label="$i18n{siteSettingsBlocked}"
- toggle-on-label="$i18n{siteSettingsAllowedRecommended}"
+ toggle-off-label="$i18n{siteSettingsSoundBlock}"
+ toggle-on-label="$i18n{siteSettingsSoundAllowRecommended}"
category="{{ContentSettingsTypes.SOUND}}">
</category-default-setting>
<category-setting-exceptions
@@ -358,8 +358,8 @@
block-header="$i18n{siteSettingsBlockSound}">
</category-setting-exceptions>
</settings-subpage>
- </template>
- </template>
+ </template>
+ </template>
<template is="dom-if" route-path="/content/microphone" no-search>
<settings-subpage page-title="$i18n{siteSettingsCategoryMicrophone}">
<media-picker label="$i18n{siteSettingsMicrophoneLabel}" type="mic">
@@ -516,6 +516,22 @@
</if>
</settings-subpage>
</template>
+ <template is="dom-if" if="[[enableClipboardContentSetting_]]"
+ no-search>
+ <template is="dom-if" route-path="/content/clipboard" no-search>
+ <settings-subpage page-title="$i18n{siteSettingsClipboard}">
+ <category-default-setting
+ toggle-off-label="$i18n{siteSettingsClipboardBlock}"
+ toggle-on-label="$i18n{siteSettingsClipboardAskRecommended}"
+ category="{{ContentSettingsTypes.CLIPBOARD}}">
+ </category-default-setting>
+ <category-setting-exceptions
+ category="{{ContentSettingsTypes.CLIPBOARD}}"
+ block-header="$i18n{siteSettingsBlock}">
+ </category-setting-exceptions>
+ </settings-subpage>
+ </template>
+ </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 cb15fd06ff5..46afb457824 100644
--- a/chromium/chrome/browser/resources/settings/privacy_page/privacy_page.js
+++ b/chromium/chrome/browser/resources/settings/privacy_page/privacy_page.js
@@ -115,6 +115,14 @@ Polymer({
}
},
+ /** @private */
+ enableClipboardContentSetting_: {
+ type: Boolean,
+ value: function() {
+ return loadTimeData.getBoolean('enableClipboardContentSetting');
+ }
+ },
+
/** @private {!Map<string, string>} */
focusConfig_: {
type: Object,
diff --git a/chromium/chrome/browser/resources/settings/reset_page/compiled_resources2.gyp b/chromium/chrome/browser/resources/settings/reset_page/compiled_resources2.gyp
index c1e99cfafce..39f600e4c60 100644
--- a/chromium/chrome/browser/resources/settings/reset_page/compiled_resources2.gyp
+++ b/chromium/chrome/browser/resources/settings/reset_page/compiled_resources2.gyp
@@ -11,6 +11,25 @@
'<(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/cr/ui/compiled_resources2.gyp:focus_without_ink',
+ 'reset_profile_dialog',
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'reset_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': 'reset_profile_dialog',
+ 'dependencies': [
+ '../compiled_resources2.gyp:route',
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:load_time_data',
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:web_ui_listener_behavior',
+ 'reset_browser_proxy',
],
'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
},
diff --git a/chromium/chrome/browser/resources/settings/reset_page/reset_browser_proxy.js b/chromium/chrome/browser/resources/settings/reset_page/reset_browser_proxy.js
index f43c9a08a38..8b9f2184c51 100644
--- a/chromium/chrome/browser/resources/settings/reset_page/reset_browser_proxy.js
+++ b/chromium/chrome/browser/resources/settings/reset_page/reset_browser_proxy.js
@@ -114,6 +114,7 @@ cr.define('settings', function() {
cr.addSingletonGetter(ResetBrowserProxyImpl);
return {
+ ResetBrowserProxy: ResetBrowserProxy,
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 fc55ba1f8f4..44214d07820 100644
--- a/chromium/chrome/browser/resources/settings/reset_page/reset_page.html
+++ b/chromium/chrome/browser/resources/settings/reset_page/reset_page.html
@@ -3,53 +3,95 @@
<link rel="import" href="chrome://resources/cr_elements/cr_lazy_render/cr_lazy_render.html">
<link rel="import" href="chrome://resources/html/assert.html">
<link rel="import" href="chrome://resources/html/cr/ui/focus_without_ink.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/neon-animation/neon-animatable.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button-light.html">
<link rel="import" href="../i18n_setup.html">
<link rel="import" href="reset_profile_dialog.html">
<link rel="import" href="../route.html">
+<link rel="import" href="../settings_page/settings_animated_pages.html">
<link rel="import" href="../settings_shared_css.html">
<if expr="chromeos">
<link rel="import" href="powerwash_dialog.html">
</if>
+<if expr="_google_chrome and is_win">
+<link rel="import" href="../chrome_cleanup_page/chrome_cleanup_page.html">
+</if>
+
<dom-module id="settings-reset-page">
<template>
<style include="settings-shared"></style>
- <div class="settings-box first two-line" id="resetProfile"
- on-tap="onShowResetProfileDialog_" actionable>
- <div class="start">
- $i18n{resetPageTitle}
- <div class="secondary" id="resetProfileSecondary">
- $i18n{resetPageDescription}
+ <settings-animated-pages id="reset-pages" section="reset">
+ <neon-animatable route-path="default">
+ <div class="settings-box first two-line" id="resetProfile"
+ on-tap="onShowResetProfileDialog_" actionable>
+ <div class="start">
+ $i18n{resetPageTitle}
+ <div class="secondary" id="resetProfileSecondary">
+ $i18n{resetPageDescription}
+ </div>
+ </div>
+ <button id="resetProfileArrow" is="paper-icon-button-light"
+ class="subpage-arrow" aria-label="$i18n{resetPageTitle}"
+ aria-describedby="resetProfileSecondary"></button>
</div>
- </div>
- <button id="resetProfileArrow" is="paper-icon-button-light"
- class="subpage-arrow" aria-label="$i18n{resetPageTitle}"
- aria-describedby="resetProfileSecondary"></button>
- </div>
- <template is="dom-if" if="[[showResetProfileDialog_]]" restamp>
- <settings-reset-profile-dialog on-close="onResetProfileDialogClose_">
- </settings-reset-profile-dialog>
- </template>
+ <!-- Keep a single instance of reset-profile-dialog on purpose, to
+ preserve state across show/hide operations. -->
+ <template is="cr-lazy-render" id="resetProfileDialog">
+ <settings-reset-profile-dialog on-close="onResetProfileDialogClose_">
+ </settings-reset-profile-dialog>
+ </template>
<if expr="chromeos">
- <div class="settings-box two-line" id="powerwash" actionable
- on-tap="onShowPowerwashDialog_" hidden="[[!allowPowerwash_]]">
- <div class="start">
- $i18n{powerwashTitle}
- <div class="secondary" id="powerwashSecondary">
- $i18n{powerwashDescription}
+ <div class="settings-box two-line" id="powerwash" actionable
+ on-tap="onShowPowerwashDialog_" hidden="[[!allowPowerwash_]]">
+ <div class="start">
+ $i18n{powerwashTitle}
+ <div class="secondary" id="powerwashSecondary">
+ $i18n{powerwashDescription}
+ </div>
+ </div>
+ <button id="powerwashArrow" is="paper-icon-button-light"
+ class="subpage-arrow" aria-label="$i18n{powerwashTitle}"
+ aria-describedby="powerwashSecondary"></button>
</div>
- </div>
- <button id="powerwashArrow" is="paper-icon-button-light"
- class="subpage-arrow" aria-label="$i18n{powerwashTitle}"
- aria-describedby="powerwashSecondary"></button>
- </div>
- <template is="dom-if" if="[[showPowerwashDialog_]]" restamp>
- <settings-powerwash-dialog on-close="onPowerwashDialogClose_">
- </settings-powerwash-dialog>
- </template>
+ <template is="dom-if" if="[[showPowerwashDialog_]]" restamp>
+ <settings-powerwash-dialog on-close="onPowerwashDialogClose_">
+ </settings-powerwash-dialog>
+ </template>
+</if>
+<!-- This needs to be conditioned to a feature being enabled. -->
+<if expr="_google_chrome and is_win">
+ <template is="dom-if" if="[[userInitiatedCleanupsEnabled_]]" restamp>
+ <div class="settings-box two-line" id="chromeCleanupSubpageTrigger"
+ on-tap="onChromeCleanupTap_" actionable>
+ <div class="start">
+ $i18n{resetCleanupComputerTrigger}
+ <div class="secondary" id="chromeCleanupSecondary">
+ $i18n{resetCleanupComputerTriggerDescription}
+ </div>
+ </div>
+ <button id="chromeCleanupArrow" is="paper-icon-button-light"
+ class="subpage-arrow"
+ aria-label="$i18n{resetCleanupComputerTrigger}"
+ aria-describedby="chromeCleanupSecondary"></button>
+ </div>
+ </template>
+</if>
+ </neon-animatable>
+<if expr="_google_chrome and is_win">
+ <template is="dom-if" if="[[userInitiatedCleanupsEnabled_]]">
+ <template is="dom-if" route-path="/cleanup">
+ <settings-subpage id="chromeCleanupSubpage"
+ associated-control="[[$$('#chromeCleanupSubpageTrigger')]]"
+ page-title="$i18n{resetCleanupComputerTrigger}"
+ learn-more-url="$i18n{chromeCleanupLearnMoreUrl}">
+ <settings-chrome-cleanup-page></settings-chrome-cleanup-page>
+ </settings-subpage>
+ </template>
+ </template>
</if>
+ </settings-animated-pages>
</template>
<script src="reset_page.js"></script>
</dom-module>
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 2c4d88e249c..fb5c2229223 100644
--- a/chromium/chrome/browser/resources/settings/reset_page/reset_page.js
+++ b/chromium/chrome/browser/resources/settings/reset_page/reset_page.js
@@ -32,11 +32,15 @@ Polymer({
value: cr.isChromeOS ? loadTimeData.getBoolean('allowPowerwash') : false
},
+ // <if expr="_google_chrome and is_win">
/** @private */
- showResetProfileDialog_: {
+ userInitiatedCleanupsEnabled_: {
type: Boolean,
- value: false,
+ value: function() {
+ return loadTimeData.getBoolean('userInitiatedCleanupsEnabled');
+ },
},
+ // </if>
},
/**
@@ -45,9 +49,12 @@ Polymer({
* @protected
*/
currentRouteChanged: function(route) {
- this.showResetProfileDialog_ =
- route == settings.routes.TRIGGERED_RESET_DIALOG ||
- route == settings.routes.RESET_DIALOG;
+ if (route == settings.routes.TRIGGERED_RESET_DIALOG ||
+ route == settings.routes.RESET_DIALOG) {
+ /** @type {!SettingsResetProfileDialogElement} */ (
+ this.$.resetProfileDialog.get())
+ .show();
+ }
},
/** @private */
@@ -78,4 +85,11 @@ Polymer({
cr.ui.focusWithoutInk(assert(this.$.powerwashArrow));
},
// </if>
+
+ // <if expr="_google_chrome and is_win">
+ onChromeCleanupTap_: function() {
+ settings.navigateTo(settings.routes.CHROME_CLEANUP);
+ },
+ // </if>
+
});
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 40827a89e20..b7c6519625c 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
@@ -41,7 +41,7 @@ Polymer({
},
},
- /** @private {!settings.ResetBrowserProxy} */
+ /** @private {?settings.ResetBrowserProxy} */
browserProxy_: null,
/**
@@ -87,12 +87,12 @@ Polymer({
/** @private */
showDialog_: function() {
- this.$.dialog.showModal();
+ if (!this.$.dialog.open)
+ this.$.dialog.showModal();
this.browserProxy_.onShowResetProfileDialog();
},
- /** @override */
- attached: function() {
+ show: function() {
this.isTriggered_ =
settings.getCurrentRoute() == settings.routes.TRIGGERED_RESET_DIALOG;
if (this.isTriggered_) {
diff --git a/chromium/chrome/browser/resources/settings/route.js b/chromium/chrome/browser/resources/settings/route.js
index 20b8d4b29a7..d6bf83c237b 100644
--- a/chromium/chrome/browser/resources/settings/route.js
+++ b/chromium/chrome/browser/resources/settings/route.js
@@ -20,10 +20,12 @@
* BLUETOOTH_DEVICES: (undefined|!settings.Route),
* CERTIFICATES: (undefined|!settings.Route),
* CHANGE_PICTURE: (undefined|!settings.Route),
+ * CHROME_CLEANUP: (undefined|!settings.Route),
* CLEAR_BROWSER_DATA: (undefined|!settings.Route),
* CLOUD_PRINTERS: (undefined|!settings.Route),
* CUPS_PRINTERS: (undefined|!settings.Route),
* DATETIME: (undefined|!settings.Route),
+ * DATETIME_TIMEZONE_SUBPAGE: (undefined|!settings.Route),
* DEFAULT_BROWSER: (undefined|!settings.Route),
* DETAILED_BUILD_INFO: (undefined|!settings.Route),
* DEVICE: (undefined|!settings.Route),
@@ -45,7 +47,6 @@
* MANAGE_PASSWORDS: (undefined|!settings.Route),
* MANAGE_PROFILE: (undefined|!settings.Route),
* MULTIDEVICE: (undefined|!settings.Route),
- * NETWORK_CONFIG: (undefined|!settings.Route),
* NETWORK_DETAIL: (undefined|!settings.Route),
* ON_STARTUP: (undefined|!settings.Route),
* PASSWORDS: (undefined|!settings.Route),
@@ -65,6 +66,7 @@
* SITE_SETTINGS_AUTOMATIC_DOWNLOADS: (undefined|!settings.Route),
* SITE_SETTINGS_BACKGROUND_SYNC: (undefined|!settings.Route),
* SITE_SETTINGS_CAMERA: (undefined|!settings.Route),
+ * SITE_SETTINGS_CLIPBOARD: (undefined|!settings.Route),
* SITE_SETTINGS_COOKIES: (undefined|!settings.Route),
* SITE_SETTINGS_DATA_DETAILS: (undefined|!settings.Route),
* SITE_SETTINGS_FLASH: (undefined|!settings.Route),
@@ -135,7 +137,7 @@ cr.define('settings', function() {
// |path| extends this route's path if it doesn't have a leading slash.
// If it does have a leading slash, it's just set as the new route's URL.
- var newUrl = path[0] == '/' ? path : this.path + '/' + path;
+ var newUrl = path[0] == '/' ? path : `${this.path}/${path}`;
var route = new Route(newUrl);
route.parent = this;
@@ -216,7 +218,6 @@ cr.define('settings', function() {
// <if expr="chromeos">
r.INTERNET = r.BASIC.createSection('/internet', 'internet');
r.INTERNET_NETWORKS = r.INTERNET.createChild('/networks');
- r.NETWORK_CONFIG = r.INTERNET.createChild('/networkConfig');
r.NETWORK_DETAIL = r.INTERNET.createChild('/networkDetail');
r.KNOWN_NETWORKS = r.INTERNET.createChild('/knownNetworks');
r.BLUETOOTH = r.BASIC.createSection('/bluetooth', 'bluetooth');
@@ -290,10 +291,9 @@ cr.define('settings', function() {
r.SITE_SETTINGS_ALL = r.SITE_SETTINGS.createChild('all');
r.SITE_SETTINGS_SITE_DETAILS =
r.SITE_SETTINGS_ALL.createChild('/content/siteDetails');
- } else if (loadTimeData.getBoolean('enableSiteDetails')) {
+ } else {
// When there is no "All Sites", pressing 'back' from "Site Details"
- // should return to "Content Settings". This should only occur when
- // |kSiteSettings| is off and |kSiteDetails| is on.
+ // should return to "Content Settings".
r.SITE_SETTINGS_SITE_DETAILS =
r.SITE_SETTINGS.createChild('/content/siteDetails');
}
@@ -308,6 +308,7 @@ cr.define('settings', function() {
r.SITE_SETTINGS_BACKGROUND_SYNC =
r.SITE_SETTINGS.createChild('backgroundSync');
r.SITE_SETTINGS_CAMERA = r.SITE_SETTINGS.createChild('camera');
+ r.SITE_SETTINGS_CLIPBOARD = r.SITE_SETTINGS.createChild('clipboard');
r.SITE_SETTINGS_COOKIES = r.SITE_SETTINGS.createChild('cookies');
r.SITE_SETTINGS_SITE_DATA =
r.SITE_SETTINGS_COOKIES.createChild('/siteData');
@@ -335,6 +336,8 @@ cr.define('settings', function() {
// <if expr="chromeos">
if (pageVisibility.dateTime !== false) {
r.DATETIME = r.ADVANCED.createSection('/dateTime', 'dateTime');
+ r.DATETIME_TIMEZONE_SUBPAGE =
+ r.DATETIME.createChild('/dateTime/timeZone');
}
// </if>
@@ -380,6 +383,12 @@ cr.define('settings', function() {
r.TRIGGERED_RESET_DIALOG =
r.ADVANCED.createChild('/triggeredResetProfileSettings');
r.TRIGGERED_RESET_DIALOG.isNavigableDialog = true;
+ // <if expr="_google_chrome and is_win">
+ // This should only be added if the feature is enabled.
+ if (loadTimeData.getBoolean('userInitiatedCleanupsEnabled')) {
+ r.CHROME_CLEANUP = r.RESET.createChild('/cleanup');
+ }
+ // </if>
}
}
diff --git a/chromium/chrome/browser/resources/settings/search_engines_page/search_engines_browser_proxy.js b/chromium/chrome/browser/resources/settings/search_engines_page/search_engines_browser_proxy.js
index 947dcbefc39..27db88365fa 100644
--- a/chromium/chrome/browser/resources/settings/search_engines_page/search_engines_browser_proxy.js
+++ b/chromium/chrome/browser/resources/settings/search_engines_page/search_engines_browser_proxy.js
@@ -37,18 +37,6 @@ var SearchEngine;
*/
var SearchEnginesInfo;
-/**
- * @typedef {{
- * allowed: boolean,
- * enabled: boolean,
- * alwaysOn: boolean,
- * errorMessage: string,
- * userName: string,
- * historyEnabled: boolean
- * }}
- */
-var SearchPageHotwordInfo;
-
cr.define('settings', function() {
/** @interface */
class SearchEnginesBrowserProxy {
@@ -80,12 +68,6 @@ cr.define('settings', function() {
*/
validateSearchEngineInput(fieldName, fieldValue) {}
- /** @return {!Promise<!SearchPageHotwordInfo>} */
- getHotwordInfo() {}
-
- /** @param {boolean} enabled */
- setHotwordSearchEnabled(enabled) {}
-
turnOnGoogleAssistant() {}
}
@@ -134,16 +116,6 @@ cr.define('settings', function() {
}
/** @override */
- getHotwordInfo() {
- return cr.sendWithPromise('getHotwordInfo');
- }
-
- /** @override */
- setHotwordSearchEnabled(enabled) {
- chrome.send('setHotwordSearchEnabled', [enabled]);
- }
-
- /** @override */
turnOnGoogleAssistant() {
chrome.send('turnOnGoogleAssistant');
}
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 e10d8141330..1e9f88f1e7c 100644
--- a/chromium/chrome/browser/resources/settings/search_page/search_page.html
+++ b/chromium/chrome/browser/resources/settings/search_page/search_page.html
@@ -82,62 +82,6 @@
</template>
</div>
- <template is="dom-if" if="[[hotwordInfo_.allowed]]">
- <!-- Hotword (OK Google) -->
- <settings-toggle-button id="hotwordSearchEnable"
- class="continuation indented"
- pref="{{hotwordSearchEnablePref_}}"
- label="$i18n{searchOkGoogleLabel}"
- sub-label="[[getHotwordSearchEnableSubLabel_(
- hotwordInfo_.alwaysOn)]]"
- on-change="onHotwordSearchEnableChange_">
- </settings-toggle-button>
- <div class="settings-row indented"
- hidden$="[[!getShowHotwordSearchRetrain_(hotwordInfo_.*)]]">
- <div class="separator"></div>
- <paper-button on-tap="onRetrainTap_" class="secondary-button">
- $i18n{searchOkGoogleRetrain}
- </paper-button>
- </div>
-
- <template is="dom-if"
- if="[[getShowHotwordError_(hotwordInfo_.*,
- hotwordSearchEnablePref_)]]">
- <div class="settings-box continuation indented">
- <iron-icon icon="settings:warning"></iron-icon>
- <div inner-h-t-m-l="[[hotwordInfo_.errorMessage]]"></div>
- </div>
- </template>
-
- <template is="dom-if" if="[[hotwordInfo_.historyEnabled]]">
- <a class="settings-box two-line continuation indented inherit-color
- no-outline" tabindex="-1" target="_blank"
- href="$i18n{manageAudioHistoryUrl}">
- <div class="start">
- [[i18n('searchOkGoogleAudioHistoryLabel',
- hotwordInfo_.userName)]]
- <div class="secondary" id="audioHistorySecondary">
- $i18n{searchOkGoogleAudioHistorySubtext}
- </div>
- </div>
- <button actionable class="icon-external"
- is="paper-icon-button-light"
- aria-label$="[[i18n('searchOkGoogleAudioHistoryLabel',
- hotwordInfo_.userName)]]"
- aria-describedby="audioHistorySecondary"></button>
- </a>
- </template>
- </template>
-
-<if expr="chromeos">
- <template is="dom-if"
- if="[[hotwordSearchEnablePref_.value]]">
- <div class="start settings-box continuation indented">
- $i18n{searchOkGoogleDisabled}
- </div>
- </template>
-</if>
-
<!-- Manage search engines -->
<div id="engines-subpage-trigger" class="settings-box"
on-tap="onManageSearchEnginesTap_" actionable>
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 3dbfcf19d69..9a3d913e969 100644
--- a/chromium/chrome/browser/resources/settings/search_page/search_page.js
+++ b/chromium/chrome/browser/resources/settings/search_page/search_page.js
@@ -34,18 +34,6 @@ Polymer({
/** @private Filter applied to search engines. */
searchEnginesFilter_: String,
- /** @private {!SearchPageHotwordInfo|undefined} */
- hotwordInfo_: Object,
-
- /**
- * This is a local PrefObject used to reflect the enabled state of hotword
- * search. It is not tied directly to a pref. (There are two prefs
- * associated with state and they do not map directly to whether or not
- * hotword search is actually enabled).
- * @private {!chrome.settingsPrivate.PrefObject|undefined}
- */
- hotwordSearchEnablePref_: Object,
-
/** @type {?Map<string, string>} */
focusConfig_: Object,
@@ -80,15 +68,10 @@ Polymer({
// Omnibox search engine
var updateSearchEngines = searchEngines => {
this.set('searchEngines_', searchEngines.defaults);
- this.requestHotwordInfoUpdate_();
};
this.browserProxy_.getSearchEnginesList().then(updateSearchEngines);
cr.addWebUIListener('search-engines-changed', updateSearchEngines);
- // Hotword (OK Google) listener
- cr.addWebUIListener(
- 'hotword-info-update', this.hotwordInfoUpdate_.bind(this));
-
this.focusConfig_ = new Map();
if (settings.routes.SEARCH_ENGINES) {
this.focusConfig_.set(
@@ -139,68 +122,6 @@ Polymer({
},
// </if>
- /**
- * @param {!Event} event
- * @private
- */
- onHotwordSearchEnableChange_: function(event) {
- // Do not set the pref directly, allow Chrome to run the setup app instead.
- this.browserProxy_.setHotwordSearchEnabled(
- !!this.hotwordSearchEnablePref_.value);
- },
-
- /** @private */
- requestHotwordInfoUpdate_: function() {
- this.browserProxy_.getHotwordInfo().then(hotwordInfo => {
- this.hotwordInfoUpdate_(hotwordInfo);
- });
- },
-
- /**
- * @param {!SearchPageHotwordInfo} hotwordInfo
- * @private
- */
- hotwordInfoUpdate_: function(hotwordInfo) {
- this.hotwordInfo_ = hotwordInfo;
- this.hotwordSearchEnablePref_ = {
- key: 'unused', // required for PrefObject
- type: chrome.settingsPrivate.PrefType.BOOLEAN,
- value: this.hotwordInfo_.enabled,
- };
- },
-
- /**
- * @return {string}
- * @private
- */
- getHotwordSearchEnableSubLabel_: function() {
- return this.i18n(
- this.hotwordInfo_.alwaysOn ? 'searchOkGoogleSubtextAlwaysOn' :
- 'searchOkGoogleSubtextNoHardware');
- },
-
- /**
- * @return {boolean}
- * @private
- */
- getShowHotwordSearchRetrain_: function() {
- return this.hotwordInfo_.enabled && this.hotwordInfo_.alwaysOn;
- },
-
- /**
- * @return {boolean} True if the pref is enabled but hotword is not.
- * @private
- */
- getShowHotwordError_: function() {
- return this.hotwordInfo_.enabled && !!this.hotwordInfo_.errorMessage;
- },
-
- /** @private */
- onRetrainTap_: function() {
- // Re-enable hotword search enable; this will trigger the retrain UI.
- this.browserProxy_.setHotwordSearchEnabled(this.hotwordInfo_.enabled);
- },
-
// <if expr="chromeos">
/**
* @param {boolean} toggleValue
diff --git a/chromium/chrome/browser/resources/settings/search_settings.js b/chromium/chrome/browser/resources/settings/search_settings.js
index b05aa1106f4..0b89de713a7 100644
--- a/chromium/chrome/browser/resources/settings/search_settings.js
+++ b/chromium/chrome/browser/resources/settings/search_settings.js
@@ -517,7 +517,7 @@ cr.define('settings', function() {
// problematic for regular expressions.
var searchText = this.rawQuery_.trim().replace(SANITIZE_REGEX, '\\$&');
if (searchText.length > 0)
- regExp = new RegExp('(' + searchText + ')', 'i');
+ regExp = new RegExp(`(${searchText})`, 'i');
return regExp;
}
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 17101c8f335..644879a6d93 100644
--- a/chromium/chrome/browser/resources/settings/settings_page/settings_section.html
+++ b/chromium/chrome/browser/resources/settings/settings_page/settings_section.html
@@ -20,9 +20,7 @@
}
#header .title {
- color: var(--paper-grey-700);
- font-size: 100%;
- font-weight: 500;
+ @apply(--cr-section-text);
margin-bottom: 0;
margin-top: var(--settings-page-vertical-margin);
}
diff --git a/chromium/chrome/browser/resources/settings/settings_resources.grd b/chromium/chrome/browser/resources/settings/settings_resources.grd
index 93c5edf1a72..f5cc6960361 100644
--- a/chromium/chrome/browser/resources/settings/settings_resources.grd
+++ b/chromium/chrome/browser/resources/settings/settings_resources.grd
@@ -681,6 +681,12 @@
<structure name="IDR_SETTINGS_PASSWORD_EDIT_DIALOG_JS"
file="passwords_and_forms_page/password_edit_dialog.js"
type="chrome_html" />
+ <structure name="IDR_SETTINGS_PASSWORDS_EXPORT_DIALOG_HTML"
+ file="passwords_and_forms_page/passwords_export_dialog.html"
+ type="chrome_html" />
+ <structure name="IDR_SETTINGS_PASSWORDS_EXPORT_DIALOG_JS"
+ file="passwords_and_forms_page/passwords_export_dialog.js"
+ type="chrome_html" />
<structure name="IDR_SETTINGS_PEOPLE_PAGE_HTML"
file="people_page/people_page.html"
type="chrome_html"
@@ -813,6 +819,14 @@
file="printing_page/cups_add_printer_dialog_util.js"
type="chrome_html" />
</if>
+ <if expr="not chromeos">
+ <structure name="IDR_SETTINGS_PRINTING_BROWSER_PROXY_HTML"
+ file="printing_page/printing_browser_proxy.html"
+ type="chrome_html" />
+ <structure name="IDR_SETTINGS_PRINTING_BROWSER_PROXY_JS"
+ file="printing_page/printing_browser_proxy.js"
+ type="chrome_html" />
+ </if>
<structure name="IDR_SETTINGS_CLOUD_PRINTING_PAGE_HTML"
file="printing_page/cloud_printers.html"
type="chrome_html" />
@@ -856,9 +870,11 @@
type="chrome_html" />
<structure name="IDR_SETTINGS_PROTOCOL_HANDLERS_HTML"
file="site_settings/protocol_handlers.html"
+ preprocess="true"
type="chrome_html" />
<structure name="IDR_SETTINGS_PROTOCOL_HANDLERS_JS"
file="site_settings/protocol_handlers.js"
+ preprocess="true"
type="chrome_html" />
<structure name="IDR_SETTINGS_ROUTE_HTML"
file="route.html"
@@ -909,6 +925,7 @@
type="chrome_html" />
<structure name="IDR_SETTINGS_SITE_SETTINGS_PREFS_BROWSER_PROXY_JS"
file="site_settings/site_settings_prefs_browser_proxy.js"
+ preprocess="true"
type="chrome_html" />
<structure name="IDR_SETTINGS_SITE_DETAILS_HTML"
file="site_settings/site_details.html"
@@ -1105,6 +1122,24 @@
<structure name="IDR_SETTINGS_DATE_TIME_PAGE_JS"
file="date_time_page/date_time_page.js"
type="chrome_html" />
+ <structure name="IDR_SETTINGS_DATE_TIME_TYPES_HTML"
+ file="date_time_page/date_time_types.html"
+ type="chrome_html" />
+ <structure name="IDR_SETTINGS_DATE_TIME_TYPES_JS"
+ file="date_time_page/date_time_types.js"
+ type="chrome_html" />
+ <structure name="IDR_SETTINGS_TIMEZONE_SELECTOR_HTML"
+ file="date_time_page/timezone_selector.html"
+ type="chrome_html" />
+ <structure name="IDR_SETTINGS_TIMEZONE_SELECTOR_JS"
+ file="date_time_page/timezone_selector.js"
+ type="chrome_html" />
+ <structure name="IDR_SETTINGS_TIMEZONE_SUBPAGE_HTML"
+ file="date_time_page/timezone_subpage.html"
+ type="chrome_html" />
+ <structure name="IDR_SETTINGS_TIMEZONE_SUBPAGE_JS"
+ file="date_time_page/timezone_subpage.js"
+ type="chrome_html" />
<structure name="IDR_SETTINGS_INTERNET_CONFIG_HTML"
file="internet_page/internet_config.html"
type="chrome_html" />
@@ -1123,6 +1158,12 @@
<structure name="IDR_SETTINGS_INTERNET_KNOWN_NETWORKS_PAGE_JS"
file="internet_page/internet_known_networks_page.js"
type="chrome_html" />
+ <structure name="IDR_SETTINGS_INTERNET_PAGE_BROWSER_PROXY_HTML"
+ file="internet_page/internet_page_browser_proxy.html"
+ type="chrome_html" />
+ <structure name="IDR_SETTINGS_INTERNET_PAGE_BROWSER_PROXY_JS"
+ file="internet_page/internet_page_browser_proxy.js"
+ type="chrome_html" />
<structure name="IDR_SETTINGS_INTERNET_PAGE_HTML"
file="internet_page/internet_page.html"
type="chrome_html" />
@@ -1150,12 +1191,6 @@
<structure name="IDR_SETTINGS_NETWORK_PROXY_SECTION_JS"
file="internet_page/network_proxy_section.js"
type="chrome_html" />
- <structure name="IDR_SETTINGS_NETWORK_SIMINFO_HTML"
- file="internet_page/network_siminfo.html"
- type="chrome_html" />
- <structure name="IDR_SETTINGS_NETWORK_SIMINFO_JS"
- file="internet_page/network_siminfo.js"
- type="chrome_html" />
<structure name="IDR_SETTINGS_NETWORK_SUMMARY_HTML"
file="internet_page/network_summary.html"
type="chrome_html" />
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 0b217e7ada0..7aca114c1af 100644
--- a/chromium/chrome/browser/resources/settings/settings_ui/settings_ui.html
+++ b/chromium/chrome/browser/resources/settings/settings_ui/settings_ui.html
@@ -39,7 +39,6 @@
cr-toolbar {
@apply(--layout-center);
- --cr-toolbar-field-width: var(--settings-card-max-width);
--iron-icon-fill-color: white;
background-color: var(--google-blue-700);
color: white;
diff --git a/chromium/chrome/browser/resources/settings/site_settings/category_default_setting.js b/chromium/chrome/browser/resources/settings/site_settings/category_default_setting.js
index 08f2e59a2fa..a73e3303987 100644
--- a/chromium/chrome/browser/resources/settings/site_settings/category_default_setting.js
+++ b/chromium/chrome/browser/resources/settings/site_settings/category_default_setting.js
@@ -108,6 +108,7 @@ Polymer({
break;
case settings.ContentSettingsTypes.AUTOMATIC_DOWNLOADS:
case settings.ContentSettingsTypes.CAMERA:
+ case settings.ContentSettingsTypes.CLIPBOARD:
case settings.ContentSettingsTypes.GEOLOCATION:
case settings.ContentSettingsTypes.MIC:
case settings.ContentSettingsTypes.NOTIFICATIONS:
diff --git a/chromium/chrome/browser/resources/settings/site_settings/compiled_resources2.gyp b/chromium/chrome/browser/resources/settings/site_settings/compiled_resources2.gyp
index fbc1a37e421..952595bdf69 100644
--- a/chromium/chrome/browser/resources/settings/site_settings/compiled_resources2.gyp
+++ b/chromium/chrome/browser/resources/settings/site_settings/compiled_resources2.gyp
@@ -88,6 +88,7 @@
'<(DEPTH)/ui/webui/resources/cr_elements/cr_action_menu/compiled_resources2.gyp:cr_action_menu',
'<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:web_ui_listener_behavior',
'site_settings_behavior',
+ '../android_apps_page/compiled_resources2.gyp:android_apps_browser_proxy',
],
'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 44fbc1546d1..468d0b9fff3 100644
--- a/chromium/chrome/browser/resources/settings/site_settings/constants.js
+++ b/chromium/chrome/browser/resources/settings/site_settings/constants.js
@@ -32,6 +32,7 @@ settings.ContentSettingsTypes = {
ZOOM_LEVELS: 'zoom-levels',
PROTECTED_CONTENT: 'protectedContent',
ADS: 'ads',
+ CLIPBOARD: 'clipboard',
};
/**
@@ -56,6 +57,8 @@ settings.ContentSetting = {
* @enum {string}
*/
settings.SiteSettingSource = {
+ ADS_BLOCKED: 'ads-blocked',
+ ADS_FILTER_BLACKLIST: 'ads-filter-blacklist',
DEFAULT: 'default',
// This source is for the Protected Media Identifier / Protected Content
// content setting only, which is only available on ChromeOS.
diff --git a/chromium/chrome/browser/resources/settings/site_settings/cookie_info.js b/chromium/chrome/browser/resources/settings/site_settings/cookie_info.js
index 43056bb906f..c41527432e4 100644
--- a/chromium/chrome/browser/resources/settings/site_settings/cookie_info.js
+++ b/chromium/chrome/browser/resources/settings/site_settings/cookie_info.js
@@ -61,6 +61,8 @@ var CookieDataForDisplay;
['origin', 'serviceWorkerOrigin'], ['size', 'serviceWorkerSize'],
['scopes', 'serviceWorkerScopes']
],
+ 'shared_worker':
+ [['worker', 'sharedWorkerWorker'], ['name', 'sharedWorkerName']],
'cache_storage': [
['origin', 'cacheStorageOrigin'], ['size', 'cacheStorageSize'],
['modified', 'cacheStorageLastModified']
diff --git a/chromium/chrome/browser/resources/settings/site_settings/local_data_browser_proxy.js b/chromium/chrome/browser/resources/settings/site_settings/local_data_browser_proxy.js
index 28d4a1dccce..224b4ba722d 100644
--- a/chromium/chrome/browser/resources/settings/site_settings/local_data_browser_proxy.js
+++ b/chromium/chrome/browser/resources/settings/site_settings/local_data_browser_proxy.js
@@ -28,7 +28,6 @@ var LocalDataItem;
* TODO(dschuyler): add |filter| and |order|.
* @typedef {{
* items: !Array<!LocalDataItem>,
- * start: number,
* total: number,
* }}
*/
@@ -39,13 +38,9 @@ cr.define('settings', function() {
class LocalDataBrowserProxy {
/**
* @param {string} filter Search filter (use "" for none).
- * @param {number} begin Which element to start with. (Similar to 'offset'
- * in SQL). The first item is at 0.
- * @param {number} count How many list elements are displayed. (Similar to
- * 'limit' in SQL). Pass -1 to get all remaining items.
* @return {!Promise<!LocalDataList>}
*/
- getDisplayList(filter, begin, count) {}
+ getDisplayList(filter) {}
/**
* Removes all local data (local storage, cookies, etc.).
@@ -93,9 +88,8 @@ cr.define('settings', function() {
*/
class LocalDataBrowserProxyImpl {
/** @override */
- getDisplayList(filter, begin, count) {
- return cr.sendWithPromise(
- 'localData.getDisplayList', filter, begin, count);
+ getDisplayList(filter) {
+ return cr.sendWithPromise('localData.getDisplayList', filter);
}
/** @override */
diff --git a/chromium/chrome/browser/resources/settings/site_settings/protocol_handlers.html b/chromium/chrome/browser/resources/settings/site_settings/protocol_handlers.html
index 04de6344da3..a37356e6dda 100644
--- a/chromium/chrome/browser/resources/settings/site_settings/protocol_handlers.html
+++ b/chromium/chrome/browser/resources/settings/site_settings/protocol_handlers.html
@@ -1,10 +1,10 @@
<link rel="import" href="chrome://resources/html/polymer.html">
-<link rel="import" href="chrome://resources/cr_elements/icons.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button-light.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/paper-toggle-button/paper-toggle-button.html">
<link rel="import" href="chrome://resources/cr_elements/cr_action_menu/cr_action_menu.html">
+<link rel="import" href="chrome://resources/cr_elements/cr_toggle/cr_toggle.html">
+<link rel="import" href="chrome://resources/cr_elements/icons.html">
<link rel="import" href="chrome://resources/html/web_ui_listener_behavior.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button-light.html">
<link rel="import" href="../i18n_setup.html">
<link rel="import" href="../settings_shared_css.html">
<link rel="import" href="site_settings_behavior.html">
@@ -27,9 +27,9 @@
<div id="categoryLabel" class="start">
[[computeHandlersDescription_(categoryEnabled)]]
</div>
- <paper-toggle-button id="toggle" checked="{{categoryEnabled}}"
+ <cr-toggle id="toggle" checked="{{categoryEnabled}}"
on-change="onToggleChange_" aria-labelledby="categoryLabel">
- </paper-toggle-button>
+ </cr-toggle>
</div>
<template is="dom-repeat" items="[[protocols]]" as="protocol">
@@ -67,6 +67,18 @@
$i18n{handlerRemove}
</button>
</dialog>
+
+<if expr="chromeos">
+ <template is="dom-if" if="[[settingsAppAvailable_]]">
+ <div class="settings-box first"
+ on-tap="onManageAndroidAppsTap_" actionable>
+ <div class="start">
+ <div>$i18n{androidAppsManageAppLinks}</div>
+ </div>
+ <button class="icon-external" is="paper-icon-button-light"></button>
+ </div>
+ </template>
+</if>
</template>
<script src="protocol_handlers.js"></script>
</dom-module>
diff --git a/chromium/chrome/browser/resources/settings/site_settings/protocol_handlers.js b/chromium/chrome/browser/resources/settings/site_settings/protocol_handlers.js
index 871659b8eb8..7da371a9afe 100644
--- a/chromium/chrome/browser/resources/settings/site_settings/protocol_handlers.js
+++ b/chromium/chrome/browser/resources/settings/site_settings/protocol_handlers.js
@@ -59,6 +59,14 @@ Polymer({
/* Labels for the toggle on/off positions. */
toggleOffLabel: String,
toggleOnLabel: String,
+
+ // <if expr="chromeos">
+ /** @private */
+ settingsAppAvailable_: {
+ type: Boolean,
+ value: false,
+ },
+ // </if>
},
/** @override */
@@ -73,6 +81,29 @@ Polymer({
this.browserProxy.observeProtocolHandlers();
},
+ // <if expr="chromeos">
+ /** @override */
+ attached: function() {
+ if (settings.AndroidAppsBrowserProxyImpl) {
+ cr.addWebUIListener(
+ 'android-apps-info-update', this.androidAppsInfoUpdate_.bind(this));
+ settings.AndroidAppsBrowserProxyImpl.getInstance()
+ .requestAndroidAppsInfo();
+ }
+ },
+ // </if>
+
+ // <if expr="chromeos">
+ /**
+ * Receives updates on whether or not ARC settings app is available.
+ * @param {AndroidAppsInfo} info
+ * @private
+ */
+ androidAppsInfoUpdate_: function(info) {
+ this.settingsAppAvailable_ = info.settingsAppAvailable;
+ },
+ // </if>
+
/**
* Obtains the description for the main toggle.
* @return {string} The description to use.
@@ -177,5 +208,15 @@ Polymer({
.showAt(
/** @type {!Element} */ (
Polymer.dom(/** @type {!Event} */ (event)).localTarget));
- }
+ },
+
+ // <if expr="chromeos">
+ /**
+ * Opens an activity to handle App links (preferred apps).
+ * @private
+ */
+ onManageAndroidAppsTap_: function() {
+ this.browserProxy.showAndroidManageAppLinks();
+ },
+ // </if>
});
diff --git a/chromium/chrome/browser/resources/settings/site_settings/site_data.html b/chromium/chrome/browser/resources/settings/site_settings/site_data.html
index eb7d2da4117..72c73a87961 100644
--- a/chromium/chrome/browser/resources/settings/site_settings/site_data.html
+++ b/chromium/chrome/browser/resources/settings/site_settings/site_data.html
@@ -9,6 +9,7 @@
<link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html">
<link rel="import" href="chrome://resources/polymer/v1_0/iron-list/iron-list.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button-light.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-spinner/paper-spinner-lite.html">
<link rel="import" href="../global_scroll_target_behavior.html">
<link rel="import" href="../settings_page/settings_subpage_search.html">
<link rel="import" href="../settings_shared_css.html">
@@ -22,6 +23,16 @@
border-top: none;
}
+ paper-spinner-lite {
+ @apply(--cr-icon-height-width);
+ opacity: 0;
+ transition-delay: 1s;
+ }
+
+ paper-spinner-lite[active] {
+ opacity: 1;
+ }
+
#removeShowingSites {
-webkit-margin-start: auto;
}
@@ -31,7 +42,9 @@
}
</style>
<div class="settings-box continuation">
- <paper-button class="secondary-button" id="removeShowingSites"
+ <paper-spinner-lite active="[[isLoading_]]"></paper-spinner-lite>
+ <paper-button class="secondary-button"
+ disabled$="[[isLoading_]]" id="removeShowingSites"
on-tap="onRemoveShowingSitesTap_" hidden$="[[!sites.length]]">
[[computeRemoveLabel_(filter)]]
</paper-button>
diff --git a/chromium/chrome/browser/resources/settings/site_settings/site_data.js b/chromium/chrome/browser/resources/settings/site_settings/site_data.js
index 097465dbc0a..e0e85e99d8b 100644
--- a/chromium/chrome/browser/resources/settings/site_settings/site_data.js
+++ b/chromium/chrome/browser/resources/settings/site_settings/site_data.js
@@ -60,6 +60,8 @@ Polymer({
observer: 'focusConfigChanged_',
},
+ isLoading_: Boolean,
+
/** @type {!Array<!LocalDataItem>} */
sites: {
type: Array,
@@ -99,6 +101,7 @@ Polymer({
settings.GlobalScrollTargetBehaviorImpl.currentRouteChanged.call(
this, currentRoute);
if (currentRoute == settings.routes.SITE_SETTINGS_SITE_DATA) {
+ this.isLoading_ = true;
this.browserProxy_.reloadCookies().then(this.updateSiteList_.bind(this));
}
},
@@ -138,12 +141,12 @@ Polymer({
* @private
*/
updateSiteList_: function() {
- this.browserProxy_
- .getDisplayList(this.filter, 0 /* start */, -1 /* count */)
- .then((listInfo) => {
- this.sites = listInfo.items;
- this.fire('site-data-list-complete');
- });
+ this.isLoading_ = true;
+ this.browserProxy_.getDisplayList(this.filter).then((listInfo) => {
+ this.sites = listInfo.items;
+ this.isLoading_ = false;
+ this.fire('site-data-list-complete');
+ });
},
/**
diff --git a/chromium/chrome/browser/resources/settings/site_settings/site_data_details_subpage.js b/chromium/chrome/browser/resources/settings/site_settings/site_data_details_subpage.js
index 8e8b802b64a..b749a1f87d4 100644
--- a/chromium/chrome/browser/resources/settings/site_settings/site_data_details_subpage.js
+++ b/chromium/chrome/browser/resources/settings/site_settings/site_data_details_subpage.js
@@ -15,6 +15,7 @@ var categoryLabels = {
indexed_db: loadTimeData.getString('cookieDatabaseStorage'),
local_storage: loadTimeData.getString('cookieLocalStorage'),
service_worker: loadTimeData.getString('cookieServiceWorker'),
+ shared_worker: loadTimeData.getString('cookieSharedWorker'),
media_license: loadTimeData.getString('cookieMediaLicense'),
};
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 4f903171bb8..9a10a9ebf6b 100644
--- a/chromium/chrome/browser/resources/settings/site_settings/site_details.html
+++ b/chromium/chrome/browser/resources/settings/site_settings/site_details.html
@@ -107,6 +107,12 @@
icon="cr:open-in-new" id="popups" label="$i18n{siteSettingsPopups}">
</site-details-permission>
<site-details-permission
+ category="{{ContentSettingsTypes.ADS}}"
+ icon="settings:ads" id="ads"
+ label="$i18n{siteSettingsAds}"
+ hidden$="[[!enableSafeBrowsingSubresourceFilter_]]">
+ </site-details-permission>
+ <site-details-permission
category="{{ContentSettingsTypes.BACKGROUND_SYNC}}"
icon="settings:sync" id="backgroundSync"
label="$i18n{siteSettingsBackgroundSync}">
@@ -126,6 +132,12 @@
id="midiDevices" label="$i18n{siteSettingsMidiDevices}">
</site-details-permission>
<site-details-permission
+ category="{{ContentSettingsTypes.CLIPBOARD}}"
+ icon="settings:clipboard" id="clipboard"
+ label="$i18n{siteSettingsClipboard}"
+ hidden$="[[!enableClipboardContentSetting_]]">
+ </site-details-permission>
+ <site-details-permission
category="{{ContentSettingsTypes.UNSANDBOXED_PLUGINS}}"
icon="cr:extension" id="unsandboxedPlugins"
label="$i18n{siteSettingsUnsandboxedPlugins}">
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 cc2e9aec5c9..b7fe492082f 100644
--- a/chromium/chrome/browser/resources/settings/site_settings/site_details.js
+++ b/chromium/chrome/browser/resources/settings/site_settings/site_details.js
@@ -51,6 +51,14 @@ Polymer({
},
/** @private */
+ enableSafeBrowsingSubresourceFilter_: {
+ type: Boolean,
+ value: function() {
+ return loadTimeData.getBoolean('enableSafeBrowsingSubresourceFilter');
+ },
+ },
+
+ /** @private */
enableSoundContentSetting_: {
type: Boolean,
value: function() {
@@ -58,6 +66,14 @@ Polymer({
},
},
+ /** @private */
+ enableClipboardContentSetting_: {
+ type: Boolean,
+ value: function() {
+ return loadTimeData.getBoolean('enableClipboardContentSetting');
+ },
+ },
+
/**
* The type of storage for the origin.
* @private
@@ -125,8 +141,9 @@ Polymer({
*/
onPermissionChanged_: function(category, origin, embeddingOrigin) {
if (this.origin === undefined || this.origin == '' ||
- origin === undefined || origin == '')
+ origin === undefined || origin == '') {
return;
+ }
if (!this.getCategoryList_().includes(category))
return;
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 c55f5716acf..fdf7d369701 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
@@ -15,7 +15,8 @@
<style include="settings-shared md-select"></style>
<div id="details">
<div id="permissionItem"
- class$="list-item [[permissionSourceStringClass_(site.source)]]">
+ class$="list-item [[permissionInfoStringClass_(site.source, category,
+ site.setting)]]">
<div>
<iron-icon icon="[[icon]]">
</iron-icon>
@@ -23,9 +24,14 @@
<div class="middle" id="permissionHeader">
[[label]]
<div class="secondary"
- hidden$="[[!hasPermissionSourceString_(site.source)]]"
- inner-h-t-m-l="[[permissionSourceString_(
+ hidden$="[[!hasPermissionInfoString_(site.source, category,
+ site.setting)]]"
+ inner-h-t-m-l="[[permissionInfoString_(
site.source,
+ category,
+ site.setting,
+ '$i18nPolymer{siteSettingsSourceAdsBlacklist}',
+ '$i18nPolymer{siteSettingsAdsBlockSingular}',
'$i18nPolymer{siteSettingsSourceEmbargo}',
'$i18nPolymer{siteSettingsSourceInsecureOrigin}',
'$i18nPolymer{siteSettingsSourceKillSwitch}',
@@ -41,8 +47,10 @@
<select id="permission" class="md-select"
aria-labelledby="permissionHeader"
on-change="onPermissionSelectionChange_"
- disabled$="[[!isPermissionUserControlled_(site.source)]]">
- <option id="default" value$="[[ContentSetting.DEFAULT]]">
+ disabled$="[[!isPermissionUserControlled_(site.source, category,
+ site.setting)]]">
+ <option id="default" value$="[[ContentSetting.DEFAULT]]"
+ hidden$="[[isAdsCategory_(category)]]">
[[defaultSettingString_(
defaultSetting_,
'$i18nPolymer{siteSettingsActionAskDefault}',
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 27c34c2dce2..e01a47a8478 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
@@ -118,38 +118,52 @@ Polymer({
},
/**
- * Returns true if there's a string to display that describes the source of
- * this permission's setting. Currently, this only gets called when
+ * Returns true if there's a string to display that provides more information
+ * about this permission's setting. Currently, this only gets called when
* |this.site| is updated.
* @param {!settings.SiteSettingSource} source The source of the permission.
+ * @param {!settings.ContentSettingsTypes} category The permission type.
+ * @param {!settings.ContentSetting} setting The permission setting.
+ * @return {boolean} Whether the permission will have a source string to
+ * display.
* @private
*/
- hasPermissionSourceString_: function(source) {
+ hasPermissionInfoString_: function(source, category, setting) {
return (
source != settings.SiteSettingSource.DEFAULT &&
source != settings.SiteSettingSource.PREFERENCE);
},
/**
- * Checks if there's a permission source string to display, and returns the
+ * Checks if there's a additional information to display, and returns the
* class name to apply to permissions if so.
+ * @param {!settings.SiteSettingSource} source The source of the permission.
+ * @param {!settings.ContentSettingsTypes} category The permission type.
+ * @param {!settings.ContentSetting} setting The permission setting.
* @return {string} CSS class applied when there is an additional description
* string.
* @private
*/
- permissionSourceStringClass_: function(source) {
- return this.hasPermissionSourceString_(source) ? 'two-line' : '';
+ permissionInfoStringClass_: function(source, category, setting) {
+ return this.hasPermissionInfoString_(source, category, setting) ?
+ 'two-line' :
+ '';
},
/**
- * Returns true if this permission's source is controlled by the user.
+ * Returns true if this permission can be controlled by the user.
+ * @param {!settings.SiteSettingSource} source The source of the permission.
+ * @param {!settings.ContentSettingsTypes} category The permission type.
+ * @param {!settings.ContentSetting} setting The permission setting.
* @return {boolean}
* @private
*/
- isPermissionUserControlled_: function(source) {
- // Users are able override embargo.
- return !this.hasPermissionSourceString_(source) ||
- source == settings.SiteSettingSource.EMBARGO;
+ isPermissionUserControlled_: function(source, category, setting) {
+ // Users are able override embargo and ads blacklisting.
+ return !this.hasPermissionInfoString_(source, category, setting) ||
+ source == settings.SiteSettingSource.EMBARGO ||
+ source == settings.SiteSettingSource.ADS_FILTER_BLACKLIST ||
+ source == settings.SiteSettingSource.ADS_BLOCKED;
},
/**
@@ -173,9 +187,25 @@ Polymer({
},
/**
- * Updates the string used to describe the source of this permission setting.
+ * Returns true if this permission is the Ads permission.
+ * @param {!settings.ContentSettingsTypes} category The permission type.
+ * @return {boolean}
+ * @private
+ */
+ isAdsCategory_: function(category) {
+ return category == settings.ContentSettingsTypes.ADS;
+ },
+
+ /**
+ * Updates the information string for the current permission.
* Currently, this only gets called when |this.site| is updated.
* @param {!settings.SiteSettingSource} source The source of the permission.
+ * @param {!settings.ContentSettingsTypes} category The permission type.
+ * @param {!settings.ContentSetting} setting The permission setting.
+ * @param {!string} adsBlacklistString The string to show if the site is
+ * blacklisted for showing bad ads.
+ * @param {!string} adsBlockString The string to show if ads are blocked, but
+ * the site is not blacklisted.
* @param {!string} embargoString
* @param {!string} insecureOriginString
* @param {!string} killSwitchString
@@ -187,8 +217,9 @@ Polymer({
* @param {!string} policyAskString
* @private
*/
- permissionSourceString_: function(
- source, embargoString, insecureOriginString, killSwitchString,
+ permissionInfoString_: function(
+ source, category, setting, adsBlacklistString, adsBlockString,
+ embargoString, insecureOriginString, killSwitchString,
extensionAllowString, extensionBlockString, extensionAskString,
policyAllowString, policyBlockString, policyAskString) {
@@ -204,12 +235,25 @@ Polymer({
policyStrings[settings.ContentSetting.BLOCK] = policyBlockString;
policyStrings[settings.ContentSetting.ASK] = policyAskString;
- if (source == settings.SiteSettingSource.DRM_DISABLED) {
+ if (source == settings.SiteSettingSource.ADS_FILTER_BLACKLIST) {
+ assert(
+ settings.ContentSettingsTypes.ADS == category,
+ 'The ads filter blacklist only applies to Ads.');
+ return adsBlacklistString;
+ } else if (source == settings.SiteSettingSource.ADS_BLOCKED) {
assert(
- settings.ContentSetting.BLOCK == this.site.setting,
+ settings.ContentSettingsTypes.ADS == category,
+ 'The Ads user-blocked source only applies to Ads.');
+ assert(
+ settings.ContentSetting.ALLOW != setting,
+ 'The Ads setting must be blocked for this source.');
+ return adsBlockString;
+ } else if (source == settings.SiteSettingSource.DRM_DISABLED) {
+ assert(
+ settings.ContentSetting.BLOCK == setting,
'If DRM is disabled, Protected Content must be blocked.');
assert(
- settings.ContentSettingsTypes.PROTECTED_CONTENT == this.category,
+ settings.ContentSettingsTypes.PROTECTED_CONTENT == category,
'The DRM disabled source only applies to Protected Content.');
return this.i18nAdvanced('siteSettingsSourceDrmDisabled', {
substitutions:
@@ -217,29 +261,28 @@ Polymer({
});
} else if (source == settings.SiteSettingSource.EMBARGO) {
assert(
- settings.ContentSetting.BLOCK == this.site.setting,
+ settings.ContentSetting.BLOCK == setting,
'Embargo is only used to block permissions.');
return embargoString;
} else if (source == settings.SiteSettingSource.EXTENSION) {
- return extensionStrings[this.site.setting];
+ return extensionStrings[setting];
} else if (source == settings.SiteSettingSource.INSECURE_ORIGIN) {
assert(
- settings.ContentSetting.BLOCK == this.site.setting,
+ settings.ContentSetting.BLOCK == setting,
'Permissions can only be blocked due to insecure origins.');
return insecureOriginString;
} else if (source == settings.SiteSettingSource.KILL_SWITCH) {
assert(
- settings.ContentSetting.BLOCK == this.site.setting,
+ settings.ContentSetting.BLOCK == setting,
'The permissions kill switch can only be used to block permissions.');
return killSwitchString;
} else if (source == settings.SiteSettingSource.POLICY) {
- return policyStrings[this.site.setting];
+ return policyStrings[setting];
} else if (
source == settings.SiteSettingSource.DEFAULT ||
source == settings.SiteSettingSource.PREFERENCE) {
return '';
}
- assertNotReached(
- `No string for ${this.category} setting source '${source}'`);
+ assertNotReached(`No string for ${category} setting source '${source}'`);
},
});
diff --git a/chromium/chrome/browser/resources/settings/site_settings/site_settings_prefs_browser_proxy.js b/chromium/chrome/browser/resources/settings/site_settings/site_settings_prefs_browser_proxy.js
index 6ab9c0a38a5..e19f90cfec8 100644
--- a/chromium/chrome/browser/resources/settings/site_settings/site_settings_prefs_browser_proxy.js
+++ b/chromium/chrome/browser/resources/settings/site_settings/site_settings_prefs_browser_proxy.js
@@ -266,6 +266,14 @@ cr.define('settings', function() {
* @param {string} host The host to remove zoom levels for.
*/
removeZoomLevel(host) {}
+
+ // <if expr="chromeos">
+ /**
+ * Links to com.android.settings.Settings$ManageDomainUrlsActivity on ARC
+ * side, this is to manage app preferences.
+ */
+ showAndroidManageAppLinks() {}
+ // </if>
}
/**
@@ -386,6 +394,13 @@ cr.define('settings', function() {
removeZoomLevel(host) {
chrome.send('removeZoomLevel', [host]);
}
+
+ // <if expr="chromeos">
+ /** @override */
+ showAndroidManageAppLinks() {
+ chrome.send('showAndroidManageAppLinks');
+ }
+ // </if>
}
// The singleton instance_ is replaced with a test version of this wrapper
diff --git a/chromium/chrome/browser/resources/settings/site_settings/usb_devices.html b/chromium/chrome/browser/resources/settings/site_settings/usb_devices.html
index 7388b9f6fd2..0d49492c635 100644
--- a/chromium/chrome/browser/resources/settings/site_settings/usb_devices.html
+++ b/chromium/chrome/browser/resources/settings/site_settings/usb_devices.html
@@ -21,7 +21,7 @@
}
</style>
- <div class="settings-box" hidden$="[[hasDevices_(devices_)]]">
+ <div class="settings-box first" hidden$="[[hasDevices_(devices_)]]">
$i18n{noUsbDevicesFound}
</div>
<template is="dom-repeat" items="[[devices_]]">
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 b0d1207994a..c523b2f8536 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
@@ -234,8 +234,8 @@
<div class="secondary" id="soundSecondary">
[[defaultSettingLabel_(
default_.sound,
- '$i18nPolymer{siteSettingsAllowed}',
- '$i18nPolymer{siteSettingsBlocked}')]]
+ '$i18nPolymer{siteSettingsSoundAllow}',
+ '$i18nPolymer{siteSettingsSoundBlock}')]]
</div>
</div>
<button class="subpage-arrow" is="paper-icon-button-light"
@@ -317,6 +317,26 @@
aria-label="$i18n{siteSettingsMidiDevices}"
aria-describedby="midiDevicesSecondary"></button>
</div>
+ <template is="dom-if" if="[[enableClipboardContentSetting_]]">
+ <div id="clipboard" class="settings-box two-line"
+ category$="[[ContentSettingsTypes.CLIPBOARD]]"
+ data-route="SITE_SETTINGS_CLIPBOARD" on-tap="onTapNavigate_"
+ actionable>
+ <iron-icon icon="settings:clipboard"></iron-icon>
+ <div class="middle">
+ $i18n{siteSettingsClipboard}
+ <div class="secondary" id="clipboardSecondary">
+ [[defaultSettingLabel_(
+ default_.clipboard,
+ '$i18nPolymer{siteSettingsAskBeforeAccessing}',
+ '$i18nPolymer{siteSettingsBlocked}')]]
+ </div>
+ </div>
+ <button class="subpage-arrow" is="paper-icon-button-light"
+ aria-label="$i18n{siteSettingsClipboard}"
+ aria-describedby="clipboardSecondary"></button>
+ </div>
+ </template>
<div id="zoom-levels" class="settings-box"
category$="[[ContentSettingsTypes.ZOOM_LEVELS]]"
data-route="SITE_SETTINGS_ZOOM_LEVELS" on-tap="onTapNavigate_"
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 e3354d023cb..cc72fa6d4fa 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
@@ -52,6 +52,14 @@ Polymer({
},
/** @private */
+ enableClipboardContentSetting_: {
+ type: Boolean,
+ value: function() {
+ return loadTimeData.getBoolean('enableClipboardContentSetting');
+ }
+ },
+
+ /** @private */
enableSoundContentSetting_: {
type: Boolean,
value: function() {
@@ -96,6 +104,7 @@ Polymer({
[R.SITE_SETTINGS_USB_DEVICES, 'usb-devices'],
[R.SITE_SETTINGS_PDF_DOCUMENTS, 'pdf-documents'],
[R.SITE_SETTINGS_PROTECTED_CONTENT, 'protected-content'],
+ [R.SITE_SETTINGS_CLIPBOARD, "clipboard"],
].forEach(pair => {
var route = pair[0];
var id = pair[1];
diff --git a/chromium/chrome/browser/resources/signin/dice_sync_confirmation/sync_confirmation.css b/chromium/chrome/browser/resources/signin/dice_sync_confirmation/sync_confirmation.css
new file mode 100644
index 00000000000..a7102e677a0
--- /dev/null
+++ b/chromium/chrome/browser/resources/signin/dice_sync_confirmation/sync_confirmation.css
@@ -0,0 +1,322 @@
+/* Copyright 2017 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file. */
+
+.picture img {
+ border-radius: 50%;
+ max-height: 100%;
+ max-width: 100%;
+}
+
+.details {
+ padding: 0 24px;
+}
+
+#picture-container {
+ align-items: center;
+ display: flex;
+ justify-content: center;
+ padding-bottom: 32px;
+ padding-top: 24px;
+}
+
+.picture {
+ -webkit-margin-start: 84px;
+ height: 96px;
+ position: relative;
+ width: 96px;
+}
+
+#profile-picture,
+.checkmark-circle {
+ position: absolute;
+}
+
+.message-container {
+ display: flex;
+ margin-bottom: 16px;
+}
+
+.message-container:last-child {
+ margin-bottom: 32px;
+}
+
+.message-container .logo {
+ -webkit-margin-end: 20px;
+ background-size: cover;
+ flex-shrink: 0;
+ height: 20px;
+ position: relative;
+ top: -2px;
+ width: 20px;
+}
+
+#chrome-logo {
+ background-image: url(../../../../../ui/webui/resources/images/200-logo_chrome.png);
+}
+
+#googleg-logo {
+ background-image: url(../../../../../ui/webui/resources/images/200-logo_googleg.png);
+}
+
+.message-container .title {
+ font-weight: 500;
+ margin-bottom: 4px;
+}
+
+.message-container .body {
+ color: #646464;
+}
+
+.message-container .text {
+ line-height: 20px;
+}
+
+.message-container #activityControlsCheckbox {
+ -webkit-margin-start: 40px;
+}
+
+#undoButton {
+ -webkit-margin-start: 8px;
+}
+
+#syncDisabledDetails {
+ line-height: 20px;
+ margin-bottom: 8px;
+ margin-top: 16px;
+ padding: 0 24px;
+}
+
+#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/signin/dice_sync_confirmation/sync_confirmation.html b/chromium/chrome/browser/resources/signin/dice_sync_confirmation/sync_confirmation.html
new file mode 100644
index 00000000000..16ae2127862
--- /dev/null
+++ b/chromium/chrome/browser/resources/signin/dice_sync_confirmation/sync_confirmation.html
@@ -0,0 +1,102 @@
+<!doctype html>
+<html dir="$i18n{textdirection}" lang="$i18n{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="import" href="chrome://resources/polymer/v1_0/paper-styles/color.html">
+ <link rel="import" href="signin_shared_css.html">
+ <link rel="stylesheet" href="chrome://resources/css/text_defaults_md.css">
+ <link rel="stylesheet" href="sync_confirmation.css"></link>
+ <style is="custom-style" include="signin-dialog-shared">
+<if expr="is_macosx or is_linux">
+ #undoButton {
+ -webkit-margin-end: 8px;
+ -webkit-margin-start: 0;
+ }
+</if>
+ </style>
+ </head>
+ <body>
+ <div class="container">
+ <div class="top-title-bar">$i18n{syncConfirmationTitle}</div>
+ <div class="details" id="syncConfirmationDetails">
+ <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">
+ <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="message-container">
+ <!--
+ "Chrome sync" is the Google Cloud Based services used for sync. Thus
+ this section uses the Chrome logo even for Chromium builds.
+ -->
+ <div id="chrome-logo" class="logo"></div>
+ <div>
+ <div class="title">$i18n{syncConfirmationChromeSyncTitle}</div>
+ <div class="body text">$i18n{syncConfirmationChromeSyncBody}</div>
+ </div>
+ </div>
+ <div class="message-container">
+ <!--
+ This section uses the Google logo even for Chromium builds as the
+ user can personalize their Google services from this screen.
+ -->
+ <div id="googleg-logo" class="logo"></div>
+ <div>
+ <div class="title">
+ $i18n{syncConfirmationPersonalizeServicesTitle}
+ </div>
+ <div class="body text">
+ $i18n{syncConfirmationPersonalizeServicesBody}
+ </div>
+ </div>
+ </div>
+ <div class="message-container">
+ <div class="body">$i18nRaw{syncConfirmationSyncSettingsLinkBody}</div>
+ </div>
+ </div>
+ <div class="details" id="syncDisabledDetails">
+ <div class="body text">$i18n{syncDisabledConfirmationDetails}</div>
+ </div>
+ <div class="action-container">
+ <paper-button class="primary-action" id="confirmButton">
+ $i18n{syncConfirmationConfirmLabel}
+ </paper-button>
+ <paper-button class="secondary-action" id="undoButton">
+ $i18n{syncConfirmationUndoLabel}
+ </paper-button>
+ </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>
+</html>
diff --git a/chromium/chrome/browser/resources/signin/dice_sync_confirmation/sync_confirmation.js b/chromium/chrome/browser/resources/signin/dice_sync_confirmation/sync_confirmation.js
new file mode 100644
index 00000000000..315f22e296a
--- /dev/null
+++ b/chromium/chrome/browser/resources/signin/dice_sync_confirmation/sync_confirmation.js
@@ -0,0 +1,72 @@
+/* Copyright 2017 The Chromium 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);
+ if (loadTimeData.getBoolean('isSyncAllowed')) {
+ $('settingsLink').addEventListener('click', onGoToSettings);
+ $('profile-picture').addEventListener('load', onPictureLoaded);
+ $('syncDisabledDetails').hidden = true;
+ } else {
+ $('syncConfirmationDetails').hidden = true;
+ }
+
+ // Prefer using |document.body.offsetHeight| instead of
+ // |document.body.scrollHeight| as it returns the correct height of the
+ // even when the page zoom in Chrome is different than 100%.
+ chrome.send('initializedWithSize', [document.body.offsetHeight]);
+ }
+
+ function clearFocus() {
+ document.activeElement.blur();
+ }
+
+ function setUserImageURL(url) {
+ if (loadTimeData.getBoolean('isSyncAllowed')) {
+ $('profile-picture').src = url;
+ }
+ }
+
+ function onPictureLoaded(e) {
+ if (loadTimeData.getBoolean('isSyncAllowed')) {
+ $('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.key == 'Enter' &&
+ !/^(A|PAPER-(BUTTON|CHECKBOX))$/.test(document.activeElement.tagName)) {
+ $('confirmButton').click();
+ e.preventDefault();
+ }
+ }
+
+ return {
+ clearFocus: clearFocus,
+ initialize: initialize,
+ setUserImageURL: setUserImageURL
+ };
+});
+
+document.addEventListener('DOMContentLoaded', sync.confirmation.initialize);
diff --git a/chromium/chrome/browser/resources/snippets_internals.html b/chromium/chrome/browser/resources/snippets_internals.html
index 07898877d79..27ee59e3a95 100644
--- a/chromium/chrome/browser/resources/snippets_internals.html
+++ b/chromium/chrome/browser/resources/snippets_internals.html
@@ -99,6 +99,11 @@ found in the LICENSE file.
<div>
<button id="debug-log-dump" type="button">Dump the debug log</button>
</div>
+ <div>
+ <button type="button" class="submit-clear-cached-suggestions">
+ Clear cached suggestions
+ </button>
+ </div>
</div>
</div>
@@ -150,10 +155,6 @@ found in the LICENSE file.
</div>
<div class="vertical-buttons">
<button jsvalues="category-id:categoryId" type="button"
- class="submit-clear-cached-suggestions">
- Clear cached suggestions
- </button>
- <button jsvalues="category-id:categoryId" type="button"
class="toggle-dismissed-suggestions">
Show dismissed suggestions
</button>
diff --git a/chromium/chrome/browser/resources/snippets_internals.js b/chromium/chrome/browser/resources/snippets_internals.js
index 63f19c5267c..eb316f77664 100644
--- a/chromium/chrome/browser/resources/snippets_internals.js
+++ b/chromium/chrome/browser/resources/snippets_internals.js
@@ -111,8 +111,7 @@ cr.define('chrome.SnippetsInternals', function() {
function onClearCachedButtonClicked(event) {
event.preventDefault();
- var id = parseInt(event.currentTarget.getAttribute('category-id'), 10);
- chrome.send('clearCachedSuggestions', [id]);
+ chrome.send('clearCachedSuggestions');
}
function onClearDismissedButtonClicked(event) {
diff --git a/chromium/chrome/browser/resources/task_scheduler_internals/resources.grd b/chromium/chrome/browser/resources/task_scheduler_internals/resources.grd
index 08419ac7291..7fee6ca5144 100644
--- a/chromium/chrome/browser/resources/task_scheduler_internals/resources.grd
+++ b/chromium/chrome/browser/resources/task_scheduler_internals/resources.grd
@@ -14,13 +14,16 @@
<includes>
<include name="IDR_TASK_SCHEDULER_INTERNALS_RESOURCES_INDEX_HTML"
file="index.html"
- type="BINDATA" />
+ type="BINDATA"
+ compress="gzip" />
<include name="IDR_TASK_SCHEDULER_INTERNALS_RESOURCES_INDEX_CSS"
file="index.css"
- type="BINDATA" />
+ type="BINDATA"
+ compress="gzip" />
<include name="IDR_TASK_SCHEDULER_INTERNALS_RESOURCES_INDEX_JS"
file="index.js"
- type="BINDATA" />
+ type="BINDATA"
+ compress="gzip" />
</includes>
</release>
</grit>
diff --git a/chromium/chrome/browser/resources/unpack_pak.py b/chromium/chrome/browser/resources/unpack_pak.py
index 8eda2e871fb..cf77483dfad 100755
--- a/chromium/chrome/browser/resources/unpack_pak.py
+++ b/chromium/chrome/browser/resources/unpack_pak.py
@@ -25,7 +25,7 @@ def unpack(pak_path, out_path):
pak_dir = os.path.dirname(pak_path)
pak_id = os.path.splitext(os.path.basename(pak_path))[0]
- data = data_pack.DataPack.ReadDataPack(pak_path)
+ data = data_pack.ReadDataPack(pak_path)
# Associate numerical grit IDs to strings.
# For example 120045 -> 'IDR_SETTINGS_ABOUT_PAGE_HTML'
diff --git a/chromium/chrome/browser/resources/welcome/default.webp b/chromium/chrome/browser/resources/welcome/default.webp
new file mode 100644
index 00000000000..eb75d055893
--- /dev/null
+++ b/chromium/chrome/browser/resources/welcome/default.webp
Binary files differ
diff --git a/chromium/chrome/browser/resources/welcome/dice_welcome/compiled_resources2.gyp b/chromium/chrome/browser/resources/welcome/dice_welcome/compiled_resources2.gyp
new file mode 100644
index 00000000000..9b34e91a70b
--- /dev/null
+++ b/chromium/chrome/browser/resources/welcome/dice_welcome/compiled_resources2.gyp
@@ -0,0 +1,24 @@
+# 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': 'welcome_app',
+ 'dependencies': [
+ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
+ '<(EXTERNS_GYP):web_animations',
+ 'welcome_browser_proxy',
+ ],
+ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+ },
+ {
+ 'target_name': 'welcome_browser_proxy',
+ '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/welcome/dice_welcome/welcome.css b/chromium/chrome/browser/resources/welcome/dice_welcome/welcome.css
new file mode 100644
index 00000000000..07febed0c40
--- /dev/null
+++ b/chromium/chrome/browser/resources/welcome/dice_welcome/welcome.css
@@ -0,0 +1,33 @@
+/* Copyright 2017 The Chromium 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 {
+ align-items: center;
+ color: var(--google-grey-700);
+ display: flex;
+ flex-direction: column;
+ font-size: 100%;
+ justify-content: center;
+ margin: 0;
+ min-height: 100vh;
+ text-align: center;
+}
+
+.watermark {
+ -webkit-mask-image: url(chrome://resources/images/google_logo.svg);
+ -webkit-mask-repeat: no-repeat;
+ -webkit-mask-size: 100%;
+ animation: fadeIn 1s cubic-bezier(0, 0, .2, 1) both;
+ background: var(--paper-grey-400);
+ bottom: 24px;
+ height: 24px;
+ position: absolute;
+ width: 74px;
+}
+
+@media(max-height: 608px) {
+ .watermark {
+ display: none;
+ }
+}
diff --git a/chromium/chrome/browser/resources/welcome/dice_welcome/welcome.html b/chromium/chrome/browser/resources/welcome/dice_welcome/welcome.html
new file mode 100644
index 00000000000..f62bf685ccd
--- /dev/null
+++ b/chromium/chrome/browser/resources/welcome/dice_welcome/welcome.html
@@ -0,0 +1,18 @@
+<!doctype html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>$i18n{headerText}</title>
+
+ <link rel="import" href="chrome://resources/html/polymer.html">
+ <link rel="import" href="chrome://resources/polymer/v1_0/paper-styles/color.html">
+ <link rel="import" href="welcome_app.html">
+
+ <link rel="stylesheet" href="chrome://resources/css/text_defaults_md.css">
+ <link rel="stylesheet" href="chrome://welcome/welcome.css">
+ </head>
+ <body>
+ <welcome-app></welcome-app>
+ <div class="watermark"></div>
+ </body>
+</html>
diff --git a/chromium/chrome/browser/resources/welcome/dice_welcome/welcome_app.html b/chromium/chrome/browser/resources/welcome/dice_welcome/welcome_app.html
new file mode 100644
index 00000000000..1ecd003b38f
--- /dev/null
+++ b/chromium/chrome/browser/resources/welcome/dice_welcome/welcome_app.html
@@ -0,0 +1,205 @@
+<link rel="import" href="chrome://resources/html/polymer.html">
+
+<link rel="import" href="chrome://resources/html/action_link.html">
+<link rel="import" href="chrome://resources/html/action_link_css.html">
+<link rel="import" href="chrome://resources/html/cr.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-styles/color.html">
+<link rel="import" href="welcome_browser_proxy.html">
+
+<dom-module id="welcome-app">
+ <template>
+ <style include="action-link">
+ @keyframes slideUpContent {
+ from {
+ transform: translateY(120px);
+ }
+ }
+
+ @keyframes fadeIn {
+ from {
+ opacity: 0;
+ }
+ }
+
+ @keyframes fadeInAndSlideUp {
+ from {
+ opacity: 0;
+ transform: translateY(8px);
+ }
+ }
+
+ @keyframes fadeOutAndSlideUp {
+ to {
+ height: 0;
+ opacity: 0;
+ transform: translateY(-8px);
+ }
+ }
+
+ @keyframes spin {
+ from {
+ transform: rotate(1440deg) scale(0.8);
+ }
+ }
+
+ @keyframes colorize {
+ from {
+ filter: grayscale(100%) brightness(128%) contrast(20%) brightness(161%);
+ opacity: .6;
+ }
+ }
+
+ @keyframes bounce {
+ 0% {
+ transform: matrix3d(0.8, 0, 0, 0, 0, 0.8, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
+ }
+ 7.61% {
+ transform: matrix3d(0.907, 0, 0, 0, 0, 0.907, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
+ }
+ 11.41% {
+ transform: matrix3d(0.948, 0, 0, 0, 0, 0.948, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
+ }
+ 15.12% {
+ transform: matrix3d(0.976, 0, 0, 0, 0, 0.976, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
+ }
+ 18.92% {
+ transform: matrix3d(0.996, 0, 0, 0, 0, 0.996, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
+ }
+ 22.72% {
+ transform: matrix3d(1.008, 0, 0, 0, 0, 1.008, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
+ }
+ 30.23% {
+ transform: matrix3d(1.014, 0, 0, 0, 0, 1.014, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
+ }
+ 50.25% {
+ transform: matrix3d(1.003, 0, 0, 0, 0, 1.003, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
+ }
+ 70.27% {
+ transform: matrix3d(0.999, 0, 0, 0, 0, 0.999, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
+ }
+ 100% {
+ transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
+ }
+ }
+
+ .slider {
+ align-items: center;
+ animation: slideUpContent 600ms 3s cubic-bezier(.4, .2, 0, 1) both;
+ display: flex;
+ flex: 1;
+ flex-direction: column;
+ justify-content: center;
+ max-width: 500px;
+ }
+
+ .heading-container {
+ animation: fadeInAndSlideUp 1s 600ms cubic-bezier(.4, .2, 0, 1) both;
+ color: var(--paper-grey-800);
+ font-size: 2.5em;
+ line-height: 1em;
+ margin-bottom: 0.25em;
+ margin-top: 1.5em;
+ position: relative;
+ }
+
+ .heading {
+ animation: fadeOutAndSlideUp 600ms 2.6s cubic-bezier(.4, .2, 0, 1) forwards;
+ /* Makes sure fading-in/out doesn't impact the logo position. */
+ position: absolute;
+ }
+
+ .second-heading {
+ animation: fadeInAndSlideUp 600ms 3s cubic-bezier(.4, .2, 0, 1) both;
+ font-size: 0.6em;
+ }
+
+ #logoWrapper {
+ animation: fadeIn 600ms both, bounce 1s 600ms linear both;
+ height: 96px;
+ position: relative;
+ width: 96px;
+ }
+
+ #logo {
+ animation: spin 2.4s cubic-bezier(.4, .2, 0, 1) both,
+ colorize 300ms 700ms linear both;
+ background-image: -webkit-image-set(url(chrome://welcome/logo.png) 1x,
+ url(chrome://welcome/logo2x.png) 2x);
+ background-size: 100%;
+ height: 96px;
+ width: 96px;
+ }
+
+ .signin {
+ animation: fadeInAndSlideUp 600ms 3s cubic-bezier(.4, .2, 0, 1) both;
+ }
+
+ .signin-description {
+ font-size: 1em;
+ line-height: 1.725em;
+ max-width: 344px;
+ }
+
+ .signin-buttons {
+ align-items: center;
+ display: flex;
+ flex-direction: row;
+ font-size: .8125em;
+ font-weight: 500;
+ justify-content: space-between;
+ margin-top: 2.5em;
+ text-transform: uppercase;
+ }
+
+ #acceptButton {
+ -webkit-font-smoothing: antialiased;
+ background: var(--google-blue-500);
+ border-radius: 2px;
+ box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .1);
+ color: white;
+ line-height: 2.25rem;
+ padding: 0 2em;
+ transition: 300ms cubic-bezier(.4, .2, 0, 1);
+ will-change: box-shadow;
+ }
+
+ #acceptButton:hover {
+ background: var(--paper-blue-a400);
+ box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .1), 0 1px 2px rgba(0, 0, 0, .24);
+ }
+
+ #acceptButton.keyboard-focus {
+ background: var(--google-blue-700);
+ }
+
+ #declineButton {
+ color: var(--paper-grey-800);
+ display: inline-block;
+ margin: 1.5em;
+ text-decoration: none;
+ }
+ </style>
+ <div class="slider">
+ <div id="logoWrapper">
+ <div id="logo" on-tap="onLogoTap_"></div>
+ </div>
+ <div class="heading-container">
+ <div class="heading">$i18n{headerText}</div>
+ <div class="second-heading">$i18n{secondHeaderText}</div>
+ </div>
+ <div class="signin">
+ <div class="signin-description">$i18n{descriptionText}</div>
+ <div class="signin-buttons">
+ <a is="action-link" id="declineButton" on-tap="onDecline_">
+ $i18n{declineText}
+ </a>
+ <paper-button id="acceptButton" on-tap="onAccept_">
+ $i18n{acceptText}
+ </paper-button>
+ </div>
+ </div>
+ </div>
+ </template>
+ <script src="welcome_app.js"></script>
+</dom-module> \ No newline at end of file
diff --git a/chromium/chrome/browser/resources/welcome/dice_welcome/welcome_app.js b/chromium/chrome/browser/resources/welcome/dice_welcome/welcome_app.js
new file mode 100644
index 00000000000..8b663ea5f91
--- /dev/null
+++ b/chromium/chrome/browser/resources/welcome/dice_welcome/welcome_app.js
@@ -0,0 +1,36 @@
+// Copyright 2017 The Chromium 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: 'welcome-app',
+
+ welcomeBrowserProxy_: null,
+
+ /** @override */
+ ready: function() {
+ this.welcomeBrowserProxy_ = welcome.WelcomeBrowserProxyImpl.getInstance();
+ },
+
+ /** @private */
+ onAccept_: function() {
+ this.welcomeBrowserProxy_.handleActivateSignIn();
+ },
+
+ /** @private */
+ onDecline_: function() {
+ this.welcomeBrowserProxy_.handleUserDecline();
+ },
+
+ /** @private */
+ onLogoTap_: function() {
+ this.$.logo.animate(
+ {
+ transform: ['none', 'rotate(-10turn)'],
+ },
+ /** @type {!KeyframeEffectOptions} */ ({
+ duration: 500,
+ easing: 'cubic-bezier(1, 0, 0, 1)',
+ }));
+ },
+});
diff --git a/chromium/chrome/browser/resources/welcome/dice_welcome/welcome_browser_proxy.html b/chromium/chrome/browser/resources/welcome/dice_welcome/welcome_browser_proxy.html
new file mode 100644
index 00000000000..24f332053f2
--- /dev/null
+++ b/chromium/chrome/browser/resources/welcome/dice_welcome/welcome_browser_proxy.html
@@ -0,0 +1,2 @@
+<link rel="import" href="chrome://resources/html/cr.html">
+<script src="welcome_browser_proxy.js"></script>
diff --git a/chromium/chrome/browser/resources/welcome/dice_welcome/welcome_browser_proxy.js b/chromium/chrome/browser/resources/welcome/dice_welcome/welcome_browser_proxy.js
new file mode 100644
index 00000000000..9511779ccfb
--- /dev/null
+++ b/chromium/chrome/browser/resources/welcome/dice_welcome/welcome_browser_proxy.js
@@ -0,0 +1,37 @@
+// Copyright 2017 The Chromium 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 by the welcome page to interact with
+ * the browser.
+ */
+
+cr.define('welcome', function() {
+
+ /** @interface */
+ class WelcomeBrowserProxy {
+ handleActivateSignIn() {}
+ handleUserDecline() {}
+ }
+
+ /** @implements {welcome.WelcomeBrowserProxy} */
+ class WelcomeBrowserProxyImpl {
+ /** @override */
+ handleActivateSignIn() {
+ chrome.send('handleActivateSignIn');
+ }
+
+ /** @override */
+ handleUserDecline() {
+ chrome.send('handleUserDecline');
+ }
+ }
+
+ cr.addSingletonGetter(WelcomeBrowserProxyImpl);
+
+ return {
+ WelcomeBrowserProxy: WelcomeBrowserProxy,
+ WelcomeBrowserProxyImpl: WelcomeBrowserProxyImpl,
+ };
+});
diff --git a/chromium/chrome/browser/resources/welcome/win10/pin-small.webp b/chromium/chrome/browser/resources/welcome/pin.webp
index a5281755428..a5281755428 100644
--- a/chromium/chrome/browser/resources/welcome/win10/pin-small.webp
+++ b/chromium/chrome/browser/resources/welcome/pin.webp
Binary files differ
diff --git a/chromium/chrome/browser/resources/welcome/welcome.css b/chromium/chrome/browser/resources/welcome/welcome.css
index 78c743be800..bf81b228580 100644
--- a/chromium/chrome/browser/resources/welcome/welcome.css
+++ b/chromium/chrome/browser/resources/welcome/welcome.css
@@ -215,7 +215,7 @@ body {
}
.watermark {
- -webkit-mask-image: url(chrome://welcome/watermark.svg);
+ -webkit-mask-image: url(chrome://resources/images/google_logo.svg);
-webkit-mask-repeat: no-repeat;
-webkit-mask-size: 100%;
animation: fadeIn 1s cubic-bezier(0, 0, .2, 1) both;
diff --git a/chromium/chrome/browser/resources/welcome/win10/inline.css b/chromium/chrome/browser/resources/welcome/welcome_win10.css
index 13e1025a420..13e1025a420 100644
--- a/chromium/chrome/browser/resources/welcome/win10/inline.css
+++ b/chromium/chrome/browser/resources/welcome/welcome_win10.css
diff --git a/chromium/chrome/browser/resources/welcome/win10/inline.html b/chromium/chrome/browser/resources/welcome/welcome_win10.html
index fa5e6acc374..1689bdfbe12 100644
--- a/chromium/chrome/browser/resources/welcome/win10/inline.html
+++ b/chromium/chrome/browser/resources/welcome/welcome_win10.html
@@ -16,12 +16,13 @@
<link rel="import" href="chrome://resources/polymer/v1_0/paper-styles/color.html">
<link rel="stylesheet" href="chrome://resources/css/text_defaults_md.css">
- <link rel="stylesheet" href="/welcome.css">
+ <link rel="stylesheet" href="/welcome_win10.css">
- <dom-module id="welcome-win10-inline">
+ <dom-module id="welcome-win10">
<template>
<style include="action-link">
:host {
+ --expandable-section-height: 28.375em;
align-items: flex-start;
display: inline-flex;
flex-direction: column;
@@ -119,7 +120,7 @@
}
.section.expandable .section-steps {
- height: 26.375em;
+ height: var(--expandable-section-height);
max-height: 0;
opacity: 0;
transition: max-height 300ms cubic-bezier(.4, .2, 0, 1) 50ms,
@@ -128,7 +129,7 @@
}
.section.expandable.expanded .section-steps {
- max-height: 26.375em;
+ max-height: var(--expandable-section-height);
opacity: 1;
transition: max-height 300ms cubic-bezier(.4, .2, 0, 1) 50ms,
opacity 150ms 250ms;
@@ -219,16 +220,6 @@
cursor: default;
}
- #browser-overlay {
- left: 41%;
- top: 81%;
- }
-
- #edge-overlay {
- left: 49%;
- top: 88%;
- }
-
#taskbar-overlay {
left: 31%;
top: 73%;
@@ -240,6 +231,16 @@
font-weight: 500;
}
+ #switch-anyway-overlay {
+ left: 38%;
+ top: 83%;
+ }
+
+ #switch-anyway-overlay div {
+ color: rgb(0, 117, 218);
+ font-family: Segoe UI;
+ }
+
#icon-overlay {
background-image: url(chrome://welcome-win10/logo-small.png);
background-size: cover;
@@ -252,32 +253,24 @@
/* These values are precisely set so that the text over the screenshot
* starts scaling at the same time the image starts scaling too. */
@media (max-width: 626px) {
- #browser-overlay {
- font-size: 1.28vw;
- }
-
- #edge-overlay {
- font-size: 1.44vw;
- }
-
#taskbar-overlay {
font-size: 1.95vw;
}
+
+ #switch-anyway-overlay {
+ font-size: 1.92vw;
+ }
}
/* Font-sizes used when the screenshot exactly reaches its max size. */
@media (min-width: 626px) {
- #browser-overlay {
- font-size: 8px;
- }
-
- #edge-overlay {
- font-size: 9px;
- }
-
#taskbar-overlay {
font-size: 12.2px;
}
+
+ #switch-anyway-overlay {
+ font-size: 12px;
+ }
}
</style>
<div class="header-logo" role="presentation"></div>
@@ -311,21 +304,23 @@
$i18n{openSettingsText}
</a>
</li>
+ <template is="dom-if" if="[[!isAccelerated]]">
+ <li>
+ <div role="presentation">$i18nRaw{clickEdgeText}</div>
+ </li>
+ </template>
+ <li>
+ <div role="presentation">$i18nRaw{clickSelectChrome}</div>
+ </li>
<li>
- <div role="presentation">$i18nRaw{clickEdgeText}</div>
+ <div role="presentation">$i18nRaw{clickSwitchAnywayText}</div>
<div class="screenshot-image" id="default-image"
role="presentation">
- <div class="screenshot-overlay" id="browser-overlay">
- <div aria-hidden="true">$i18n{webBrowserLabel}</div>
- </div>
- <div class="screenshot-overlay" id="edge-overlay">
- <div aria-hidden="true">$i18n{microsoftEdgeLabel}</div>
+ <div class="screenshot-overlay" id="switch-anyway-overlay">
+ <div aria-hidden="true">$i18n{switchAnywayLabel}</div>
</div>
</div>
</li>
- <li>
- <div role="presentation">$i18nRaw{clickSelectChrome}</div>
- </li>
</ol>
</div>
<template is="dom-if" if="[[isCombined]]">
@@ -363,10 +358,10 @@
$i18n{continueText}
</paper-button>
</template>
- <script src="/welcome.js"></script>
+ <script src="/welcome_win10.js"></script>
</dom-module>
</head>
<body>
- <welcome-win10-inline></welcome-win10-inline>
+ <welcome-win10></welcome-win10>
</body>
</html>
diff --git a/chromium/chrome/browser/resources/welcome/win10/inline.js b/chromium/chrome/browser/resources/welcome/welcome_win10.js
index df67df5afb2..a961634a306 100644
--- a/chromium/chrome/browser/resources/welcome/win10/inline.js
+++ b/chromium/chrome/browser/resources/welcome/welcome_win10.js
@@ -3,23 +3,25 @@
// found in the LICENSE file.
Polymer({
- is: 'welcome-win10-inline',
+ is: 'welcome-win10',
properties: {
// Determines if the combined variant should be displayed. The combined
// variant includes instructions on how to pin Chrome to the taskbar.
- isCombined: Boolean
+ isCombined: Boolean,
+
+ // Indicates if the accelerated flow is enabled.
+ isAccelerated: Boolean,
},
receivePinnedState_: function(isPinnedToTaskbar) {
// Allow overriding of the result via a query parameter.
// TODO(pmonette): Remove these checks when they are no longer needed.
- /** @const */
- var VARIANT_KEY = 'variant';
- var VariantTypeMap = {'defaultonly': false, 'combined': true};
- var params = new URLSearchParams(location.search.slice(1));
- if (params.has(VARIANT_KEY) && params.get(VARIANT_KEY) in VariantTypeMap)
- this.isCombined = VariantTypeMap[params.get(VARIANT_KEY)];
+ const VARIANT_KEY = 'variant';
+ const VARIANT_TYPE_MAP = {'defaultonly': false, 'combined': true};
+ var params = new URLSearchParams(location.search);
+ if (params.has(VARIANT_KEY) && params.get(VARIANT_KEY) in VARIANT_TYPE_MAP)
+ this.isCombined = VARIANT_TYPE_MAP[params.get(VARIANT_KEY)];
else
this.isCombined = !isPinnedToTaskbar;
@@ -29,6 +31,25 @@ Polymer({
ready: function() {
this.isCombined = false;
+ this.isAccelerated = false;
+
+ const FLOWTYPE_KEY = 'flowtype';
+ const FLOW_TYPE_MAP = {'regular': false, 'accelerated': true};
+ var params = new URLSearchParams(location.search);
+ if (params.has(FLOWTYPE_KEY)) {
+ if (params.get(FLOWTYPE_KEY) in FLOW_TYPE_MAP) {
+ this.isAccelerated = FLOW_TYPE_MAP[params.get(FLOWTYPE_KEY)];
+
+ // Adjust the height since the accelerated flow contains fewer steps.
+ this.customStyle['--expandable-section-height'] = '26.375em';
+ this.updateStyles();
+ } else {
+ console.log(
+ 'Found invalid value for the \'flowtype\' parameter: %s',
+ params.get(FLOWTYPE_KEY));
+ }
+ }
+
// Asynchronously check if Chrome is pinned to the taskbar.
cr.sendWithPromise('getPinnedToTaskbarState')
.then(this.receivePinnedState_.bind(this));
diff --git a/chromium/chrome/browser/resources/welcome/win10/README.md b/chromium/chrome/browser/resources/welcome/win10/README.md
deleted file mode 100644
index efaee2433ff..00000000000
--- a/chromium/chrome/browser/resources/welcome/win10/README.md
+++ /dev/null
@@ -1,7 +0,0 @@
-# Windows 10 Welcome page
-
-There are 2 different styles of the Windows 10 Welcome Page. A/B testing will
-be done to find out which one of them is better.
-
-TODO(pmonette): Experiment with the 2 versions of the Welcome Page and
-get rid of one of them. Bug id 658918.
diff --git a/chromium/chrome/browser/resources/welcome/win10/default-large.webp b/chromium/chrome/browser/resources/welcome/win10/default-large.webp
deleted file mode 100644
index cb55e122d12..00000000000
--- a/chromium/chrome/browser/resources/welcome/win10/default-large.webp
+++ /dev/null
Binary files differ
diff --git a/chromium/chrome/browser/resources/welcome/win10/default-small.webp b/chromium/chrome/browser/resources/welcome/win10/default-small.webp
deleted file mode 100644
index 9a1345ada51..00000000000
--- a/chromium/chrome/browser/resources/welcome/win10/default-small.webp
+++ /dev/null
Binary files differ
diff --git a/chromium/chrome/browser/resources/welcome/win10/pin-large.webp b/chromium/chrome/browser/resources/welcome/win10/pin-large.webp
deleted file mode 100644
index bf1779515cd..00000000000
--- a/chromium/chrome/browser/resources/welcome/win10/pin-large.webp
+++ /dev/null
Binary files differ
diff --git a/chromium/chrome/browser/resources/welcome/win10/sectioned.css b/chromium/chrome/browser/resources/welcome/win10/sectioned.css
deleted file mode 100644
index c37f446a782..00000000000
--- a/chromium/chrome/browser/resources/welcome/win10/sectioned.css
+++ /dev/null
@@ -1,323 +0,0 @@
-/* Copyright 2016 The Chromium Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file. */
-
-body {
- box-sizing: border-box;
- color: var(--paper-grey-900);
- display: flex;
- flex-direction: column;
- font-size: 100%;
- justify-content: center;
- margin: 0;
- min-height: 100vh;
-}
-
-a {
- color: var(--google-blue-500);
- text-decoration: none;
-}
-
-ol {
- margin: 0;
- padding: 0;
-}
-
-strong {
- font-weight: 500;
-}
-
-.content {
- padding: 64px 24px 24px 24px;
-}
-
-.header-logo {
- content: url(chrome://welcome-win10/logo-large.png);
- height: 4em;
-}
-
-.text {
- margin: 0 auto;
- max-width: 45em;
-}
-
-.heading {
- font-size: 2.125em;
- margin-bottom: .25em;
- margin-top: 1.5em;
-}
-
-.subheading {
- color: var(--google-grey-500);
- font-size: 1em;
- margin-bottom: 1.5em;
- margin-top: .25em;
- text-align: center;
-}
-
-.sections {
- margin-bottom: 2em;
-}
-
-.section.expandable {
- border-top: 1px solid var(--google-grey-300);
-}
-
-.section.expandable:last-child {
- border-bottom: 1px solid var(--google-grey-300);
-}
-
-.section.expandable .section-heading {
- color: var(--google-blue-500);
- cursor: pointer;
-}
-
-.section-heading {
- align-items: center;
- display: flex;
- padding: 1.5em 0;
-}
-
-.section-heading-text {
- flex: 1;
- font-weight: 500;
-}
-
-.section.expandable .section-heading-text {
- font-weight: normal;
-}
-
-.section.expandable.expanded .section-heading-text {
- font-weight: 500;
-}
-
-.section-heading-expand {
- height: 1.25em;
- opacity: 0.54;
- transition: transform 150ms cubic-bezier(.4, .2, 0, 1) 50ms;
- width: 1.25em;
-}
-
-.section.expandable.expanded .section-heading-expand {
- transform: rotate(180deg);
- transition-delay: 150ms;
-}
-
-.section-steps {
- overflow: hidden;
-}
-
-.section-steps li {
- -webkit-margin-start: 1.25em;
- -webkit-padding-start: 1em;
- margin-bottom: 1em;
-}
-
-.section-steps li:last-child {
- margin-bottom: 1em;
-}
-
-.section.expandable .section-steps {
- max-height: 0;
- opacity: 0;
- transition: max-height 300ms cubic-bezier(.4, .2, 0, 1) 50ms, opacity 150ms;
-}
-
-.section.expandable.expanded .section-steps {
- max-height: 8.75em;
- opacity: 1;
- transition: max-height 300ms cubic-bezier(.4, .2, 0, 1) 50ms,
- opacity 150ms 250ms;
-}
-
-.button {
- -webkit-font-smoothing: antialiased;
- background: var(--google-blue-500);
- border-radius: 2px;
- box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .1);
- color: #fff;
- display: inline-block;
- font-size: .8125em;
- font-weight: 500;
- line-height: 2.25rem;
- padding: 0 1em;
- text-align: center;
- transition: 300ms cubic-bezier(.4, .2, 0, 1);
- will-change: box-shadow;
-}
-
-.button:hover {
- background: var(--paper-blue-a400);
- box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .1), 0 1px 2px rgba(0, 0, 0, .24);
-}
-
-.bg {
- background: var(--paper-light-blue-700);
- flex: 1;
- margin-top: 96px;
- padding: 24px;
-}
-
-.logo-small {
- content: url(chrome://welcome-win10/logo-small.png);
- display: inline;
- height: 1.25em;
- vertical-align: top;
- width: 1.25em;
-}
-
-.screenshots {
- display: block;
- height: 440px;
- margin: 0 auto;
- max-width: 100%;
- position: relative;
- top: -96px;
- width: 720px;
-}
-
-.screenshot-image {
- box-shadow: 0 0 8px rgba(0, 0, 0, .12), 0 4px 16px rgba(0, 0, 0, .24);
- height: 56vw;
- max-height: 440px;
- max-width: 720px;
- min-height: 294px;
- min-width: 480px;
- position: absolute;
- transition: opacity 150ms;
- width: 92vw;
-}
-
-.screenshot-image.hidden {
- opacity: 0;
-}
-
-#default-image {
- background: url(chrome://welcome-win10/default.webp);
- background-repeat: no-repeat;
- background-size: cover;
-}
-
-#taskbar-image {
- background: url(chrome://welcome-win10/pin.webp);
- background-repeat: no-repeat;
- background-size: cover;
-}
-
-.screenshot-overlay {
- box-sizing: border-box;
- line-height: 0;
- position: absolute;
-}
-
-#browser-overlay {
- left: 42.5%;
- top: 76%;
-}
-
-#edge-overlay {
- left: 50%;
- top: 84%;
-}
-
-#taskbar-overlay {
- left: 62.2%;
- top: 81.5%;
-}
-
-#taskbar-overlay div {
- color: #ccc;
- font-family: Tahoma, Verdana, Segoe, sans-serif;
- font-weight: 500;
-}
-
-#icon-overlay {
- background-image: url(chrome://welcome-win10/logo-small.png);
- background-size: cover;
- height: 5.8%;
- left: 70.60%;
- top: 93.1%;
- width: 3.5%;
-}
-
-
-/* These values are precisely set so that the text over the screenshot starts
- * scaling at the same time the image starts scaling too. */
-@media (min-width: 520px) {
- #browser-overlay {
- font-size: 1.8vw;
- }
-
- #edge-overlay {
- font-size: 2.05vw;
- }
-
- #taskbar-overlay {
- font-size: 1.35vw;
- }
-}
-
-/* Font-sizes used when the screenshot exactly reaches its max size. */
-@media (min-width: 780px) {
- #browser-overlay {
- font-size: 14px;
- }
-
- #edge-overlay {
- font-size: 16px;
- }
-
- #taskbar-overlay {
- font-size: 10.5px;
- }
-}
-
-/* Font-sizes used when the screenshot exactly reaches its min size. */
-@media(max-width: 520px) {
- #browser-overlay {
- font-size: 9px;
- }
-
- #edge-overlay {
- font-size: 10.5px;
- }
-
- #taskbar-overlay {
- font-size: 7px;
- }
-}
-
-@media (min-width: 1280px) {
- body {
- flex-direction: row;
- }
-
- .content {
- align-items: center;
- display: flex;
- flex: 1;
- justify-content: flex-end;
- padding: 96px;
- }
-
- .text {
- margin: 0 180px;
- max-width: none;
- width: 400px;
- }
-
- .bg {
- align-items: center;
- display: flex;
- flex: 1;
- margin: 0;
- max-width: 42%;
- padding: 0;
- }
-
- .screenshots {
- margin-left: -180px;
- max-width: none;
- top: 0;
- }
-}
diff --git a/chromium/chrome/browser/resources/welcome/win10/sectioned.html b/chromium/chrome/browser/resources/welcome/win10/sectioned.html
deleted file mode 100644
index 13b7ff6b059..00000000000
--- a/chromium/chrome/browser/resources/welcome/win10/sectioned.html
+++ /dev/null
@@ -1,90 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
- <meta charset="utf-8">
- <title>$i18n{headerText}</title>
-
- <link rel="import" href="chrome://resources/html/polymer.html">
-
- <link rel="import" href="chrome://resources/cr_elements/icons.html">
- <link rel="import" href="chrome://resources/html/cr.html">
- <link rel="import" href="chrome://resources/html/util.html">
- <link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html">
- <link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html">
- <link rel="import" href="chrome://resources/polymer/v1_0/paper-styles/color.html">
-
- <link rel="stylesheet" href="chrome://resources/css/text_defaults_md.css">
- <link rel="stylesheet" href="/welcome.css">
-
- <script src="/welcome.js"></script>
-</head>
-<body>
- <template is="dom-bind" id="sectioned-app">
- <div class="content">
- <div class="text">
- <div class="header-logo"></div>
- <div class="heading">$i18n{headerText}</div>
- <div class="sections">
- <div class$="[[computeClasses(isCombined)]]">
- <div class="section-heading" on-tap="onToggle">
- <div class="section-heading-text">
- $i18n{defaultBrowserSubheaderText}
- </div>
- <template is="dom-if" if="[[isCombined]]">
- <iron-icon class="section-heading-expand" icon="cr:expand-more">
- </iron-icon>
- </template>
- </div>
- <ol class="section-steps">
- <li>
- <a href="#" on-tap="onOpenSettings">$i18n{openSettingsText}</a>
- </li>
- <li>$i18nRaw{clickEdgeText}</li>
- <li>$i18nRaw{clickSelectChrome}</li>
- </ol>
- </div>
- <template is="dom-if" if="[[isCombined]]">
- <div class="section expandable">
- <div class="section-heading" on-tap="onToggle">
- <div class="section-heading-text">$i18n{pinSubheaderText}</div>
- <iron-icon class="section-heading-expand" icon="cr:expand-more">
- </iron-icon>
- </div>
- <ol class="section-steps">
- <li>$i18nRaw{rightClickText}</li>
- <li>$i18nRaw{pinInstructionText}</li>
- </ol>
- </div>
- </template>
- </div>
- <paper-button class="button" on-tap="onContinue">
- $i18n{continueText}
- </paper-button>
- </div>
- </div>
- <div class="bg">
- <div class="screenshots">
- <div class="screenshot-image" id="default-image">
- <div class="screenshot-overlay"
- id="browser-overlay">
- <div>$i18n{webBrowserLabel}</div>
- </div>
- <div class="screenshot-overlay"
- id="edge-overlay">
- <div>$i18n{microsoftEdgeLabel}</div>
- </div>
- </div>
- <div class="screenshot-image hidden" id="taskbar-image">
- <div class="screenshot-overlay"
- id="taskbar-overlay">
- <div>$i18n{pinToTaskbarLabel}</div>
- </div>
- <div class="screenshot-overlay"
- id="icon-overlay">
- </div>
- </div>
- </div>
- </div>
- </template>
-</body>
-</html>
diff --git a/chromium/chrome/browser/resources/welcome/win10/sectioned.js b/chromium/chrome/browser/resources/welcome/win10/sectioned.js
deleted file mode 100644
index 09137e957f6..00000000000
--- a/chromium/chrome/browser/resources/welcome/win10/sectioned.js
+++ /dev/null
@@ -1,74 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-cr.define('sectioned', function() {
- 'use strict';
-
- function computeClasses(isCombined) {
- if (isCombined)
- return 'section expandable expanded';
- return 'section';
- }
-
- function onContinue() {
- chrome.send('handleContinue');
- }
-
- function onOpenSettings() {
- chrome.send('handleSetDefaultBrowser');
- }
-
- function onToggle(app) {
- if (app.isCombined) {
- // Toggle sections.
- var sections = document.querySelectorAll('.section.expandable');
- sections.forEach(function(section) {
- section.classList.toggle('expanded');
- });
- // Toggle screenshots.
- var screenshots = document.querySelectorAll('.screenshot-image');
- screenshots.forEach(function(screenshot) {
- screenshot.classList.toggle('hidden');
- });
- }
- }
-
- function initialize() {
- var app = $('sectioned-app');
-
- // Set variables.
- // Determines if the combined variant should be displayed. The combined
- // variant includes instructions on how to pin Chrome to the taskbar.
- app.isCombined = false;
-
- // Set handlers.
- app.computeClasses = computeClasses;
- app.onContinue = onContinue;
- app.onOpenSettings = onOpenSettings;
- app.onToggle = onToggle.bind(this, app);
-
-
- // Asynchronously check if Chrome is pinned to the taskbar.
- cr.sendWithPromise('getPinnedToTaskbarState')
- .then(function(isPinnedToTaskbar) {
- // Allow overriding of the result via a query parameter.
- // TODO(pmonette): Remove these checks when they are no longer needed.
- /** @const */ var VARIANT_KEY = 'variant';
- var VariantType = {DEFAULT_ONLY: 'defaultonly', COMBINED: 'combined'};
- var params = new URLSearchParams(location.search.slice(1));
- if (params.has(VARIANT_KEY)) {
- if (params.get(VARIANT_KEY) === VariantType.DEFAULT_ONLY)
- app.isCombined = false;
- else if (params.get(VARIANT_KEY) === VariantType.COMBINED)
- app.isCombined = true;
- } else {
- app.isCombined = !isPinnedToTaskbar;
- }
- });
- }
-
- return {initialize: initialize};
-});
-
-document.addEventListener('DOMContentLoaded', sectioned.initialize);