| // Copyright 2018 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| import 'chrome://resources/cr_elements/cr_toast/cr_toast.js'; |
| import 'chrome://resources/cr_elements/cr_view_manager/cr_view_manager.js'; |
| import 'chrome://resources/cr_elements/hidden_style_css.m.js'; |
| import './google_apps/nux_google_apps.js'; |
| import './landing_view.js'; |
| import './ntp_background/nux_ntp_background.js'; |
| import './set_as_default/nux_set_as_default.js'; |
| import './signin_view.js'; |
| import '../strings.m.js'; |
| |
| import {CrViewManagerElement} from 'chrome://resources/cr_elements/cr_view_manager/cr_view_manager.js'; |
| import {assert} from 'chrome://resources/js/assert_ts.js'; |
| import {FocusOutlineManager} from 'chrome://resources/js/cr/ui/focus_outline_manager.js'; |
| import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js'; |
| import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; |
| |
| import {NavigationMixin, Routes} from './navigation_mixin.js'; |
| import {NuxSetAsDefaultProxyImpl} from './set_as_default/nux_set_as_default_proxy.js'; |
| import {BookmarkBarManager} from './shared/bookmark_proxy.js'; |
| import {getTemplate} from './welcome_app.html.js'; |
| import {WelcomeBrowserProxyImpl} from './welcome_browser_proxy.js'; |
| |
| /** |
| * The strings contained in the arrays should be valid DOM-element tag names. |
| */ |
| interface NuxOnboardingModules { |
| 'new-user': string[]; |
| 'returning-user': string[]; |
| } |
| |
| /** |
| * This list needs to be updated if new modules need to be supported in the |
| * onboarding flow. |
| */ |
| const MODULES_WHITELIST: Set<string> = new Set([ |
| 'nux-google-apps', |
| 'nux-ntp-background', |
| 'nux-set-as-default', |
| 'signin-view', |
| ]); |
| |
| /** |
| * This list needs to be updated if new modules that need step-indicators are |
| * added. |
| */ |
| const MODULES_NEEDING_INDICATOR: Set<string> = |
| new Set(['nux-google-apps', 'nux-ntp-background', 'nux-set-as-default']); |
| |
| export interface WelcomeAppElement { |
| $: { |
| viewManager: CrViewManagerElement, |
| }; |
| } |
| |
| const WelcomeAppElementBase = NavigationMixin(PolymerElement); |
| |
| /** @polymer */ |
| export class WelcomeAppElement extends WelcomeAppElementBase { |
| static get is() { |
| return 'welcome-app'; |
| } |
| |
| static get template() { |
| return getTemplate(); |
| } |
| |
| static get properties() { |
| return { |
| modulesInitialized_: Boolean, |
| }; |
| } |
| private currentRoute_: Routes|null = null; |
| private modules_: NuxOnboardingModules; |
| |
| // Default to false so view-manager is hidden until views are |
| // initialized. |
| private modulesInitialized_: boolean = false; |
| |
| constructor() { |
| super(); |
| this.modules_ = { |
| 'new-user': loadTimeData.getString('newUserModules').split(','), |
| 'returning-user': |
| loadTimeData.getString('returningUserModules').split(','), |
| }; |
| } |
| |
| override ready() { |
| super.ready(); |
| this.setAttribute('role', 'main'); |
| this.addEventListener( |
| 'default-browser-change', () => this.onDefaultBrowserChange_()); |
| |
| // Initiate focus-outline-manager for this document so that action-link |
| // style can take advantage of it. |
| FocusOutlineManager.forDocument(document); |
| } |
| |
| private onDefaultBrowserChange_() { |
| this.shadowRoot!.querySelector('cr-toast')!.show(); |
| } |
| |
| override onRouteChange(route: Routes, step: number) { |
| const setStep = () => { |
| // If the specified step doesn't exist, that means there are no more |
| // steps. In that case, replace this page with NTP. |
| if (!this.shadowRoot!.querySelector(`#step-${step}`)) { |
| WelcomeBrowserProxyImpl.getInstance().goToNewTabPage( |
| /* replace */ true); |
| } else { // Otherwise, go to the chosen step of that route. |
| // At this point, views are ready to be shown. |
| this.modulesInitialized_ = true; |
| this.$.viewManager.switchView( |
| `step-${step}`, 'fade-in', 'no-animation'); |
| } |
| }; |
| |
| // If the route changed, initialize the steps of modules for that route. |
| if (this.currentRoute_ !== route) { |
| this.initializeModules(route).then(setStep); |
| } else { |
| setStep(); |
| } |
| |
| this.currentRoute_ = route; |
| } |
| |
| initializeModules(route: Routes) { |
| // Remove all views except landing. |
| this.$.viewManager |
| .querySelectorAll('[slot="view"]:not([id="step-landing"])') |
| .forEach(element => element.remove()); |
| |
| // If it is on landing route, end here. |
| if (route === Routes.LANDING) { |
| return Promise.resolve(); |
| } |
| |
| let modules = this.modules_[route]; |
| assert(modules); // Modules should be defined if on a valid route. |
| const defaultBrowserPromise = |
| NuxSetAsDefaultProxyImpl.getInstance() |
| .requestDefaultBrowserState() |
| .then((status) => { |
| if (status.isDefault || !status.canBeDefault) { |
| return false; |
| } else if (!status.isDisabledByPolicy && !status.isUnknownError) { |
| return true; |
| } else { // Unknown error. |
| return false; |
| } |
| }); |
| |
| // Wait until the default-browser state and bookmark visibility are known |
| // before anything initializes. |
| return Promise |
| .all([ |
| defaultBrowserPromise, |
| BookmarkBarManager.getInstance().initialized, |
| ]) |
| .then(([canSetDefault]) => { |
| modules = modules.filter(module => { |
| if (module === 'nux-set-as-default') { |
| return canSetDefault; |
| } |
| |
| if (!MODULES_WHITELIST.has(module)) { |
| // Makes sure the module specified by the feature configuration is |
| // whitelisted. |
| return false; |
| } |
| |
| return true; |
| }); |
| |
| const indicatorElementCount = modules.reduce((count, module) => { |
| return count += MODULES_NEEDING_INDICATOR.has(module) ? 1 : 0; |
| }, 0); |
| |
| let indicatorActiveCount = 0; |
| modules.forEach((elementTagName, index) => { |
| const element = |
| document.createElement(elementTagName) as PolymerElement; |
| element.id = 'step-' + (index + 1); |
| element.setAttribute('slot', 'view'); |
| this.$.viewManager.appendChild(element); |
| if (MODULES_NEEDING_INDICATOR.has(elementTagName)) { |
| element.set('indicatorModel', { |
| total: indicatorElementCount, |
| active: indicatorActiveCount++, |
| }); |
| } |
| }); |
| }); |
| } |
| } |
| |
| declare global { |
| interface HTMLElementTagNameMap { |
| 'welcome-app': WelcomeAppElement; |
| } |
| } |
| |
| customElements.define(WelcomeAppElement.is, WelcomeAppElement); |