blob: 238cb82cda5cba54bcf1511a610f91ba975eca9c [file] [log] [blame]
// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* @fileoverview
* 'os-settings-main' displays the selected settings page.
*/
import 'chrome://resources/cr_components/managed_footnote/managed_footnote.js';
import 'chrome://resources/cr_components/settings_prefs/prefs.js';
import 'chrome://resources/cr_elements/cr_hidden_style.css.js';
import 'chrome://resources/cr_elements/icons.html.js';
import 'chrome://resources/js/search_highlight_utils.js';
import 'chrome://resources/polymer/v3_0/iron-icon/iron-icon.js';
import '../os_about_page/os_about_page.js';
import '../os_settings_page/os_settings_page.js';
import '../../settings_shared.css.js';
import '../../settings_vars.css.js';
import {loadTimeData} from 'chrome://resources/js/load_time_data.js';
import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
import {assertExists} from '../assert_extras.js';
import {OsPageAvailability} from '../os_page_availability.js';
import {routes} from '../os_settings_routes.js';
import {RouteObserverMixin} from '../route_observer_mixin.js';
import {Route, Router} from '../router.js';
import {getTemplate} from './os_settings_main.html.js';
interface MainPageVisibility {
about: boolean;
settings: boolean;
}
export interface OsSettingsMainElement {
$: {
overscroll: HTMLDivElement,
};
}
const OsSettingsMainElementBase = RouteObserverMixin(PolymerElement);
export class OsSettingsMainElement extends OsSettingsMainElementBase {
static get is() {
return 'os-settings-main';
}
static get template() {
return getTemplate();
}
static get properties() {
return {
/**
* Preferences state.
*/
prefs: {
type: Object,
notify: true,
},
advancedToggleExpanded: {
type: Boolean,
notify: true,
},
overscroll_: {
type: Number,
observer: 'overscrollChanged_',
},
/**
* Controls which main pages are displayed via dom-ifs, based on the
* current route.
*/
showPages_: {
type: Object,
value() {
return {about: false, settings: false};
},
},
showingSubpage_: Boolean,
toolbarSpinnerActive: {
type: Boolean,
value: false,
notify: true,
},
/**
* Dictionary defining page availability.
*/
pageAvailability: Object,
showAndroidApps: Boolean,
showArcvmManageUsb: Boolean,
showCrostini: Boolean,
showKerberosSection: Boolean,
havePlayStoreApp: Boolean,
};
}
prefs: Object;
advancedToggleExpanded: boolean;
toolbarSpinnerActive: boolean;
pageAvailability: OsPageAvailability;
showAndroidApps: boolean;
showArcvmManageUsb: boolean;
showCrostini: boolean;
showKerberosSection: boolean;
havePlayStoreApp: boolean;
private overscroll_: number;
private showPages_: MainPageVisibility;
private showingSubpage_: boolean;
private boundScroll_: (() => void)|null;
constructor() {
super();
this.boundScroll_ = null;
}
private overscrollChanged_() {
assertExists(this.offsetParent);
if (!this.overscroll_ && this.boundScroll_) {
this.offsetParent.removeEventListener('scroll', this.boundScroll_);
window.removeEventListener('resize', this.boundScroll_);
this.boundScroll_ = null;
} else if (this.overscroll_ && !this.boundScroll_) {
this.boundScroll_ = () => {
if (!this.showingSubpage_) {
this.setOverscroll_(0);
}
};
this.offsetParent.addEventListener('scroll', this.boundScroll_);
window.addEventListener('resize', this.boundScroll_);
}
}
/**
* Sets the overscroll padding. Never forces a scroll, i.e., always leaves
* any currently visible overflow as-is.
* @param minHeight The minimum overscroll height needed.
*/
private setOverscroll_(minHeight?: number) {
const scroller = this.offsetParent;
if (!scroller) {
return;
}
const overscroll = this.$.overscroll;
const visibleBottom = scroller.scrollTop + scroller.clientHeight;
const overscrollBottom = overscroll.offsetTop + overscroll.scrollHeight;
// How much of the overscroll is visible (may be negative).
const visibleOverscroll =
overscroll.scrollHeight - (overscrollBottom - visibleBottom);
this.overscroll_ = Math.max(minHeight || 0, Math.ceil(visibleOverscroll));
}
/**
* Updates the hidden state of the about and settings pages based on the
* current route.
*/
override currentRouteChanged(newRoute: Route) {
const inAbout = routes.ABOUT.contains(Router.getInstance().currentRoute);
this.showPages_ = {about: inAbout, settings: !inAbout};
if (!newRoute.isSubpage()) {
document.title = inAbout ? loadTimeData.getStringF(
'settingsAltPageTitle',
loadTimeData.getString('aboutPageTitle')) :
loadTimeData.getString('settings');
}
}
private onShowingSubpage_() {
this.showingSubpage_ = true;
}
private onShowingMainPage_() {
this.showingSubpage_ = false;
}
/**
* A handler for the 'showing-section' event fired from os-settings-page,
* indicating that a section should be scrolled into view as a result of a
* navigation.
*/
private onShowingSection_(e: CustomEvent<HTMLElement>) {
const section = e.detail;
// Calculate the height that the overscroll padding should be set to, so
// that the given section is displayed at the top of the viewport.
// Find the distance from the section's top to the overscroll.
const sectionTop =
(section.offsetParent as HTMLElement).offsetTop + section.offsetTop;
const distance = this.$.overscroll.offsetTop - sectionTop;
const overscroll = Math.max(0, this.offsetParent!.clientHeight - distance);
this.setOverscroll_(overscroll);
section.scrollIntoView();
section.focus();
}
private showManagedHeader_(): boolean {
return !this.showingSubpage_ && !this.showPages_.about;
}
}
declare global {
interface HTMLElementTagNameMap {
'os-settings-main': OsSettingsMainElement;
}
}
customElements.define(OsSettingsMainElement.is, OsSettingsMainElement);