Commit 43116fdd authored by Nikita Podguzov's avatar Nikita Podguzov Committed by Commit Bot

Disable editing managed network config fields.

* Disable network configuration field if the field is enforced by policy.
* Add policy network indicator if the field is controlled by policy.

Bug: 877424
Change-Id: Icfdb6d7fb3deb09696b6d2edce27d3c9851043a2
Reviewed-on: https://chromium-review.googlesource.com/c/1251447
Commit-Queue: Nikita Podguzov <nikitapodguzov@google.com>
Reviewed-by: default avatarSteven Bennetts <stevenjb@chromium.org>
Reviewed-by: default avatarAlexander Hendrich <hendrich@chromium.org>
Cr-Commit-Position: refs/heads/master@{#600735}
parent be9b6eb4
...@@ -55,12 +55,12 @@ ...@@ -55,12 +55,12 @@
</style> </style>
<cr-dialog id="dialog" no-cancel> <cr-dialog id="dialog" no-cancel>
<div slot="title">[[getDialogTitle_(networkProperties_)]]</div> <div slot="title">[[getDialogTitle_(managedProperties_)]]</div>
<div slot="body"> <div slot="body">
<network-config id="networkConfig" class="flex" <network-config id="networkConfig" class="flex"
networking-private="[[networkingPrivate]]" networking-private="[[networkingPrivate]]"
global-policy="[[globalPolicy_]]" global-policy="[[globalPolicy_]]"
network-properties="{{networkProperties_}}" managed-properties="{{managedProperties_}}"
enable-connect="{{enableConnect_}}" enable-connect="{{enableConnect_}}"
share-allow-enable="[[shareAllowEnable_]]" share-allow-enable="[[shareAllowEnable_]]"
share-default="[[shareDefault_]]" share-default="[[shareDefault_]]"
......
...@@ -55,9 +55,9 @@ Polymer({ ...@@ -55,9 +55,9 @@ Polymer({
* The current properties if an existing network is being configured, or * The current properties if an existing network is being configured, or
* a minimal subset for a new network. Note: network-config may modify * a minimal subset for a new network. Note: network-config may modify
* this (specifically .name). * this (specifically .name).
* @type {!chrome.networkingPrivate.NetworkProperties} * @type {!chrome.networkingPrivate.ManagedProperties}
*/ */
networkProperties_: Object, managedProperties_: Object,
/** /**
* Set by network-config when a configuration error occurs. * Set by network-config when a configuration error occurs.
...@@ -85,9 +85,9 @@ Polymer({ ...@@ -85,9 +85,9 @@ Polymer({
this.guid_ = params.get('guid') || ''; this.guid_ = params.get('guid') || '';
} }
this.networkProperties_ = { this.managedProperties_ = {
GUID: this.guid_, GUID: this.guid_,
Name: '', Name: {Active: ''},
Type: /** @type {chrome.networkingPrivate.NetworkType} */ (type), Type: /** @type {chrome.networkingPrivate.NetworkType} */ (type),
}; };
...@@ -110,7 +110,7 @@ Polymer({ ...@@ -110,7 +110,7 @@ Polymer({
* @private * @private
*/ */
getDialogTitle_: function() { getDialogTitle_: function() {
var type = this.i18n('OncType' + this.networkProperties_.Type); var type = this.i18n('OncType' + this.managedProperties_.Type);
return this.i18n('internetJoinType', type); return this.i18n('internetJoinType', type);
}, },
......
...@@ -24,12 +24,12 @@ ...@@ -24,12 +24,12 @@
</style> </style>
<cr-dialog id="dialog" close-text="$i18n{close}"> <cr-dialog id="dialog" close-text="$i18n{close}">
<div slot="title">[[getDialogTitle_(networkProperties_)]]</div> <div slot="title">[[getDialogTitle_(managedProperties_)]]</div>
<div slot="body"> <div slot="body">
<network-config id="networkConfig" class="flex" <network-config id="networkConfig" class="flex"
networking-private="[[networkingPrivate]]" networking-private="[[networkingPrivate]]"
global-policy="[[globalPolicy]]" global-policy="[[globalPolicy]]"
network-properties="{{networkProperties_}}" managed-properties="{{managedProperties_}}"
enable-connect="{{enableConnect_}}" enable-save="{{enableSave_}}" enable-connect="{{enableConnect_}}" enable-save="{{enableSave_}}"
share-allow-enable="[[shareAllowEnable_]]" share-allow-enable="[[shareAllowEnable_]]"
share-default="[[shareDefault_]]" share-default="[[shareDefault_]]"
......
...@@ -69,9 +69,9 @@ Polymer({ ...@@ -69,9 +69,9 @@ Polymer({
* The current properties if an existing network is being configured, or * The current properties if an existing network is being configured, or
* a minimal subset for a new network. Note: network-config may modify * a minimal subset for a new network. Note: network-config may modify
* this (specifically .name). * this (specifically .name).
* @private {!chrome.networkingPrivate.NetworkProperties} * @private {!chrome.networkingPrivate.ManagedProperties}
*/ */
networkProperties_: Object, managedProperties_: Object,
/** /**
* Set by network-config when a configuration error occurs. * Set by network-config when a configuration error occurs.
...@@ -88,12 +88,12 @@ Polymer({ ...@@ -88,12 +88,12 @@ Polymer({
if (!dialog.open) if (!dialog.open)
dialog.showModal(); dialog.showModal();
// Set networkProperties for new configurations and for existing // Set managedProperties for new configurations and for existing
// configurations until the current properties are loaded. // configurations until the current properties are loaded.
assert(this.type && this.type != CrOnc.Type.ALL); assert(this.type && this.type != CrOnc.Type.ALL);
this.networkProperties_ = { this.managedProperties_ = {
GUID: this.guid, GUID: this.guid,
Name: this.name, Name: {Active: this.name},
Type: this.type, Type: this.type,
}; };
this.$.networkConfig.init(); this.$.networkConfig.init();
...@@ -120,10 +120,11 @@ Polymer({ ...@@ -120,10 +120,11 @@ Polymer({
* @private * @private
*/ */
getDialogTitle_: function() { getDialogTitle_: function() {
const name = this.networkProperties_.Name; const name = /** @type {string} */ (
CrOnc.getActiveValue(this.managedProperties_.Name));
if (name) if (name)
return this.i18n('internetConfigName', HTMLEscape(name)); return this.i18n('internetConfigName', HTMLEscape(name));
const type = this.i18n('OncType' + this.networkProperties_.Type); const type = this.i18n('OncType' + this.managedProperties_.Type);
return this.i18n('internetJoinType', type); return this.i18n('internetJoinType', type);
}, },
......
...@@ -3,8 +3,12 @@ ...@@ -3,8 +3,12 @@
// found in the LICENSE file. // found in the LICENSE file.
/** /**
* @fileoverview loadTimeData override values for ONC strings used in * @fileoverview This file has two parts:
* network_config.html and other network configuration UI. *
* 1. loadTimeData override values for ONC strings used in network_config.html
* and other network configuration UI.
*
* 2. Helper functions to convert and handle ONC properties for using in tests.
*/ */
var CrOncTest = CrOncTest || {}; var CrOncTest = CrOncTest || {};
...@@ -81,3 +85,30 @@ CrOncTest.overrideCrOncStrings = function() { ...@@ -81,3 +85,30 @@ CrOncTest.overrideCrOncStrings = function() {
}; };
loadTimeData.overrideValues(oncKeys); loadTimeData.overrideValues(oncKeys);
}; };
/**
* Converts an unmanaged ONC dictionary into a managed dictionary by
* setting properties 'Active' values to values from unmanaged dictionary.
* NOTE: Because of having not only managed variables in ManagedProperty (e.g.
* 'GUID', 'Source', 'Type', etc) this function can handle only simple
* dictionaries such as provided in network_config_test.js.
* @param {!Object|undefined} properties An unmanaged ONC dictionary
* @return {!Object|undefined} A managed version of |properties|.
*/
CrOncTest.convertToManagedProperties = function(properties) {
'use strict';
if (!properties)
return undefined;
var result = {};
var keys = Object.keys(properties);
if (typeof properties != 'object')
return {Active: properties};
for (var i = 0; i < keys.length; ++i) {
var k = keys[i];
if (['GUID', 'Source', 'Type'].includes(k))
result[k] = properties[k];
else
result[k] = this.convertToManagedProperties(properties[k]);
}
return result;
};
...@@ -116,8 +116,7 @@ cr.define('chrome', function() { ...@@ -116,8 +116,7 @@ cr.define('chrome', function() {
var result = this.networkStates_.find(function(state) { var result = this.networkStates_.find(function(state) {
return state.GUID == guid; return state.GUID == guid;
}); });
// TODO(stevenjb): Convert state to ManagedProperties. callback(CrOncTest.convertToManagedProperties(result));
callback(result);
this.methodCalled('getManagedProperties'); this.methodCalled('getManagedProperties');
}, },
......
...@@ -13,11 +13,12 @@ suite('network-config', function() { ...@@ -13,11 +13,12 @@ suite('network-config', function() {
CrOncTest.overrideCrOncStrings(); CrOncTest.overrideCrOncStrings();
}); });
function setNetworkConfig(networkProperties) { function setNetworkConfig(properties) {
PolymerTest.clearBody(); PolymerTest.clearBody();
networkConfig = document.createElement('network-config'); networkConfig = document.createElement('network-config');
networkConfig.networkingPrivate = api_; networkConfig.networkingPrivate = api_;
networkConfig.networkProperties = networkProperties; networkConfig.managedProperties =
CrOncTest.convertToManagedProperties(properties);
} }
function initNetworkConfig() { function initNetworkConfig() {
...@@ -73,8 +74,10 @@ suite('network-config', function() { ...@@ -73,8 +74,10 @@ suite('network-config', function() {
test('Default', function() { test('Default', function() {
return flushAsync().then(() => { return flushAsync().then(() => {
assertEquals('someguid', networkConfig.networkProperties.GUID); assertEquals('someguid', networkConfig.managedProperties.GUID);
assertEquals('somename', networkConfig.networkProperties.Name); assertEquals(
'somename',
CrOnc.getActiveValue(networkConfig.managedProperties.Name));
assertFalse(!!networkConfig.$$('#share')); assertFalse(!!networkConfig.$$('#share'));
assertTrue(!!networkConfig.$$('#ssid')); assertTrue(!!networkConfig.$$('#ssid'));
assertTrue(!!networkConfig.$$('#security')); assertTrue(!!networkConfig.$$('#security'));
...@@ -225,8 +228,10 @@ suite('network-config', function() { ...@@ -225,8 +228,10 @@ suite('network-config', function() {
assertEquals('WPA-EAP', networkConfig.security_); assertEquals('WPA-EAP', networkConfig.security_);
assertEquals( assertEquals(
'PEAP', 'PEAP',
networkConfig.get( CrOnc.getActiveValue(
'Ethernet.EAP.Outer', networkConfig.networkProperties)); /** @type {chrome.networkingPrivate.ManagedDOMString|undefined} */
(networkConfig.get(
'Ethernet.EAP.Outer', networkConfig.managedProperties))));
let outer = networkConfig.$$('#outer'); let outer = networkConfig.$$('#outer');
assertTrue(!!outer); assertTrue(!!outer);
assertTrue(!outer.disabled); assertTrue(!outer.disabled);
......
...@@ -1391,6 +1391,7 @@ CrSettingsInternetPageTest.prototype = { ...@@ -1391,6 +1391,7 @@ CrSettingsInternetPageTest.prototype = {
ROOT_PATH + 'ui/webui/resources/js/assert.js', ROOT_PATH + 'ui/webui/resources/js/assert.js',
'../fake_chrome_event.js', '../fake_chrome_event.js',
'../chromeos/fake_networking_private.js', '../chromeos/fake_networking_private.js',
'../chromeos/cr_onc_strings.js',
'internet_page_tests.js', 'internet_page_tests.js',
]), ]),
}; };
...@@ -1419,6 +1420,7 @@ CrSettingsInternetDetailPageTest.prototype = { ...@@ -1419,6 +1420,7 @@ CrSettingsInternetDetailPageTest.prototype = {
ROOT_PATH + 'ui/webui/resources/js/util.js', ROOT_PATH + 'ui/webui/resources/js/util.js',
'../fake_chrome_event.js', '../fake_chrome_event.js',
'../chromeos/fake_networking_private.js', '../chromeos/fake_networking_private.js',
'../chromeos/cr_onc_strings.js',
'internet_detail_page_tests.js', 'internet_detail_page_tests.js',
]), ]),
}; };
......
...@@ -9,7 +9,9 @@ js_type_check("closure_compile") { ...@@ -9,7 +9,9 @@ js_type_check("closure_compile") {
":network_apnlist", ":network_apnlist",
":network_choose_mobile", ":network_choose_mobile",
":network_config", ":network_config",
":network_config_input",
":network_config_select", ":network_config_select",
":network_config_toggle",
":network_ip_config", ":network_ip_config",
":network_nameservers", ":network_nameservers",
":network_password_input", ":network_password_input",
...@@ -48,8 +50,25 @@ js_library("network_config") { ...@@ -48,8 +50,25 @@ js_library("network_config") {
extra_sources = [ "$interfaces_path/networking_private_interface.js" ] extra_sources = [ "$interfaces_path/networking_private_interface.js" ]
} }
js_library("network_config_element_behavior") {
deps = [
"//ui/webui/resources/cr_elements/chromeos/network:cr_onc_types",
]
}
js_library("network_config_input") {
deps = [
":network_config_element_behavior",
"//ui/webui/resources/cr_elements/policy:cr_policy_network_behavior",
]
externs_list = [ "$externs_path/networking_private.js" ]
extra_sources = [ "$interfaces_path/networking_private_interface.js" ]
}
js_library("network_config_select") { js_library("network_config_select") {
deps = [ deps = [
":network_config_element_behavior",
"//ui/webui/resources/cr_elements/policy:cr_policy_network_behavior",
"//ui/webui/resources/js:assert", "//ui/webui/resources/js:assert",
"//ui/webui/resources/js:i18n_behavior", "//ui/webui/resources/js:i18n_behavior",
] ]
...@@ -57,6 +76,15 @@ js_library("network_config_select") { ...@@ -57,6 +76,15 @@ js_library("network_config_select") {
extra_sources = [ "$interfaces_path/networking_private_interface.js" ] extra_sources = [ "$interfaces_path/networking_private_interface.js" ]
} }
js_library("network_config_toggle") {
deps = [
":network_config_element_behavior",
"//ui/webui/resources/cr_elements/policy:cr_policy_network_behavior",
]
externs_list = [ "$externs_path/networking_private.js" ]
extra_sources = [ "$interfaces_path/networking_private_interface.js" ]
}
js_library("network_ip_config") { js_library("network_ip_config") {
deps = [ deps = [
"//ui/webui/resources/cr_elements/chromeos/network:cr_onc_types", "//ui/webui/resources/cr_elements/chromeos/network:cr_onc_types",
...@@ -73,8 +101,12 @@ js_library("network_nameservers") { ...@@ -73,8 +101,12 @@ js_library("network_nameservers") {
js_library("network_password_input") { js_library("network_password_input") {
deps = [ deps = [
":network_config_element_behavior",
"//ui/webui/resources/cr_elements/policy:cr_policy_network_behavior",
"//ui/webui/resources/js:i18n_behavior", "//ui/webui/resources/js:i18n_behavior",
] ]
externs_list = [ "$externs_path/networking_private.js" ]
extra_sources = [ "$interfaces_path/networking_private_interface.js" ]
} }
js_library("network_property_list") { js_library("network_property_list") {
......
...@@ -97,7 +97,7 @@ Polymer({ ...@@ -97,7 +97,7 @@ Polymer({
apn = cellular.APN; apn = cellular.APN;
if (apn && apn.AccessPointName) { if (apn && apn.AccessPointName) {
activeApn = /** @type {!CrOnc.APNProperties|undefined} */ ( activeApn = /** @type {!CrOnc.APNProperties|undefined} */ (
CrOnc.getSimpleActiveProperties(apn)); CrOnc.getActiveProperties(apn));
} else if (cellular.LastGoodAPN && cellular.LastGoodAPN.AccessPointName) { } else if (cellular.LastGoodAPN && cellular.LastGoodAPN.AccessPointName) {
activeApn = cellular.LastGoodAPN; activeApn = cellular.LastGoodAPN;
} }
......
<link rel="import" href="chrome://resources/html/polymer.html"> <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/chromeos/network/cr_onc_types.html">
<link rel="import" href="chrome://resources/cr_elements/cr_input/cr_input.html">
<link rel="import" href="chrome://resources/cr_elements/cr_toggle/cr_toggle.html"> <link rel="import" href="chrome://resources/cr_elements/cr_toggle/cr_toggle.html">
<link rel="import" href="chrome://resources/html/i18n_behavior.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-flex-layout/iron-flex-layout-classes.html">
<link rel="import" href="network_shared_css.html"> <link rel="import" href="network_config_input.html">
<link rel="import" href="network_password_input.html">
<link rel="import" href="network_config_select.html"> <link rel="import" href="network_config_select.html">
<link rel="import" href="network_config_toggle.html">
<link rel="import" href="network_password_input.html">
<link rel="import" href="network_shared_css.html">
<dom-module id="network-config"> <dom-module id="network-config">
<template> <template>
...@@ -16,9 +17,9 @@ ...@@ -16,9 +17,9 @@
<!-- SSID (WiFi) --> <!-- SSID (WiFi) -->
<template is="dom-if" if="[[isType_(NetworkType_.WI_FI, type)]]" restamp> <template is="dom-if" if="[[isType_(NetworkType_.WI_FI, type)]]" restamp>
<cr-input id="ssid" label="[[i18n('OncWiFi-SSID')]]" <network-config-input id="ssid" label="[[i18n('OncWiFi-SSID')]]"
value="{{configProperties_.WiFi.SSID}}" readonly="[[hasGuid_(guid)]]"> value="{{configProperties_.WiFi.SSID}}" readonly="[[hasGuid_(guid)]]">
</cr-input> </network-config-input>
</template> </template>
<!-- Security (WiFi and Ethernet) --> <!-- Security (WiFi and Ethernet) -->
...@@ -27,7 +28,8 @@ ...@@ -27,7 +28,8 @@
value="{{security_}}" value="{{security_}}"
disabled="[[!securityIsEnabled_(guid, type)]]" disabled="[[!securityIsEnabled_(guid, type)]]"
items="[[getSecurityItems_(type)]]" items="[[getSecurityItems_(type)]]"
onc-prefix="WiFi.Security"> onc-prefix="WiFi.Security"
property="[[getManagedSecurity_(managedProperties)]]">
</network-config-select> </network-config-select>
</template> </template>
...@@ -36,119 +38,132 @@ ...@@ -36,119 +38,132 @@
restamp> restamp>
<network-password-input label="[[i18n('OncWiFi-Passphrase')]]" <network-password-input label="[[i18n('OncWiFi-Passphrase')]]"
value="{{configProperties_.WiFi.Passphrase}}" value="{{configProperties_.WiFi.Passphrase}}"
on-enter="connectIfConfigured_"> on-enter="connectIfConfigured_"
property="[[managedProperties.WiFi.Passphrase]]">
</network-password-input> </network-password-input>
</template> </template>
<!-- VPN --> <!-- VPN -->
<template is="dom-if" if="[[showVpn_]]" restamp> <template is="dom-if" if="[[showVpn_]]" restamp>
<cr-input label="[[i18n('OncVPN-Host')]]" <network-config-input label="[[i18n('OncVPN-Host')]]"
value="{{configProperties_.VPN.Host}}"> value="{{configProperties_.VPN.Host}}"
</cr-input> property="[[managedProperties.VPN.Host]]">
<cr-input label="[[i18n('OncName')]]" </network-config-input>
value="{{configProperties_.Name}}" readonly="[[hasGuid_(guid)]]"> <network-config-input label="[[i18n('OncName')]]"
</cr-input> value="{{configProperties_.Name}}"
readonly="[[hasGuid_(guid)]]">
</network-config-input>
<network-config-select id="outer" label="[[i18n('OncVPN-Type')]]" <network-config-select id="outer" label="[[i18n('OncVPN-Type')]]"
value="{{vpnType_}}" items="[[vpnTypeItems_]]" value="{{vpnType_}}" items="[[vpnTypeItems_]]"
onc-prefix="VPN.Type" disabled="[[hasGuid_(guid)]]"> onc-prefix="VPN.Type" disabled="[[hasGuid_(guid)]]"
property="[[managedProperties.VPN.Type]]">
</network-config-select> </network-config-select>
<template is="dom-if" if="[[!showVpn_.OpenVPN]]"> <template is="dom-if" if="[[!showVpn_.OpenVPN]]">
<cr-input label="[[i18n('OncVPN-L2TP-Username')]]" <network-config-input label="[[i18n('OncVPN-L2TP-Username')]]"
value="{{configProperties_.VPN.L2TP.Username}}"> value="{{configProperties_.VPN.L2TP.Username}}"
</cr-input> property="[[managedProperties.VPN.L2TP.Username]]">
</network-config-input>
<network-password-input label="[[i18n('OncVPN-L2TP-Password')]]" <network-password-input label="[[i18n('OncVPN-L2TP-Password')]]"
value="{{configProperties_.VPN.L2TP.Password}}"> value="{{configProperties_.VPN.L2TP.Password}}"
property="[[managedProperties.VPN.L2TP.Password]]">
</network-password-input> </network-password-input>
<cr-input label="[[i18n('OncVPN-IPsec-Group')]]" <network-config-input label="[[i18n('OncVPN-IPsec-Group')]]"
value="{{configProperties_.VPN.IPsec.Group}}"> value="{{configProperties_.VPN.IPsec.Group}}"
</cr-input> property="[[managedProperties.VPN.IPsec.Group]]">
</network-config-input>
<template is="dom-if" if="[[!showVpn_.Cert]]"> <template is="dom-if" if="[[!showVpn_.Cert]]">
<network-password-input label="[[i18n('OncVPN-IPsec-PSK')]]" <network-password-input label="[[i18n('OncVPN-IPsec-PSK')]]"
value="{{configProperties_.VPN.IPsec.PSK}}" value="{{configProperties_.VPN.IPsec.PSK}}"
on-focus="onPskFocus_" on-blur="onPskBlur_" on-focus="onPskFocus_" on-blur="onPskBlur_"
on-input="onPskInput_"> on-input="onPskInput_"
property="[[managedProperties.VPN.IPsec.PSK]]">
</network-password-input> </network-password-input>
</template> </template>
</template> </template>
<template is="dom-if" if="[[showVpn_.OpenVPN]]"> <template is="dom-if" if="[[showVpn_.OpenVPN]]">
<cr-input label="[[i18n('OncVPN-OpenVPN-Username')]]" <network-config-input label="[[i18n('OncVPN-OpenVPN-Username')]]"
value="{{configProperties_.VPN.OpenVPN.Username}}"> value="{{configProperties_.VPN.OpenVPN.Username}}"
</cr-input> property="[[managedProperties.VPN.OpenVPN.Username]]">
</network-config-input>
<network-password-input label="[[i18n('OncVPN-OpenVPN-Password')]]" <network-password-input label="[[i18n('OncVPN-OpenVPN-Password')]]"
value="{{configProperties_.VPN.OpenVPN.Password}}"> value="{{configProperties_.VPN.OpenVPN.Password}}"
property="[[managedProperties.VPN.OpenVPN.Password]]">
</network-password-input> </network-password-input>
<cr-input label="[[i18n('OncVPN-OpenVPN-OTP')]]" <network-config-input label="[[i18n('OncVPN-OpenVPN-OTP')]]"
value="{{configProperties_.VPN.OpenVPN.OTP}}"> value="{{configProperties_.VPN.OpenVPN.OTP}}"
</cr-input> property="[[managedProperties.VPN.OpenVPN.OTP]]">
</network-config-input>
</template> </template>
<template is="dom-if" if="[[showVpn_.Cert]]"> <template is="dom-if" if="[[showVpn_.Cert]]">
<network-config-select id="vpnServerCa" <network-config-select id="vpnServerCa"
label="[[i18n('OncEAP-ServerCA')]]" label="[[i18n('OncEAP-ServerCA')]]"
value="{{selectedServerCaHash_}}" items="[[serverCaCerts_]]" value="{{selectedServerCaHash_}}" items="[[serverCaCerts_]]"
cert-list> cert-list
property="[[getManagedVpnServerCaRefs_(managedProperties)]]">
</network-config-select> </network-config-select>
<network-config-select id="vpnUserCert" <network-config-select id="vpnUserCert"
label="[[i18n('OncEAP-UserCert')]]" label="[[i18n('OncEAP-UserCert')]]"
value="{{selectedUserCertHash_}}" items="[[userCerts_]]" value="{{selectedUserCertHash_}}" items="[[userCerts_]]"
cert-list> cert-list
property="[[getManagedVpnClientCertType_(managedProperties)]]">
</network-config-select> </network-config-select>
</template> </template>
<div class="property-box"> <network-config-toggle label="[[i18n('networkConfigSaveCredentials')]]"
<div id="vpnSaveCredentialsLabel" class="start"> checked="{{vpnSaveCredentials_}}"
[[i18n('networkConfigSaveCredentials')]] property="[[getManagedVpnSaveCredentials_(managedProperties)]]">
</div> </network-config-toggle>
<cr-toggle checked="{{vpnSaveCredentials_}}"
aria-labelledby="vpnSaveCredentialsLabel">
</cr-toggle>
</div>
</template> </template>
<!-- EAP (WiFi, WiMAX, Ethernet) --> <!-- EAP (WiFi, WiMAX, Ethernet) -->
<template is="dom-if" if="[[showEap_]]" restamp> <template is="dom-if" if="[[showEap_]]" restamp>
<network-config-select id="outer" label="[[i18n('OncEAP-Outer')]]" <network-config-select id="outer" label="[[i18n('OncEAP-Outer')]]"
value="{{eapProperties_.Outer}}" items="[[eapOuterItems_]]" value="{{eapProperties_.Outer}}" items="[[eapOuterItems_]]"
onc-prefix="EAP.Outer" hidden="[[!showEap_.Outer]]"> onc-prefix="EAP.Outer" hidden="[[!showEap_.Outer]]"
property="[[managedEapProperties_.Outer]]">
</network-config-select> </network-config-select>
<network-config-select id="inner" label="[[i18n('OncEAP-Inner')]]" <network-config-select id="inner" label="[[i18n('OncEAP-Inner')]]"
value="{{eapProperties_.Inner}}" value="{{eapProperties_.Inner}}"
items="[[getEapInnerItems_(eapProperties_.Outer)]]" items="[[getEapInnerItems_(eapProperties_.Outer)]]"
onc-prefix="EAP.Inner" hidden="[[!showEap_.Inner]]"> onc-prefix="EAP.Inner" hidden="[[!showEap_.Inner]]"
property="[[managedEapProperties_.Inner]]">
</network-config-select> </network-config-select>
<network-config-select id="serverCa" label="[[i18n('OncEAP-ServerCA')]]" <network-config-select id="serverCa" label="[[i18n('OncEAP-ServerCA')]]"
value="{{selectedServerCaHash_}}" items="[[serverCaCerts_]]" value="{{selectedServerCaHash_}}" items="[[serverCaCerts_]]"
hidden="[[!showEap_.ServerCA]]" cert-list> hidden="[[!showEap_.ServerCA]]" cert-list
property="[[managedEapProperties_.UseSystemCAs]]">
</network-config-select> </network-config-select>
<cr-input label="[[i18n('OncEAP-SubjectMatch')]]" <network-config-input label="[[i18n('OncEAP-SubjectMatch')]]"
value="{{eapProperties_.SubjectMatch}}" value="{{eapProperties_.SubjectMatch}}"
hidden="[[!showEap_.SubjectMatch]]"> hidden="[[!showEap_.SubjectMatch]]"
</cr-input> property="[[managedEapProperties_.SubjectMatch]]">
</network-config-input>
<network-config-select id="userCert" label="[[i18n('OncEAP-UserCert')]]" <network-config-select id="userCert" label="[[i18n('OncEAP-UserCert')]]"
value="{{selectedUserCertHash_}}" items="[[userCerts_]]" value="{{selectedUserCertHash_}}" items="[[userCerts_]]"
hidden="[[!showEap_.UserCert]]" cert-list> hidden="[[!showEap_.UserCert]]" cert-list
property="[[managedEapProperties_.ClientCertType]]">
</network-config-select> </network-config-select>
<cr-input label="[[i18n('OncEAP-Identity')]]" <network-config-input label="[[i18n('OncEAP-Identity')]]"
value="{{eapProperties_.Identity}}" hidden="[[!showEap_.Identity]]"> value="{{eapProperties_.Identity}}" hidden="[[!showEap_.Identity]]"
</cr-input> property="[[managedEapProperties_.Identity]]">
</network-config-input>
<network-password-input label="[[i18n('OncEAP-Password')]]" <network-password-input label="[[i18n('OncEAP-Password')]]"
value="{{eapProperties_.Password}}" hidden="[[!showEap_.Password]]"> value="{{eapProperties_.Password}}" hidden="[[!showEap_.Password]]"
property="[[managedEapProperties_.Password]]">
</network-password-input> </network-password-input>
<cr-input label="[[i18n('OncEAP-AnonymousIdentity')]]" <network-config-input label="[[i18n('OncEAP-AnonymousIdentity')]]"
value="{{eapProperties_.AnonymousIdentity}}" value="{{eapProperties_.AnonymousIdentity}}"
hidden="[[!showEap_.AnonymousIdentity]]"> hidden="[[!showEap_.AnonymousIdentity]]"
</cr-input> property="[[managedEapProperties_.AnonymousIdentity]]">
<div class="property-box"> </network-config-input>
<div id="eapSaveCredentialsLabel" class="start"> <network-config-toggle label="[[i18n('networkConfigSaveCredentials')]]"
[[i18n('networkConfigSaveCredentials')]] checked="{{eapProperties_.SaveCredentials}}"
</div> property="[[managedEapProperties_.SaveCredentials]]">
<cr-toggle checked="{{eapProperties_.SaveCredentials}}" </network-config-toggle>
aria-labelledby="eapSaveCredentialsLabel">
</cr-toggle>
</div>
</template> </template>
<!-- Share (WiFi and WiMAX) --> <!-- Share (WiFi and WiMAX) -->
<template is="dom-if" <template is="dom-if"
if="[[shareIsVisible_(guid, type, networkProperties)]]" restamp> if="[[shareIsVisible_(guid, type, managedProperties)]]" restamp>
<div class="property-box"> <div class="property-box">
<div id="shareLabel" class="start">[[i18n('networkConfigShare')]]</div> <div id="shareLabel" class="start">[[i18n('networkConfigShare')]]</div>
<cr-toggle id="share" checked="{{shareNetwork_}}" <cr-toggle id="share" checked="{{shareNetwork_}}"
......
...@@ -79,26 +79,36 @@ Polymer({ ...@@ -79,26 +79,36 @@ Polymer({
value: false, value: false,
}, },
/** Set to any error from the last configuration result. */
error: {
type: String,
notify: true,
},
/** /**
* The current properties if an existing network being configured. * The managed properties of an existing network.
* This is used for determination of managed fields.
* This will be undefined when configuring a new network. * This will be undefined when configuring a new network.
* @private {!chrome.networkingPrivate.NetworkProperties|undefined} * @private {!chrome.networkingPrivate.ManagedProperties|undefined}
*/ */
networkProperties: { managedProperties: {
type: Object, type: Object,
notify: true, notify: true,
}, },
/** Set to any error from the last configuration result. */ /**
error: { * Managed EAP properties used for determination of managed EAP fields.
type: String, * @private {?chrome.networkingPrivate.ManagedEAPProperties}
notify: true, */
managedEapProperties_: {
type: Object,
value: null,
}, },
/** Set if |guid| is not empty once networkProperties are received. */ /** Set if |guid| is not empty once managedProperties are received. */
propertiesReceived_: Boolean, propertiesReceived_: Boolean,
/** Set once properties have been sent; prevents multiple saves. */ /** Set once managedProperties have been sent; prevents multiple saves. */
propertiesSent_: Boolean, propertiesSent_: Boolean,
/** /**
...@@ -312,7 +322,7 @@ Polymer({ ...@@ -312,7 +322,7 @@ Polymer({
observers: [ observers: [
'setEnableConnect_(isConfigured_, propertiesSent_)', 'setEnableConnect_(isConfigured_, propertiesSent_)',
'setEnableSave_(isConfigured_, propertiesReceived_)', 'setEnableSave_(isConfigured_, propertiesReceived_)',
'updateConfigProperties_(networkProperties)', 'updateConfigProperties_(managedProperties)',
'updateSecurity_(configProperties_, security_)', 'updateSecurity_(configProperties_, security_)',
'updateEapOuter_(eapProperties_.Outer)', 'updateEapOuter_(eapProperties_.Outer)',
'updateEapCerts_(eapProperties_.*, serverCaCerts_, userCerts_)', 'updateEapCerts_(eapProperties_.*, serverCaCerts_, userCerts_)',
...@@ -358,13 +368,14 @@ Polymer({ ...@@ -358,13 +368,14 @@ Polymer({
this.propertiesSent_ = false; this.propertiesSent_ = false;
this.selectedServerCaHash_ = undefined; this.selectedServerCaHash_ = undefined;
this.selectedUserCertHash_ = undefined; this.selectedUserCertHash_ = undefined;
this.guid = this.networkProperties.GUID; this.guid = this.managedProperties.GUID;
this.type = this.networkProperties.Type; this.type = this.managedProperties.Type;
if (this.guid) { if (this.guid) {
this.networkingPrivate.getProperties(this.guid, (properties) => { this.networkingPrivate.getManagedProperties(
this.getPropertiesCallback_(properties); this.guid, (managedProperties) => {
this.focusFirstInput_(); this.getManagedPropertiesCallback_(managedProperties);
}); this.focusFirstInput_();
});
} else { } else {
this.async(() => { this.async(() => {
this.focusFirstInput_(); this.focusFirstInput_();
...@@ -418,7 +429,7 @@ Polymer({ ...@@ -418,7 +429,7 @@ Polymer({
focusFirstInput_: function() { focusFirstInput_: function() {
Polymer.dom.flush(); Polymer.dom.flush();
var e = this.$$( var e = this.$$(
'cr-input:not([readonly]),' + 'network-config-input:not([readonly]),' +
'network-password-input:not([disabled]),' + 'network-password-input:not([disabled]),' +
'network-config-select:not([disabled])'); 'network-config-select:not([disabled])');
if (e) if (e)
...@@ -453,7 +464,7 @@ Polymer({ ...@@ -453,7 +464,7 @@ Polymer({
getSource_: function() { getSource_: function() {
if (!this.guid) if (!this.guid)
return CrOnc.Source.NONE; return CrOnc.Source.NONE;
var source = this.networkProperties.Source; var source = this.managedProperties.Source;
return source ? /** @type {!CrOnc.Source} */ (source) : CrOnc.Source.NONE; return source ? /** @type {!CrOnc.Source} */ (source) : CrOnc.Source.NONE;
}, },
...@@ -508,45 +519,54 @@ Polymer({ ...@@ -508,45 +519,54 @@ Polymer({
}, },
/** /**
* networkingPrivate.getProperties callback. * networkingPrivate.getManagedProperties callback.
* @param {!chrome.networkingPrivate.NetworkProperties} properties * @param {!chrome.networkingPrivate.ManagedProperties} managedProperties
* @private * @private
*/ */
getPropertiesCallback_: function(properties) { getManagedPropertiesCallback_: function(managedProperties) {
if (!properties) { if (!managedProperties) {
// If |properties| is null, the network no longer exists; close the page. // If |managedProperties| is null,
// the network no longer exists; close the page.
console.error('Network no longer exists: ' + this.guid); console.error('Network no longer exists: ' + this.guid);
this.close_(); this.close_();
return; return;
} }
if (properties.Type == CrOnc.Type.ETHERNET && if (managedProperties.Type == CrOnc.Type.ETHERNET &&
this.get('Ethernet.Authentication', properties) != CrOnc.getActiveValue(
/** @type {chrome.networkingPrivate.ManagedDOMString|undefined} */
(this.get('Ethernet.Authentication', managedProperties))) !=
CrOnc.Authentication.WEP_8021X) { CrOnc.Authentication.WEP_8021X) {
// Ethernet may have EAP properties set in a separate EthernetEap // Ethernet may have EAP properties set in a separate EthernetEap
// configuration. Request that before calling |setNetworkProperties_|. // configuration. Request that before calling |setManagedProperties_|.
this.networkingPrivate.getNetworks( this.networkingPrivate.getNetworks(
{networkType: CrOnc.Type.ETHERNET, visible: false, configured: true}, {networkType: CrOnc.Type.ETHERNET, visible: false, configured: true},
this.getEthernetEap_.bind(this, properties)); this.getEthernetEap_.bind(this, managedProperties));
return; return;
} }
if (properties.Type == CrOnc.Type.VPN) { if (managedProperties.Type == CrOnc.Type.VPN) {
this.vpnSaveCredentials_ = this.vpnSaveCredentials_ =
!!this.get('VPN.OpenVPN.SaveCredentials', properties) || !!CrOnc.getActiveValue(
!!this.get('VPN.IPsec.SaveCredentials', properties) || /** @type {chrome.networkingPrivate.ManagedBoolean|undefined} */
!!this.get('VPN.L2TP.SaveCredentials', properties); (this.get('VPN.OpenVPN.SaveCredentials', managedProperties))) ||
if (this.get('VPN.IPsec.PSK', properties) === '') { !!CrOnc.getActiveValue(
/** @type {chrome.networkingPrivate.ManagedBoolean|undefined} */
(this.get('VPN.IPsec.SaveCredentials', managedProperties))) ||
!!CrOnc.getActiveValue(
/** @type {chrome.networkingPrivate.ManagedBoolean|undefined} */
(this.get('VPN.L2TP.SaveCredentials', managedProperties)));
if (CrOnc.getActiveValue(
/** @type {chrome.networkingPrivate.ManagedDOMString|undefined} */
(this.get('VPN.IPsec.PSK', managedProperties))) === '') {
// If an empty PSK is provided, show a blank value in the UI to indicate // If an empty PSK is provided, show a blank value in the UI to indicate
// that the PSK has a saved value. // that the PSK has a saved value.
this.pskSavedUnknown_ = true; this.pskSavedUnknown_ = true;
this.set('VPN.IPsec.PSK', UNKNOWN_PSK, properties);
} else { } else {
this.pskSavedUnknown_ = false; this.pskSavedUnknown_ = false;
} }
} }
this.setManagedProperties_(managedProperties);
this.setNetworkProperties_(properties);
}, },
/** /**
...@@ -589,13 +609,14 @@ Polymer({ ...@@ -589,13 +609,14 @@ Polymer({
}, },
/** /**
* @param {!chrome.networkingPrivate.NetworkProperties} properties * @param {!chrome.networkingPrivate.ManagedProperties} managedProperties
* @private * @private
*/ */
setNetworkProperties_: function(properties) { setManagedProperties_: function(managedProperties) {
this.propertiesReceived_ = true; this.propertiesReceived_ = true;
this.networkProperties = properties; this.managedProperties = managedProperties;
this.setError_(properties.ErrorState); this.managedEapProperties_ = this.getManagedEap_(managedProperties);
this.setError_(managedProperties.ErrorState);
this.updateCertError_(); this.updateCertError_();
// Set the current shareNetwork_ value when properties are received. // Set the current shareNetwork_ value when properties are received.
...@@ -605,13 +626,13 @@ Polymer({ ...@@ -605,13 +626,13 @@ Polymer({
/** /**
* networkingPrivate.getNetworks callback. Expects an array of Ethernet * networkingPrivate.getNetworks callback. Expects an array of Ethernet
* networks and looks for an EAP configuration to apply. * networks and looks for an EAP configuration to apply.
* @param {!chrome.networkingPrivate.NetworkProperties} properties * @param {!chrome.networkingPrivate.ManagedProperties} managedProperties
* @param {!Array<chrome.networkingPrivate.NetworkStateProperties>} networks * @param {!Array<chrome.networkingPrivate.NetworkStateProperties>} networks
* @private * @private
*/ */
getEthernetEap_: function(properties, networks) { getEthernetEap_: function(managedProperties, networks) {
if (this.getRuntimeError_()) { if (this.getRuntimeError_()) {
this.setNetworkProperties_(properties); this.setManagedProperties_(managedProperties);
return; return;
} }
...@@ -622,19 +643,20 @@ Polymer({ ...@@ -622,19 +643,20 @@ Polymer({
network.Ethernet.Authentication == CrOnc.Authentication.WEP_8021X; network.Ethernet.Authentication == CrOnc.Authentication.WEP_8021X;
}); });
if (!ethernetEap) { if (!ethernetEap) {
this.setNetworkProperties_(properties); this.setManagedProperties_(managedProperties);
return; return;
} }
this.networkingPrivate.getProperties(ethernetEap.GUID, (eapProperties) => { this.networkingPrivate.getManagedProperties(
if (!this.getRuntimeError_() && eapProperties.Ethernet.EAP) { ethernetEap.GUID, (eapProperties) => {
this.guid = eapProperties.GUID; if (!this.getRuntimeError_() && eapProperties.Ethernet.EAP) {
this.security_ = CrOnc.Security.WPA_EAP; this.guid = eapProperties.GUID;
properties.GUID = eapProperties.GUID; this.security_ = CrOnc.Security.WPA_EAP;
properties.Ethernet.EAP = eapProperties.Ethernet.EAP; managedProperties.GUID = eapProperties.GUID;
} managedProperties.Ethernet.EAP = eapProperties.Ethernet.EAP;
this.setNetworkProperties_(properties); }
}); this.setManagedProperties_(managedProperties);
});
}, },
/** /**
...@@ -642,7 +664,7 @@ Polymer({ ...@@ -642,7 +664,7 @@ Polymer({
* @private * @private
*/ */
getSecurityItems_() { getSecurityItems_() {
if (this.networkProperties.Type == CrOnc.Type.WI_FI) { if (this.managedProperties.Type == CrOnc.Type.WI_FI) {
return [ return [
CrOnc.Security.NONE, CrOnc.Security.WEP_PSK, CrOnc.Security.WPA_PSK, CrOnc.Security.NONE, CrOnc.Security.WEP_PSK, CrOnc.Security.WPA_PSK,
CrOnc.Security.WPA_EAP CrOnc.Security.WPA_EAP
...@@ -666,7 +688,7 @@ Polymer({ ...@@ -666,7 +688,7 @@ Polymer({
} }
if (this.shareAllowEnable) { if (this.shareAllowEnable) {
// New insecure WiFi networks are always shared. // New insecure WiFi networks are always shared.
if (this.networkProperties.Type == CrOnc.Type.WI_FI && if (this.managedProperties.Type == CrOnc.Type.WI_FI &&
this.security_ == CrOnc.Security.NONE) { this.security_ == CrOnc.Security.NONE) {
this.shareNetwork_ = true; this.shareNetwork_ = true;
return; return;
...@@ -682,7 +704,7 @@ Polymer({ ...@@ -682,7 +704,7 @@ Polymer({
}, },
/** /**
* Updates the config properties when |this.networkProperties| changes. * Updates the config properties when |this.managedProperties| changes.
* This gets called once when navigating to the page when default properties * This gets called once when navigating to the page when default properties
* are set, and again for existing networks when the properties are received. * are set, and again for existing networks when the properties are received.
* @private * @private
...@@ -692,21 +714,27 @@ Polymer({ ...@@ -692,21 +714,27 @@ Polymer({
this.showVpn_ = null; this.showVpn_ = null;
this.vpnType_ = undefined; this.vpnType_ = undefined;
var properties = this.networkProperties; var managedProperties = this.managedProperties;
var configProperties = var configProperties =
/** @type {chrome.networkingPrivate.NetworkConfigProperties} */ ({ /** @type {chrome.networkingPrivate.NetworkConfigProperties} */ ({
Name: properties.Name || '', Name: managedProperties.Name || '',
Type: properties.Type, Type: managedProperties.Type,
}); });
switch (properties.Type) { switch (managedProperties.Type) {
case CrOnc.Type.WI_FI: case CrOnc.Type.WI_FI:
if (properties.WiFi) { if (managedProperties.WiFi) {
configProperties.WiFi = { configProperties.WiFi = {
AutoConnect: properties.WiFi.AutoConnect, AutoConnect:
EAP: Object.assign({}, properties.WiFi.EAP), /** @type {boolean|undefined} */ (
Passphrase: properties.WiFi.Passphrase, CrOnc.getActiveValue(managedProperties.WiFi.AutoConnect)),
SSID: properties.WiFi.SSID, EAP: Object.assign(
Security: properties.WiFi.Security {}, CrOnc.getActiveProperties(managedProperties.WiFi.EAP)),
Passphrase: /** @type {string|undefined} */ (
CrOnc.getActiveValue(managedProperties.WiFi.Passphrase)),
SSID: /** @type {string|undefined} */ (
CrOnc.getActiveValue(managedProperties.WiFi.SSID)),
Security: /** @type {string|undefined} */ (
CrOnc.getActiveValue(managedProperties.WiFi.Security))
}; };
} else { } else {
configProperties.WiFi = { configProperties.WiFi = {
...@@ -720,11 +748,13 @@ Polymer({ ...@@ -720,11 +748,13 @@ Polymer({
break; break;
case CrOnc.Type.ETHERNET: case CrOnc.Type.ETHERNET:
configProperties.Ethernet = { configProperties.Ethernet = {
AutoConnect: !!this.get('Ethernet.AutoConnect', properties) AutoConnect: !!CrOnc.getActiveValue(
/** @type {chrome.networkingPrivate.ManagedBoolean|undefined} */ (
this.get('Ethernet.AutoConnect', managedProperties)))
}; };
if (properties.Ethernet && properties.Ethernet.EAP) { if (managedProperties.Ethernet && managedProperties.Ethernet.EAP) {
configProperties.Ethernet.EAP = configProperties.Ethernet.EAP = Object.assign(
Object.assign({}, properties.Ethernet.EAP), {}, CrOnc.getActiveProperties(managedProperties.Ethernet.EAP)),
configProperties.Ethernet.EAP.Outer = configProperties.Ethernet.EAP.Outer =
configProperties.Ethernet.EAP.Outer || CrOnc.EAPType.LEAP; configProperties.Ethernet.EAP.Outer || CrOnc.EAPType.LEAP;
} }
...@@ -733,10 +763,13 @@ Polymer({ ...@@ -733,10 +763,13 @@ Polymer({
CrOnc.Security.NONE; CrOnc.Security.NONE;
break; break;
case CrOnc.Type.WI_MAX: case CrOnc.Type.WI_MAX:
if (properties.WiMAX) { if (managedProperties.WiMAX) {
configProperties.WiMAX = { configProperties.WiMAX = {
AutoConnect: properties.WiMAX.AutoConnect, AutoConnect:
EAP: Object.assign({}, properties.WiMAX.EAP), /** @type {boolean|undefined} */ (
CrOnc.getActiveValue(managedProperties.WiMAX.AutoConnect)),
EAP: Object.assign(
{}, CrOnc.getActiveProperties(managedProperties.WiMAX.EAP)),
}; };
// WiMAX has no EAP.Outer property, only Identity and Password. // WiMAX has no EAP.Outer property, only Identity and Password.
} else { } else {
...@@ -747,21 +780,30 @@ Polymer({ ...@@ -747,21 +780,30 @@ Polymer({
this.security_ = CrOnc.Security.WPA_EAP; this.security_ = CrOnc.Security.WPA_EAP;
break; break;
case CrOnc.Type.VPN: case CrOnc.Type.VPN:
if (properties.VPN) { if (managedProperties.VPN) {
var vpn = { var vpn = {
Host: properties.VPN.Host, Host: /** @type {string|undefined} */ (
Type: properties.VPN.Type, CrOnc.getActiveValue(managedProperties.VPN.Host)),
Type: /** @type {string|undefined} */ (
CrOnc.getActiveValue(managedProperties.VPN.Type)),
}; };
if (vpn.Type == CrOnc.VPNType.L2TP_IPSEC) { if (vpn.Type == CrOnc.VPNType.L2TP_IPSEC) {
vpn.IPsec = vpn.IPsec =
/** @type {chrome.networkingPrivate.IPSecProperties} */ ( /** @type {chrome.networkingPrivate.IPSecProperties} */ (
Object.assign( Object.assign(
{AuthenticationType: CrOnc.IPsecAuthenticationType.PSK}, {AuthenticationType: CrOnc.IPsecAuthenticationType.PSK},
properties.VPN.IPsec)); CrOnc.getActiveProperties(
vpn.L2TP = Object.assign({Username: ''}, properties.VPN.L2TP); managedProperties.VPN.IPsec)));
if (this.pskSavedUnknown_) {
this.set('IPsec.PSK', UNKNOWN_PSK, vpn);
}
vpn.L2TP = Object.assign(
{Username: ''},
CrOnc.getActiveProperties(managedProperties.VPN.L2TP));
} else { } else {
assert(vpn.Type == CrOnc.VPNType.OPEN_VPN); assert(vpn.Type == CrOnc.VPNType.OPEN_VPN);
vpn.OpenVPN = Object.assign({}, properties.VPN.OpenVPN); vpn.OpenVPN = Object.assign(
{}, CrOnc.getActiveProperties(managedProperties.VPN.OpenVPN));
} }
configProperties.VPN = vpn; configProperties.VPN = vpn;
} else { } else {
...@@ -778,7 +820,7 @@ Polymer({ ...@@ -778,7 +820,7 @@ Polymer({
this.set('eapProperties_', this.getEap_(this.configProperties_)); this.set('eapProperties_', this.getEap_(this.configProperties_));
if (!this.eapProperties_) if (!this.eapProperties_)
this.showEap_ = null; this.showEap_ = null;
if (properties.Type == CrOnc.Type.VPN) if (managedProperties.Type == CrOnc.Type.VPN)
this.vpnType_ = this.getVpnTypeFromProperties_(this.configProperties_); this.vpnType_ = this.getVpnTypeFromProperties_(this.configProperties_);
}, },
...@@ -917,6 +959,28 @@ Polymer({ ...@@ -917,6 +959,28 @@ Polymer({
this.set('eapProperties_', eapProperties); this.set('eapProperties_', eapProperties);
}, },
/**
* @param {!chrome.networkingPrivate.ManagedProperties} managedProperties
* @return {?chrome.networkingPrivate.ManagedEAPProperties}
* @private
*/
getManagedEap_: function(managedProperties) {
var managedEap;
switch (managedProperties.Type) {
case CrOnc.Type.WI_FI:
managedEap = managedProperties.WiFi && managedProperties.WiFi.EAP;
break;
case CrOnc.Type.ETHERNET:
managedEap =
managedProperties.Ethernet && managedProperties.Ethernet.EAP;
break;
case CrOnc.Type.WI_MAX:
managedEap = managedProperties.WiMAX && managedProperties.WiMAX.EAP;
break;
}
return managedEap || null;
},
/** /**
* @param {!chrome.networkingPrivate.NetworkConfigProperties} properties * @param {!chrome.networkingPrivate.NetworkConfigProperties} properties
* @private * @private
...@@ -1394,7 +1458,7 @@ Polymer({ ...@@ -1394,7 +1458,7 @@ Polymer({
this.propertiesSent_ = false; this.propertiesSent_ = false;
return; return;
} }
var connectState = this.networkProperties.ConnectionState; var connectState = this.managedProperties.ConnectionState;
if (connect && if (connect &&
(!connectState || (!connectState ||
connectState == CrOnc.ConnectionState.NOT_CONNECTED)) { connectState == CrOnc.ConnectionState.NOT_CONNECTED)) {
...@@ -1413,7 +1477,7 @@ Polymer({ ...@@ -1413,7 +1477,7 @@ Polymer({
this.setError_(this.getRuntimeError_()); this.setError_(this.getRuntimeError_());
if (this.error) { if (this.error) {
console.error( console.error(
'createNetworkError, type: ' + this.networkProperties.Type + ': ' + 'createNetworkError, type: ' + this.managedProperties.Type + ': ' +
'error: ' + this.error); 'error: ' + this.error);
this.propertiesSent_ = false; this.propertiesSent_ = false;
return; return;
...@@ -1473,5 +1537,59 @@ Polymer({ ...@@ -1473,5 +1537,59 @@ Polymer({
setError_: function(error) { setError_: function(error) {
this.error = error || ''; this.error = error || '';
}, },
/**
* @param {!chrome.networkingPrivate.ManagedProperties} managedProperties
* @return {chrome.networkingPrivate.ManagedDOMString|undefined}
* @private
*/
getManagedSecurity_: function(managedProperties) {
var managedSecurity = undefined;
switch (managedProperties.Type) {
case CrOnc.Type.WI_FI:
managedSecurity =
managedProperties.WiFi && managedProperties.WiFi.Security;
break;
case CrOnc.Type.ETHERNET:
managedSecurity = managedProperties.Ethernet &&
managedProperties.Ethernet.Authentication;
break;
}
return managedSecurity;
},
/**
* @param {!chrome.networkingPrivate.ManagedProperties} managedProperties
* @return {!chrome.networkingPrivate.ManagedBoolean|undefined}
* @private
*/
getManagedVpnSaveCredentials_: function(managedProperties) {
return /** @type {chrome.networkingPrivate.ManagedBoolean|undefined} */ (
this.get('VPN.OpenVPN.SaveCredentials', managedProperties) ||
this.get('VPN.IPsec.SaveCredentials', managedProperties) ||
this.get('VPN.L2TP.SaveCredentials', managedProperties));
},
/**
* @param {!chrome.networkingPrivate.ManagedProperties} managedProperties
* @return {!chrome.networkingPrivate.ManagedDOMStringList|undefined}
* @private
*/
getManagedVpnServerCaRefs_: function(managedProperties) {
return /** @type {chrome.networkingPrivate.ManagedDOMStringList|undefined} */ (
this.get('VPN.OpenVPN.ServerCARefs', managedProperties) ||
this.get('VPN.IPsec.ServerCARefs', managedProperties));
},
/**
* @param {!chrome.networkingPrivate.ManagedProperties} managedProperties
* @return {!chrome.networkingPrivate.ManagedDOMString|undefined}
* @private
*/
getManagedVpnClientCertType_: function(managedProperties) {
return /** @type {chrome.networkingPrivate.ManagedDOMString|undefined} */ (
this.get('VPN.OpenVPN.ClientCertType', managedProperties) ||
this.get('VPN.IPsec.ClientCertType', managedProperties));
},
}); });
})(); })();
<link rel="import" href="chrome://resources/cr_elements/chromeos/network/cr_onc_types.html">
<script src="network_config_element_behavior.js"></script>
// 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.
/**
* @fileoverview Behavior for network config elements.
*/
/** @polymerBehavior */
var NetworkConfigElementBehavior = {
properties: {
disabled: {
type: Boolean,
value: false,
reflectToAttribute: true,
},
/**
* Network managed property associated with the config element.
* @type {?CrOnc.ManagedProperty}
*/
property: {
type: Object,
value: null,
},
},
/**
* @param {boolean} disabled
* @param {?CrOnc.ManagedProperty} property
* @return {boolean} True if the element should be disabled.
* @private
*/
getDisabled_: function(disabled, property) {
return disabled || (!!property && this.isNetworkPolicyEnforced(property));
},
};
<link rel="import" href="chrome://resources/html/polymer.html">
<link rel="import" href="chrome://resources/cr_elements/cr_input/cr_input.html">
<link rel="import" href="chrome://resources/cr_elements/policy/cr_policy_network_behavior.html">
<link rel="import" href="chrome://resources/cr_elements/policy/cr_policy_network_indicator.html">
<link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html">
<link rel="import" href="network_config_element_behavior.html">
<link rel="import" href="network_shared_css.html">
<dom-module id="network-config-input">
<template>
<style include="network-shared">
#container {
align-items: center;
display: flex;
flex-direction: row;
}
cr-input {
width: 100%;
}
cr-policy-network-indicator {
--cr-tooltip-icon-margin-start: var(--cr-controlled-by-spacing);
}
</style>
<div id="container">
<cr-input label="[[label]]" value="{{value}}"
hidden="[[hidden]]" readonly="[[readonly]]"
disabled="[[getDisabled_(disabled, property)]]">
</cr-input>
<cr-policy-network-indicator
property="[[property]]" tooltip-position="left">
</cr-policy-network-indicator>
</div>
</template>
<script src="network_config_input.js"></script>
</dom-module>
// 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.
/**
* @fileoverview Polymer element for network configuration input fields.
*/
Polymer({
is: 'network-config-input',
behaviors: [CrPolicyNetworkBehavior, NetworkConfigElementBehavior],
properties: {
label: String,
hidden: {
type: Boolean,
reflectToAttribute: true,
},
readonly: {
type: Boolean,
reflectToAttribute: true,
},
value: {
type: String,
notify: true,
},
},
focus: function() {
this.$$('cr-input').focus();
},
});
<link rel="import" href="chrome://resources/html/polymer.html"> <link rel="import" href="chrome://resources/html/polymer.html">
<link rel="import" href="chrome://resources/cr_elements/policy/cr_policy_network_behavior.html">
<link rel="import" href="chrome://resources/cr_elements/policy/cr_policy_network_indicator.html">
<link rel="import" href="chrome://resources/cr_elements/policy/cr_tooltip_icon.html">
<link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html"> <link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html">
<link rel="import" href="chrome://resources/html/md_select_css.html"> <link rel="import" href="chrome://resources/html/md_select_css.html">
<link rel="import" href="network_config_element_behavior.html">
<link rel="import" href="network_shared_css.html"> <link rel="import" href="network_shared_css.html">
<dom-module id="network-config-select"> <dom-module id="network-config-select">
...@@ -24,19 +28,35 @@ ...@@ -24,19 +28,35 @@
margin-bottom: var(--cr-form-field-bottom-spacing); margin-bottom: var(--cr-form-field-bottom-spacing);
padding: 0; padding: 0;
} }
#inner {
align-items: center;
display: flex;
flex-direction: row;
}
cr-policy-network-indicator {
--cr-tooltip-icon-margin-start: var(--cr-controlled-by-spacing);
}
</style> </style>
<div id="outer"> <div id="outer">
<div id="label">[[label]]</div> <div id="label">[[label]]</div>
<select class="md-select" disabled="[[disabled]]" <div id="inner">
value="{{value::change}}" aria-label$="[[label]]"> <select class="md-select"
<template is="dom-repeat" items="[[items]]"> disabled="[[getDisabled_(disabled, property)]]"
<option value="[[getItemValue_(item)]]" value="{{value::change}}" aria-label$="[[label]]">
disabled="[[!getItemEnabled_(item)]]"> <template is="dom-repeat" items="[[items]]">
[[getItemLabel_(item, oncPrefix)]] <option value="[[getItemValue_(item)]]"
</option> disabled="[[!getItemEnabled_(item)]]">
</template> [[getItemLabel_(item, oncPrefix)]]
</select> </option>
</template>
</select>
<cr-policy-network-indicator
property="[[property]]" tooltip-position="left">
</cr-policy-network-indicator>
</div>
</div> </div>
</template> </template>
......
...@@ -8,16 +8,15 @@ ...@@ -8,16 +8,15 @@
Polymer({ Polymer({
is: 'network-config-select', is: 'network-config-select',
behaviors: [I18nBehavior], behaviors: [
I18nBehavior,
CrPolicyNetworkBehavior,
NetworkConfigElementBehavior,
],
properties: { properties: {
label: String, label: String,
disabled: {
type: Boolean,
reflectToAttribute: true,
},
/** Set to true if |items| is a list of certificates. */ /** Set to true if |items| is a list of certificates. */
certList: Boolean, certList: Boolean,
......
<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_network_behavior.html">
<link rel="import" href="chrome://resources/cr_elements/policy/cr_policy_network_indicator.html">
<link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html">
<link rel="import" href="network_config_element_behavior.html">
<link rel="import" href="network_shared_css.html">
<dom-module id="network-config-toggle">
<template>
<style include="network-shared">
cr-policy-network-indicator {
--cr-tooltip-icon-margin-start: var(--cr-controlled-by-spacing);
}
</style>
<div class="property-box">
<div class="start">
[[label]]
</div>
<cr-toggle checked="{{checked}}"
disabled="[[getDisabled_(disabled, property)]]"
aria-label$="[[label]]">
</cr-toggle>
<cr-policy-network-indicator
property="[[property]]" tooltip-position="left">
</cr-policy-network-indicator>
</div>
</template>
<script src="network_config_toggle.js"></script>
</dom-module>
// 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.
/**
* @fileoverview Polymer element for network configuration toggle.
*/
Polymer({
is: 'network-config-toggle',
behaviors: [CrPolicyNetworkBehavior, NetworkConfigElementBehavior],
properties: {
label: String,
checked: {
type: Boolean,
value: false,
reflectToAttribute: true,
notify: true,
},
},
});
<link rel="import" href="chrome://resources/html/polymer.html"> <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/cr_elements/cr_icons_css.html">
<link rel="import" href="chrome://resources/cr_elements/cr_input/cr_input.html"> <link rel="import" href="chrome://resources/cr_elements/cr_input/cr_input.html">
<link rel="import" href="chrome://resources/cr_elements/policy/cr_policy_network_behavior.html">
<link rel="import" href="chrome://resources/cr_elements/policy/cr_policy_network_indicator.html">
<link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html">
<link rel="import" href="chrome://resources/html/i18n_behavior.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-icon-button/paper-icon-button-light.html">
<link rel="import" href="network_config_element_behavior.html">
<link rel="import" href="network_shared_css.html"> <link rel="import" href="network_shared_css.html">
<dom-module id="network-password-input"> <dom-module id="network-password-input">
<template> <template>
<style include="network-shared"> <style include="network-shared">
#container {
align-items: center;
display: flex;
flex-direction: row;
}
cr-input { cr-input {
width: 100%; width: 100%;
} }
paper-icon-button-light { cr-policy-network-indicator {
margin: 0; --cr-tooltip-icon-margin-start: var(--cr-controlled-by-spacing);
width: var(--network-control-margin);
} }
</style> </style>
<cr-input id="input" label="[[label]]" value="{{value}}" <div id="container">
disabled="[[disabled]]" type="[[getInputType_(showPassword)]]" <cr-input id="input" label="[[label]]" value="{{value}}"
on-keypress="onInputKeypress_"> disabled="[[getDisabled_(disabled, property)]]"
<paper-icon-button-light id="icon" slot="suffix" type="[[getInputType_(showPassword)]]" on-keypress="onInputKeypress_">
class$="[[getIconClass_(showPassword)]]"> </cr-input>
<button on-tap="onShowPasswordTap_" <template is="dom-if" if="[[!getDisabled_(disabled, property)]]" restamp>
title="[[getShowPasswordTitle_(showPassword)]]"> <paper-icon-button-light id="icon" slot="suffix"
</button> class$="[[getIconClass_(showPassword)]]">
</paper-icon-button-light> <button on-tap="onShowPasswordTap_"
</cr-input> title="[[getShowPasswordTitle_(showPassword)]]">
</button>
</paper-icon-button-light>
</template>
<template is="dom-if" if="[[getDisabled_(disabled, property)]]" restamp>
<cr-policy-network-indicator
property="[[property]]" tooltip-position="left">
</cr-policy-network-indicator>
</template>
</div>
</template> </template>
<script src="network_password_input.js"></script> <script src="network_password_input.js"></script>
</dom-module> </dom-module>
...@@ -8,7 +8,11 @@ ...@@ -8,7 +8,11 @@
Polymer({ Polymer({
is: 'network-password-input', is: 'network-password-input',
behaviors: [I18nBehavior], behaviors: [
I18nBehavior,
CrPolicyNetworkBehavior,
NetworkConfigElementBehavior,
],
properties: { properties: {
label: { label: {
...@@ -16,11 +20,6 @@ Polymer({ ...@@ -16,11 +20,6 @@ Polymer({
reflectToAttribute: true, reflectToAttribute: true,
}, },
disabled: {
type: Boolean,
reflectToAttribute: true,
},
value: { value: {
type: String, type: String,
notify: true, notify: true,
......
...@@ -168,23 +168,22 @@ Polymer({ ...@@ -168,23 +168,22 @@ Polymer({
proxy.Type = /** @type {!CrOnc.ProxySettingsType} */ ( proxy.Type = /** @type {!CrOnc.ProxySettingsType} */ (
CrOnc.getActiveValue(proxySettings.Type)); CrOnc.getActiveValue(proxySettings.Type));
if (proxySettings.Manual) { if (proxySettings.Manual) {
proxy.Manual.HTTPProxy = /** @type {!CrOnc.ProxyLocation|undefined} */ ( proxy.Manual.HTTPProxy =
CrOnc.getSimpleActiveProperties( /** @type {!CrOnc.ProxyLocation|undefined} */ (
proxySettings.Manual.HTTPProxy)) || CrOnc.getActiveProperties(proxySettings.Manual.HTTPProxy)) ||
{Host: '', Port: 80}; {Host: '', Port: 80};
proxy.Manual.SecureHTTPProxy = proxy.Manual.SecureHTTPProxy =
/** @type {!CrOnc.ProxyLocation|undefined} */ ( /** @type {!CrOnc.ProxyLocation|undefined} */ (
CrOnc.getSimpleActiveProperties( CrOnc.getActiveProperties(
proxySettings.Manual.SecureHTTPProxy)) || proxySettings.Manual.SecureHTTPProxy)) ||
{Host: '', Port: 80}; {Host: '', Port: 80};
proxy.Manual.FTPProxy = proxy.Manual.FTPProxy =
/** @type {!CrOnc.ProxyLocation|undefined} */ ( /** @type {!CrOnc.ProxyLocation|undefined} */ (
CrOnc.getSimpleActiveProperties( CrOnc.getActiveProperties(proxySettings.Manual.FTPProxy)) ||
proxySettings.Manual.FTPProxy)) ||
{Host: '', Port: 80}; {Host: '', Port: 80};
proxy.Manual.SOCKS = proxy.Manual.SOCKS =
/** @type {!CrOnc.ProxyLocation|undefined} */ ( /** @type {!CrOnc.ProxyLocation|undefined} */ (
CrOnc.getSimpleActiveProperties(proxySettings.Manual.SOCKS)) || CrOnc.getActiveProperties(proxySettings.Manual.SOCKS)) ||
{Host: '', Port: 80}; {Host: '', Port: 80};
var jsonHttp = proxy.Manual.HTTPProxy; var jsonHttp = proxy.Manual.HTTPProxy;
this.useSameProxy_ = this.useSameProxy_ =
......
...@@ -269,15 +269,27 @@ CrOnc.getStateOrActiveString = function(property) { ...@@ -269,15 +269,27 @@ CrOnc.getStateOrActiveString = function(property) {
return /** @type {string} */ (CrOnc.getActiveValue(property)); return /** @type {string} */ (CrOnc.getActiveValue(property));
}; };
/**
* Return if the property is simple, i.e. doesn't contain any nested
* dictionaries.
* @param property {!Object|undefined}
* @return {boolean}
*/
CrOnc.isSimpleProperty = function(property) {
for (var prop of ['Active', 'Effective', 'UserSetting', 'SharedSetting']) {
if (prop in property)
return true;
}
return false;
};
/** /**
* Converts a managed ONC dictionary into an unmanaged dictionary (i.e. a * Converts a managed ONC dictionary into an unmanaged dictionary (i.e. a
* dictionary of active values). * dictionary of active values).
* NOTE: This is not intended to be used with dictionaries that contain
* nested dictionaries. This will fail and return undefined in that case.
* @param {!Object|undefined} properties A managed ONC dictionary * @param {!Object|undefined} properties A managed ONC dictionary
* @return {!Object|undefined} An unmanaged version of |properties|. * @return {!Object|undefined} An unmanaged version of |properties|.
*/ */
CrOnc.getSimpleActiveProperties = function(properties) { CrOnc.getActiveProperties = function(properties) {
'use strict'; 'use strict';
if (!properties) if (!properties)
return undefined; return undefined;
...@@ -285,14 +297,24 @@ CrOnc.getSimpleActiveProperties = function(properties) { ...@@ -285,14 +297,24 @@ CrOnc.getSimpleActiveProperties = function(properties) {
var keys = Object.keys(properties); var keys = Object.keys(properties);
for (var i = 0; i < keys.length; ++i) { for (var i = 0; i < keys.length; ++i) {
var k = keys[i]; var k = keys[i];
var prop = CrOnc.getActiveValue(properties[k]); var property = properties[k];
if (prop == undefined) { // Skip policy properties with no effective value.
// TODO(nikitapodguzov@ / raleksandrov@): Remove this when crbug.com/888959
// providing dummy values for password fields will be fixed.
if ('Effective' in property && !(property.Effective in property))
continue;
var propertyValue;
if (CrOnc.isSimpleProperty(property))
propertyValue = CrOnc.getActiveValue(property);
else
propertyValue = CrOnc.getActiveProperties(property);
if (propertyValue == undefined) {
console.error( console.error(
'getSimpleActiveProperties called on invalid ONC object: ' + 'getActiveProperties called on invalid ONC object: ' +
JSON.stringify(properties)); JSON.stringify(properties));
return undefined; return undefined;
} }
result[k] = prop; result[k] = propertyValue;
} }
return result; return result;
}; };
...@@ -324,7 +346,7 @@ CrOnc.getIPConfigForType = function(properties, type) { ...@@ -324,7 +346,7 @@ CrOnc.getIPConfigForType = function(properties, type) {
var staticIpConfig = var staticIpConfig =
/** @type {!CrOnc.IPConfigProperties|undefined} */ ( /** @type {!CrOnc.IPConfigProperties|undefined} */ (
CrOnc.getSimpleActiveProperties(properties.StaticIPConfig)); CrOnc.getActiveProperties(properties.StaticIPConfig));
if (!staticIpConfig) if (!staticIpConfig)
return ipConfig; return ipConfig;
......
...@@ -7,9 +7,23 @@ ...@@ -7,9 +7,23 @@
<dom-module id="cr-policy-network-indicator"> <dom-module id="cr-policy-network-indicator">
<template> <template>
<style include="cr-hidden-style"></style> <style include="cr-hidden-style">
/* This field is used for controlling margin of icon outside the indicator
* element (i.e. in the element which uses indicator itself). It's useful
* when we don't want to add margin to indicator if it's hidden and also
* don't want to move/duplicate logic about showing indicator and margin
* outside of indicator element. */
:host {
--cr-tooltip-icon-margin-start: 0;
}
cr-tooltip-icon {
margin-inline-start: var(--cr-tooltip-icon-margin-start);
}
</style>
<cr-tooltip-icon hidden$="[[!indicatorVisible]]" <cr-tooltip-icon hidden$="[[!indicatorVisible]]"
tooltip-text="[[indicatorTooltip_]]" icon-class="[[indicatorIcon]]"> tooltip-text="[[indicatorTooltip_]]" icon-class="[[indicatorIcon]]"
tooltip-position="[[tooltipPosition]]">
</cr-tooltip-icon> </cr-tooltip-icon>
</template> </template>
<script src="cr_policy_network_indicator.js"></script> <script src="cr_policy_network_indicator.js"></script>
......
...@@ -15,10 +15,13 @@ Polymer({ ...@@ -15,10 +15,13 @@ Polymer({
properties: { properties: {
/** /**
* Network property associated with the indicator. * Network property associated with the indicator.
* @type {!CrOnc.ManagedProperty|undefined} * @type {?CrOnc.ManagedProperty|undefined}
*/ */
property: Object, property: Object,
/** Position of tooltip popup related to the policy indicator. */
tooltipPosition: String,
/** /**
* Recommended value for non enforced properties. * Recommended value for non enforced properties.
* @private {!CrOnc.NetworkPropertyType|undefined} * @private {!CrOnc.NetworkPropertyType|undefined}
...@@ -37,7 +40,7 @@ Polymer({ ...@@ -37,7 +40,7 @@ Polymer({
/** @private */ /** @private */
propertyChanged_: function() { propertyChanged_: function() {
var property = this.property; var property = this.property;
if (!this.isControlled(property)) { if (property == null || !this.isControlled(property)) {
this.indicatorType = CrPolicyIndicatorType.NONE; this.indicatorType = CrPolicyIndicatorType.NONE;
return; return;
} }
......
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
</style> </style>
<iron-icon id="indicator" tabindex="0" aria-label$="[[iconAriaLabel]]" <iron-icon id="indicator" tabindex="0" aria-label$="[[iconAriaLabel]]"
aria-describedby="tooltip" icon="[[iconClass]]"></iron-icon> aria-describedby="tooltip" icon="[[iconClass]]"></iron-icon>
<paper-tooltip id="tooltip" for="indicator" position="top" <paper-tooltip id="tooltip" for="indicator" position="[[tooltipPosition]]"
fit-to-visible-bounds> fit-to-visible-bounds>
[[tooltipText]] [[tooltipText]]
</paper-tooltip> </paper-tooltip>
......
...@@ -4,10 +4,19 @@ ...@@ -4,10 +4,19 @@
Polymer({ Polymer({
is: 'cr-tooltip-icon', is: 'cr-tooltip-icon',
properties: { properties: {
iconAriaLabel: String, iconAriaLabel: String,
iconClass: String, iconClass: String,
tooltipText: String, tooltipText: String,
/** Position of tooltip popup related to the icon. */
tooltipPosition: {
type: String,
value: 'top',
}
}, },
/** @return {!Element} */ /** @return {!Element} */
......
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