blob: 8eef615b90f9dd9af4d724fb516a174662765a2c [file] [log] [blame]
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* @fileoverview
* 'category-default-setting' is the polymer element for showing a certain
* category under Site Settings.
*
* |optionLabel_| toggle is enabled:
* +-------------------------------------------------+
* | Category |<-- Not defined here
* | |
* | optionLabel_ ( O) |
* | optionDescription_ |
* | |
* | subOptionLabel ( O) |<-- SubOptionMode.PREF
* | subOptionDescription | (optional)
* | |
* +-------------------------------------------------+
*
* |optionLabel_| toggle is disabled:
* +-------------------------------------------------+
* | Category |<-- Not defined here
* | |
* | optionLabel_ (O ) |
* | optionDescription_ |
* | |
* | subOptionLabel (O ) |<-- Toggle is off and
* | subOptionDescription | disabled; or hidden
* | |
* +-------------------------------------------------+
*
* TODO(crbug.com/1113642): Remove this element when content settings redesign
* is launched.
*/
import '../controls/settings_toggle_button.js';
import '../settings_shared_css.js';
import {assert, assertNotReached} from 'chrome://resources/js/assert.m.js';
import {WebUIListenerBehavior, WebUIListenerBehaviorInterface} from 'chrome://resources/js/web_ui_listener_behavior.m.js';
import {html, mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
import {loadTimeData} from '../i18n_setup.js';
import {routes} from '../route.js';
import {ContentSetting, ContentSettingsTypes} from './constants.js';
import {SiteSettingsMixin, SiteSettingsMixinInterface} from './site_settings_mixin.js';
import {ContentSettingProvider, DefaultContentSetting} from './site_settings_prefs_browser_proxy.js';
/**
* The setting to display as a sub-option, if any.
* @enum {string}
*/
const SubOptionMode = {
PREF: 'pref',
NONE: 'none',
};
/**
* @constructor
* @extends {PolymerElement}
* @implements {SiteSettingsMixinInterface}
* @implements {WebUIListenerBehaviorInterface}
*/
const CategoryDefaultSettingElementBase =
mixinBehaviors([WebUIListenerBehavior], SiteSettingsMixin(PolymerElement));
/** @polymer */
class CategoryDefaultSettingElement extends CategoryDefaultSettingElementBase {
static get is() {
return 'category-default-setting';
}
static get template() {
return html`{__html_template__}`;
}
static get properties() {
return {
/* The on/off text for |optionLabel_| below. */
toggleOffLabel: String,
toggleOnLabel: String,
/* The on/off text for |optionDescription_| below. */
toggleOffDescription: String,
toggleOnDescription: String,
/* The sub-option is a separate toggle. Setting this label will show the
* additional sub option. Shown above |subOptionDescription|. (optional)
*/
subOptionLabel: String,
/* The second line, shown under the |subOptionLabel| line. (optional) */
subOptionDescription: String,
/* The valid sub-option modes. */
subOptionMode: String,
/* The pref that the sub-option state is bound to, when |subOptionMode| is
* set to SubOptionMode.PREF. */
subOptionPref: Boolean,
/* Pref based
/** @private {chrome.settingsPrivate.PrefObject} */
controlParams_: {
type: Object,
value() {
return /** @type {chrome.settingsPrivate.PrefObject} */ ({});
},
},
/**
* The label to be shown next to the toggle (above
* |optionDescription_|). This will be either toggleOffLabel or
* toggleOnLabel.
* @private
*/
optionLabel_: String,
/* The second line, shown under the |optionLabel_| line. This will be
* either toggleOffDescription or toggleOnDescription. (optional)
* @private
*/
optionDescription_: String,
/** @private {!DefaultContentSetting} */
priorDefaultContentSetting_: {
type: Object,
value() {
return /** @type {DefaultContentSetting} */ ({});
},
},
};
}
static get observers() {
return [
'onCategoryChanged_(category)',
'onChangePermissionControl_(category, controlParams_.value)',
];
}
/** @override */
ready() {
super.ready();
this.addWebUIListener(
'contentSettingCategoryChanged', this.onCategoryChanged_.bind(this));
}
/** @return {boolean} */
get categoryEnabled() {
return !!assert(this.controlParams_).value;
}
/**
* A handler for changing the default permission value for a content type.
* This is also called during page setup after we get the default state.
* @private
*/
onChangePermissionControl_() {
if (this.category === undefined ||
this.controlParams_.value === undefined) {
// Do nothing unless all dependencies are defined.
return;
}
// Don't override user settings with enforced settings.
if (this.controlParams_.enforcement ===
chrome.settingsPrivate.Enforcement.ENFORCED) {
return;
}
/**
* This list must be kept in sync with the list in
* settings_category_default_radio_group.js
*/
switch (this.category) {
case ContentSettingsTypes.ADS:
case ContentSettingsTypes.BACKGROUND_SYNC:
case ContentSettingsTypes.IMAGES:
case ContentSettingsTypes.JAVASCRIPT:
case ContentSettingsTypes.MIXEDSCRIPT:
case ContentSettingsTypes.PAYMENT_HANDLER:
case ContentSettingsTypes.POPUPS:
case ContentSettingsTypes.PROTECTED_CONTENT:
case ContentSettingsTypes.PROTOCOL_HANDLERS:
case ContentSettingsTypes.SENSORS:
case ContentSettingsTypes.SOUND:
// "Allowed" vs "Blocked".
this.browserProxy.setDefaultValueForContentType(
this.category,
this.categoryEnabled ? ContentSetting.ALLOW : ContentSetting.BLOCK);
break;
case ContentSettingsTypes.AR:
case ContentSettingsTypes.AUTOMATIC_DOWNLOADS:
case ContentSettingsTypes.BLUETOOTH_DEVICES:
case ContentSettingsTypes.BLUETOOTH_SCANNING:
case ContentSettingsTypes.CAMERA:
case ContentSettingsTypes.CLIPBOARD:
case ContentSettingsTypes.FILE_HANDLING:
case ContentSettingsTypes.FILE_SYSTEM_WRITE:
case ContentSettingsTypes.FONT_ACCESS:
case ContentSettingsTypes.GEOLOCATION:
case ContentSettingsTypes.HID_DEVICES:
case ContentSettingsTypes.IDLE_DETECTION:
case ContentSettingsTypes.MIC:
case ContentSettingsTypes.MIDI_DEVICES:
case ContentSettingsTypes.NOTIFICATIONS:
case ContentSettingsTypes.SERIAL_PORTS:
case ContentSettingsTypes.USB_DEVICES:
case ContentSettingsTypes.VR:
case ContentSettingsTypes.WINDOW_PLACEMENT:
// "Ask" vs "Blocked".
this.browserProxy.setDefaultValueForContentType(
this.category,
this.categoryEnabled ? ContentSetting.ASK : ContentSetting.BLOCK);
break;
default:
assertNotReached('Invalid category: ' + this.category);
}
}
/**
* Update the control parameter values from the content settings.
* @param {!DefaultContentSetting} update
* @private
*/
updateControlParams_(update) {
// Early out if there is no actual change.
if (this.priorDefaultContentSetting_.setting === update.setting &&
this.priorDefaultContentSetting_.source === update.source) {
return;
}
this.priorDefaultContentSetting_ = update;
const basePref = {
'key': 'controlParams',
'type': chrome.settingsPrivate.PrefType.BOOLEAN,
};
if (update.source !== undefined &&
update.source !== ContentSettingProvider.PREFERENCE) {
basePref.enforcement = chrome.settingsPrivate.Enforcement.ENFORCED;
switch (update.source) {
case ContentSettingProvider.POLICY:
basePref.controlledBy =
chrome.settingsPrivate.ControlledBy.DEVICE_POLICY;
break;
case ContentSettingProvider.SUPERVISED_USER:
basePref.controlledBy = chrome.settingsPrivate.ControlledBy.PARENT;
break;
case ContentSettingProvider.EXTENSION:
basePref.controlledBy = chrome.settingsPrivate.ControlledBy.EXTENSION;
break;
default:
basePref.controlledBy =
chrome.settingsPrivate.ControlledBy.USER_POLICY;
break;
}
}
const prefValue = this.computeIsSettingEnabled(update.setting);
// The controlParams_ must be replaced (rather than just value changes) so
// that observers will be notified of the change.
this.controlParams_ = /** @type {chrome.settingsPrivate.PrefObject} */ (
Object.assign({'value': prefValue}, basePref));
}
/**
* Handles changes to the category pref and the |category| member variable.
* @private
*/
onCategoryChanged_() {
this.browserProxy.getDefaultValueForContentType(this.category)
.then(defaultValue => {
this.updateControlParams_(defaultValue);
const categoryEnabled =
this.computeIsSettingEnabled(defaultValue.setting);
this.optionLabel_ =
categoryEnabled ? this.toggleOnLabel : this.toggleOffLabel;
this.optionDescription_ = categoryEnabled ? this.toggleOnDescription :
this.toggleOffDescription;
});
}
/**
* @return {boolean}
* @private
*/
isToggleDisabled_() {
return this.category === ContentSettingsTypes.POPUPS &&
loadTimeData.getBoolean('isGuest');
}
/**
* @return {boolean}
* @private
*/
showPrefSubOption_(subOptionMode) {
return (subOptionMode === SubOptionMode.PREF);
}
}
customElements.define(
CategoryDefaultSettingElement.is, CategoryDefaultSettingElement);