Commit bc71a2d3 authored by Tymofii Chudakov's avatar Tymofii Chudakov Committed by Commit Bot

WebUI Settings: Added (radio button)-based CS web component.

Added category-default-setting-radio component for managing content
settings, which should substitute the toggle-based
category-default-setting component. The functionality is presersed.

Bug: 1113642
Change-Id: I4f168f9f5a774349386e482952590979b0ba10e8
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2297505
Commit-Queue: Tymofii Chudakov <tchudakov@chromium.org>
Reviewed-by: default avatardpapad <dpapad@chromium.org>
Reviewed-by: default avatarTheodore Olsauskas-Warren <sauski@google.com>
Reviewed-by: default avatarSean Harrison <harrisonsean@chromium.org>
Cr-Commit-Position: refs/heads/master@{#804733}
parent 704079a4
......@@ -1608,6 +1608,12 @@
<message name="IDS_SETTINGS_SITE_SETTINGS_SITE_REPRESENTATION_SEPARATOR" desc="The separator used to split up the display of a URL into host and scheme/protocol, when the scheme is not HTTPS. For example, it will be used in a string that looks like 'google.co.uk — http'.">
</message>
<message name="IDS_SETTINGS_SITE_SETTINGS_DEFAULT_BEHAVIOR" desc="Label for the site settings default behavior.">
Default behavior
</message>
<message name="IDS_SETTINGS_SITE_SETTINGS_DEFAULT_BEHAVIOR_DESCRIPTION" desc="Description for the site settings default behavior.">
Sites automatically follow this setting when you visit them
</message>
<message name="IDS_SETTINGS_SITE_SETTINGS_ADS" desc="Label for the ads site settings.">
Ads
</message>
......
8fff01ec3881be24f3b1932baa0b67da5dbfcec6
\ No newline at end of file
25ec1fee64ae01c79c897fcea7ff13bbf5a588a4
\ No newline at end of file
......@@ -269,6 +269,7 @@ js_library("lazy_load") {
"privacy_page:security_page",
"site_settings:local_data_browser_proxy",
"site_settings:protocol_handlers",
"site_settings:settings_category_default_radio_group",
"site_settings:site_settings_prefs_browser_proxy",
"site_settings_page",
]
......
......@@ -21,6 +21,7 @@ import './site_settings/category_setting_exceptions.js';
import './site_settings/chooser_exception_list.js';
import './site_settings/media_picker.js';
import './site_settings/pdf_documents.js';
import './site_settings/settings_category_default_radio_group.js';
import './site_settings/site_data.js';
import './site_settings/site_details.js';
import './site_settings/zoom_levels.js';
......
......@@ -39,6 +39,10 @@
width: 100%;
}
#buttonIcon {
padding-inline-end: 6px;
}
#labelWrapper {
--cr-radio-button-label-spacing: 0;
padding-bottom: 6px;
......@@ -67,6 +71,8 @@
<div class="disc"></div>
</div>
<div id="borderWrapper">
<iron-icon id="buttonIcon"
icon="[[icon]]" hidden$="[[!icon]]"></iron-icon>
<div id="labelWrapper">
<div id="label" aria-hidden="true">
[[label]]
......
......@@ -5,6 +5,7 @@
import 'chrome://resources/cr_elements/cr_expand_button/cr_expand_button.m.js';
import 'chrome://resources/cr_elements/cr_radio_button/cr_radio_button_style_css.m.js';
import 'chrome://resources/polymer/v3_0/iron-collapse/iron-collapse.js';
import 'chrome://resources/polymer/v3_0/iron-icon/iron-icon.js';
import '../settings_shared_css.m.js';
import {CrRadioButtonBehavior} from 'chrome://resources/cr_elements/cr_radio_button/cr_radio_button_behavior.m.js';
......@@ -35,6 +36,11 @@ Polymer({
label: String,
icon: {
type: String,
value: null,
},
/*
* The Preference associated with the radio group.
* @type {!chrome.settingsPrivate.PrefObject|undefined}
......
......@@ -780,6 +780,10 @@
use_base_dir="false"
compress="false" type="BINDATA"
preprocess="true" />
<include name="IDR_SETTINGS_SITE_SETTINGS_SETTINGS_CATEGORY_DEFAULT_RADIO_GROUP_JS"
file="${root_gen_dir}/chrome/browser/resources/settings/site_settings/settings_category_default_radio_group.js"
use_base_dir="false"
compress="false" type="BINDATA" />
<include name="IDR_SETTINGS_SITE_SETTINGS_SITE_DATA_JS"
file="${root_gen_dir}/chrome/browser/resources/settings/site_settings/site_data.js"
use_base_dir="false"
......
......@@ -24,6 +24,7 @@ js_type_check("closure_compile_module") {
":media_picker",
":pdf_documents",
":protocol_handlers",
":settings_category_default_radio_group",
":site_data",
":site_data_details_subpage",
":site_data_entry",
......@@ -170,6 +171,19 @@ js_library("protocol_handlers") {
]
}
js_library("settings_category_default_radio_group") {
deps = [
":constants",
":site_settings_behavior",
"../controls:settings_radio_group.m",
"../privacy_page:collapse_radio_button",
"//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
"//ui/webui/resources/js:assert.m",
"//ui/webui/resources/js:load_time_data.m",
]
externs_list = [ "$externs_path/settings_private.js" ]
}
js_library("site_data") {
deps = [
":local_data_browser_proxy",
......@@ -332,6 +346,7 @@ html_to_js("web_components") {
"media_picker.js",
"pdf_documents.js",
"protocol_handlers.js",
"settings_category_default_radio_group.js",
"site_data.js",
"site_data_details_subpage.js",
"site_data_entry.js",
......
......@@ -31,6 +31,8 @@
* | |
* +-------------------------------------------------+
*
* TODO(crbug.com/1113642): Remove this element when content settings redesign
* is launched.
*/
import '../controls/settings_toggle_button.m.js';
import '../settings_shared_css.m.js';
......
<style include="settings-shared">
#radioSection {
padding: 0 var(--cr-section-padding);
}
#radioGroupSubLabel {
padding-bottom: 10px;
}
settings-collapse-radio-button:not(:first-of-type) {
--settings-collapse-separator-line: var(--cr-separator-line);
}
</style>
<div id="radioSection">
<h2>$i18n{siteSettingsDefaultBehavior}</h2>
<div id="radioGroupSubLabel" class="secondary">
$i18n{siteSettingsDefaultBehaviorDescription}
</div>
<settings-radio-group
id="settingsCategoryDefaultRadioGroup"
pref="{{pref_}}"
selectable-elements="settings-collapse-radio-button"
on-change="onSelectedChanged_">
<settings-collapse-radio-button
id="enabledRadioOption"
name="[[siteContentRadioSettingEnum_.ENABLED]]"
pref="[[pref_]]"
label="[[allowOptionLabel]]"
sub-label="[[allowOptionSubLabel]]"
disabled$="[[isRadioGroupDisabled_(category)]]"
icon="[[allowOptionIcon]]"
no-collapse>
</settings-collapse-radio-button>
<settings-collapse-radio-button
id="disabledRadioOption"
name="[[siteContentRadioSettingEnum_.DISABLED]]"
pref="[[pref_]]"
label="[[blockOptionLabel]]"
sub-label="[[blockOptionSubLabel]]"
disabled$="[[isRadioGroupDisabled_(category)]]"
icon="[[blockOptionIcon]]"
no-collapse>
</settings-collapse-radio-button>
</settings-radio-group>
</div>
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* @fileoverview
* 'settings-category-default-radio-group' is the polymer element for showing
* a certain category under Site Settings.
*/
import '../settings_shared_css.m.js';
import '../controls/settings_radio_group.m.js';
import '../privacy_page/collapse_radio_button.js';
import {assert, assertNotReached} from 'chrome://resources/js/assert.m.js';
import {WebUIListenerBehavior} from 'chrome://resources/js/web_ui_listener_behavior.m.js';
import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
import {loadTimeData} from '../i18n_setup.js';
import {ContentSetting, ContentSettingsTypes} from './constants.js';
import {SiteSettingsBehavior} from './site_settings_behavior.js';
import {ContentSettingProvider, DefaultContentSetting} from './site_settings_prefs_browser_proxy.js';
/**
* Selected content setting radio option.
* @enum {number}
*/
export const SiteContentRadioSetting = {
DISABLED: 0,
ENABLED: 1,
};
Polymer({
is: 'settings-category-default-radio-group',
_template: html`{__html_template__}`,
behaviors: [SiteSettingsBehavior, WebUIListenerBehavior],
properties: {
allowOptionLabel: String,
allowOptionSubLabel: String,
allowOptionIcon: String,
blockOptionLabel: String,
blockOptionSubLabel: String,
blockOptionIcon: String,
/** @private */
siteContentRadioSettingEnum_: {
type: Object,
value: SiteContentRadioSetting,
},
/**
* Preference object used to keep track of the selected content setting
* option.
* @private {!chrome.settingsPrivate.PrefObject}
*/
pref_: {
type: Object,
value() {
return /** @type {!chrome.settingsPrivate.PrefObject} */ ({
type: chrome.settingsPrivate.PrefType.NUMBER,
value: -1, // No element is selected until the value is loaded.
});
},
},
},
observers: [
'onCategoryChanged_(category)',
],
/** @override */
ready() {
this.addWebUIListener(
'contentSettingCategoryChanged', this.onCategoryChanged_.bind(this));
},
/**
* @return {!ContentSetting}
* @private
*/
getAllowOptionForCategory_() {
switch (this.category) {
case ContentSettingsTypes.ADS:
case ContentSettingsTypes.BACKGROUND_SYNC:
case ContentSettingsTypes.IMAGES:
case ContentSettingsTypes.JAVASCRIPT:
case ContentSettingsTypes.MIXEDSCRIPT:
case ContentSettingsTypes.SOUND:
case ContentSettingsTypes.SENSORS:
case ContentSettingsTypes.PAYMENT_HANDLER:
case ContentSettingsTypes.POPUPS:
case ContentSettingsTypes.PROTOCOL_HANDLERS:
// "Allowed" vs "Blocked".
return ContentSetting.ALLOW;
case ContentSettingsTypes.AUTOMATIC_DOWNLOADS:
case ContentSettingsTypes.CAMERA:
case ContentSettingsTypes.CLIPBOARD:
case ContentSettingsTypes.GEOLOCATION:
case ContentSettingsTypes.MIC:
case ContentSettingsTypes.NOTIFICATIONS:
case ContentSettingsTypes.UNSANDBOXED_PLUGINS:
case ContentSettingsTypes.MIDI_DEVICES:
case ContentSettingsTypes.USB_DEVICES:
case ContentSettingsTypes.SERIAL_PORTS:
case ContentSettingsTypes.BLUETOOTH_DEVICES:
case ContentSettingsTypes.BLUETOOTH_SCANNING:
case ContentSettingsTypes.HID_DEVICES:
case ContentSettingsTypes.VR:
case ContentSettingsTypes.AR:
case ContentSettingsTypes.WINDOW_PLACEMENT:
// "Ask" vs "Blocked".
return ContentSetting.ASK;
case ContentSettingsTypes.PLUGINS:
// "Run important content" vs. "Block".
return ContentSetting.IMPORTANT_CONTENT;
default:
assertNotReached('Invalid category: ' + this.category);
return ContentSetting.ALLOW;
}
},
/**
* 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
*/
onSelectedChanged_() {
assert(
this.pref_.enforcement !== chrome.settingsPrivate.Enforcement.ENFORCED);
const allowOption =
/** @type {!ContentSetting} */ (this.getAllowOptionForCategory_());
this.browserProxy.setDefaultValueForContentType(
this.category,
this.categoryEnabled_ ? allowOption : ContentSetting.BLOCK);
},
/**
* Update the pref values from the content settings.
* @param {!DefaultContentSetting} update The updated content setting value.
* @private
*/
updatePref_(update) {
if (update.source !== undefined &&
update.source !== ContentSettingProvider.PREFERENCE) {
this.set(
'pref_.enforcement', chrome.settingsPrivate.Enforcement.ENFORCED);
let controlledBy = chrome.settingsPrivate.ControlledBy.USER_POLICY;
switch (update.source) {
case ContentSettingProvider.POLICY:
controlledBy = chrome.settingsPrivate.ControlledBy.DEVICE_POLICY;
break;
case ContentSettingProvider.SUPERVISED_USER:
controlledBy = chrome.settingsPrivate.ControlledBy.PARENT;
break;
case ContentSettingProvider.EXTENSION:
controlledBy = chrome.settingsPrivate.ControlledBy.EXTENSION;
break;
}
this.set('pref_.controlledBy', controlledBy);
}
const enabled = this.computeIsSettingEnabled(update.setting);
const prefValue = enabled ? this.siteContentRadioSettingEnum_.ENABLED :
this.siteContentRadioSettingEnum_.DISABLED;
this.set('pref_.value', prefValue);
},
/** @private */
async onCategoryChanged_(category) {
if (category !== this.category) {
return;
}
const defaultValue =
await this.browserProxy.getDefaultValueForContentType(this.category);
this.updatePref_(defaultValue);
},
/**
* @return {boolean}
* @private
*/
get categoryEnabled_() {
return this.pref_.value === SiteContentRadioSetting.ENABLED;
},
/**
* Check if the category is popups and the user is logged in guest mode.
* Users in guest mode are not allowed to modify pop-ups content setting.
* @return {boolean}
* @private
*/
isRadioGroupDisabled_() {
return this.category === ContentSettingsTypes.POPUPS &&
loadTimeData.getBoolean('isGuest');
},
});
......@@ -1932,6 +1932,10 @@ void AddSiteSettingsStrings(content::WebUIDataSource* html_source,
{"incognitoSiteExceptionDesc",
IDS_SETTINGS_SITE_SETTINGS_INCOGNITO_SITE_EXCEPTION_DESC},
{"noSitesAdded", IDS_SETTINGS_SITE_NO_SITES_ADDED},
{"siteSettingsDefaultBehavior",
IDS_SETTINGS_SITE_SETTINGS_DEFAULT_BEHAVIOR},
{"siteSettingsDefaultBehaviorDescription",
IDS_SETTINGS_SITE_SETTINGS_DEFAULT_BEHAVIOR_DESCRIPTION},
{"siteSettingsAds", IDS_SETTINGS_SITE_SETTINGS_ADS},
{"siteSettingsAdsBlock", IDS_SETTINGS_SITE_SETTINGS_ADS_BLOCK},
{"siteSettingsAdsBlockRecommended",
......
......@@ -149,6 +149,8 @@ js_type_check("closure_compile") {
":security_page_test",
#":settings_animated_pages_test",
":settings_category_default_radio_group_tests",
#":settings_main_test",
#":settings_menu_test",
":settings_page_test_util",
......@@ -375,6 +377,18 @@ js_library("search_page_test") {
externs_list = [ "$externs_path/mocha-2.5.js" ]
}
js_library("settings_category_default_radio_group_tests") {
deps = [
":test_site_settings_prefs_browser_proxy",
":test_util",
"..:chai_assert",
"..:test_util.m",
"//chrome/browser/resources/settings:lazy_load",
"//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
]
externs_list = [ "$externs_path/mocha-2.5.js" ]
}
js_library("security_page_test") {
deps = [
":test_metrics_browser_proxy",
......
......@@ -192,4 +192,11 @@ suite('CrCollapseRadioButton', function() {
assertTrue(isChildVisible(collapseRadioButton, 'cr-policy-pref-indicator'));
assertFalse(collapseRadioButton.disabled);
});
test('iconVisibleWhenSet', function() {
assertFalse(isChildVisible(collapseRadioButton, '#buttonIcon'));
collapseRadioButton.set('icon', 'cr:location-on');
assertTrue(isChildVisible(collapseRadioButton, '#buttonIcon'));
});
});
......@@ -499,6 +499,10 @@ TEST_F('CrSettingsAdvancedPageV3Test', 'MAYBE_Load', function() {
['AppearanceFontsPage', 'appearance_fonts_page_test.js'],
['AppearancePage', 'appearance_page_test.js'],
['BasicPage', 'basic_page_test.js'],
[
'SettingsCategoryDefaultRadioGroup',
'settings_category_default_radio_group_tests.js'
],
['CategoryDefaultSetting', 'category_default_setting_tests.js'],
['CategorySettingExceptions', 'category_setting_exceptions_tests.js'],
['Checkbox', 'checkbox_tests.js'],
......
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// clang-format off
import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
import {ContentSetting, ContentSettingProvider, ContentSettingsTypes, SiteSettingsPrefsBrowserProxyImpl} from 'chrome://settings/lazy_load.js';
import {assertEquals, assertNotEquals, assertTrue} from '../chai_assert.js';
import {flushTasks} from '../test_util.m.js';
import {TestSiteSettingsPrefsBrowserProxy} from './test_site_settings_prefs_browser_proxy.js';
import {createContentSettingTypeToValuePair, createDefaultContentSetting, createSiteSettingsPrefs, SiteSettingsPref} from './test_util.js';
// clang-format on
/** @fileoverview Suite of tests for settings-category-default-radio-group. */
suite('SettingsCategoryDefaultRadioGroup', function() {
/**
* A settings-category-default-radio-group created before each test.
* @type {SettingsCategoryDefaultRadioGroupElement}
*/
let testElement;
/**
* The mock proxy object to use during test.
* @type {TestSiteSettingsPrefsBrowserProxy}
*/
let browserProxy = null;
// Initialize a settings-category-default-radio-group before each test.
setup(function() {
browserProxy = new TestSiteSettingsPrefsBrowserProxy();
SiteSettingsPrefsBrowserProxyImpl.instance_ = browserProxy;
document.body.innerHTML = '';
testElement = /** @type {!SettingsCategoryDefaultRadioGroupElement} */
(document.createElement('settings-category-default-radio-group'));
document.body.appendChild(testElement);
});
teardown(function() {
testElement.remove();
});
/**
* @param {!ContentSettingsTypes} category The preference category.
* @param {!ContentSetting} contentSetting The preference content setting.
* @return {SiteSettingsPref} The created preference object.
*/
function createPref(category, contentSetting) {
return createSiteSettingsPrefs(
[
createContentSettingTypeToValuePair(
category, createDefaultContentSetting({
setting: contentSetting,
})),
],
[]);
}
/**
* Verifies that the widget works as expected for a given |category|,
* initial |prefs|, and given expectations.
* @param {SettingsCategoryDefaultRadioGroupElement} element The
* settings-category-default-radio-group element to test.
* @param {TestSiteSettingsPrefsBrowserProxy} proxy The mock proxy object.
* @param {SiteSettingsPref} prefs The preference object.
* @param {ContentSettingsTypes} expectedCategory The category of the
* |element|.
* @param {boolean} expectedEnabled If the category is enabled by default.
* @param {ContentSetting} expectedEnabledContentSetting The enabled content
* setting value of the |expectedCategory|.
*/
async function testCategoryEnabled(
element, proxy, prefs, expectedCategory, expectedEnabled,
expectedEnabledContentSetting) {
proxy.reset();
proxy.setPrefs(prefs);
element.set('category', expectedCategory);
let category = await proxy.whenCalled('getDefaultValueForContentType');
let categoryEnabled = element.$$('#enabledRadioOption').checked;
assertEquals(expectedCategory, category);
assertEquals(expectedEnabled, categoryEnabled);
// Click the button specifying the alternative option
// and verify that the preference value is updated correctly.
proxy.resetResolver('setDefaultValueForContentType');
const oppositeRadioButton =
expectedEnabled ? '#disabledRadioOption' : '#enabledRadioOption';
element.$$(oppositeRadioButton).click();
let setting;
[category, setting] =
await proxy.whenCalled('setDefaultValueForContentType');
assertEquals(expectedCategory, category);
const oppositeSetting =
expectedEnabled ? ContentSetting.BLOCK : expectedEnabledContentSetting;
categoryEnabled = element.$$('#enabledRadioOption').checked;
assertEquals(oppositeSetting, setting);
assertNotEquals(expectedEnabled, categoryEnabled);
// Click the initially selected option and verify that the
// preference value is set back to the initial state.
proxy.resetResolver('setDefaultValueForContentType');
const initialRadioButton =
expectedEnabled ? '#enabledRadioOption' : '#disabledRadioOption';
element.$$(initialRadioButton).click();
[category, setting] =
await proxy.whenCalled('setDefaultValueForContentType');
assertEquals(expectedCategory, category);
const initialSetting =
expectedEnabled ? expectedEnabledContentSetting : ContentSetting.BLOCK;
categoryEnabled = element.$$('#enabledRadioOption').checked;
assertEquals(initialSetting, setting);
assertEquals(expectedEnabled, categoryEnabled);
}
test('ask location disable click triggers update', async function() {
const enabledPref =
createPref(ContentSettingsTypes.GEOLOCATION, ContentSetting.ASK);
await testCategoryEnabled(
testElement, browserProxy, enabledPref,
ContentSettingsTypes.GEOLOCATION, true, ContentSetting.ASK);
});
test('block location enable click triggers update', async function() {
const disabledPref =
createPref(ContentSettingsTypes.GEOLOCATION, ContentSetting.BLOCK);
await testCategoryEnabled(
testElement, browserProxy, disabledPref,
ContentSettingsTypes.GEOLOCATION, false, ContentSetting.ASK);
});
test('allow ads disable click triggers update', async function() {
const enabledPref =
createPref(ContentSettingsTypes.ADS, ContentSetting.ALLOW);
await testCategoryEnabled(
testElement, browserProxy, enabledPref, ContentSettingsTypes.ADS, true,
ContentSetting.ALLOW);
});
test('block ads enable click triggers update', async function() {
const disabledPref =
createPref(ContentSettingsTypes.ADS, ContentSetting.BLOCK);
await testCategoryEnabled(
testElement, browserProxy, disabledPref, ContentSettingsTypes.ADS,
false, ContentSetting.ALLOW);
});
test('imp. content flash disable click triggers update', async function() {
const enabledPref = createPref(
ContentSettingsTypes.PLUGINS, ContentSetting.IMPORTANT_CONTENT);
await testCategoryEnabled(
testElement, browserProxy, enabledPref, ContentSettingsTypes.PLUGINS,
true, ContentSetting.IMPORTANT_CONTENT);
});
test('block flash enable click triggers update', async function() {
const disabledPref =
createPref(ContentSettingsTypes.PLUGINS, ContentSetting.BLOCK);
await testCategoryEnabled(
testElement, browserProxy, disabledPref, ContentSettingsTypes.PLUGINS,
false, ContentSetting.IMPORTANT_CONTENT);
});
test('radio group is disabled when pref is enforced', async function() {
const enforcedPrefs = createSiteSettingsPrefs(
[createContentSettingTypeToValuePair(
ContentSettingsTypes.GEOLOCATION, createDefaultContentSetting({
setting: ContentSetting.ASK,
source: ContentSettingProvider.EXTENSION,
}))],
[]);
browserProxy.reset();
browserProxy.setPrefs(enforcedPrefs);
testElement.category = ContentSettingsTypes.GEOLOCATION;
await browserProxy.whenCalled('getDefaultValueForContentType');
assertTrue(testElement.$$('#enabledRadioOption').disabled);
assertTrue(testElement.$$('#disabledRadioOption').disabled);
});
});
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment