diff options
author | Jocelyn Turcotte <jocelyn.turcotte@digia.com> | 2014-08-08 14:30:41 +0200 |
---|---|---|
committer | Jocelyn Turcotte <jocelyn.turcotte@digia.com> | 2014-08-12 13:49:54 +0200 |
commit | ab0a50979b9eb4dfa3320eff7e187e41efedf7a9 (patch) | |
tree | 498dfb8a97ff3361a9f7486863a52bb4e26bb898 /chromium/chrome/browser/resources/options | |
parent | 4ce69f7403811819800e7c5ae1318b2647e778d1 (diff) |
Update Chromium to beta version 37.0.2062.68
Change-Id: I188e3b5aff1bec75566014291b654eb19f5bc8ca
Reviewed-by: Andras Becsi <andras.becsi@digia.com>
Diffstat (limited to 'chromium/chrome/browser/resources/options')
99 files changed, 2915 insertions, 1537 deletions
diff --git a/chromium/chrome/browser/resources/options/OWNERS b/chromium/chrome/browser/resources/options/OWNERS index 8da21baca39..4b65fc20160 100644 --- a/chromium/chrome/browser/resources/options/OWNERS +++ b/chromium/chrome/browser/resources/options/OWNERS @@ -1,3 +1,4 @@ dbeam@chromium.org estade@chromium.org jhawkins@chromium.org +stevenjb@chromium.org diff --git a/chromium/chrome/browser/resources/options/arrow_next.png b/chromium/chrome/browser/resources/options/arrow_next.png Binary files differdeleted file mode 100644 index 7d626c0e8cd..00000000000 --- a/chromium/chrome/browser/resources/options/arrow_next.png +++ /dev/null diff --git a/chromium/chrome/browser/resources/options/autofill_edit_address_overlay.html b/chromium/chrome/browser/resources/options/autofill_edit_address_overlay.html index 44ff77f147c..3b7ef004c9c 100644 --- a/chromium/chrome/browser/resources/options/autofill_edit_address_overlay.html +++ b/chromium/chrome/browser/resources/options/autofill_edit_address_overlay.html @@ -2,64 +2,26 @@ <div class="close-button"></div> <h1 id="autofill-address-title"></h1> <div class="content-area"> - <div> - <div id="autofill-name-labels"> - <span i18n-content="autofillFirstNameLabel"></span> - <span i18n-content="autofillMiddleNameLabel"></span> - <span i18n-content="autofillLastNameLabel"></span> - </div> - </div> - <div> - <list id="full-name-list"></list> + <div id="autofill-edit-address-fields"> </div> - <label class="settings-row"> - <div i18n-content="autofillCompanyNameLabel"></div> - <input id="company-name" type="text"> - </label> - - <label class="settings-row"> - <div i18n-content="autofillAddrLine1Label"></div> - <input id="addr-line-1" type="text"> - </label> - - <label class="settings-row"> - <div i18n-content="autofillAddrLine2Label"></div> - <input id="addr-line-2" type="text"> - </label> - - <div class="input-group settings-row"> - <label> - <div i18n-content="autofillCityLabel"></div> - <input id="city" type="text"> - </label> - - <label> - <div id="state-label"></div> - <input id="state" type="text"> - </label> - + <div class="settings-row"> <label> - <div id="postal-code-label"></div> - <input id="postal-code" type="text"> + <div i18n-content="autofillCountryLabel"></div> + <select class="country" field="country"></select> </label> </div> - <div class="settings-row"> - <div i18n-content="autofillCountryLabel"></div> - <select id="country"></select> - </div> - <div class="input-group settings-row"> <div> <div i18n-content="autofillPhoneLabel"></div> - <list id="phone-list" + <list class="short" field="phone" i18n-values="placeholder:autofillAddPhonePlaceholder"></list> </div> <div> <div i18n-content="autofillEmailLabel"></div> - <list id="email-list" + <list class="short" field="email" i18n-values="placeholder:autofillAddEmailPlaceholder"></list> </div> </div> diff --git a/chromium/chrome/browser/resources/options/autofill_edit_address_overlay.js b/chromium/chrome/browser/resources/options/autofill_edit_address_overlay.js index 94b6a5d307d..d3e211324e0 100644 --- a/chromium/chrome/browser/resources/options/autofill_edit_address_overlay.js +++ b/chromium/chrome/browser/resources/options/autofill_edit_address_overlay.js @@ -6,9 +6,6 @@ cr.define('options', function() { /** @const */ var OptionsPage = options.OptionsPage; /** @const */ var ArrayDataModel = cr.ui.ArrayDataModel; - // The GUID of the loaded address. - var guid; - /** * AutofillEditAddressOverlay class * Encapsulated handling of the 'Add Page' overlay page. @@ -26,6 +23,28 @@ cr.define('options', function() { __proto__: OptionsPage.prototype, /** + * The GUID of the loaded address. + * @type {string} + */ + guid_: '', + + /** + * The BCP 47 language code for the layout of input fields. + * @type {string} + */ + languageCode_: '', + + /** + * The saved field values for the address. For example, if the user changes + * from United States to Switzerland, then the State field will be hidden + * and its value will be stored here. If the user changes back to United + * States, then the State field will be restored to its previous value, as + * stored in this object. + * @type {Object} + */ + savedFieldValues_: {}, + + /** * Initializes the page. */ initializePage: function() { @@ -46,8 +65,11 @@ cr.define('options', function() { // Blurring is delayed for list elements. Queue save and close to // ensure that pending changes have been applied. setTimeout(function() { - self.saveAddress_(); - self.dismissOverlay_(); + self.pageDiv.querySelector('[field=phone]').doneValidating().then( + function() { + self.saveAddress_(); + self.dismissOverlay_(); + }); }, 0); }; @@ -62,10 +84,17 @@ cr.define('options', function() { event.preventDefault(); }; - self.guid = ''; - self.populateCountryList_(); - self.clearInputFields_(); - self.connectInputEvents_(); + this.guid_ = ''; + this.populateCountryList_(); + this.rebuildInputFields_( + loadTimeData.getValue('autofillDefaultCountryComponents')); + this.languageCode_ = + loadTimeData.getString('autofillDefaultCountryLanguageCode'); + this.connectInputEvents_(); + this.setInputFields_({}); + this.getCountrySwitcher_().onchange = function(event) { + self.countryChanged_(); + }; }, /** @@ -79,34 +108,27 @@ cr.define('options', function() { }, /** - * Creates, decorates and initializes the multi-value lists for full name, - * phone, and email. + * Creates, decorates and initializes the multi-value lists for phone and + * email. * @private */ createMultiValueLists_: function() { - var list = $('full-name-list'); - options.autofillOptions.AutofillNameValuesList.decorate(list); - list.autoExpands = true; - - list = $('phone-list'); + var list = this.pageDiv.querySelector('[field=phone]'); options.autofillOptions.AutofillPhoneValuesList.decorate(list); list.autoExpands = true; - list = $('email-list'); + list = this.pageDiv.querySelector('[field=email]'); options.autofillOptions.AutofillValuesList.decorate(list); list.autoExpands = true; }, /** - * Updates the data model for the list named |listName| with the values from - * |entries|. - * @param {string} listName The id of the list. + * Updates the data model for the |list| with the values from |entries|. + * @param {cr.ui.List} list The list to update. * @param {Array} entries The list of items to be added to the list. + * @private */ - setMultiValueList_: function(listName, entries) { - // Add data entries. - var list = $(listName); - + setMultiValueList_: function(list, entries) { // Add special entry for adding new values. var augmentedList = entries.slice(); augmentedList.push(null); @@ -127,33 +149,104 @@ cr.define('options', function() { * @private */ dismissOverlay_: function() { - this.clearInputFields_(); - this.guid = ''; + this.setInputFields_({}); + this.inputFieldChanged_(); + this.guid_ = ''; + this.languageCode_ = ''; + this.savedInputFields_ = {}; OptionsPage.closeOverlay(); }, /** + * @return {Element} The element used to switch countries. + * @private + */ + getCountrySwitcher_: function() { + return this.pageDiv.querySelector('[field=country]'); + }, + + /** + * Returns all list elements. + * @return {!NodeList} The list elements. + * @private + */ + getLists_: function() { + return this.pageDiv.querySelectorAll('list[field]'); + }, + + /** + * Returns all text input elements. + * @return {!NodeList} The text input elements. + * @private + */ + getTextFields_: function() { + return this.pageDiv.querySelectorAll('textarea[field], input[field]'); + }, + + /** + * Creates a map from type => value for all text fields. + * @return {Object} The mapping from field names to values. + * @private + */ + getInputFields_: function() { + var address = {country: this.getCountrySwitcher_().value}; + + var lists = this.getLists_(); + for (var i = 0; i < lists.length; i++) { + address[lists[i].getAttribute('field')] = + lists[i].dataModel.slice(0, lists[i].dataModel.length - 1); + } + + var fields = this.getTextFields_(); + for (var i = 0; i < fields.length; i++) { + address[fields[i].getAttribute('field')] = fields[i].value; + } + + return address; + }, + + /** + * Sets the value of each input field according to |address|. + * @param {object} address The object with values to use. + * @private + */ + setInputFields_: function(address) { + this.getCountrySwitcher_().value = address.country || ''; + + var lists = this.getLists_(); + for (var i = 0; i < lists.length; i++) { + this.setMultiValueList_( + lists[i], address[lists[i].getAttribute('field')] || []); + } + + var fields = this.getTextFields_(); + for (var i = 0; i < fields.length; i++) { + fields[i].value = address[fields[i].getAttribute('field')] || ''; + } + }, + + /** * Aggregates the values in the input fields into an array and sends the * array to the Autofill handler. * @private */ saveAddress_: function() { - var address = new Array(); - address[0] = this.guid; - var list = $('full-name-list'); - address[1] = list.dataModel.slice(0, list.dataModel.length - 1); - address[2] = $('company-name').value; - address[3] = $('addr-line-1').value; - address[4] = $('addr-line-2').value; - address[5] = $('city').value; - address[6] = $('state').value; - address[7] = $('postal-code').value; - address[8] = $('country').value; - list = $('phone-list'); - address[9] = list.dataModel.slice(0, list.dataModel.length - 1); - list = $('email-list'); - address[10] = list.dataModel.slice(0, list.dataModel.length - 1); - + var inputFields = this.getInputFields_(); + var address = [ + this.guid_, + inputFields.fullName || [], + inputFields.companyName || '', + inputFields.addrLines || '', + inputFields.dependentLocality || '', + inputFields.city || '', + inputFields.state || '', + inputFields.postalCode || '', + inputFields.sortingCode || '', + inputFields.country || '', + inputFields.phone || [], + inputFields.email || [], + this.languageCode_, + ]; chrome.send('setAddress', address); }, @@ -164,52 +257,53 @@ cr.define('options', function() { * @private */ connectInputEvents_: function() { - var self = this; - $('company-name').oninput = $('addr-line-1').oninput = - $('addr-line-2').oninput = $('city').oninput = $('state').oninput = - $('postal-code').oninput = function(event) { - self.inputFieldChanged_(); - }; - - $('country').onchange = function(event) { - self.countryChanged_(); - }; + var fields = this.getTextFields_(); + for (var i = 0; i < fields.length; i++) { + fields[i].oninput = this.inputFieldChanged_.bind(this); + } }, /** - * Checks the values of each of the input fields and disables the 'Ok' - * button if all of the fields are empty. + * Disables the 'Ok' button if all of the fields are empty. * @private */ inputFieldChanged_: function() { - // Length of lists are tested for <= 1 due to the "add" placeholder item - // in the list. - var disabled = - $('full-name-list').items.length <= 1 && - !$('company-name').value && - !$('addr-line-1').value && !$('addr-line-2').value && - !$('city').value && !$('state').value && !$('postal-code').value && - !$('country').value && $('phone-list').items.length <= 1 && - $('email-list').items.length <= 1; + var disabled = !this.getCountrySwitcher_().value; + if (disabled) { + // Length of lists are tested for > 1 due to the "add" placeholder item + // in the list. + var lists = this.getLists_(); + for (var i = 0; i < lists.length; i++) { + if (lists[i].items.length > 1) { + disabled = false; + break; + } + } + } + + if (disabled) { + var fields = this.getTextFields_(); + for (var i = 0; i < fields.length; i++) { + if (fields[i].value) { + disabled = false; + break; + } + } + } + $('autofill-edit-address-apply-button').disabled = disabled; }, /** - * Updates the postal code and state field labels appropriately for the - * selected country. + * Updates the address fields appropriately for the selected country. * @private */ countryChanged_: function() { - var countryCode = $('country').value || - loadTimeData.getString('defaultCountryCode'); - - var details = loadTimeData.getValue('autofillCountryData')[countryCode]; - var postal = $('postal-code-label'); - postal.textContent = details.postalCodeLabel; - $('state-label').textContent = details.stateLabel; - - // Also update the 'Ok' button as needed. - this.inputFieldChanged_(); + var countryCode = this.getCountrySwitcher_().value; + if (countryCode) + chrome.send('loadAddressEditorComponents', [countryCode]); + else + this.inputFieldChanged_(); }, /** @@ -220,7 +314,7 @@ cr.define('options', function() { var countryList = loadTimeData.getValue('autofillCountrySelectList'); // Add the countries to the country <select> list. - var countrySelect = $('country'); + var countrySelect = this.getCountrySwitcher_(); // Add an empty option. countrySelect.appendChild(new Option('', '')); for (var i = 0; i < countryList.length; i++) { @@ -232,52 +326,85 @@ cr.define('options', function() { }, /** - * Clears the value of each input field. + * Loads the address data from |address|, sets the input fields based on + * this data, and stores the GUID and language code of the address. + * @param {!Object} address Lots of info about an address from the browser. * @private */ - clearInputFields_: function() { - this.setMultiValueList_('full-name-list', []); - $('company-name').value = ''; - $('addr-line-1').value = ''; - $('addr-line-2').value = ''; - $('city').value = ''; - $('state').value = ''; - $('postal-code').value = ''; - $('country').value = ''; - this.setMultiValueList_('phone-list', []); - this.setMultiValueList_('email-list', []); - - this.countryChanged_(); + loadAddress_: function(address) { + this.rebuildInputFields_(address.components); + this.setInputFields_(address); + this.inputFieldChanged_(); + this.connectInputEvents_(); + this.guid_ = address.guid; + this.languageCode_ = address.languageCode; }, /** - * Loads the address data from |address|, sets the input fields based on - * this data and stores the GUID of the address. + * Takes a snapshot of the input values, clears the input values, loads the + * address input layout from |input.components|, restores the input values + * from snapshot, and stores the |input.languageCode| for the address. + * @param {{languageCode: string, components: Array.<Array.<Object>>}} input + * Info about how to layout inputs fields in this dialog. * @private */ - loadAddress_: function(address) { - this.setInputFields_(address); + loadAddressComponents_: function(input) { + var inputFields = this.getInputFields_(); + for (var fieldName in inputFields) { + if (inputFields.hasOwnProperty(fieldName)) + this.savedFieldValues_[fieldName] = inputFields[fieldName]; + } + this.rebuildInputFields_(input.components); + this.setInputFields_(this.savedFieldValues_); this.inputFieldChanged_(); - this.guid = address.guid; + this.connectInputEvents_(); + this.languageCode_ = input.languageCode; }, /** - * Sets the value of each input field according to |address| + * Clears address inputs and rebuilds the input fields according to + * |components|. + * @param {Array.<Array.<Object>>} components A list of information about + * each input field. * @private */ - setInputFields_: function(address) { - this.setMultiValueList_('full-name-list', address.fullName); - $('company-name').value = address.companyName; - $('addr-line-1').value = address.addrLine1; - $('addr-line-2').value = address.addrLine2; - $('city').value = address.city; - $('state').value = address.state; - $('postal-code').value = address.postalCode; - $('country').value = address.country; - this.setMultiValueList_('phone-list', address.phone); - this.setMultiValueList_('email-list', address.email); - - this.countryChanged_(); + rebuildInputFields_: function(components) { + var content = $('autofill-edit-address-fields'); + content.innerHTML = ''; + + var customContainerElements = {fullName: 'div'}; + var customInputElements = {fullName: 'list', addrLines: 'textarea'}; + + for (var i in components) { + var row = document.createElement('div'); + row.classList.add('input-group', 'settings-row'); + content.appendChild(row); + + for (var j in components[i]) { + if (components[i][j].field == 'country') + continue; + + var fieldContainer = document.createElement( + customContainerElements[components[i][j].field] || 'label'); + row.appendChild(fieldContainer); + + var fieldName = document.createElement('div'); + fieldName.textContent = components[i][j].name; + fieldContainer.appendChild(fieldName); + + var input = document.createElement( + customInputElements[components[i][j].field] || 'input'); + input.setAttribute('field', components[i][j].field); + input.classList.add(components[i][j].length); + input.setAttribute('placeholder', components[i][j].placeholder || ''); + fieldContainer.appendChild(input); + + if (input.tagName == 'LIST') { + options.autofillOptions.AutofillValuesList.decorate(input); + input.autoExpands = true; + } + } + } }, }; @@ -285,13 +412,19 @@ cr.define('options', function() { AutofillEditAddressOverlay.getInstance().loadAddress_(address); }; + AutofillEditAddressOverlay.loadAddressComponents = function(input) { + AutofillEditAddressOverlay.getInstance().loadAddressComponents_(input); + }; + AutofillEditAddressOverlay.setTitle = function(title) { $('autofill-address-title').textContent = title; }; AutofillEditAddressOverlay.setValidatedPhoneNumbers = function(numbers) { - AutofillEditAddressOverlay.getInstance().setMultiValueList_('phone-list', - numbers); + var instance = AutofillEditAddressOverlay.getInstance(); + var phoneList = instance.pageDiv.querySelector('[field=phone]'); + instance.setMultiValueList_(phoneList, numbers); + phoneList.didReceiveValidationResult(); }; // Export diff --git a/chromium/chrome/browser/resources/options/autofill_edit_overlay.css b/chromium/chrome/browser/resources/options/autofill_edit_overlay.css index 166f0cd3da1..24500e6a2fb 100644 --- a/chromium/chrome/browser/resources/options/autofill_edit_overlay.css +++ b/chromium/chrome/browser/resources/options/autofill_edit_overlay.css @@ -10,14 +10,21 @@ min-width: 500px; } -#full-name-list input, -#company-name, -#addr-line-1, -#addr-line-2 { +#autofill-edit-address-overlay .long div[role='listitem'] > div > div, +#autofill-edit-address-overlay .long input, +#autofill-edit-address-overlay textarea.long, +#autofill-edit-address-overlay input.long { width: 16em; } -#country { +#autofill-edit-address-overlay .short div[role='listitem'] > div > div, +#autofill-edit-address-overlay .short input, +#autofill-edit-address-overlay textarea.short, +#autofill-edit-address-overlay input.short { + width: 14em; +} + +#autofill-edit-address-overlay .country { max-width: 450px; } @@ -33,45 +40,19 @@ -webkit-padding-end: 4px; -webkit-padding-start: 4px; border: 1px solid darkGray; + /* Border should go "inside" the height. */ + box-sizing: border-box; /* Set the line-height and min-height to match the height of an input element, * so that even empty cells renderer with the correct height. */ - line-height: 1.75em; - min-height: 1.75em; + height: 2em; + line-height: 2em; } :-webkit-any(#autofill-edit-credit-card-overlay, #autofill-edit-address-overlay) - .settings-row div + :-webkit-any(input, select) { + .settings-row label > :-webkit-any(input, select, textarea, list) { margin-top: 4px; } -#autofill-name-labels { - display: -webkit-inline-box; -} - -#autofill-name-labels span { - -webkit-box-flex: 1; - display: block; -} - -#full-name-list { - display: inline-block; -} - -#full-name-list div[role='listitem'] > div { - display: -webkit-box; -} - -#full-name-list div[role='listitem'] > div > div, -#autofill-name-labels span { - -webkit-margin-end: 5px; - width: 16em; -} - -:-webkit-any(#phone-list, #email-list) div[role='listitem'] > div > div, -:-webkit-any(#phone-list, #email-list) input { - width: 14em; -} - .input-group > * { -webkit-box-orient: vertical; -webkit-margin-end: 2px; diff --git a/chromium/chrome/browser/resources/options/autofill_options.html b/chromium/chrome/browser/resources/options/autofill_options.html index 27a869aced5..f24da00fe72 100644 --- a/chromium/chrome/browser/resources/options/autofill_options.html +++ b/chromium/chrome/browser/resources/options/autofill_options.html @@ -5,7 +5,8 @@ <if expr="is_macosx"> <div class="checkbox"> <label> - <input pref="autofill.auxiliary_profiles_enabled" type="checkbox" + <input pref="autofill.use_mac_address_book" type="checkbox" + id="autofill-use-mac-address-book-checkbox" metric="Options_AutofillAuxiliaryProfiles"> <span i18n-content="auxiliaryProfilesEnabled"></span> </label> diff --git a/chromium/chrome/browser/resources/options/autofill_options.js b/chromium/chrome/browser/resources/options/autofill_options.js index 65fb71964ae..bc4c90cf703 100644 --- a/chromium/chrome/browser/resources/options/autofill_options.js +++ b/chromium/chrome/browser/resources/options/autofill_options.js @@ -55,6 +55,19 @@ cr.define('options', function() { $('autofill-options-confirm').onclick = function(event) { OptionsPage.closeOverlay(); }; +<if expr="is_macosx"> + $('autofill-use-mac-address-book-checkbox').onchange = function(event) { + if (this.checked) { + setTimeout(function() { + // Prompt the user to give Chrome access to the user's Address + // Book, if the user was not previously prompted. The dialog that + // appears blocks the Chrome process, so wait for a small period of + // time to allow the checkbox to appear filled in. + chrome.send('accessAddressBook'); + }, 10); + } + }; +</if> // TODO(jhawkins): What happens when Autofill is disabled whilst on the // Autofill options page? diff --git a/chromium/chrome/browser/resources/options/autofill_options_list.js b/chromium/chrome/browser/resources/options/autofill_options_list.js index 0be698d3e2a..8fd7fdb6a09 100644 --- a/chromium/chrome/browser/resources/options/autofill_options_list.js +++ b/chromium/chrome/browser/resources/options/autofill_options_list.js @@ -489,9 +489,52 @@ cr.define('options.autofillOptions', function() { var info = new Array(); info[0] = index; info[1] = numbers; - info[2] = $('country').value; + info[2] = document.querySelector( + '#autofill-edit-address-overlay [field=country]').value; + this.validationRequests_++; chrome.send('validatePhoneNumbers', info); }, + + /** + * The number of ongoing validation requests. + * @type {number} + * @private + */ + validationRequests_: 0, + + /** + * Pending Promise resolver functions. + * @type {Array.<!Function>} + * @private + */ + validationPromiseResolvers_: [], + + /** + * This should be called when a reply of chrome.send('validatePhoneNumbers') + * is received. + */ + didReceiveValidationResult: function() { + this.validationRequests_--; + assert(this.validationRequests_ >= 0); + if (this.validationRequests_ <= 0) { + while (this.validationPromiseResolvers_.length) { + this.validationPromiseResolvers_.pop()(); + } + } + }, + + /** + * Returns a Promise which is fulfilled when all of validation requests are + * completed. + * @return {!Promise} A promise. + */ + doneValidating: function() { + if (this.validationRequests_ <= 0) + return Promise.resolve(); + return new Promise(function(resolve) { + this.validationPromiseResolvers_.push(resolve); + }.bind(this)); + } }; return { diff --git a/chromium/chrome/browser/resources/options/automatic_settings_reset_banner.html b/chromium/chrome/browser/resources/options/automatic_settings_reset_banner.html new file mode 100644 index 00000000000..8eae144ba40 --- /dev/null +++ b/chromium/chrome/browser/resources/options/automatic_settings_reset_banner.html @@ -0,0 +1,15 @@ +<div id="automatic-settings-reset-banner" class="settings-banner" hidden> + <div id="automatic-settings-reset-banner-close" class="close-button"></div> + <div class="content-area"> + <div class="badge"></div> + <div class="text"> + <p> + <span i18n-values=".innerHTML:automaticSettingsResetBannerText"> + </span> + <a id="automatic-settings-reset-learn-more" class="nowrap" + i18n-values="href:automaticSettingsResetLearnMoreUrl" + i18n-content="learnMore" target="_blank"></a> + </p> + </div> + </div> +</div> diff --git a/chromium/chrome/browser/resources/options/automatic_settings_reset_banner.js b/chromium/chrome/browser/resources/options/automatic_settings_reset_banner.js new file mode 100644 index 00000000000..15877ad4b7f --- /dev/null +++ b/chromium/chrome/browser/resources/options/automatic_settings_reset_banner.js @@ -0,0 +1,60 @@ +// Copyright 2014 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. + +// Note: the native-side handler for this is AutomaticSettingsResetHandler. + +cr.define('options', function() { + /** @const */ var SettingsBannerBase = options.SettingsBannerBase; + + /** + * AutomaticSettingsResetBanner class + * Provides encapsulated handling of the Reset Profile Settings banner. + * @constructor + */ + function AutomaticSettingsResetBanner() {} + + cr.addSingletonGetter(AutomaticSettingsResetBanner); + + AutomaticSettingsResetBanner.prototype = { + __proto__: SettingsBannerBase.prototype, + + /** + * Initializes the banner's event handlers. + */ + initialize: function() { + this.showMetricName_ = 'AutomaticSettingsReset_WebUIBanner_BannerShown'; + + this.dismissNativeCallbackName_ = + 'onDismissedAutomaticSettingsResetBanner'; + + this.setVisibilibyDomElement_ = $('automatic-settings-reset-banner'); + + $('automatic-settings-reset-banner-close').onclick = function(event) { + chrome.send('metricsHandler:recordAction', + ['AutomaticSettingsReset_WebUIBanner_ManuallyClosed']); + AutomaticSettingsResetBanner.dismiss(); + }; + $('automatic-settings-reset-learn-more').onclick = function(event) { + chrome.send('metricsHandler:recordAction', + ['AutomaticSettingsReset_WebUIBanner_LearnMoreClicked']); + }; + }, + }; + + // Forward public APIs to private implementations. + [ + 'show', + 'dismiss', + ].forEach(function(name) { + AutomaticSettingsResetBanner[name] = function() { + var instance = AutomaticSettingsResetBanner.getInstance(); + return instance[name + '_'].apply(instance, arguments); + }; + }); + + // Export + return { + AutomaticSettingsResetBanner: AutomaticSettingsResetBanner + }; +}); diff --git a/chromium/chrome/browser/resources/options/browser_options.css b/chromium/chrome/browser/resources/options/browser_options.css index a3dcba14d10..24ed45d766d 100644 --- a/chromium/chrome/browser/resources/options/browser_options.css +++ b/chromium/chrome/browser/resources/options/browser_options.css @@ -87,6 +87,12 @@ html[dir=rtl] #account-picture-wrapper { min-height: 0; } +#profiles-list .profile-container { + -webkit-box-align: center; + display: -webkit-box; + max-width: 100%; +} + #profiles-list .profile-name { -webkit-box-flex: 1; overflow: hidden; @@ -94,6 +100,11 @@ html[dir=rtl] #account-picture-wrapper { white-space: nowrap; } +#profiles-list .profile-supervised { + color: #999; + margin-left: 5px; +} + #profiles-list > * { height: 40px; } @@ -148,6 +159,21 @@ input[type='range'] { padding-top: 0; } +.extension-controlled-warning-box { + background-color: #fbfbfb; + border: 1px solid #cecece; + border-radius: 3px; + padding: 19px; +} + +.extension-controlled-warning { + -webkit-padding-start: 35px; + background-repeat: no-repeat; + margin-bottom: 14px; + padding-bottom: 6px; + padding-top: 3px; +} + /* Override a platform specific rule in Widgets that may no longer be relevant. * Too late in the development cycle to update Widgets.css due to the number * of pages that depend on it. @@ -156,6 +182,10 @@ input[type='range'] { padding-bottom: 0; } +.hotword-settings { + -webkit-margin-start: 22px; +} + /* Internet settings */ #network-settings { @@ -399,10 +429,6 @@ list:not([disabled]) > .network-group[selected] { overflow: hidden; } -#auto-open-file-types-label { - padding: 0.45em 0 -} - .sliding { -webkit-transition: height 200ms; overflow-y: hidden; diff --git a/chromium/chrome/browser/resources/options/browser_options.html b/chromium/chrome/browser/resources/options/browser_options.html index 22c61ff490b..4c05757cd72 100644 --- a/chromium/chrome/browser/resources/options/browser_options.html +++ b/chromium/chrome/browser/resources/options/browser_options.html @@ -3,17 +3,20 @@ <h1 i18n-content="settingsTitle"></h1> </header> <include src="reset_profile_settings_banner.html"> -<if expr="not pp_ifdef('chromeos')"> - <include src="sync_section.html"> -</if> -<if expr="pp_ifdef('chromeos')"> + <include src="automatic_settings_reset_banner.html"> +<if expr="chromeos"> + <include src="secondary_user_banner.html"> <section> - <h3 i18n-content="sectionTitleInternet"></h3> + <div id="network-section-header" class="section-header"> + <h3 i18n-content="sectionTitleInternet"></h3> + <span class="controlled-setting-indicator" plural></span> + </div> <div id="network-settings"> <list id="network-list"></list> <div id="shared-proxies" class="checkbox"> <label> <input id="use-shared-proxies" type="checkbox" + metric="Options_NetworkUseSharedProxies" pref="settings.use_shared_proxies"> <span i18n-content="useSharedProxies"></span> </label> @@ -22,24 +25,32 @@ </div> </section> </if> -<if expr="not pp_ifdef('chromeos')"> +<if expr="not chromeos"> + <include src="sync_section.html"> <include src="startup_section.html"> </if> + <section id="proxy-section" hidden> + <h3 i18n-content="sectionTitleProxy"></h3> + <div id="proxy-section-content"></div> + </section> + <section> <h3 i18n-content="sectionTitleAppearance"></h3> <div class="settings-row"> -<if expr="pp_ifdef('chromeos')"> +<if expr="chromeos"> <button id="set-wallpaper" i18n-content="setWallpaper" guest-visibility="disabled"></button> + <span id="wallpaper-indicator" class="controlled-setting-indicator"> + </span> </if> -<if expr="not pp_ifdef('chromeos') and is_posix and not is_macosx"> +<if expr="not chromeos and is_posix and not is_macosx"> <button id="themes-gallery" i18n-content="themesGallery"></button> <button id="themes-native-button" i18n-content="themesNativeButton"></button> <button id="themes-reset" i18n-content="themesSetClassic"></button> </if> -<if expr="pp_ifdef('chromeos') or is_win or is_macosx"> +<if expr="chromeos or is_win or is_macosx"> <button id="themes-gallery" i18n-content="themesGallery"></button> <button id="themes-reset" i18n-content="themesReset"></button> </if> @@ -65,6 +76,7 @@ <span id="home-page-url" class="home-page-label"></span> <button id="change-home-page" class="link-button" i18n-content="changeHomePage"></button> + <div id="extension-controlled-container"></div> </div> </div> <div class="checkbox" guest-visibility="disabled"> @@ -82,7 +94,7 @@ </span> </span> </div> -<if expr="not pp_ifdef('toolkit_views') and is_posix and not is_macosx"> +<if expr="is_posix and not chromeos and not is_macosx"> <div class="checkbox"><label> <input id="show-window-decorations" type="checkbox" pref="browser.custom_chrome_frame" metric="Options_CustomFrame" @@ -91,7 +103,7 @@ </label></div> </if> </section> -<if expr="pp_ifdef('chromeos')"> +<if expr="chromeos"> <section> <h3 i18n-content="sectionTitleDevice"></h3> <div> @@ -125,14 +137,14 @@ </if> <section> <h3 i18n-content="sectionTitleSearch"></h3> - <div> + <div id="search-section-content"> <label for="default-search-engine" class="settings-row" i18n-values=".innerHTML:defaultSearchGroupLabel"> </label> <div class="settings-row"> <select id="default-search-engine" class="weakrtl"></select> <span class="controlled-setting-indicator" - pref="default_search_provider.enabled"> + pref="default_search_provider_data.template_url_data"> </span> <button id="manage-default-search-engines" i18n-content="defaultSearchManageEngines"> @@ -142,7 +154,7 @@ </section> <section id="sync-users-section" guest-visibility="hidden"> <h3 i18n-content="sectionTitleUsers"></h3> -<if expr="pp_ifdef('chromeos')"> +<if expr="chromeos"> <include src="sync_section.html"> </if> <div id="profiles-section" hidden> @@ -152,7 +164,7 @@ </div> <div id="profiles-buttons"> <button id="profiles-create" i18n-content="profilesCreate"></button> -<if expr="pp_ifdef('enable_settings_app')"> +<if expr="enable_settings_app"> <button id="profiles-app-list-switch" i18n-content="profilesAppListSwitch" hidden> </button> @@ -160,7 +172,7 @@ <button id="profiles-manage" i18n-content="profilesManage" disabled> </button> <button id="profiles-delete" i18n-content="profilesDelete"></button> -<if expr="not pp_ifdef('chromeos')"> +<if expr="not chromeos"> <button id="import-data" i18n-content="importData"></button> </if> </div> @@ -169,8 +181,8 @@ i18n-values=".innerHTML:profilesSupervisedDashboardTip" hidden> </div> </section> -<if expr="not pp_ifdef('chromeos')"> - <section> + <section id="set-default-browser-section"> +<if expr="not chromeos"> <h3 i18n-content="sectionTitleDefaultBrowser"></h3> <div> <button id="set-as-default-browser" @@ -185,11 +197,11 @@ </label> </div> </div> +</if> <!-- not chromeos --> </section> -</if> <!-- not pp_ifdef('chromeos') --> <div id="advanced-settings" hidden> <div id="advanced-settings-container"> -<if expr="pp_ifdef('chromeos')"> +<if expr="chromeos"> <section> <h3 i18n-content="datetimeTitle"></h3> <div class="option-control-table"> @@ -203,13 +215,30 @@ </select> </div> </div> - <div class="checkbox"> + <div class="checkbox settings-row"> <label> <input id="use-24hour-clock" pref="settings.clock.use_24hour_clock" type="checkbox"> <span i18n-content="use24HourClock"></span> </label> </div> + <div id="time-synced-explanation" class="settings-row" + i18n-content="timeSyncedExplanation"></div> + <div id="set-time" class="settings-row" hidden> + <button id="set-time-button" + i18n-content="setTimeButton"></button> + </div> + </div> + </section> + + <section id="security-section" hidden> + <h3 i18n-content="securityTitle"></h3> + <div class="settings-row"> + <span i18n-content="consumerManagementEnrollDescription"></span> + </div> + <div class="settings-row"> + <button id="consumer-management-enroll-button" + i18n-content="consumerManagementEnrollButton"></button> </div> </section> </if> @@ -272,6 +301,22 @@ </div> <div class="checkbox"> <span class="controlled-setting-with-label"> + <input id="safe-browsing-extended-reporting-enabled" + metric="Options_SafeBrowsingExtendedReportingCheckbox" + pref="safebrowsing.extended_reporting_enabled" + type="checkbox"> + <span> + <label for="safe-browsing-extended-reporting-enabled" + i18n-content="safeBrowsingEnableExtendedReporting"> + </label> + <span class="controlled-setting-indicator" + pref="safebrowsing.extended_reporting_enabled"> + </span> + </span> + </span> + </div> + <div class="checkbox"> + <span class="controlled-setting-with-label"> <input id="safeBrowsingEnabled" pref="safebrowsing.enabled" metric="Options_SafeBrowsingCheckbox" type="checkbox"> <span> @@ -284,10 +329,11 @@ </span> </span> </div> -<if expr="pp_ifdef('_google_chrome')"> +<if expr="_google_chrome"> <div class="checkbox"> <span class="controlled-setting-with-label"> <input id="spelling-enabled-control" type="checkbox" + metric="Options_SpellingServiceCheckbox" pref="spellcheck.use_spelling_service" dialog-pref> <span> <label for="spelling-enabled-control" i18n-content="spellingPref"> @@ -301,7 +347,7 @@ </div> <div id="metricsReportingSetting" class="checkbox"> <span class="controlled-setting-with-label"> -<if expr="pp_ifdef('chromeos')"> +<if expr="chromeos"> <input id="metricsReportingEnabled" pref="cros.metrics.reportingEnabled" type="checkbox"> <span> @@ -312,7 +358,7 @@ </span> </span> </if> -<if expr="not pp_ifdef('chromeos')"> +<if expr="not chromeos"> <input id="metricsReportingEnabled" pref="user_experience_metrics.reporting_enabled" type="checkbox"> <span> @@ -325,7 +371,7 @@ </if> </span> </div> -</if> <!-- pp_ifdef('_google_chrome') --> +</if> <!-- _google_chrome --> <div class="checkbox"> <label> <input id="do-not-track-enabled" pref="enable_do_not_track" @@ -333,7 +379,7 @@ <span i18n-content="doNotTrack"></span> </label> </div> -<if expr="pp_ifdef('chromeos')"> +<if expr="chromeos"> <div class="checkbox"> <span class="controlled-setting-with-label"> <input id="content-protection-attestation-enabled" type="checkbox" @@ -352,9 +398,25 @@ </span> </div> </if> + <div id="hotword-search" hidden> + <div class="checkbox"> + <span class="controlled-setting-with-label"> + <input id="hotword-search-enable" pref="hotword.search_enabled_2" + metric="Options_HotwordCheckbox" type="checkbox" dialog-pref> + <span> + <label for="hotword-search-enable" + i18n-values=".innerHTML:hotwordSearchEnable"> + </label> + <span id="hotword-search-setting-indicator" + pref="hotword.search_enabled_2" dialog-pref> + </span> + </span> + </span> + </div> + </div> </div> </section> -<if expr="pp_ifdef('chromeos')"> +<if expr="chromeos"> <!-- By default, the bluetooth section is hidden. It is only visible if a bluetooth adapter is discovered --> <section id="bluetooth-devices" hidden> @@ -381,7 +443,7 @@ </div> </div> </section> -</if> <!-- pp_ifdef('chromeos') --> +</if> <!-- chromeos --> <section id="passwords-and-autofill-section"> <h3 i18n-content="passwordsAndAutofillGroupName"></h3> <div class="checkbox"> @@ -416,18 +478,47 @@ </span> </span> </div> - <div class="checkbox" id="password-generation-checkbox"> - <label> - <input id="password-generation-enabled" pref="password_generation.enabled" - metric="Options_PasswordGenerationCheckbox" type="checkbox"> - <span i18n-content="passwordGenerationEnabledDescription"></span> - </label> - </div> <if expr="is_macosx"> <div id="mac-passwords-warning" i18n-content="macPasswordsWarning" hidden> </div> </if> </section> + <section id="easy-unlock-section" guest-visibility="hidden" hidden> + <h3 i18n-content="easyUnlockSectionTitle"></h3> + <!-- Options shown when the user has not set up Easy Unlock --> + <div id='easy-unlock-setup' hidden> + <button id="easy-unlock-setup-button" + i18n-content="easyUnlockSetupButton"></button> + <div> + <a target="_blank" i18n-content="learnMore" + i18n-values="href:easyUnlockLearnMoreURL"></a> + </div> + </div> + <!-- Options shown when the user has set up Easy Unlock --> + <div id='easy-unlock-enable' hidden> + <div class="checkbox"> + <span class="controlled-setting-with-label"> + <input id="easy-unlock-check" type="checkbox" + pref="easy_unlock.enabled" + metric="EasyUnlock_Enabled"> + <span> + <label for="easy-unlock-checkbox"> + <span i18n-content="easyUnlockCheckboxLabel"></span> + <a target="_blank" i18n-content="learnMore" + i18n-values="href:easyUnlockLearnMoreURL"></a> + </label> + <span class="controlled-setting-indicator" + pref="easy_unlock.enabled"> + </span> + </span> + </span> + </div> + <div> + <a target="_blank" i18n-content="easyUnlockManagement" + i18n-values="href:easyUnlockManagementURL"></a> + </div> + </div> + </section> <section id="web-content-section"> <h3 i18n-content="advancedSectionTitleContent"></h3> <div> @@ -466,11 +557,13 @@ </if> </div> </section> -<if expr="not pp_ifdef('chromeos')"> +<if expr="not chromeos"> <section id="network-section"> <h3 i18n-content="advancedSectionTitleNetwork"></h3> <div> - <span id="proxiesLabel" class="settings-row"></span> + <span id="proxiesLabel" + class="settings-row" + i18n-content="proxiesLabelSystem"></span> <div class="settings-row"> <button id="proxiesConfigureButton" i18n-content="proxiesConfigureButton"></button> @@ -481,7 +574,11 @@ </if> <section id="languages-section"> <h3 i18n-content="advancedSectionTitleLanguages"></h3> - <span class="settings-row" i18n-content="languageSectionLabel"></span> + <div class="settings-row"> + <span i18n-content="languageSectionLabel"></span> + <a target="_blank" i18n-content="learnMore" + i18n-values="href:languagesLearnMoreURL"></a> + </div> <div class="settings-row"> <button id="language-button" i18n-content="languageAndSpellCheckSettingsButton"></button> @@ -534,7 +631,7 @@ </span> </span> </div> -<if expr="pp_ifdef('chromeos')"> +<if expr="chromeos"> <div class="checkbox" id="disable-drive-row" guest-visibility="disabled"> <span class="controlled-setting-with-label"> <input id="drive-disabled" type="checkbox" @@ -548,40 +645,32 @@ </span> </div> </if> -<if expr="not pp_ifdef('chromeos')"> <div id="auto-open-file-types-section" hidden> <div id="auto-open-file-types-container"> - <div id="auto-open-file-types-label" + <div id="auto-open-file-types-label" class="settings-row" i18n-content="autoOpenFileTypesInfo"></div> - <button id="autoOpenFileTypesResetToDefault" - i18n-content="autoOpenFileTypesResetToDefault"></button> + <div class="settings-row"> + <button id="autoOpenFileTypesResetToDefault" + i18n-content="autoOpenFileTypesResetToDefault"></button> + </div> </div> </div> -</if> </div> </section> <section> - <h3 i18n-content="advancedSectionTitleSecurity"></h3> + <h3 i18n-content="advancedSectionTitleCertificates"></h3> <div> -<if expr="pp_ifdef('use_nss') or is_win or is_macosx"> +<if expr="use_nss or is_win or is_macosx"> <div class="settings-row"> <button id="certificatesManageButton" i18n-content="certificatesManageButton"></button> </div> </if> - <div class="checkbox"> - <label> - <input id="sslCheckRevocation" pref="ssl.rev_checking.enabled" - type="checkbox"> - <span i18n-content="sslCheckRevocation"></span> - </label> - </div> </div> </section> - <section id="cloud-print-connector-section"> - <h3 i18n-content="advancedSectionTitleCloudPrint"></h3> -<if expr="pp_ifdef('enable_mdns')"> - <div id="cloudprint-options-mdns" hidden> +<if expr="enable_service_discovery"> + <section id="cloudprint-options-mdns"> + <h3 i18n-content="advancedSectionTitleCloudPrint"></h3> <div class="settings-row"> <span i18n-content="cloudPrintOptionLabel"></span> <a target="_blank" i18n-content="learnMore" @@ -597,7 +686,7 @@ <input id="local-discovery-notifications-enabled" pref="local_discovery.notifications_enabled" type="checkbox" - metric="LocalDiscoveryNotificationsDisabled_Settings" /> + metric="LocalDiscoveryNotificationsDisabled_Settings"> <span> <label for="local-discovery-notifications-enabled" i18n-content="cloudPrintEnableNotificationsLabel"> @@ -606,52 +695,27 @@ pref="local_discovery.notifications_enabled"> </span> </span> + </span> </div> - </div> -</if> - - <div id="cloudprint-options-nomdns"> -<if expr="pp_ifdef('chromeos')"> - <div> - <span i18n-content="cloudPrintOptionLabel"></span> - <a target="_blank" i18n-content="learnMore" - i18n-values="href:cloudPrintLearnMoreURL"></a> - </div> -</if> - -<if expr="not pp_ifdef('chromeos')"> - <p id="cloudPrintConnectorLabel" class="settings-row" - i18n-content="cloudPrintConnectorDisabledLabel"></p> -</if> - - <div class="settings-row"> -<if expr="not pp_ifdef('chromeos')"> - <button id="cloudPrintConnectorSetupButton" - i18n-content="cloudPrintConnectorDisabledButton"></button> + </section> </if> - <button id="cloudPrintManageButton" - i18n-content="cloudPrintManageButton"> - </button> - </div> - </div> - </section> - -<if expr="pp_ifdef('chromeos')"> +<if expr="chromeos"> <include src="startup_section.html"> <section> <h3 i18n-content="accessibilityTitle"></h3> <div class="option-control-table"> <p id="accessibility-explanation" class="settings-row"> <span i18n-content="accessibilityExplanation"></span> - <a target="_blank" i18n-content="learnMore" - i18n-values="href:accessibilityLearnMoreURL"></a> + <a id="accessibility-learn-more" target="_blank" + i18n-content="learnMore"></a> </p> <div class="option-name"> <div class="checkbox"> <span class="controlled-setting-with-label"> <input id="accessibility-should-always-show-menu" - pref="settings.a11y.enable_menu" type="checkbox"> + pref="settings.a11y.enable_menu" type="checkbox" + metric="Options_AccessibilitySystemMenu"> <span> <label for="accessibility-should-always-show-menu" i18n-content="accessibilityAlwaysShowMenu"> @@ -666,7 +730,8 @@ <div class="checkbox"> <span class="controlled-setting-with-label"> <input id="accessibility-large-cursor-check" - pref="settings.a11y.large_cursor_enabled" type="checkbox"> + pref="settings.a11y.large_cursor_enabled" type="checkbox" + metric="Options_AccessibilityLargeMouseCursor"> <span> <label for="accessibility-large-cursor-check" i18n-content="accessibilityLargeCursor"> @@ -682,7 +747,8 @@ <div class="checkbox"> <span class="controlled-setting-with-label"> <input id="accessibility-high-contrast-check" - pref="settings.a11y.high_contrast_enabled" type="checkbox"> + pref="settings.a11y.high_contrast_enabled" type="checkbox" + metric="Options_AccessibilityHighContrastMode"> <span> <label for="accessibility-high-contrast-check" i18n-content="accessibilityHighContrast"> @@ -694,11 +760,12 @@ </span> </div> </div> - <div id="accessibility-sticky-keys" class="option-name" hidden> + <div id="accessibility-sticky-keys" class="option-name"> <div class="checkbox"> <span class="controlled-setting-with-label"> <input id="accessibility-sticky-keys-check" - pref="settings.a11y.sticky_keys_enabled" type="checkbox"> + pref="settings.a11y.sticky_keys_enabled" type="checkbox" + metric="Options_AccessibilityStickyKeys"> <span> <label for="accessibility-sticky-keys-check" i18n-content="accessibilityStickyKeys"> @@ -714,7 +781,8 @@ <div class="checkbox"> <span class="controlled-setting-with-label"> <input id="accessibility-spoken-feedback-check" - pref="settings.accessibility" type="checkbox"> + pref="settings.accessibility" type="checkbox" + metric="Options_AccessibilitySpokenFeedback"> <span> <label for="accessibility-spoken-feedback-check" i18n-content="accessibilitySpokenFeedback"> @@ -734,7 +802,8 @@ <div class="checkbox"> <span class="controlled-setting-with-label"> <input id="accessibility-screen-magnifier-check" - pref="settings.a11y.screen_magnifier" type="checkbox"> + pref="settings.a11y.screen_magnifier" type="checkbox" + metric="Options_AccessibilityScreenMagnifier"> <span> <label for="accessibility-screen-magnifier-check" i18n-content="accessibilityScreenMagnifier"> @@ -750,7 +819,8 @@ <div class="checkbox"> <label> <input id="accessibility-tap-dragging-check" - pref="settings.touchpad.enable_tap_dragging" type="checkbox"> + pref="settings.touchpad.enable_tap_dragging" type="checkbox" + metric="Options_AccessibilityTapDragging"> <span i18n-content="accessibilityTapDragging"></span> </label> </div> @@ -795,8 +865,25 @@ </span> </div> </div> + <div class="option_name" id="accessibility_onscreen_keyboard"> + <div class="checkbox"> + <span class="controlled-setting-with-label"> + <input id="accessibility-virtual-keyboard-check" + pref="settings.a11y.virtual_keyboard" type="checkbox" + metric="Options_AccessibilityOnScreenKeyboard"> + <span> + <label for="accessibility-virtual-keyboard-check" + i18n-content="accessibilityVirtualKeyboard"> + </label> + <span class="controlled-setting-indicator" + pref="settings.a11y.virtual_keyboard"> + </span> + </span> + </span> + </div> + </div> </section> -<if expr="pp_ifdef('chromeos')"> +<if expr="chromeos"> <section id="factory-reset-section" hidden> <h3 i18n-content="factoryResetTitle"></h3> <div> @@ -809,7 +896,7 @@ </section> </if> </if> -<if expr="not pp_ifdef('chromeos')"> +<if expr="not chromeos"> <section id="system-section"> <h3 i18n-content="advancedSectionTitleSystem"></h3> <if expr="not is_macosx"> diff --git a/chromium/chrome/browser/resources/options/browser_options.js b/chromium/chrome/browser/resources/options/browser_options.js index 60cacd18495..dc1302d4952 100644 --- a/chromium/chrome/browser/resources/options/browser_options.js +++ b/chromium/chrome/browser/resources/options/browser_options.js @@ -6,6 +6,7 @@ cr.define('options', function() { var OptionsPage = options.OptionsPage; var ArrayDataModel = cr.ui.ArrayDataModel; var RepeatingButton = cr.ui.RepeatingButton; + var HotwordSearchSettingIndicator = options.HotwordSearchSettingIndicator; // // BrowserOptions class @@ -18,6 +19,16 @@ cr.define('options', function() { cr.addSingletonGetter(BrowserOptions); + /** + * @param {HTMLElement} section The section to show or hide. + * @return {boolean} Whether the section should be shown. + * @private + */ + BrowserOptions.shouldShowSection_ = function(section) { + // If the section is hidden or hiding, it should be shown. + return section.style.height == '' || section.style.height == '0px'; + }; + BrowserOptions.prototype = { __proto__: options.OptionsPage.prototype, @@ -29,6 +40,14 @@ cr.define('options', function() { signedIn_: false, /** + * Indicates whether signing out is allowed or whether a complete profile + * wipe is required to remove the current enterprise account. + * @type {boolean} + * @private + */ + signoutAllowed_: true, + + /** * Keeps track of whether |onShowHomeButtonChanged_| has been called. See * |onShowHomeButtonChanged_|. * @type {boolean} @@ -45,6 +64,14 @@ cr.define('options', function() { */ initializationComplete_: false, + /** + * When a section is waiting to change its height, this will be a number. + * Otherwise it'll be null. + * @type {?number} + * @private + */ + sectionHeightChangeTimeout_: null, + /** @override */ initializePage: function() { OptionsPage.prototype.initializePage.call(this); @@ -57,39 +84,57 @@ cr.define('options', function() { window.addEventListener('message', this.handleWindowMessage_.bind(this)); - $('advanced-settings-expander').onclick = function() { - self.toggleSectionWithAnimation_( - $('advanced-settings'), - $('advanced-settings-container')); - - // If the link was focused (i.e., it was activated using the keyboard) - // and it was used to show the section (rather than hiding it), focus - // the first element in the container. - if (document.activeElement === $('advanced-settings-expander') && - $('advanced-settings').style.height === '') { - var focusElement = $('advanced-settings-container').querySelector( - 'button, input, list, select, a[href]'); - if (focusElement) - focusElement.focus(); - } + if (loadTimeData.getBoolean('allowAdvancedSettings')) { + $('advanced-settings-expander').onclick = function() { + var showAdvanced = + BrowserOptions.shouldShowSection_($('advanced-settings')); + if (showAdvanced) { + chrome.send('coreOptionsUserMetricsAction', + ['Options_ShowAdvancedSettings']); + } + self.toggleSectionWithAnimation_( + $('advanced-settings'), + $('advanced-settings-container')); + + // If the link was focused (i.e., it was activated using the keyboard) + // and it was used to show the section (rather than hiding it), focus + // the first element in the container. + if (document.activeElement === $('advanced-settings-expander') && + showAdvanced) { + var focusElement = $('advanced-settings-container').querySelector( + 'button, input, list, select, a[href]'); + if (focusElement) + focusElement.focus(); + } + }; + } else { + $('advanced-settings-expander').hidden = true; + $('advanced-settings').hidden = true; } $('advanced-settings').addEventListener('webkitTransitionEnd', this.updateAdvancedSettingsExpander_.bind(this)); - if (cr.isChromeOS) + if (cr.isChromeOS) { UIAccountTweaks.applyGuestModeVisibility(document); + if (loadTimeData.getBoolean('secondaryUser')) + $('secondary-user-banner').hidden = false; + } // Sync (Sign in) section. this.updateSyncState_(loadTimeData.getValue('syncData')); $('start-stop-sync').onclick = function(event) { - if (self.signedIn_) - SyncSetupOverlay.showStopSyncingUI(); - else if (cr.isChromeOS) + if (self.signedIn_) { + if (self.signoutAllowed_) + SyncSetupOverlay.showStopSyncingUI(); + else + chrome.send('showDisconnectManagedProfileDialog'); + } else if (cr.isChromeOS) { SyncSetupOverlay.showSetupUI(); - else + } else { SyncSetupOverlay.startSignIn(); + } }; $('customize-sync').onclick = function(event) { SyncSetupOverlay.showSetupUI(); @@ -98,6 +143,14 @@ cr.define('options', function() { // Internet connection section (ChromeOS only). if (cr.isChromeOS) { options.network.NetworkList.decorate($('network-list')); + // Show that the network settings are shared if this is a secondary user + // in a multi-profile session. + if (loadTimeData.getBoolean('secondaryUser')) { + var networkIndicator = document.querySelector( + '#network-section-header > .controlled-setting-indicator'); + networkIndicator.setAttribute('controlled-by', 'shared'); + networkIndicator.location = cr.ui.ArrowLocation.TOP_START; + } options.network.NetworkList.refreshNetworkData( loadTimeData.getValue('networkData')); } @@ -126,16 +179,27 @@ cr.define('options', function() { $('change-home-page').onclick = function(event) { OptionsPage.navigateToPage('homePageOverlay'); + chrome.send('coreOptionsUserMetricsAction', + ['Options_Homepage_ShowSettings']); }; + chrome.send('requestHotwordAvailable'); + var hotwordIndicator = $('hotword-search-setting-indicator'); + HotwordSearchSettingIndicator.decorate(hotwordIndicator); + hotwordIndicator.disabledOnErrorSection = $('hotword-search-enable'); + if ($('set-wallpaper')) { $('set-wallpaper').onclick = function(event) { chrome.send('openWallpaperManager'); + chrome.send('coreOptionsUserMetricsAction', + ['Options_OpenWallpaperManager']); }; } $('themes-gallery').onclick = function(event) { window.open(loadTimeData.getString('themesGalleryURL')); + chrome.send('coreOptionsUserMetricsAction', + ['Options_ThemesGallery']); }; $('themes-reset').onclick = function(event) { chrome.send('themesReset'); @@ -155,9 +219,13 @@ cr.define('options', function() { if (cr.isChromeOS) { $('keyboard-settings-button').onclick = function(evt) { OptionsPage.navigateToPage('keyboard-overlay'); + chrome.send('coreOptionsUserMetricsAction', + ['Options_ShowKeyboardSettings']); }; $('pointer-settings-button').onclick = function(evt) { OptionsPage.navigateToPage('pointer-overlay'); + chrome.send('coreOptionsUserMetricsAction', + ['Options_ShowTouchpadSettings']); }; } @@ -169,15 +237,11 @@ cr.define('options', function() { }; $('default-search-engine').addEventListener('change', this.setDefaultSearchEngine_); - // Without this, the bubble would overlap the uber frame navigation pane - // and would not get mouse event as explained in crbug.com/311421. - document.querySelector( - '#default-search-engine + .controlled-setting-indicator').location = - cr.ui.ArrowLocation.TOP_START; // Users section. if (loadTimeData.valueExists('profilesInfo')) { $('profiles-section').hidden = false; + this.maybeShowUserSection_(); var profilesList = $('profiles-list'); options.browser_options.ProfileList.decorate(profilesList); @@ -228,6 +292,11 @@ cr.define('options', function() { chrome.send('coreOptionsUserMetricsAction', ['Options_ManageAccounts']); }; + + document.querySelector( + '#enable-screen-lock + span > .controlled-setting-indicator'). + setAttribute('textshared', + loadTimeData.getString('screenLockShared')); } else { $('import-data').onclick = function(event) { ImportDataOverlay.show(); @@ -241,8 +310,15 @@ cr.define('options', function() { } } + // Date and time section (CrOS only). + if ($('set-time-button')) + $('set-time-button').onclick = this.handleSetTime_.bind(this); + // Default browser section. if (!cr.isChromeOS) { + if (!loadTimeData.getBoolean('showSetDefault')) { + $('set-default-browser-section').hidden = true; + } $('set-as-default-browser').onclick = function(event) { chrome.send('becomeDefaultBrowser'); }; @@ -340,6 +416,23 @@ cr.define('options', function() { }; } + // Security section. + if (cr.isChromeOS && + loadTimeData.getBoolean('consumerManagementEnabled')) { + $('security-section').hidden = false; + $('consumer-management-enroll-button').onclick = function(event) { + chrome.send('enrollConsumerManagement'); + }; + } + + // Easy Unlock section. + if (loadTimeData.getBoolean('easyUnlockEnabled')) { + $('easy-unlock-section').hidden = false; + $('easy-unlock-setup-button').onclick = function(event) { + chrome.send('launchEasyUnlockSetup'); + }; + } + // Web Content section. $('fontSettingsCustomizeFontsButton').onclick = function(event) { OptionsPage.navigateToPage('fonts'); @@ -372,14 +465,13 @@ cr.define('options', function() { $('downloadLocationChangeButton').onclick = function(event) { chrome.send('selectDownloadLocation'); }; - if (!cr.isChromeOS) { - $('autoOpenFileTypesResetToDefault').onclick = function(event) { - chrome.send('autoOpenFileTypesAction'); - }; - } else { + if (cr.isChromeOS) { $('disable-drive-row').hidden = UIAccountTweaks.loggedInAsLocallyManagedUser(); } + $('autoOpenFileTypesResetToDefault').onclick = function(event) { + chrome.send('autoOpenFileTypesAction'); + }; // HTTPS/SSL section. if (cr.isWindows || cr.isMac) { @@ -394,29 +486,8 @@ cr.define('options', function() { }; } - // Cloud Print section. - // 'cloudPrintProxyEnabled' is true for Chrome branded builds on - // certain platforms, or could be enabled by a lab. - if (!cr.isChromeOS) { - $('cloudPrintConnectorSetupButton').onclick = function(event) { - if ($('cloudPrintManageButton').style.display == 'none') { - // Disable the button, set its text to the intermediate state. - $('cloudPrintConnectorSetupButton').textContent = - loadTimeData.getString('cloudPrintConnectorEnablingButton'); - $('cloudPrintConnectorSetupButton').disabled = true; - chrome.send('showCloudPrintSetupDialog'); - } else { - chrome.send('disableCloudPrintConnector'); - } - }; - } - $('cloudPrintManageButton').onclick = function(event) { - chrome.send('showCloudPrintManagePage'); - }; - if (loadTimeData.getBoolean('cloudPrintShowMDnsOptions')) { $('cloudprint-options-mdns').hidden = false; - $('cloudprint-options-nomdns').hidden = true; $('cloudPrintDevicesPageButton').onclick = function() { chrome.send('showCloudPrintDevicesPage'); }; @@ -431,17 +502,24 @@ cr.define('options', function() { Preferences.getInstance().addEventListener( 'settings.accessibility', updateAccessibilitySettingsButton); - $('accessibility-settings-button').onclick = function(event) { + $('accessibility-learn-more').onclick = function(unused_event) { + window.open(loadTimeData.getString('accessibilityLearnMoreURL')); + chrome.send('coreOptionsUserMetricsAction', + ['Options_AccessibilityLearnMore']); + }; + $('accessibility-settings-button').onclick = function(unused_event) { window.open(loadTimeData.getString('accessibilitySettingsURL')); }; - $('accessibility-spoken-feedback-check').onchange = function(event) { + $('accessibility-spoken-feedback-check').onchange = function( + unused_event) { chrome.send('spokenFeedbackChange', [$('accessibility-spoken-feedback-check').checked]); updateAccessibilitySettingsButton(); }; updateAccessibilitySettingsButton(); - $('accessibility-high-contrast-check').onchange = function(event) { + $('accessibility-high-contrast-check').onchange = function( + unused_event) { chrome.send('highContrastChange', [$('accessibility-high-contrast-check').checked]); }; @@ -453,9 +531,6 @@ cr.define('options', function() { Preferences.getInstance().addEventListener( $('accessibility-autoclick-check').getAttribute('pref'), updateDelayDropdown); - - $('accessibility-sticky-keys').hidden = - !loadTimeData.getBoolean('enableStickyKeys'); } // Display management section (CrOS only). @@ -471,6 +546,7 @@ cr.define('options', function() { if (cr.isChromeOS) { $('factory-reset-restart').onclick = function(event) { OptionsPage.navigateToPage('factoryResetData'); + chrome.send('onPowerwashDialogShow'); }; } @@ -496,6 +572,33 @@ cr.define('options', function() { }; $('reset-profile-settings-section').hidden = !loadTimeData.getBoolean('enableResetProfileSettings'); + + // Extension controlled UI. + this.addExtensionControlledBox_('search-section-content', + 'search-engine-controlled', + true); + this.addExtensionControlledBox_('extension-controlled-container', + 'homepage-controlled', + true); + this.addExtensionControlledBox_('startup-section-content', + 'startpage-controlled', + false); + this.addExtensionControlledBox_('newtab-section-content', + 'newtab-controlled', + false); + this.addExtensionControlledBox_('proxy-section-content', + 'proxy-controlled', + true); + + document.body.addEventListener('click', function(e) { + var button = findAncestor(e.target, function(el) { + return el.tagName == 'BUTTON' && + el.dataset.extensionId !== undefined && + el.dataset.extensionId.length; + }); + if (button) + chrome.send('disableExtension', [button.dataset.extensionId]); + }); }, /** @override */ @@ -549,6 +652,35 @@ cr.define('options', function() { }, /** + * Animatedly changes height |from| a px number |to| a px number. + * @param {HTMLElement} section The section to animate. + * @param {HTMLElement} container The container of |section|. + * @param {boolean} showing Whether to go from 0 -> container height or + * container height -> 0. + * @private + */ + animatedSectionHeightChange_: function(section, container, showing) { + // If the section is already animating, dispatch a synthetic transition + // end event as the upcoming code will cancel the current one. + if (section.classList.contains('sliding')) + cr.dispatchSimpleEvent(section, 'webkitTransitionEnd'); + + this.addTransitionEndListener_(section); + + section.hidden = false; + section.style.height = (showing ? 0 : container.offsetHeight) + 'px'; + section.classList.add('sliding'); + + if (this.sectionHeightChangeTimeout_ !== null) + clearTimeout(this.sectionHeightChangeTimeout_); + + this.sectionHeightChangeTimeout_ = setTimeout(function() { + section.style.height = (showing ? container.offsetHeight : 0) + 'px'; + this.sectionHeightChangeTimeout_ = null; + }); + }, + + /** * Shows the given section. * @param {HTMLElement} section The section to be shown. * @param {HTMLElement} container The container for the section. Must be @@ -557,30 +689,15 @@ cr.define('options', function() { * @private */ showSection_: function(section, container, animate) { - if (animate) - this.addTransitionEndListener_(section); - - // Unhide - section.hidden = false; - section.style.height = '0px'; - - var expander = function() { - // Reveal the section using a WebKit transition if animating. - if (animate) { - section.classList.add('sliding'); - section.style.height = container.offsetHeight + 'px'; - } else { - section.style.height = 'auto'; - } - }; - // Delay starting the transition if animating so that hidden change will // be processed. - if (animate) - setTimeout(expander, 0); - else - expander(); - }, + if (animate) { + this.animatedSectionHeightChange_(section, container, true); + } else { + section.hidden = false; + section.style.height = 'auto'; + } + }, /** * Shows the given section, with animation. @@ -590,33 +707,29 @@ cr.define('options', function() { * @private */ showSectionWithAnimation_: function(section, container) { - this.showSection_(section, container, /*animate */ true); + this.showSection_(section, container, /* animate */ true); }, /** - * See showSectionWithAnimation_. + * Hides the given |section| with animation. + * @param {HTMLElement} section The section to be hidden. + * @param {HTMLElement} container The container for the section. Must be + * inside of |section|. + * @private */ hideSectionWithAnimation_: function(section, container) { - this.addTransitionEndListener_(section); - - // Before we start hiding the section, we need to set - // the height to a pixel value. - section.style.height = container.offsetHeight + 'px'; - - // Delay starting the transition so that the height change will be - // processed. - setTimeout(function() { - // Hide the section using a WebKit transition. - section.classList.add('sliding'); - section.style.height = '0px'; - }, 0); + this.animatedSectionHeightChange_(section, container, false); }, /** - * See showSectionWithAnimation_. + * Toggles the visibility of |section| in an animated way. + * @param {HTMLElement} section The section to be toggled. + * @param {HTMLElement} container The container for the section. Must be + * inside of |section|. + * @private */ toggleSectionWithAnimation_: function(section, container) { - if (section.style.height == '') + if (BrowserOptions.shouldShowSection_(section)) this.showSectionWithAnimation_(section, container); else this.hideSectionWithAnimation_(section, container); @@ -633,7 +746,10 @@ cr.define('options', function() { scrollToSection_: function(section) { var advancedSettings = $('advanced-settings'); var container = $('advanced-settings-container'); - if (advancedSettings.hidden && section.parentNode == container) { + var expander = $('advanced-settings-expander'); + if (!expander.hidden && + advancedSettings.hidden && + section.parentNode == container) { this.showSection_($('advanced-settings'), $('advanced-settings-container'), /* animate */ false); @@ -686,17 +802,23 @@ cr.define('options', function() { /** * Called after an animation transition has ended. + * @param {Event} The webkitTransitionEnd event. NOTE: May be synthetic. * @private */ onTransitionEnd_: function(event) { - if (event.propertyName != 'height') + if (event.propertyName && event.propertyName != 'height') { + // If not a synthetic event or a real transition we care about, bail. return; + } var section = event.target; - - // Disable WebKit transitions. section.classList.remove('sliding'); + if (!event.propertyName) { + // Only real transitions past this point. + return; + } + if (section.style.height == '0px') { // Hide the content so it can't get tab focus. section.hidden = true; @@ -708,9 +830,10 @@ cr.define('options', function() { } }, + /** @private */ updateAdvancedSettingsExpander_: function() { var expander = $('advanced-settings-expander'); - if ($('advanced-settings').style.height == '') + if (BrowserOptions.shouldShowSection_($('advanced-settings'))) expander.textContent = loadTimeData.getString('showAdvancedSettings'); else expander.textContent = loadTimeData.getString('hideAdvancedSettings'); @@ -726,22 +849,25 @@ cr.define('options', function() { if (!syncData.signinAllowed && (!syncData.supervisedUser || !cr.isChromeOS)) { $('sync-section').hidden = true; + this.maybeShowUserSection_(); return; } $('sync-section').hidden = false; + this.maybeShowUserSection_(); + + if (cr.isChromeOS && syncData.supervisedUser) { + var subSection = $('sync-section').firstChild; + while (subSection) { + if (subSection.nodeType == Node.ELEMENT_NODE) + subSection.hidden = true; + subSection = subSection.nextSibling; + } - var subSection = $('sync-section').firstChild; - while (subSection) { - if (subSection.nodeType == Node.ELEMENT_NODE) - subSection.hidden = syncData.supervisedUser; - subSection = subSection.nextSibling; - } - - if (syncData.supervisedUser) { $('account-picture-wrapper').hidden = false; $('sync-general').hidden = false; $('sync-status').hidden = true; + return; } @@ -778,8 +904,8 @@ cr.define('options', function() { // Disable the "sign in" button if we're currently signing in, or if we're // already signed in and signout is not allowed. var signInButton = $('start-stop-sync'); - signInButton.disabled = syncData.setupInProgress || - !syncData.signoutAllowed; + signInButton.disabled = syncData.setupInProgress; + this.signoutAllowed_ = syncData.signoutAllowed; if (!syncData.signoutAllowed) $('start-stop-sync-indicator').setAttribute('controlled-by', 'policy'); else @@ -829,23 +955,27 @@ cr.define('options', function() { customizeSyncButton.disabled = syncData.hasUnrecoverableError || (!syncData.setupCompleted && !$('sync-action-link').hidden); + }, - // Move #enable-auto-login-checkbox to a different location on CrOS. - if (cr.isChromeOs) { - $('sync-general').insertBefore($('sync-status').nextSibling, - $('enable-auto-login-checkbox')); - } - $('enable-auto-login-checkbox').hidden = !syncData.autoLoginVisible; + /** + * Update the UI depending on whether the current profile has a pairing for + * Easy Unlock. + * @param {boolean} hasPairing True if the current profile has a pairing. + */ + updateEasyUnlock_: function(hasPairing) { + $('easy-unlock-setup').hidden = hasPairing; + $('easy-unlock-enable').hidden = !hasPairing; }, /** * Update the UI depending on whether the current profile manages any * supervised users. - * @param {boolean} value True if the current profile manages any supervised + * @param {boolean} show True if the current profile manages any supervised * users. */ - updateManagesSupervisedUsers_: function(value) { - $('profiles-supervised-dashboard-tip').hidden = !value; + updateManagesSupervisedUsers_: function(show) { + $('profiles-supervised-dashboard-tip').hidden = !show; + this.maybeShowUserSection_(); }, /** @@ -878,6 +1008,18 @@ cr.define('options', function() { }, /** + * Activates the Hotword section from the System settings page. + * @param {string} opt_error The error message to display. + * @param {string} opt_help_link The link to a troubleshooting page. + * @private + */ + showHotwordSection_: function(opt_error, opt_help_link) { + $('hotword-search').hidden = false; + $('hotword-search-setting-indicator').errorText = opt_error; + $('hotword-search-setting-indicator').helpLink = opt_help_link; + }, + + /** * Event listener for the 'homepage is NTP' preference. Updates the label * next to the 'Change' button. * @param {Event} event The preference change event. @@ -928,12 +1070,13 @@ cr.define('options', function() { onDefaultDownloadDirectoryChanged_: function(event) { $('downloadLocationPath').value = event.value.value; if (cr.isChromeOS) { - // On ChromeOS, replace /special/drive/root with Drive for drive paths, - // /home/chronos/user/Downloads or /home/chronos/u-<hash>/Downloads - // with Downloads for local paths, and '/' with ' \u203a ' (angled quote - // sign) everywhere. The modified path is used only for display purpose. + // On ChromeOS, replace /special/drive-<hash>/root with "Google Drive" + // for remote files, /home/chronos/user/Downloads or + // /home/chronos/u-<hash>/Downloads with "Downloads" for local paths, + // and '/' with ' \u203a ' (angled quote sign) everywhere. The modified + // path is used only for display purpose. var path = $('downloadLocationPath').value; - path = path.replace(/^\/special\/drive\/root/, 'Google Drive'); + path = path.replace(/^\/special\/drive[^\/]*\/root/, 'Google Drive'); path = path.replace(/^\/home\/chronos\/(user|u-[^\/]*)\//, ''); path = path.replace(/\//g, ' \u203a '); $('downloadLocationPath').value = path; @@ -1092,7 +1235,8 @@ cr.define('options', function() { * name: "Profile Name", * iconURL: "chrome://path/to/icon/image", * filePath: "/path/to/profile/data/on/disk", - * isCurrentProfile: false + * isCurrentProfile: false, + * isManaged: false * }; * @private */ @@ -1180,6 +1324,15 @@ cr.define('options', function() { 'There should always be a current profile, but none found.'); }, + /** + * Propmpts user to confirm deletion of the profile for this browser + * window. + * @private + */ + deleteCurrentProfile_: function() { + ManageProfileOverlay.showDeleteDialog(this.getCurrentProfile_()); + }, + setNativeThemeButtonEnabled_: function(enabled) { var button = $('themes-native-button'); if (button) @@ -1221,6 +1374,20 @@ cr.define('options', function() { } }, + setWallpaperManaged_: function(managed) { + var button = $('set-wallpaper'); + button.disabled = !!managed; + + // Create a synthetic pref change event decorated as + // CoreOptionsHandler::CreateValueForPref() does. + var event = new Event('wallpaper'); + if (managed) + event.value = { controlledBy: 'policy' }; + else + event.value = {}; + $('wallpaper-indicator').handlePrefChange(event); + }, + /** * Handle the 'add device' button click. * @private @@ -1266,17 +1433,6 @@ cr.define('options', function() { }, /** - * Set the visibility of the password generation checkbox. - * @private - */ - setPasswordGenerationSettingVisibility_: function(visible) { - if (visible) - $('password-generation-checkbox').style.display = 'block'; - else - $('password-generation-checkbox').style.display = 'none'; - }, - - /** * Set the font size selected item. This item actually reflects two * preferences: the default font size and the default fixed font size. * @@ -1351,9 +1507,6 @@ cr.define('options', function() { * @private */ setAutoOpenFileTypesDisplayed_: function(display) { - if (cr.isChromeOS) - return; - if ($('advanced-settings').hidden) { // If the Advanced section is hidden, don't animate the transition. $('auto-open-file-types-section').hidden = !display; @@ -1371,10 +1524,14 @@ cr.define('options', function() { }, /** - * Set the enabled state for the proxy settings button. + * Set the enabled state for the proxy settings button and its associated + * message when extension controlled. + * @param {boolean} disabled Whether the button should be disabled. + * @param {boolean} extensionControlled Whether the proxy is extension + * controlled. * @private */ - setupProxySettingsSection_: function(disabled, extensionControlled) { + setupProxySettingsButton_: function(disabled, extensionControlled) { if (!cr.isChromeOS) { $('proxiesConfigureButton').disabled = disabled; $('proxiesLabel').textContent = @@ -1384,37 +1541,6 @@ cr.define('options', function() { }, /** - * Set the Cloud Print proxy UI to enabled, disabled, or processing. - * @private - */ - setupCloudPrintConnectorSection_: function(disabled, label, allowed) { - if (!cr.isChromeOS) { - $('cloudPrintConnectorLabel').textContent = label; - if (disabled || !allowed) { - $('cloudPrintConnectorSetupButton').textContent = - loadTimeData.getString('cloudPrintConnectorDisabledButton'); - $('cloudPrintManageButton').style.display = 'none'; - } else { - $('cloudPrintConnectorSetupButton').textContent = - loadTimeData.getString('cloudPrintConnectorEnabledButton'); - $('cloudPrintManageButton').style.display = 'inline'; - } - $('cloudPrintConnectorSetupButton').disabled = !allowed; - } - }, - - /** - * @private - */ - removeCloudPrintConnectorSection_: function() { - if (!cr.isChromeOS) { - var connectorSectionElm = $('cloud-print-connector-section'); - if (connectorSectionElm) - connectorSectionElm.parentNode.removeChild(connectorSectionElm); - } - }, - - /** * Set the initial state of the spoken feedback checkbox. * @private */ @@ -1447,6 +1573,92 @@ cr.define('options', function() { }, /** + * Adds hidden warning boxes for settings potentially controlled by + * extensions. + * @param {string} parentDiv The div name to append the bubble to. + * @param {string} bubbleId The ID to use for the bubble. + * @param {boolean} first Add as first node if true, otherwise last. + * @private + */ + addExtensionControlledBox_: function(parentDiv, bubbleId, first) { + var bubble = $('extension-controlled-warning-template').cloneNode(true); + bubble.id = bubbleId; + var parent = $(parentDiv); + if (first) + parent.insertBefore(bubble, parent.firstChild); + else + parent.appendChild(bubble); + }, + + /** + * Adds a bubble showing that an extension is controlling a particular + * setting. + * @param {string} parentDiv The div name to append the bubble to. + * @param {string} bubbleId The ID to use for the bubble. + * @param {string} extensionId The ID of the controlling extension. + * @param {string} extensionName The name of the controlling extension. + * @private + */ + toggleExtensionControlledBox_: function( + parentDiv, bubbleId, extensionId, extensionName) { + var bubble = $(bubbleId); + assert(bubble); + bubble.hidden = extensionId.length == 0; + if (bubble.hidden) + return; + + // Set the extension image. + var div = bubble.firstElementChild; + div.style.backgroundImage = + 'url(chrome://extension-icon/' + extensionId + '/24/1)'; + + // Set the bubble label. + var label = loadTimeData.getStringF('extensionControlled', extensionName); + var docFrag = parseHtmlSubset('<div>' + label + '</div>', ['B', 'DIV']); + div.innerHTML = docFrag.firstChild.innerHTML; + + // Wire up the button to disable the right extension. + var button = div.nextElementSibling; + button.dataset.extensionId = extensionId; + }, + + /** + * Toggles the warning boxes that show which extension is controlling + * various settings of Chrome. + * @param {object} details A dictionary of ID+name pairs for each of the + * settings controlled by an extension. + * @private + */ + toggleExtensionIndicators_: function(details) { + this.toggleExtensionControlledBox_('search-section-content', + 'search-engine-controlled', + details.searchEngine.id, + details.searchEngine.name); + this.toggleExtensionControlledBox_('extension-controlled-container', + 'homepage-controlled', + details.homePage.id, + details.homePage.name); + this.toggleExtensionControlledBox_('startup-section-content', + 'startpage-controlled', + details.startUpPage.id, + details.startUpPage.name); + this.toggleExtensionControlledBox_('newtab-section-content', + 'newtab-controlled', + details.newTabPage.id, + details.newTabPage.name); + this.toggleExtensionControlledBox_('proxy-section-content', + 'proxy-controlled', + details.proxy.id, + details.proxy.name); + + // The proxy section contains just the warning box and nothing else, so + // if we're hiding the proxy warning box, we should also hide its header + // section. + $('proxy-section').hidden = details.proxy.id.length == 0; + }, + + + /** * Show/hide touchpad-related settings. * @private */ @@ -1550,12 +1762,44 @@ cr.define('options', function() { */ showImagerPickerOverlay_: function() { OptionsPage.navigateToPage('changePicture'); - } + }, + + /** + * Shows (or not) the "User" section of the settings page based on whether + * any of the sub-sections are present (or not). + * @private + */ + maybeShowUserSection_: function() { + $('sync-users-section').hidden = + $('profiles-section').hidden && + $('sync-section').hidden && + $('profiles-supervised-dashboard-tip').hidden; + }, + + /** + * Updates the date and time section with time sync information. + * @param {boolean} canSetTime Whether the system time can be set. + * @private + */ + setCanSetTime_: function(canSetTime) { + // If the time has been network-synced, it cannot be set manually. + $('time-synced-explanation').hidden = canSetTime; + $('set-time').hidden = !canSetTime; + }, + + /** + * Handle the 'set date and time' button click. + * @private + */ + handleSetTime_: function() { + chrome.send('showSetTime'); + }, }; //Forward public APIs to private implementations. [ 'addBluetoothDevice', + 'deleteCurrentProfile', 'enableCertificateButton', 'enableFactoryResetSection', 'getCurrentProfile', @@ -1563,35 +1807,37 @@ cr.define('options', function() { 'hideBluetoothSettings', 'notifyInitializationComplete', 'removeBluetoothDevice', - 'removeCloudPrintConnectorSection', 'scrollToSection', 'setAccountPictureManaged', + 'setWallpaperManaged', 'setAutoOpenFileTypesDisplayed', 'setBluetoothState', + 'setCanSetTime', 'setFontSize', 'setNativeThemeButtonEnabled', 'setHighContrastCheckboxState', 'setMetricsReportingCheckboxState', 'setMetricsReportingSettingVisibility', - 'setPasswordGenerationSettingVisibility', 'setProfilesInfo', 'setSpokenFeedbackCheckboxState', 'setThemesResetButtonEnabled', 'setVirtualKeyboardCheckboxState', - 'setupCloudPrintConnectorSection', 'setupPageZoomSelector', - 'setupProxySettingsSection', + 'setupProxySettingsButton', 'showBluetoothSettings', 'showCreateProfileError', 'showCreateProfileSuccess', 'showCreateProfileWarning', + 'showHotwordSection', 'showManagedUserImportError', 'showManagedUserImportSuccess', 'showMouseControls', 'showTouchpadControls', + 'toggleExtensionIndicators', 'updateAccountPicture', 'updateAutoLaunchState', 'updateDefaultBrowserState', + 'updateEasyUnlock', 'updateManagesSupervisedUsers', 'updateSearchEngines', 'updateStartupPages', diff --git a/chromium/chrome/browser/resources/options/browser_options_profile_list.js b/chromium/chrome/browser/resources/options/browser_options_profile_list.js index 7a60ca3cf16..429780ede63 100644 --- a/chromium/chrome/browser/resources/options/browser_options_profile_list.js +++ b/chromium/chrome/browser/resources/options/browser_options_profile_list.js @@ -9,7 +9,7 @@ cr.define('options.browser_options', function() { /** * Creates a new profile list item. - * @param {Object} profileInfo The profile this item respresents. + * @param {Object} profileInfo The profile this item represents. * @constructor * @extends {cr.ui.DeletableItem} */ @@ -52,16 +52,19 @@ cr.define('options.browser_options', function() { var profileInfo = this.profileInfo_; + var containerEl = this.ownerDocument.createElement('div'); + containerEl.className = 'profile-container'; + var iconEl = this.ownerDocument.createElement('img'); iconEl.className = 'profile-img'; - iconEl.style.content = imageset(profileInfo.iconURL + '@scalefactorx'); - this.contentElement.appendChild(iconEl); + iconEl.style.content = getProfileAvatarIcon(profileInfo.iconURL); + containerEl.appendChild(iconEl); var nameEl = this.ownerDocument.createElement('div'); nameEl.className = 'profile-name'; if (profileInfo.isCurrentProfile) nameEl.classList.add('profile-item-current'); - this.contentElement.appendChild(nameEl); + containerEl.appendChild(nameEl); var displayName = profileInfo.name; if (profileInfo.isCurrentProfile) { @@ -70,6 +73,16 @@ cr.define('options.browser_options', function() { } nameEl.textContent = displayName; + if (profileInfo.isManaged) { + var supervisedEl = this.ownerDocument.createElement('div'); + supervisedEl.className = 'profile-supervised'; + supervisedEl.textContent = + '(' + loadTimeData.getStringF('managedUserLabel') + ')'; + containerEl.appendChild(supervisedEl); + } + + this.contentElement.appendChild(containerEl); + // Ensure that the button cannot be tabbed to for accessibility reasons. this.closeButtonElement.tabIndex = -1; }, @@ -116,7 +129,7 @@ cr.define('options.browser_options', function() { }, /** - * If false, items in this list will not be deltable. + * If false, items in this list will not be deletable. * @private */ canDeleteItems_: true, @@ -126,4 +139,3 @@ cr.define('options.browser_options', function() { ProfileList: ProfileList }; }); - diff --git a/chromium/chrome/browser/resources/options/certificate_manager.html b/chromium/chrome/browser/resources/options/certificate_manager.html index 3d28e7f2b9f..30fe9dc620a 100644 --- a/chromium/chrome/browser/resources/options/certificate_manager.html +++ b/chromium/chrome/browser/resources/options/certificate_manager.html @@ -1,6 +1,6 @@ <div id="certificateManagerPage" class="page" hidden> <div class="close-button"></div> - <h1 i18n-content="certificateManagerPage"></h1> + <h1 id='cert-manager-header' i18n-content="certificateManagerPage"></h1> <div id="certificate-manager-content-area" class="content-area"> <!-- Navigation tabs --> <div class="subpages-nav-tabs"> @@ -42,9 +42,9 @@ disabled> </button> <button id="personalCertsTab-import" - i18n-content="import_certificate"> + i18n-content="import_certificate" disabled> </button> -<if expr="pp_ifdef('chromeos')"> +<if expr="chromeos"> <button id="personalCertsTab-import-and-bind" i18n-content="importAndBindCertificate" disabled> </button> @@ -72,7 +72,8 @@ <button id="serverCertsTab-view" i18n-content="view_certificate" disabled> </button> - <button id="serverCertsTab-import" i18n-content="import_certificate"> + <button id="serverCertsTab-import" i18n-content="import_certificate" + disabled> </button> <button id="serverCertsTab-export" i18n-content="export_certificate" disabled> @@ -101,7 +102,7 @@ disabled> </button> <button id="caCertsTab-import" i18n-content="import_certificate" - ></button> + disabled></button> <button id="caCertsTab-export" i18n-content="export_certificate" disabled> </button> diff --git a/chromium/chrome/browser/resources/options/certificate_manager.js b/chromium/chrome/browser/resources/options/certificate_manager.js index 5620b80c6c2..b2d46e9dc0c 100644 --- a/chromium/chrome/browser/resources/options/certificate_manager.js +++ b/chromium/chrome/browser/resources/options/certificate_manager.js @@ -11,8 +11,9 @@ cr.define('options', function() { /** * blah * @param {!string} id The id of this tab. + * @param {boolean} isKiosk True if dialog is shown during CrOS kiosk launch. */ - function CertificateManagerTab(id) { + function CertificateManagerTab(id, isKiosk) { this.tree = $(id + '-tree'); options.CertificatesTree.decorate(this.tree); @@ -44,24 +45,36 @@ cr.define('options', function() { this.backupButton = $(id + '-backup'); if (this.backupButton !== null) { - this.backupButton.onclick = function(e) { - var selected = tree.selectedItem; - chrome.send('exportPersonalCertificate', [selected.data.id]); + if (id == 'personalCertsTab' && isKiosk) { + this.backupButton.hidden = true; + } else { + this.backupButton.onclick = function(e) { + var selected = tree.selectedItem; + chrome.send('exportPersonalCertificate', [selected.data.id]); + } } } this.backupAllButton = $(id + '-backup-all'); if (this.backupAllButton !== null) { - this.backupAllButton.onclick = function(e) { - chrome.send('exportAllPersonalCertificates'); + if (id == 'personalCertsTab' && isKiosk) { + this.backupAllButton.hidden = true; + } else { + this.backupAllButton.onclick = function(e) { + chrome.send('exportAllPersonalCertificates'); + } } } this.importButton = $(id + '-import'); if (this.importButton !== null) { if (id == 'personalCertsTab') { - this.importButton.onclick = function(e) { - chrome.send('importPersonalCertificate', [false]); + if (isKiosk) { + this.importButton.hidden = true; + } else { + this.importButton.onclick = function(e) { + chrome.send('importPersonalCertificate', [false]); + } } } else if (id == 'serverCertsTab') { this.importButton.onclick = function(e) { @@ -85,9 +98,13 @@ cr.define('options', function() { this.exportButton = $(id + '-export'); if (this.exportButton !== null) { - this.exportButton.onclick = function(e) { - var selected = tree.selectedItem; - chrome.send('exportCertificate', [selected.data.id]); + if (id == 'personalCertsTab' && isKiosk) { + this.exportButton.hidden = true; + } else { + this.exportButton.onclick = function(e) { + var selected = tree.selectedItem; + chrome.send('exportCertificate', [selected.data.id]); + } } } @@ -146,26 +163,6 @@ cr.define('options', function() { }, }; - // TODO(xiyuan): Use notification from backend instead of polling. - // TPM token check polling timer. - var tpmPollingTimer; - - // Initiate tpm token check if needed. - function checkTpmToken() { - var importAndBindButton = $('personalCertsTab-import-and-bind'); - - if (importAndBindButton && importAndBindButton.disabled) - chrome.send('checkTpmTokenReady'); - } - - // Stop tpm polling timer. - function stopTpmTokenCheckPolling() { - if (tpmPollingTimer) { - window.clearTimeout(tpmPollingTimer); - tpmPollingTimer = undefined; - } - } - ///////////////////////////////////////////////////////////////////////////// // CertificateManager class: @@ -184,13 +181,14 @@ cr.define('options', function() { CertificateManager.prototype = { __proto__: OptionsPage.prototype, - initializePage: function() { + initializePage: function(isKiosk) { OptionsPage.prototype.initializePage.call(this); - this.personalTab = new CertificateManagerTab('personalCertsTab'); - this.serverTab = new CertificateManagerTab('serverCertsTab'); - this.caTab = new CertificateManagerTab('caCertsTab'); - this.otherTab = new CertificateManagerTab('otherCertsTab'); + this.personalTab = new CertificateManagerTab('personalCertsTab', + !!isKiosk); + this.serverTab = new CertificateManagerTab('serverCertsTab', !!isKiosk); + this.caTab = new CertificateManagerTab('caCertsTab', !!isKiosk); + this.otherTab = new CertificateManagerTab('otherCertsTab', !!isKiosk); this.addEventListener('visibleChange', this.handleVisibleChange_); @@ -212,14 +210,6 @@ cr.define('options', function() { OptionsPage.showTab($('personal-certs-nav-tab')); chrome.send('populateCertificateManager'); } - - if (cr.isChromeOS) { - // Ensure TPM token check on visible and stop polling when hidden. - if (this.visible) - checkTpmToken(); - else - stopTpmTokenCheckPolling(); - } } }; @@ -236,16 +226,15 @@ cr.define('options', function() { CertificateRestoreOverlay.show(); }; - CertificateManager.onCheckTpmTokenReady = function(ready) { - var importAndBindButton = $('personalCertsTab-import-and-bind'); - if (importAndBindButton) { - importAndBindButton.disabled = !ready; - - // Check again after 5 seconds if Tpm is not ready and certificate manager - // is still visible. - if (!ready && CertificateManager.getInstance().visible) - tpmPollingTimer = window.setTimeout(checkTpmToken, 5000); - } + CertificateManager.onModelReady = function(userDbAvailable, + tpmAvailable) { + if (!userDbAvailable) + return; + if (tpmAvailable) + $('personalCertsTab-import-and-bind').disabled = false; + $('personalCertsTab-import').disabled = false; + $('serverCertsTab-import').disabled = false; + $('caCertsTab-import').disabled = false; }; // Export diff --git a/chromium/chrome/browser/resources/options/chromeos/accounts_options.html b/chromium/chrome/browser/resources/options/chromeos/accounts_options.html index d0fc3bd892b..2ddc846d232 100644 --- a/chromium/chrome/browser/resources/options/chromeos/accounts_options.html +++ b/chromium/chrome/browser/resources/options/chromeos/accounts_options.html @@ -12,8 +12,9 @@ <td class="option-name"> <div class="checkbox"> <label> - <input id="allowBwsiCheck" pref="cros.accounts.allowBWSI" - type="checkbox"> + <input id="allowBwsiCheck" type="checkbox" + metric="Options_GuestBrowsing" + pref="cros.accounts.allowBWSI"> <span i18n-content="allow_BWSI"></span> </label> </div> @@ -22,9 +23,22 @@ <tr> <td class="option-name"> <div class="checkbox"> + <label> + <input id="allowSupervisedCheck" type="checkbox" + metric="Options_SupervisedUsers" + pref="cros.accounts.supervisedUsersEnabled"> + <span i18n-content="allow_supervised_users"></span> + </label> + </div> + </td> + </tr> + <tr> + <td class="option-name"> + <div class="checkbox"> <label> - <input id="showUserNamesCheck" - pref="cros.accounts.showUserNamesOnSignIn" type="checkbox"> + <input id="showUserNamesCheck" type="checkbox" + metric="Options_ShowUserNamesOnSignin" + pref="cros.accounts.showUserNamesOnSignIn"> <span i18n-content="show_user_on_signin"></span> </label> </div> @@ -34,8 +48,10 @@ <td class="option-name"> <div class="checkbox"> <label> - <input id="useWhitelistCheck" pref="cros.accounts.allowGuest" - type="checkbox" inverted_pref> + <input id="useWhitelistCheck" type="checkbox" + metric="Options_AllowAllUsers" + pref="cros.accounts.allowGuest" + inverted_pref> <span i18n-content="use_whitelist"></span> </label> </div> diff --git a/chromium/chrome/browser/resources/options/chromeos/accounts_options.js b/chromium/chrome/browser/resources/options/chromeos/accounts_options.js index eddbbaf3d31..d187f0b82ca 100644 --- a/chromium/chrome/browser/resources/options/chromeos/accounts_options.js +++ b/chromium/chrome/browser/resources/options/chromeos/accounts_options.js @@ -117,6 +117,8 @@ cr.define('options', function() { */ handleAddUser_: function(e) { chrome.send('whitelistUser', [e.user.email, e.user.name]); + chrome.send('coreOptionsUserMetricsAction', + ['Options_WhitelistedUser_Add']); }, /** @@ -126,6 +128,8 @@ cr.define('options', function() { */ handleRemoveUser_: function(e) { chrome.send('unwhitelistUser', [e.user.username]); + chrome.send('coreOptionsUserMetricsAction', + ['Options_WhitelistedUser_Remove']); } }; diff --git a/chromium/chrome/browser/resources/options/chromeos/bluetooth.css b/chromium/chrome/browser/resources/options/chromeos/bluetooth.css index e6a91e40705..3c849a981ed 100644 --- a/chromium/chrome/browser/resources/options/chromeos/bluetooth.css +++ b/chromium/chrome/browser/resources/options/chromeos/bluetooth.css @@ -23,12 +23,14 @@ -webkit-box-pack: justify; } -#bluetooth-options .button-strip #bluetooth-scanning-label { +#bluetooth-options .button-strip #bluetooth-scanning-label, +#bluetooth-options .button-strip #bluetooth-scan-stopped-label { -webkit-box-flex: 1; display: block; } -#bluetooth-scanning-label { +#bluetooth-scanning-label, +#bluetooth-scan-stopped-label { -webkit-margin-start: 5px; color: #999; } @@ -106,17 +108,15 @@ .bluetooth-keyboard-button { -webkit-padding-end: 15px; -webkit-padding-start: 15px; - background-image: -webkit-gradient(linear, - left top, - left bottom, - color-stop(0, #e9e9e9), - color-stop(1, #f5f5f5)); - border: 1px solid #d4d4d4; + background-image: linear-gradient(to bottom, + #e9e9e9, + #f5f5f5); + border: 1px solid #ccc; border-radius: 4px; - box-shadow: 0 2px 5px rgba(0, 0, 0, 0.07), + box-shadow: 0 0 0 1px #888, inset 0 1px 1px 1px #fff, - inset 0 -1px 1px 1px #ddd; - color: #666; + inset 0 -1px 1px 1px #eee; + color: #222; display: inline-block; font-size: 14px; font-weight: 600; @@ -150,13 +150,24 @@ } .bluetooth-keyboard-button.key-typed { - border: 1px solid #ccc; - box-shadow: 0 0 0 1px #888, - inset 0 1px 1px 1px #fff, - inset 0 -1px 1px 1px #eee; color: #222; } -.bluetooth-keyboard-button.key-pin { - color: #222; +.bluetooth-keyboard-button.key-next { + background-image: -webkit-linear-gradient(top, + rgb(77, 144, 254), + rgb(71, 135, 237)); + border: 1px solid rgb(77, 144, 254); + box-shadow: 0 2px 5px rgba(0, 0, 0, 0.07), + inset 0 1px 1px 1px #fff, + inset 0 -1px 1px 1px rgb(77, 144, 254); + color: #fff; +} + +.bluetooth-keyboard-button.key-untyped { + border: 1px solid #d4d4d4; + box-shadow: 0 2px 5px rgba(0, 0, 0, 0.07), + inset 0 1px 1px 1px #fff, + inset 0 -1px 1px 1px #ddd; + color: #666; } diff --git a/chromium/chrome/browser/resources/options/chromeos/bluetooth_add_device_overlay.html b/chromium/chrome/browser/resources/options/chromeos/bluetooth_add_device_overlay.html index 534d9634d30..dcb87aba490 100644 --- a/chromium/chrome/browser/resources/options/chromeos/bluetooth_add_device_overlay.html +++ b/chromium/chrome/browser/resources/options/chromeos/bluetooth_add_device_overlay.html @@ -18,6 +18,9 @@ <span id="bluetooth-scanning-label" i18n-content="bluetoothScanning"> </span> + <span id="bluetooth-scan-stopped-label" + i18n-content="bluetoothScanStopped"> + </span> <div id="bluetooth-scanning-icon" class="inline-spinner"></div> </div> </div> diff --git a/chromium/chrome/browser/resources/options/chromeos/bluetooth_add_device_overlay.js b/chromium/chrome/browser/resources/options/chromeos/bluetooth_add_device_overlay.js index 3b076a1f26f..004cc6b3ee2 100644 --- a/chromium/chrome/browser/resources/options/chromeos/bluetooth_add_device_overlay.js +++ b/chromium/chrome/browser/resources/options/chromeos/bluetooth_add_device_overlay.js @@ -33,8 +33,9 @@ cr.define('options', function() { OptionsPage.prototype.initializePage.call(this); this.createDeviceList_(); + BluetoothOptions.updateDiscoveryState(true); + $('bluetooth-add-device-cancel-button').onclick = function(event) { - chrome.send('stopBluetoothDeviceDiscovery'); OptionsPage.closeOverlay(); }; @@ -42,7 +43,6 @@ cr.define('options', function() { $('bluetooth-add-device-apply-button').onclick = function(event) { var device = self.deviceList_.selectedItem; var address = device.address; - chrome.send('stopBluetoothDeviceDiscovery'); OptionsPage.closeOverlay(); device.pairing = 'bluetoothStartConnecting'; options.BluetoothPairing.showDialog(device); @@ -68,6 +68,11 @@ cr.define('options', function() { }); }, + /** @override */ + didClosePage: function() { + chrome.send('stopBluetoothDeviceDiscovery'); + }, + /** * Creates, decorates and initializes the bluetooth device list. * @private @@ -82,11 +87,30 @@ cr.define('options', function() { * Automatically start the device discovery process if the * "Add device" dialog is visible. */ - BluetoothOptions.updateDiscovery = function() { + BluetoothOptions.startDeviceDiscovery = function() { var page = BluetoothOptions.getInstance(); if (page && page.visible) chrome.send('findBluetoothDevices'); - } + }; + + /** + * Updates the dialog to show that device discovery has stopped. Updates the + * label text and hides/unhides the spinner. based on discovery state. + */ + BluetoothOptions.updateDiscoveryState = function(discovering) { + $('bluetooth-scanning-label').hidden = !discovering; + $('bluetooth-scanning-icon').hidden = !discovering; + $('bluetooth-scan-stopped-label').hidden = discovering; + }; + + /** + * If the "Add device" dialog is visible, dismiss it. + */ + BluetoothOptions.dismissOverlay = function() { + var page = BluetoothOptions.getInstance(); + if (page && page.visible) + OptionsPage.closeOverlay(); + }; // Export return { diff --git a/chromium/chrome/browser/resources/options/chromeos/bluetooth_pair_device_overlay.js b/chromium/chrome/browser/resources/options/chromeos/bluetooth_pair_device_overlay.js index a206e8bf72a..acaa0afab39 100644 --- a/chromium/chrome/browser/resources/options/chromeos/bluetooth_pair_device_overlay.js +++ b/chromium/chrome/browser/resources/options/chromeos/bluetooth_pair_device_overlay.js @@ -86,6 +86,7 @@ cr.define('options', function() { $('bluetooth-pair-device-reject-button').onclick = function() { chrome.send('updateBluetoothDevice', [self.device_.address, 'reject']); + self.device_.pairing = PAIRING.DISMISSED; OptionsPage.closeOverlay(); }; $('bluetooth-pair-device-connect-button').onclick = function() { @@ -104,7 +105,8 @@ cr.define('options', function() { $('bluetooth-pair-device-accept-button').onclick = function() { chrome.send('updateBluetoothDevice', [self.device_.address, 'accept']); - OptionsPage.closeOverlay(); + // Prevent sending a 'accept' command twice. + $('bluetooth-pair-device-accept-button').disabled = true; }; $('bluetooth-pair-device-dismiss-button').onclick = function() { OptionsPage.closeOverlay(); @@ -182,19 +184,20 @@ cr.define('options', function() { // Update visibility of dialog elements. if (this.device_.passkey) { - this.updatePasskey_(); + this.updatePasskey_(String(this.device_.passkey)); if (this.device_.pairing == PAIRING.CONFIRM_PASSKEY) { // Confirming a match between displayed passkeys. this.displayElements_(['bluetooth-pairing-passkey-display', 'bluetooth-pair-device-accept-button', 'bluetooth-pair-device-reject-button']); + $('bluetooth-pair-device-accept-button').disabled = false; } else { // Remote entering a passkey. this.displayElements_(['bluetooth-pairing-passkey-display', 'bluetooth-pair-device-cancel-button']); } } else if (this.device_.pincode) { - this.updatePinCode_(); + this.updatePasskey_(String(this.device_.pincode)); this.displayElements_(['bluetooth-pairing-passkey-display', 'bluetooth-pair-device-cancel-button']); } else if (this.device_.pairing == PAIRING.ENTER_PIN_CODE) { @@ -267,14 +270,15 @@ cr.define('options', function() { }, /** - * Formats an element for displaying the passkey. + * Formats an element for displaying the passkey or PIN code. + * @param {string} key Passkey or PIN to display. */ - updatePasskey_: function() { + updatePasskey_: function(key) { var passkeyEl = $('bluetooth-pairing-passkey-display'); - var keyClass = this.device_.pairing == PAIRING.REMOTE_PASSKEY ? + var keyClass = (this.device_.pairing == PAIRING.REMOTE_PASSKEY || + this.device_.pairing == PAIRING.REMOTE_PIN_CODE) ? 'bluetooth-keyboard-button' : 'bluetooth-passkey-char'; this.clearElement_(passkeyEl); - var key = String(this.device_.passkey); // Passkey should always have 6 digits. key = '000000'.substring(0, 6 - key.length) + key; var progress = this.device_.entered; @@ -282,52 +286,32 @@ cr.define('options', function() { var keyEl = document.createElement('span'); keyEl.textContent = key.charAt(i); keyEl.className = keyClass; - if (progress == undefined) - keyEl.classList.add('key-pin'); - else if (i < progress) - keyEl.classList.add('key-typed'); - passkeyEl.appendChild(keyEl); - } - if (this.device_.pairing == PAIRING.REMOTE_PASSKEY) { - // Add enter key. - var label = loadTimeData.getString('bluetoothEnterKey'); - var keyEl = document.createElement('span'); - keyEl.textContent = label; - keyEl.className = keyClass; - keyEl.id = 'bluetooth-enter-key'; - if (progress == undefined) - keyEl.classList.add('key-pin'); - else if (progress > key.length) - keyEl.classList.add('key-typed'); - passkeyEl.appendChild(keyEl); - } - passkeyEl.hidden = false; - }, - - /** - * Formats an element for displaying the PIN code. - */ - updatePinCode_: function() { - var passkeyEl = $('bluetooth-pairing-passkey-display'); - var keyClass = this.device_.pairing == PAIRING.REMOTE_PIN_CODE ? - 'bluetooth-keyboard-button' : 'bluetooth-passkey-char'; - this.clearElement_(passkeyEl); - var key = String(this.device_.pincode); - for (var i = 0; i < key.length; i++) { - var keyEl = document.createElement('span'); - keyEl.textContent = key.charAt(i); - keyEl.className = keyClass; - keyEl.classList.add('key-pin'); + if (progress != undefined) { + if (i < progress) + keyEl.classList.add('key-typed'); + else if (i == progress) + keyEl.classList.add('key-next'); + else + keyEl.classList.add('key-untyped'); + } passkeyEl.appendChild(keyEl); } - if (this.device_.pairing == PAIRING.REMOTE_PIN_CODE) { + if (this.device_.pairing == PAIRING.REMOTE_PASSKEY || + this.device_.pairing == PAIRING.REMOTE_PIN_CODE) { // Add enter key. var label = loadTimeData.getString('bluetoothEnterKey'); var keyEl = document.createElement('span'); keyEl.textContent = label; keyEl.className = keyClass; - keyEl.classList.add('key-pin'); keyEl.id = 'bluetooth-enter-key'; + if (progress != undefined) { + if (progress > key.length) + keyEl.classList.add('key-typed'); + else if (progress == key.length) + keyEl.classList.add('key-next'); + else + keyEl.classList.add('key-untyped'); + } passkeyEl.appendChild(keyEl); } passkeyEl.hidden = false; diff --git a/chromium/chrome/browser/resources/options/chromeos/change_picture_options.css b/chromium/chrome/browser/resources/options/chromeos/change_picture_options.css index ab0d497df17..d68291a6e9c 100644 --- a/chromium/chrome/browser/resources/options/chromeos/change_picture_options.css +++ b/chromium/chrome/browser/resources/options/chromeos/change_picture_options.css @@ -54,13 +54,17 @@ */ #user-image-preview { - margin: 20px 10px 0 0; + margin: 18px 10px 0 0; max-width: 220px; position: relative; } #user-image-preview .perspective-box { -webkit-perspective: 600px; + border: solid 1px #cacaca; + border-radius: 4px; + padding: 3px; + width: 220px; } #user-image-preview-img { @@ -69,7 +73,7 @@ border-radius: 4px; max-height: 220px; max-width: 220px; - padding: 2px; + padding: 3px; } .camera.live #user-image-preview-img { @@ -168,14 +172,14 @@ html[dir=rtl] #flip-photo { #take-photo { display: none; height: 25px; - margin: 4px 1px; + margin: 4px; padding: 0; width: 220px; } .camera:not(.live) #discard-photo { background: url('chrome://theme/IDR_USER_IMAGE_RECYCLE') - no-repeat center 0; + no-repeat center center; display: block; } diff --git a/chromium/chrome/browser/resources/options/chromeos/change_picture_options.html b/chromium/chrome/browser/resources/options/chromeos/change_picture_options.html index 571555750df..146585dc904 100644 --- a/chromium/chrome/browser/resources/options/chromeos/change_picture_options.html +++ b/chromium/chrome/browser/resources/options/chromeos/change_picture_options.html @@ -4,7 +4,7 @@ <div class="content-area"> <div i18n-content="changePicturePageDescription"></div> <div id="user-images-area"> - <grid id="user-image-grid" class="user-image-picker"></grid> + <grid id="user-image-grid" class="user-image-picker" tabindex="1"></grid> <div id="user-image-preview"> <img id="user-image-preview-img" i18n-values="alt:previewAltText"> <div class="user-image-stream-area"> @@ -15,9 +15,12 @@ </div> <div class="spinner"></div> </div> - <button id="flip-photo" class="custom-appearance"></button> - <button id="discard-photo"></button> - <button id="take-photo"></button> + <button id="discard-photo" i18n-values="title:discardPhoto" + tabindex="2"></button> + <button id="take-photo" i18n-values="title:takePhoto" tabindex="2"> + </button> + <button id="flip-photo" class="custom-appearance" + i18n-values="title:flipPhoto" tabindex="1"></button> </div> </div> <div id="user-image-attribution"> @@ -28,7 +31,8 @@ </div> <div class="action-area"> <div class="button-strip"> - <button id="change-picture-overlay-confirm" i18n-content="done"></button> + <button id="change-picture-overlay-confirm" i18n-content="done" + tabindex="2"></button> </div> </div> </div> diff --git a/chromium/chrome/browser/resources/options/chromeos/change_picture_options.js b/chromium/chrome/browser/resources/options/chromeos/change_picture_options.js index 51ed5364e26..93982ea69c3 100644 --- a/chromium/chrome/browser/resources/options/chromeos/change_picture_options.js +++ b/chromium/chrome/browser/resources/options/chromeos/change_picture_options.js @@ -66,9 +66,6 @@ cr.define('options', function() { imageGrid.addEventListener('photoupdated', this.handlePhotoTaken_.bind(this)); - // Set the title for "Take Photo" button. - imageGrid.cameraTitle = loadTimeData.getString('takePhoto'); - // Add the "Choose file" button. imageGrid.addItem(ButtonImages.CHOOSE_FILE, loadTimeData.getString('chooseFile'), @@ -80,17 +77,19 @@ cr.define('options', function() { loadTimeData.getString('profilePhotoLoading')); this.profileImage_.type = 'profile'; + // Set the title for camera item in the grid. + imageGrid.setCameraTitles( + loadTimeData.getString('takePhoto'), + loadTimeData.getString('photoFromCamera')); + $('take-photo').addEventListener( 'click', this.handleTakePhoto_.bind(this)); $('discard-photo').addEventListener( - 'click', imageGrid.discardPhoto.bind(imageGrid)); + 'click', this.handleDiscardPhoto_.bind(this)); // Toggle 'animation' class for the duration of WebKit transition. $('flip-photo').addEventListener( - 'click', function(e) { - previewElement.classList.add('animation'); - imageGrid.flipPhoto = !imageGrid.flipPhoto; - }); + 'click', this.handleFlipPhoto_.bind(this)); $('user-image-stream-crop').addEventListener( 'webkitTransitionEnd', function(e) { previewElement.classList.remove('animation'); @@ -131,6 +130,7 @@ cr.define('options', function() { imageGrid.removeItem(this.oldImage_); this.oldImage_ = null; } + chrome.send('onChangePicturePageHidden'); }, /** @@ -152,11 +152,24 @@ cr.define('options', function() { }, /** + * Handle camera-photo flip. + */ + handleFlipPhoto_: function() { + var imageGrid = $('user-image-grid'); + imageGrid.previewElement.classList.add('animation'); + imageGrid.flipPhoto = !imageGrid.flipPhoto; + var flipMessageId = imageGrid.flipPhoto ? + 'photoFlippedAccessibleText' : 'photoFlippedBackAccessibleText'; + announceAccessibleMessage(loadTimeData.getString(flipMessageId)); + }, + + /** * Handles "Take photo" button click. * @private */ handleTakePhoto_: function() { $('user-image-grid').takePhoto(); + chrome.send('takePhoto'); }, /** @@ -165,6 +178,19 @@ cr.define('options', function() { */ handlePhotoTaken_: function(e) { chrome.send('photoTaken', [e.dataURL]); + announceAccessibleMessage( + loadTimeData.getString('photoCaptureAccessibleText')); + }, + + /** + * Handles "Discard photo" button click. + * @private + */ + handleDiscardPhoto_: function() { + $('user-image-grid').discardPhoto(); + chrome.send('discardPhoto'); + announceAccessibleMessage( + loadTimeData.getString('photoDiscardAccessibleText')); }, /** @@ -184,6 +210,10 @@ cr.define('options', function() { handleImageSelected_: function(e) { var imageGrid = $('user-image-grid'); var url = imageGrid.selectedItemUrl; + + // Flip button available only for camera picture. + imageGrid.flipPhotoElement.tabIndex = + imageGrid.selectionType == 'camera' ? 1 : -1; // Ignore selection change caused by program itself and selection of one // of the action buttons. if (!imageGrid.inProgramSelection && @@ -289,7 +319,7 @@ cr.define('options', function() { setDefaultImages_: function(imagesData) { var imageGrid = $('user-image-grid'); for (var i = 0, data; data = imagesData[i]; i++) { - var item = imageGrid.addItem(data.url); + var item = imageGrid.addItem(data.url, data.title); item.type = 'default'; item.author = data.author || ''; item.website = data.website || ''; diff --git a/chromium/chrome/browser/resources/options/chromeos/display_options.html b/chromium/chrome/browser/resources/options/chromeos/display_options.html index 989e7ed3da0..87d23de74c5 100644 --- a/chromium/chrome/browser/resources/options/chromeos/display_options.html +++ b/chromium/chrome/browser/resources/options/chromeos/display_options.html @@ -46,6 +46,15 @@ i18n-content="startCalibratingOverscan"> </button> </div> + <div class="selected-display-option-row" + id="selected-display-color-profile-row"> + <div class="selected-display-option-title" + i18n-content="selectedDisplayColorProfile"> + </div> + <select id="display-options-color-profile-selection" + class="display-options-button"> + </select> + </div> </div> </div> <!-- The arrow of display-configuration is achieved by a div diff --git a/chromium/chrome/browser/resources/options/chromeos/display_options.js b/chromium/chrome/browser/resources/options/chromeos/display_options.js index 3b000ca283e..e0285c26fd4 100644 --- a/chromium/chrome/browser/resources/options/chromeos/display_options.js +++ b/chromium/chrome/browser/resources/options/chromeos/display_options.js @@ -178,12 +178,18 @@ cr.define('options', function() { chrome.send('setOrientation', [this.displays_[this.focusedIndex_].id, ev.target.value]); }.bind(this); + $('display-options-color-profile-selection').onchange = function(ev) { + chrome.send('setColorProfile', [this.displays_[this.focusedIndex_].id, + ev.target.value]); + }.bind(this); $('selected-display-start-calibrating-overscan').onclick = function() { // Passes the target display ID. Do not specify it through URL hash, // we do not care back/forward. var displayOverscan = options.DisplayOverscan.getInstance(); displayOverscan.setDisplayId(this.displays_[this.focusedIndex_].id); OptionsPage.navigateToPage('displayOverscan'); + chrome.send('coreOptionsUserMetricsAction', + ['Options_DisplaySetOverscan']); }.bind(this); chrome.send('getDisplayInfo'); @@ -628,6 +634,23 @@ cr.define('options', function() { } resolution.disabled = (display.resolutions.length <= 1); } + + if (display.availableColorProfiles.length <= 1) { + $('selected-display-color-profile-row').hidden = true; + } else { + $('selected-display-color-profile-row').hidden = false; + var profiles = $('display-options-color-profile-selection'); + profiles.innerHTML = ''; + for (var i = 0; i < display.availableColorProfiles.length; i++) { + var option = document.createElement('option'); + var colorProfile = display.availableColorProfiles[i]; + option.value = colorProfile.profileId; + option.textContent = colorProfile.name; + option.selected = ( + display.colorProfile == colorProfile.profileId); + profiles.appendChild(option); + } + } }, /** diff --git a/chromium/chrome/browser/resources/options/chromeos/internet_detail.html b/chromium/chrome/browser/resources/options/chromeos/internet_detail.html index 556c70adb51..f3632ed49b5 100644 --- a/chromium/chrome/browser/resources/options/chromeos/internet_detail.html +++ b/chromium/chrome/browser/resources/options/chromeos/internet_detail.html @@ -359,7 +359,7 @@ <section id="cellular-device-options"> <table class="option-control-table"> <tr> - <td class="option-name" i18n-content="manufacturer"></td> + <td class="option-name" i18n-content="cellularManufacturer"></td> <td id="manufacturer" class="option-value"></td> </tr> <tr> diff --git a/chromium/chrome/browser/resources/options/chromeos/internet_detail.js b/chromium/chrome/browser/resources/options/chromeos/internet_detail.js index cbc07f21d2c..7fc6c6e88b4 100644 --- a/chromium/chrome/browser/resources/options/chromeos/internet_detail.js +++ b/chromium/chrome/browser/resources/options/chromeos/internet_detail.js @@ -526,6 +526,8 @@ cr.define('options.internet', function() { !$('proxy-use-pac-url').checked; $('auto-proxy-parms').hidden = !$('auto-proxy').checked; $('manual-proxy-parms').hidden = !$('manual-proxy').checked; + chrome.send('coreOptionsUserMetricsAction', + ['Options_NetworkManualProxy_Disable']); }, /** @@ -556,6 +558,8 @@ cr.define('options.internet', function() { $('proxy-pac-url').disabled = true; $('auto-proxy-parms').hidden = !$('auto-proxy').checked; $('manual-proxy-parms').hidden = !$('manual-proxy').checked; + chrome.send('coreOptionsUserMetricsAction', + ['Options_NetworkManualProxy_Enable']); }, }; @@ -626,6 +630,8 @@ cr.define('options.internet', function() { updateHidden('#details-internet-page .action-area', true); detailsPage.updateControls(); detailsPage.visible = true; + chrome.send('coreOptionsUserMetricsAction', + ['Options_NetworkShowProxyTab']); }; /** @@ -810,6 +816,9 @@ cr.define('options.internet', function() { data.type == Constants.TYPE_WIMAX || data.type == Constants.TYPE_VPN)) { $('details-internet-configure').hidden = false; + } else if (data.type == Constants.TYPE_ETHERNET) { + // Ethernet (802.1x) can be configured while connected. + $('details-internet-configure').hidden = false; } else { $('details-internet-configure').hidden = true; } @@ -1111,7 +1120,7 @@ cr.define('options.internet', function() { $('roaming-state').textContent = data.roamingState; $('restricted-pool').textContent = data.restrictedPool; $('error-state').textContent = data.errorState; - $('manufacturer').textContent = data.manufacturer; + $('manufacturer').textContent = data.cellularManufacturer; $('model-id').textContent = data.modelId; $('firmware-revision').textContent = data.firmwareRevision; $('hardware-revision').textContent = data.hardwareRevision; diff --git a/chromium/chrome/browser/resources/options/chromeos/keyboard_overlay.html b/chromium/chrome/browser/resources/options/chromeos/keyboard_overlay.html index 039c52e7954..4609b04c322 100644 --- a/chromium/chrome/browser/resources/options/chromeos/keyboard_overlay.html +++ b/chromium/chrome/browser/resources/options/chromeos/keyboard_overlay.html @@ -12,6 +12,7 @@ <td class="option-value"> <select id="remap-search-key-to" class="control" data-type="number" i18n-options="remapSearchKeyToValue" + metric="Options_KeyboardRemapSearchKey" pref="settings.language.xkb_remap_search_key_to" dialog-pref> </select> </td> @@ -25,6 +26,7 @@ <td class="option-value"> <select id="remap-control-key-to" class="control" data-type="number" i18n-options="remapControlKeyToValue" + metric="Options_KeyboardRemapControlKey" pref="settings.language.xkb_remap_control_key_to" dialog-pref> </select> </td> @@ -37,6 +39,7 @@ </td> <td class="option-value"> <select id="remap-alt-key-to" class="control" data-type="number" + metric="Options_KeyboardRemapAltKey" pref="settings.language.xkb_remap_alt_key_to" i18n-options="remapAltKeyToValue" dialog-pref></select> </td> @@ -52,6 +55,7 @@ <td class="option-value"> <select id="remap-caps-lock-key-to" class="control" data-type="number" + metric="Options_KeyboardRemapCapsLockKey" pref="settings.language.remap_caps_lock_key_to" i18n-options="remapCapsLockKeyToValue" dialog-pref></select> </td> @@ -67,6 +71,7 @@ <td class="option-value"> <select id="remap-diamond-key-to" class="control" data-type="number" + metric="Options_KeyboardRemapDiamondKey" pref="settings.language.remap_diamond_key_to" i18n-options="remapDiamondKeyToValue" dialog-pref></select> </td> @@ -74,11 +79,16 @@ </table> <div class="settings-row"> <div class="checkbox"> - <label> + <span class="controlled-setting-with-label"> <input id="send-function-keys" type="checkbox" pref="settings.language.send_function_keys" dialog-pref> - <span i18n-content="sendFunctionKeys"></span> - </label> + <span> + <label for="send-function-keys" i18n-content="sendFunctionKeys"> + </label> + <span class="bubble-button controlled-setting-indicator" + pref="settings.language.send_function_keys"></span> + </span> + </span> </div> <label id="send-function-keys-description" for="send-function-keys" i18n-content="sendFunctionKeysDescription"> @@ -86,6 +96,10 @@ </div> </div> <div class="content-area"> + <button id="keyboard-shortcuts" class="link-button" + i18n-content="showKeyboardShortcuts"></button> + </div> + <div class="content-area"> <button id="languages-and-input-settings" class="link-button" i18n-content="changeLanguageAndInputSettings"></button> </div> diff --git a/chromium/chrome/browser/resources/options/chromeos/keyboard_overlay.js b/chromium/chrome/browser/resources/options/chromeos/keyboard_overlay.js index 39c8a694fb3..4514adaff8d 100644 --- a/chromium/chrome/browser/resources/options/chromeos/keyboard_overlay.js +++ b/chromium/chrome/browser/resources/options/chromeos/keyboard_overlay.js @@ -28,6 +28,14 @@ cr.define('options', function() { $('languages-and-input-settings').onclick = function(e) { OptionsPage.navigateToPage('languages'); + chrome.send('coreOptionsUserMetricsAction', + ['Options_KeyboardShowLanguageSettings']); + }; + + $('keyboard-shortcuts').onclick = function(e) { + chrome.send('showKeyboardShortcuts'); + chrome.send('coreOptionsUserMetricsAction', + ['Options_KeyboardShowKeyboardShortcuts']); }; }, diff --git a/chromium/chrome/browser/resources/options/chromeos/network_list.js b/chromium/chrome/browser/resources/options/chromeos/network_list.js index 4d20937fa5f..efc2fad31c7 100644 --- a/chromium/chrome/browser/resources/options/chromeos/network_list.js +++ b/chromium/chrome/browser/resources/options/chromeos/network_list.js @@ -499,6 +499,8 @@ cr.define('options.network', function() { var dialog = options.PreferredNetworks.getInstance(); OptionsPage.showPageByName('preferredNetworksPage', false); dialog.update(list); + chrome.send('coreOptionsUserMetricsAction', + ['Options_NetworkShowPreferred']); }; addendum.push({label: loadTimeData.getString('preferredNetworks'), command: callback, diff --git a/chromium/chrome/browser/resources/options/chromeos/third_party_ime_confirm_overlay.css b/chromium/chrome/browser/resources/options/chromeos/third_party_ime_confirm_overlay.css new file mode 100644 index 00000000000..c0e8d30c9ce --- /dev/null +++ b/chromium/chrome/browser/resources/options/chromeos/third_party_ime_confirm_overlay.css @@ -0,0 +1,8 @@ +/* Copyright 2014 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. + */ + +#third-party-ime-confirm-overlay { + width: 500px; +} diff --git a/chromium/chrome/browser/resources/options/chromeos/third_party_ime_confirm_overlay.html b/chromium/chrome/browser/resources/options/chromeos/third_party_ime_confirm_overlay.html new file mode 100644 index 00000000000..63084432fd1 --- /dev/null +++ b/chromium/chrome/browser/resources/options/chromeos/third_party_ime_confirm_overlay.html @@ -0,0 +1,21 @@ +<div id="third-party-ime-confirm-overlay" class="page" hidden> + <div class="close-button"></div> + <h1 i18n-content="thirdPartyImeConfirmOverlay"></h1> + <div class="content-area"> + <span id="third-party-ime-confirm-text" + i18n-content="thirdPartyImeConfirmMessage"> + </span> + </div> + <div class="action-area"> + <div class="action-area-right"> + <div class="button-strip"> + <button id="third-party-ime-confirm-cancel" + i18n-content="thirdPartyImeConfirmDisable"> + </button> + <button id="third-party-ime-confirm-ok" class="default-button" + i18n-content="thirdPartyImeConfirmEnable"> + </button> + </div> + </div> + </div> +</div> diff --git a/chromium/chrome/browser/resources/options/chromeos/third_party_ime_confirm_overlay.js b/chromium/chrome/browser/resources/options/chromeos/third_party_ime_confirm_overlay.js new file mode 100644 index 00000000000..aaf94d928da --- /dev/null +++ b/chromium/chrome/browser/resources/options/chromeos/third_party_ime_confirm_overlay.js @@ -0,0 +1,89 @@ +// Copyright 2014 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. + +cr.define('options', function() { + /** @const */ var OptionsPage = options.OptionsPage; + /** @const */ var SettingsDialog = options.SettingsDialog; + + /** + * HomePageOverlay class + * Dialog that allows users to set the home page. + * @extends {SettingsDialog} + */ + function ThirdPartyImeConfirmOverlay() { + SettingsDialog.call( + this, 'thirdPartyImeConfirm', + loadTimeData.getString('thirdPartyImeConfirmOverlayTabTitle'), + 'third-party-ime-confirm-overlay', + $('third-party-ime-confirm-ok'), + $('third-party-ime-confirm-cancel')); + } + + cr.addSingletonGetter(ThirdPartyImeConfirmOverlay); + + ThirdPartyImeConfirmOverlay.prototype = { + __proto__: SettingsDialog.prototype, + + /** + * Callback to authorize use of an input method. + * @type {Function} + * @private + */ + confirmationCallback_: null, + + /** + * Callback to cancel enabling an input method. + * @type {Function} + * @private + */ + cancellationCallback_: null, + + /** + * Confirms enabling of a third party IME. + */ + handleConfirm: function() { + SettingsDialog.prototype.handleConfirm.call(this); + this.confirmationCallback_(); + }, + + /** + * Resets state of the checkobx. + */ + handleCancel: function() { + SettingsDialog.prototype.handleCancel.call(this); + this.cancellationCallback_(); + }, + + /** + * Displays a confirmation dialog indicating the risk fo enabling + * a third party IME. + * @param {{extension: string, confirm: Function, cancel: Function}} data + * Options for the confirmation dialog. + * @private + */ + showConfirmationDialog_: function(data) { + this.confirmationCallback_ = data.confirm; + this.cancellationCallback_ = data.cancel; + var message = loadTimeData.getStringF('thirdPartyImeConfirmMessage', + data.extension); + $('third-party-ime-confirm-text').textContent = message; + OptionsPage.showPageByName(this.name, false); + }, + }; + + /** + * Displays a confirmation dialog indicating the risk fo enabling + * a third party IME. + * @param {{extension: string, confirm: Function, cancel: Function}} data + * Options for the confirmation dialog. + */ + ThirdPartyImeConfirmOverlay.showConfirmationDialog = function(data) { + ThirdPartyImeConfirmOverlay.getInstance().showConfirmationDialog_(data); + }; + + // Export + return { + ThirdPartyImeConfirmOverlay: ThirdPartyImeConfirmOverlay + }; +}); diff --git a/chromium/chrome/browser/resources/options/clear_browser_data_overlay.html b/chromium/chrome/browser/resources/options/clear_browser_data_overlay.html index 1debae7e6ef..b018b03bbed 100644 --- a/chromium/chrome/browser/resources/options/clear_browser_data_overlay.html +++ b/chromium/chrome/browser/resources/options/clear_browser_data_overlay.html @@ -1,4 +1,4 @@ -<div id="clear-browser-data-overlay" class="page" hidden> +<div id="clear-browser-data-overlay" class="page not-resizable" hidden> <div class="close-button"></div> <h1 i18n-content="clearBrowserDataOverlay"></h1> <div id="clear-browser-data-info-banner" hidden> diff --git a/chromium/chrome/browser/resources/options/clear_browser_data_overlay.js b/chromium/chrome/browser/resources/options/clear_browser_data_overlay.js index 563a41a88ff..13f186e7ab0 100644 --- a/chromium/chrome/browser/resources/options/clear_browser_data_overlay.js +++ b/chromium/chrome/browser/resources/options/clear_browser_data_overlay.js @@ -22,17 +22,39 @@ cr.define('options', function() { // Inherit ClearBrowserDataOverlay from OptionsPage. __proto__: OptionsPage.prototype, - // Whether deleting history and downloads is allowed. + /** + * Whether deleting history and downloads is allowed. + * @type {boolean} + * @private + */ allowDeletingHistory_: true, /** + * Whether or not clearing browsing data is currently in progress. + * @type {boolean} + * @private + */ + isClearingInProgress_: false, + + /** + * Whether or not the WebUI handler has completed initialization. + * + * Unless this becomes true, it must be assumed that the above flags might + * not contain the authoritative values. + * + * @type {boolean} + * @private + */ + isInitializationComplete_: false, + + /** * Initialize the page. */ initializePage: function() { // Call base class implementation to starts preference initialization. OptionsPage.prototype.initializePage.call(this); - var f = this.updateCommitButtonState_.bind(this); + var f = this.updateStateOfControls_.bind(this); var types = ['browser.clear_data.browsing_history', 'browser.clear_data.download_history', 'browser.clear_data.cache', @@ -50,7 +72,6 @@ cr.define('options', function() { for (var i = 0; i < checkboxes.length; i++) { checkboxes[i].onclick = f; } - this.updateCommitButtonState_(); this.createStuffRemainsFooter_(); @@ -58,16 +79,25 @@ cr.define('options', function() { ClearBrowserDataOverlay.dismiss(); }; $('clear-browser-data-commit').onclick = function(event) { - ClearBrowserDataOverlay.setClearingState(true); + ClearBrowserDataOverlay.setClearing(true); chrome.send('performClearBrowserData'); }; - var show = loadTimeData.getBoolean('showDeleteBrowsingHistoryCheckboxes'); - this.showDeleteHistoryCheckboxes_(show); + // For managed profiles, hide the checkboxes controlling whether or not + // browsing and download history should be cleared. Note that this is + // different than just disabling them as a result of enterprise policies. + if (!loadTimeData.getBoolean('showDeleteBrowsingHistoryCheckboxes')) { + $('delete-browsing-history-container').hidden = true; + $('delete-download-history-container').hidden = true; + } + + this.updateStateOfControls_(); }, - // Create a footer that explains that some content is not cleared by the - // clear browsing history dialog. + /** + * Create a footer that explains that some content is not cleared by the + * clear browsing history dialog. + */ createStuffRemainsFooter_: function() { // The localized string is of the form "Saved [content settings] and // {search engines} will not be cleared and may reflect your browsing @@ -114,73 +144,101 @@ cr.define('options', function() { } }, - // Set the enabled state of the commit button. - updateCommitButtonState_: function() { - var checkboxes = document.querySelectorAll( - '#cbd-content-area input[type=checkbox]'); - var isChecked = false; - for (var i = 0; i < checkboxes.length; i++) { - if (checkboxes[i].checked) { - isChecked = true; - break; - } - } - $('clear-browser-data-commit').disabled = !isChecked; + /** + * Sets whether or not we are in the process of clearing data. + * @param {boolean} clearing Whether the browsing data is currently being + * cleared. + * @private + */ + setClearing_: function(clearing) { + this.isClearingInProgress_ = clearing; + this.updateStateOfControls_(); }, - setAllowDeletingHistory: function(allowed) { + /** + * Sets whether deleting history and downloads is disallowed by enterprise + * policies. This is called on initialization and in response to a change in + * the corresponding preference. + * @param {boolean} allowed Whether to allow deleting history and downloads. + * @private + */ + setAllowDeletingHistory_: function(allowed) { this.allowDeletingHistory_ = allowed; + this.updateStateOfControls_(); }, - showDeleteHistoryCheckboxes_: function(show) { - if (!show) { - $('delete-browsing-history-container').hidden = true; - $('delete-download-history-container').hidden = true; - } + /** + * Called by the WebUI handler to signal that it has finished calling all + * initialization methods. + * @private + */ + markInitializationComplete_: function() { + this.isInitializationComplete_ = true; + this.updateStateOfControls_(); }, - /** @override */ - didShowPage: function() { - var allowed = ClearBrowserDataOverlay.getInstance().allowDeletingHistory_; - ClearBrowserDataOverlay.updateHistoryCheckboxes(allowed); - }, + /** + * Updates the enabled/disabled/hidden status of all controls on the dialog. + * @private + */ + updateStateOfControls_: function() { + // The commit button is enabled if at least one data type selected to be + // cleared, and if we are not already in the process of clearing. + // To prevent the commit button from being hazardously enabled for a very + // short time before setClearing() is called the first time by the native + // side, also disable the button if |isInitializationComplete_| is false. + var enabled = false; + if (this.isInitializationComplete_ && !this.isClearingInProgress_) { + var checkboxes = document.querySelectorAll( + '#cbd-content-area input[type=checkbox]'); + for (var i = 0; i < checkboxes.length; i++) { + if (checkboxes[i].checked) { + enabled = true; + break; + } + } + } + $('clear-browser-data-commit').disabled = !enabled; + + // The checkboxes for clearing history/downloads are enabled unless they + // are disallowed by policies, or we are in the process of clearing data. + // To prevent flickering, these, and the rest of the controls can safely + // be enabled for a short time before the first call to setClearing(). + var enabled = this.allowDeletingHistory_ && !this.isClearingInProgress_; + $('delete-browsing-history-checkbox').disabled = !enabled; + $('delete-download-history-checkbox').disabled = !enabled; + if (!this.allowDeletingHistory_) { + $('delete-browsing-history-checkbox').checked = false; + $('delete-download-history-checkbox').checked = false; + } + + // Enable everything else unless we are in the process of clearing. + var clearing = this.isClearingInProgress_; + $('delete-cache-checkbox').disabled = clearing; + $('delete-cookies-checkbox').disabled = clearing; + $('delete-passwords-checkbox').disabled = clearing; + $('delete-form-data-checkbox').disabled = clearing; + $('delete-hosted-apps-data-checkbox').disabled = clearing; + $('deauthorize-content-licenses-checkbox').disabled = clearing; + $('clear-browser-data-time-period').disabled = clearing; + $('cbd-throbber').style.visibility = clearing ? 'visible' : 'hidden'; + $('clear-browser-data-dismiss').disabled = clearing; + } }; // // Chrome callbacks // - /** - * Updates the disabled status of the browsing-history and downloads - * checkboxes, also unchecking them if they are disabled. This is called in - * response to a change in the corresponding preference. - */ - ClearBrowserDataOverlay.updateHistoryCheckboxes = function(allowed) { - $('delete-browsing-history-checkbox').disabled = !allowed; - $('delete-download-history-checkbox').disabled = !allowed; - if (!allowed) { - $('delete-browsing-history-checkbox').checked = false; - $('delete-download-history-checkbox').checked = false; - } - ClearBrowserDataOverlay.getInstance().setAllowDeletingHistory(allowed); + ClearBrowserDataOverlay.setAllowDeletingHistory = function(allowed) { + ClearBrowserDataOverlay.getInstance().setAllowDeletingHistory_(allowed); + }; + + ClearBrowserDataOverlay.setClearing = function(clearing) { + ClearBrowserDataOverlay.getInstance().setClearing_(clearing); }; - ClearBrowserDataOverlay.setClearingState = function(state) { - $('delete-browsing-history-checkbox').disabled = state; - $('delete-download-history-checkbox').disabled = state; - $('delete-cache-checkbox').disabled = state; - $('delete-cookies-checkbox').disabled = state; - $('delete-passwords-checkbox').disabled = state; - $('delete-form-data-checkbox').disabled = state; - $('delete-hosted-apps-data-checkbox').disabled = state; - $('deauthorize-content-licenses-checkbox').disabled = state; - $('clear-browser-data-time-period').disabled = state; - $('cbd-throbber').style.visibility = state ? 'visible' : 'hidden'; - $('clear-browser-data-dismiss').disabled = state; - - if (state) - $('clear-browser-data-commit').disabled = true; - else - ClearBrowserDataOverlay.getInstance().updateCommitButtonState_(); + ClearBrowserDataOverlay.markInitializationComplete = function() { + ClearBrowserDataOverlay.getInstance().markInitializationComplete_(); }; ClearBrowserDataOverlay.setBannerVisibility = function(args) { @@ -193,13 +251,15 @@ cr.define('options', function() { // actually worked. Otherwise the dialog just vanishes instantly in most // cases. window.setTimeout(function() { + ClearBrowserDataOverlay.setClearing(false); ClearBrowserDataOverlay.dismiss(); }, 200); }; ClearBrowserDataOverlay.dismiss = function() { - OptionsPage.closeOverlay(); - this.setClearingState(false); + var topmostVisiblePage = OptionsPage.getTopmostVisiblePage(); + if (topmostVisiblePage && topmostVisiblePage.name == 'clearBrowserData') + OptionsPage.closeOverlay(); }; // Export diff --git a/chromium/chrome/browser/resources/options/confirm_dialog.js b/chromium/chrome/browser/resources/options/confirm_dialog.js index acf34e6db02..b7d235eb027 100644 --- a/chromium/chrome/browser/resources/options/confirm_dialog.js +++ b/chromium/chrome/browser/resources/options/confirm_dialog.js @@ -3,7 +3,7 @@ // found in the LICENSE file. cr.define('options', function() { - /** @const */ var OptionsPage = options.OptionsPage; + /** @const */ var SettingsDialog = options.SettingsDialog; /** * A dialog that will pop up when the user attempts to set the value of the @@ -22,13 +22,11 @@ cr.define('options', function() { * confirmed the dialog before. This ensures that the user is presented * with the dialog only once. If left |undefined| or |null|, the dialog * will pop up every time the user attempts to set |pref| to |true|. - * @extends {OptionsPage} + * @extends {SettingsDialog} */ function ConfirmDialog(name, title, pageDivName, okButton, cancelButton, pref, metric, confirmed_pref) { - OptionsPage.call(this, name, title, pageDivName); - this.okButton = okButton; - this.cancelButton = cancelButton; + SettingsDialog.call(this, name, title, pageDivName, okButton, cancelButton); this.pref = pref; this.metric = metric; this.confirmed_pref = confirmed_pref; @@ -37,7 +35,7 @@ cr.define('options', function() { ConfirmDialog.prototype = { // Set up the prototype chain - __proto__: OptionsPage.prototype, + __proto__: SettingsDialog.prototype, /** * Handle changes to |pref|. Only uncommitted changes are relevant as these @@ -68,6 +66,8 @@ cr.define('options', function() { /** @override */ initializePage: function() { + SettingsDialog.prototype.initializePage.call(this); + this.okButton.onclick = this.handleConfirm.bind(this); this.cancelButton.onclick = this.handleCancel.bind(this); Preferences.getInstance().addEventListener( @@ -82,9 +82,10 @@ cr.define('options', function() { * Handle the confirm button by committing the |pref| change. If * |confirmed_pref| has been specified, also remember that the dialog has * been confirmed to avoid bringing it up in the future. + * @override */ handleConfirm: function() { - OptionsPage.closeOverlay(); + SettingsDialog.prototype.handleConfirm.call(this); Preferences.getInstance().commitPref(this.pref, this.metric); if (this.confirmed_pref) @@ -94,10 +95,10 @@ cr.define('options', function() { /** * Handle the cancel button by rolling back the |pref| change without it * ever taking effect. + * @override */ handleCancel: function() { - OptionsPage.closeOverlay(); - + SettingsDialog.prototype.handleCancel.call(this); Preferences.getInstance().rollbackPref(this.pref); }, diff --git a/chromium/chrome/browser/resources/options/content_settings.css b/chromium/chrome/browser/resources/options/content_settings.css index 30e01d197fc..b6112eb0b0c 100644 --- a/chromium/chrome/browser/resources/options/content_settings.css +++ b/chromium/chrome/browser/resources/options/content_settings.css @@ -39,7 +39,7 @@ select.exception-setting { -webkit-box-flex: 1; } -#exception-behavior-column { +.exception-value-column-header { width: 145px; } @@ -68,15 +68,6 @@ div[role='listitem'][controlled-by] { position: relative; } -.section-header { - -webkit-margin-start: -18px; - margin-bottom: 0.8em; -} - -.section-header > h3 { - display: inline; -} - .settings-list div[role='listitem'][controlled-by='policy'], .settings-list div[role='listitem'][controlled-by='extension'] { background: rgb(250, 230, 146); diff --git a/chromium/chrome/browser/resources/options/content_settings.html b/chromium/chrome/browser/resources/options/content_settings.html index 5cebc041b44..176c72d650d 100644 --- a/chromium/chrome/browser/resources/options/content_settings.html +++ b/chromium/chrome/browser/resources/options/content_settings.html @@ -285,7 +285,7 @@ </span> </span> </div> -<if expr="pp_ifdef('enable_google_now')"> +<if expr="enable_google_now"> <div class="checkbox" id="geolocationCheckbox" hidden> <span class="controlled-setting-with-label"> <input id="googleGeolocationAccessEnabled" @@ -396,7 +396,7 @@ </div> </div> </section> -<if expr="pp_ifdef('chromeos') or is_win"> +<if expr="chromeos or is_win"> <!-- Protected Content filter --> <section guest-visibility="disabled"> <h3 i18n-content="protectedContentTabLabel" @@ -411,16 +411,18 @@ <span i18n-content="protectedContentEnable"></span> </label> </div> + <if expr="chromeos"> <div class="settings-row"> <button id="protected-content-exceptions" class="exceptions-list-button" contentType="protectedContent" i18n-content="manageExceptions"></button> </div> + </if> </div> </section> </if> <!-- Media Stream capture device filter --> - <section> + <section id="media-stream-settings"> <div class="section-header"> <h3 i18n-content="mediaStreamTabLabel"></h3> <span id="media-indicator" @@ -502,13 +504,6 @@ </div> </div> </section> - <section id="media-galleries-section" hidden> - <h3 i18n-content="mediaGalleriesSectionLabel"></h3> - <div class="settings-row"> - <button id="manage-galleries-button" - i18n-content="manageGalleriesButton"></button> - </div> - </section> <!-- Automatic Downloads filter --> <section> <h3 i18n-content="multiple-automatic-downloads_header"></h3> @@ -590,6 +585,16 @@ </div> </div> </section> + <!-- Page zoom levels --> + <section id="page-zoom-levels"> + <h3 i18n-content="zoomlevels_header"></h3> + <div> + <div class="settings-row"> + <button class="exceptions-list-button" contentType="zoomlevels" + i18n-content="zoomLevelsManage"></button> + </div> + </div> + </section> </div> <div class="action-area"> <div class="button-strip"> diff --git a/chromium/chrome/browser/resources/options/content_settings.js b/chromium/chrome/browser/resources/options/content_settings.js index 160d36f6d79..44ae39f1f8a 100644 --- a/chromium/chrome/browser/resources/options/content_settings.js +++ b/chromium/chrome/browser/resources/options/content_settings.js @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -if (!loadTimeData.getBoolean('newContentSettings')) { - cr.define('options', function() { /** @const */ var OptionsPage = options.OptionsPage; @@ -39,17 +37,11 @@ cr.define('options', function() { // history so back/forward and tab restore works. var hash = event.currentTarget.getAttribute('contentType'); var url = page.name + '#' + hash; - window.history.pushState({pageName: page.name}, - page.title, - '/' + url); + uber.pushState({pageName: page.name}, url); - // Navigate after the history has been replaced in order to have the - // correct hash loaded. + // Navigate after the local history has been replaced in order to have + // the correct hash loaded. OptionsPage.showPageByName('contentExceptions', false); - - uber.invokeMethodOnParent('setPath', {path: url}); - uber.invokeMethodOnParent('setTitle', - {title: loadTimeData.getString(hash + 'TabTitle')}); }; } @@ -60,10 +52,6 @@ cr.define('options', function() { }; } - $('manage-galleries-button').onclick = function(event) { - OptionsPage.navigateToPage('manageGalleries'); - }; - if (cr.isChromeOS) UIAccountTweaks.applyGuestModeVisibility(document); @@ -121,8 +109,9 @@ cr.define('options', function() { value: dict[group].value, controlledBy: controlledBy, }; - for (var i = 0; i < indicators.length; i++) + for (var i = 0; i < indicators.length; i++) { indicators[i].handlePrefChange(event); + } } }; @@ -170,31 +159,36 @@ cr.define('options', function() { /** * Initializes an exceptions list. * @param {string} type The content type that we are setting exceptions for. - * @param {Array} list An array of pairs, where the first element of each pair - * is the filter string, and the second is the setting (allow/block). + * @param {Array} exceptions An array of pairs, where the first element of + * each pair is the filter string, and the second is the setting + * (allow/block). */ - ContentSettings.setExceptions = function(type, list) { - var exceptionsList = - document.querySelector('div[contentType=' + type + ']' + - ' list[mode=normal]'); - exceptionsList.setExceptions(list); + ContentSettings.setExceptions = function(type, exceptions) { + this.getExceptionsList(type, 'normal').setExceptions(exceptions); }; - ContentSettings.setHandlers = function(list) { - $('handlers-list').setHandlers(list); + ContentSettings.setHandlers = function(handlers) { + $('handlers-list').setHandlers(handlers); }; - ContentSettings.setIgnoredHandlers = function(list) { - $('ignored-handlers-list').setHandlers(list); + ContentSettings.setIgnoredHandlers = function(ignoredHandlers) { + $('ignored-handlers-list').setHandlers(ignoredHandlers); }; - ContentSettings.setOTRExceptions = function(type, list) { - var exceptionsList = - document.querySelector('div[contentType=' + type + ']' + - ' list[mode=otr]'); - + ContentSettings.setOTRExceptions = function(type, otrExceptions) { + var exceptionsList = this.getExceptionsList(type, 'otr'); exceptionsList.parentNode.hidden = false; - exceptionsList.setExceptions(list); + exceptionsList.setExceptions(otrExceptions); + }; + + /** + * @param {string} type The type of exceptions (e.g. "location") to get. + * @param {string} mode The mode of the desired exceptions list (e.g. otr). + * @return {?ExceptionsList} The corresponding exceptions list or null. + */ + ContentSettings.getExceptionsList = function(type, mode) { + return document.querySelector( + 'div[contentType=' + type + '] list[mode=' + mode + ']'); }; /** @@ -208,10 +202,8 @@ cr.define('options', function() { */ ContentSettings.patternValidityCheckComplete = function(type, mode, pattern, valid) { - var exceptionsList = - document.querySelector('div[contentType=' + type + '] ' + - 'list[mode=' + mode + ']'); - exceptionsList.patternValidityCheckComplete(pattern, valid); + this.getExceptionsList(type, mode).patternValidityCheckComplete(pattern, + valid); }; /** @@ -222,7 +214,7 @@ cr.define('options', function() { */ ContentSettings.showMediaPepperFlashDefaultLink = function(show) { $('media-pepper-flash-default').hidden = !show; - } + }; /** * Shows/hides the link to the Pepper Flash camera and microphone @@ -232,7 +224,7 @@ cr.define('options', function() { */ ContentSettings.showMediaPepperFlashExceptionsLink = function(show) { $('media-pepper-flash-exceptions').hidden = !show; - } + }; /** * Shows/hides the whole Web MIDI settings. @@ -240,7 +232,7 @@ cr.define('options', function() { */ ContentSettings.showExperimentalWebMIDISettings = function(show) { $('experimental-web-midi-settings').hidden = !show; - } + }; /** * Updates the microphone/camera devices menu with the given entries. @@ -281,10 +273,9 @@ cr.define('options', function() { */ ContentSettings.enableProtectedContentExceptions = function(enable) { var exceptionsButton = $('protected-content-exceptions'); - if (exceptionsButton) { + if (exceptionsButton) exceptionsButton.disabled = !enable; - } - } + }; /** * Set the default microphone device based on the popup selection. @@ -310,5 +301,3 @@ cr.define('options', function() { }; }); - -} diff --git a/chromium/chrome/browser/resources/options/content_settings2.html b/chromium/chrome/browser/resources/options/content_settings2.html deleted file mode 100644 index e886bfdeb78..00000000000 --- a/chromium/chrome/browser/resources/options/content_settings2.html +++ /dev/null @@ -1,13 +0,0 @@ -<div id="content-settings-page2" class="page" hidden> - <div class="close-button"></div> - <h1 i18n-content="contentSettingsPage"></h1> - <div class="content-area"> - This space intentionally left blank. - </div> - <div class="action-area"> - <div class="button-strip"> - <button id="content-settings-overlay-confirm2" i18n-content="done"> - </button> - </div> - </div> -</div> diff --git a/chromium/chrome/browser/resources/options/content_settings2.js b/chromium/chrome/browser/resources/options/content_settings2.js deleted file mode 100644 index 7c6d95137e3..00000000000 --- a/chromium/chrome/browser/resources/options/content_settings2.js +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright (c) 2012 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. - -if (loadTimeData.getBoolean('newContentSettings')) { - -cr.define('options', function() { - /** @const */ var OptionsPage = options.OptionsPage; - - ////////////////////////////////////////////////////////////////////////////// - // ContentSettings class: - - /** - * Encapsulated handling of content settings page. - * @constructor - */ - function ContentSettings() { - this.activeNavTab = null; - OptionsPage.call(this, 'content', - loadTimeData.getString('contentSettingsPageTabTitle'), - 'content-settings-page2'); - } - - cr.addSingletonGetter(ContentSettings); - - ContentSettings.prototype = { - __proto__: OptionsPage.prototype, - - initializePage: function() { - OptionsPage.prototype.initializePage.call(this); - - $('content-settings-overlay-confirm2').onclick = - OptionsPage.closeOverlay.bind(OptionsPage); - }, - }; - - ContentSettings.updateHandlersEnabledRadios = function(enabled) { - // Not implemented. - }; - - /** - * Sets the values for all the content settings radios. - * @param {Object} dict A mapping from radio groups to the checked value for - * that group. - */ - ContentSettings.setContentFilterSettingsValue = function(dict) { - // Not implemented. - }; - - /** - * Initializes an exceptions list. - * @param {string} type The content type that we are setting exceptions for. - * @param {Array} list An array of pairs, where the first element of each pair - * is the filter string, and the second is the setting (allow/block). - */ - ContentSettings.setExceptions = function(type, list) { - // Not implemented. - }; - - ContentSettings.setHandlers = function(list) { - // Not implemented. - }; - - ContentSettings.setIgnoredHandlers = function(list) { - // Not implemented. - }; - - ContentSettings.setOTRExceptions = function(type, list) { - // Not implemented. - }; - - /** - * Enables the Pepper Flash camera and microphone settings. - * Please note that whether the settings are actually showed or not is also - * affected by the style class pepper-flash-settings. - */ - ContentSettings.enablePepperFlashCameraMicSettings = function() { - // Not implemented. - } - - // Export - return { - ContentSettings: ContentSettings - }; - -}); - -} diff --git a/chromium/chrome/browser/resources/options/content_settings_exceptions_area.html b/chromium/chrome/browser/resources/options/content_settings_exceptions_area.html index 1306379022b..70ee5ce8c80 100644 --- a/chromium/chrome/browser/resources/options/content_settings_exceptions_area.html +++ b/chromium/chrome/browser/resources/options/content_settings_exceptions_area.html @@ -6,7 +6,12 @@ <div id="exception-pattern-column" i18n-content="exceptionPatternHeader"> </div> <div id="exception-behavior-column" - i18n-content="exceptionBehaviorHeader"> + i18n-content="exceptionBehaviorHeader" + class="exception-value-column-header"> + </div> + <div id="exception-zoom-column" + i18n-content="exceptionZoomHeader" + class="exception-value-column-header" hidden> </div> </div> <div contentType="cookies"> @@ -123,6 +128,14 @@ <list mode="otr"></list> </div> </div> + <div contentType="zoomlevels"> + <list mode="normal"></list> + <div> + <span class="otr-explanation" i18n-content="otr_exceptions_explanation"> + </span> + <list mode="otr"></list> + </div> + </div> </div> <div class="action-area"> <div class="hbox stretch"> diff --git a/chromium/chrome/browser/resources/options/content_settings_exceptions_area.js b/chromium/chrome/browser/resources/options/content_settings_exceptions_area.js index 31c6a5ed07e..66a71c93ed6 100644 --- a/chromium/chrome/browser/resources/options/content_settings_exceptions_area.js +++ b/chromium/chrome/browser/resources/options/content_settings_exceptions_area.js @@ -104,8 +104,10 @@ cr.define('options.contentSettings', function() { this.editable = false; } - this.addEditField(select, this.settingLabel); - this.contentElement.appendChild(select); + if (this.contentType != 'zoomlevels') { + this.addEditField(select, this.settingLabel); + this.contentElement.appendChild(select); + } select.className = 'exception-setting'; select.setAttribute('aria-labelledby', 'exception-behavior-column'); @@ -123,6 +125,19 @@ cr.define('options.contentSettings', function() { this.contentElement.appendChild(videoSettingLabel); } + if (this.contentType == 'zoomlevels') { + this.deletable = true; + this.editable = false; + + var zoomLabel = cr.doc.createElement('span'); + zoomLabel.textContent = this.dataItem.zoom; + zoomLabel.className = 'exception-setting'; + zoomLabel.setAttribute('displaymode', 'static'); + zoomLabel.setAttribute('aria-labelledby', 'exception-zoom-column'); + this.contentElement.appendChild(zoomLabel); + this.zoomLabel = zoomLabel; + } + // Used to track whether the URL pattern in the input is valid. // This will be true if the browser process has informed us that the // current text in the input is valid. Changing the text resets this to @@ -541,7 +556,8 @@ cr.define('options.contentSettings', function() { return !(this.contentType == 'notifications' || this.contentType == 'location' || this.contentType == 'fullscreen' || - this.contentType == 'media-stream'); + this.contentType == 'media-stream' || + this.contentType == 'zoomlevels'); }, /** @@ -614,6 +630,9 @@ cr.define('options.contentSettings', function() { * @param {string} type The content type. */ showList: function(type) { + // Update the title for the type that was shown. + this.title = loadTimeData.getString(type + 'TabTitle'); + var header = this.pageDiv.querySelector('h1'); header.textContent = loadTimeData.getString(type + '_header'); @@ -627,6 +646,9 @@ cr.define('options.contentSettings', function() { var mediaHeader = this.pageDiv.querySelector('.media-header'); mediaHeader.hidden = type != 'media-stream'; + + $('exception-behavior-column').hidden = type == 'zoomlevels'; + $('exception-zoom-column').hidden = type != 'zoomlevels'; }, /** diff --git a/chromium/chrome/browser/resources/options/controlled_setting.css b/chromium/chrome/browser/resources/options/controlled_setting.css index 089e27dbbd7..ad2051ad8bb 100644 --- a/chromium/chrome/browser/resources/options/controlled_setting.css +++ b/chromium/chrome/browser/resources/options/controlled_setting.css @@ -27,11 +27,6 @@ padding: 0; } -input:-webkit-any([type='text'],[type='url'],:not([type])) + - .controlled-setting-indicator { - -webkit-margin-start: 5px; -} - .controlled-setting-indicator:not([controlled-by]) { display: none; } @@ -41,50 +36,30 @@ input:-webkit-any([type='text'],[type='url'],:not([type])) + } .controlled-setting-indicator[controlled-by='owner'] > div { - background-image: url('chrome://theme/IDR_CONTROLLED_SETTING_MANDATORY'); + background-image: url('chrome://theme/IDR_CONTROLLED_SETTING_OWNER'); } .controlled-setting-indicator[controlled-by='extension'] > div { background-image: url('chrome://theme/IDR_CONTROLLED_SETTING_EXTENSION'); } -.controlled-setting-indicator:-webkit-any([controlled-by='recommended'], - [controlled-by='hasRecommendation']) > div { - background-image: url('chrome://theme/IDR_CONTROLLED_SETTING_MANDATORY'); -} - -.controlled-setting-bubble-content { - -webkit-padding-start: 30px; - background-repeat: no-repeat; - background-size: 22px; - min-height: 32px; -} - -.controlled-setting-bubble-content[controlled-by='policy'] { - background-image: url('chrome://theme/IDR_CONTROLLED_SETTING_MANDATORY'); -} - -.controlled-setting-bubble-content[controlled-by='owner'] { - background-image: url('chrome://theme/IDR_CONTROLLED_SETTING_MANDATORY'); +.controlled-setting-indicator[controlled-by='shared'] > div { + background-image: url('chrome://theme/IDR_CONTROLLED_SETTING_SHARED'); } -.controlled-setting-bubble-content[controlled-by='extension'] { - background-image: url('chrome://theme/IDR_CONTROLLED_SETTING_EXTENSION'); -} - -.controlled-setting-bubble-content:-webkit-any([controlled-by='recommended'], - [controlled-by='hasRecommendation']) { +.controlled-setting-indicator:-webkit-any([controlled-by='recommended'], + [controlled-by='hasRecommendation']) > div { background-image: url('chrome://theme/IDR_CONTROLLED_SETTING_MANDATORY'); } -html[dir='rtl'] .controlled-setting-bubble-content { - background-position: right top; -} - .controlled-setting-bubble-action { padding: 0 !important; } +.controlled-setting-bubble-header { + margin-top: 3px; +} + .controlled-setting-bubble-content-row { height: 35px; position: relative; @@ -95,7 +70,7 @@ html[dir='rtl'] .controlled-setting-bubble-content { background-repeat: no-repeat; font-weight: bold; height: 24px; - margin-top: -12px; + margin-top: -9px; overflow: hidden; padding-top: 3px; position: absolute; @@ -110,7 +85,8 @@ html[dir='rtl'] .controlled-setting-bubble-extension-name { } .controlled-setting-bubble-extension-manage-link { - margin-top: -0.5em; + margin-left: -0.35em; + margin-top: -0.30em; position: absolute; top: 50%; } diff --git a/chromium/chrome/browser/resources/options/controlled_setting.js b/chromium/chrome/browser/resources/options/controlled_setting.js index 28674bd888b..5ac42d971e4 100644 --- a/chromium/chrome/browser/resources/options/controlled_setting.js +++ b/chromium/chrome/browser/resources/options/controlled_setting.js @@ -61,19 +61,9 @@ cr.define('options', function() { if (!this.value || String(event.value.value) == this.value) { this.controlledBy = event.value.controlledBy; if (event.value.extension) { - if (this.pref == 'session.restore_on_startup' || - this.pref == 'homepage_is_newtabpage') { - // Special case for the restore on startup, which is implied - // by the startup pages settings being controlled by an - // extension, and same for the home page as NTP, so we don't want - // to show two buttons in these cases. - // TODO(mad): Find a better way to handle this. - this.controlledBy = null; - } else { - this.extensionId = event.value.extension.id; - this.extensionIcon = event.value.extension.icon; - this.extensionName = event.value.extension.name; - } + this.extensionId = event.value.extension.id; + this.extensionIcon = event.value.extension.icon; + this.extensionName = event.value.extension.name; } } else { this.controlledBy = null; @@ -105,6 +95,10 @@ cr.define('options', function() { 'extensionWithName': loadTimeData.getString( 'controlledSettingsExtensionWithName'), }; + if (cr.isChromeOS) { + defaultStrings.shared = + loadTimeData.getString('controlledSettingsShared'); + } } else { var defaultStrings = { 'policy': loadTimeData.getString('controlledSettingPolicy'), @@ -119,6 +113,8 @@ cr.define('options', function() { if (cr.isChromeOS) { defaultStrings.owner = loadTimeData.getString('controlledSettingOwner'); + defaultStrings.shared = + loadTimeData.getString('controlledSettingShared'); } } @@ -136,8 +132,7 @@ cr.define('options', function() { // Create the DOM tree. var content = document.createElement('div'); - content.className = 'controlled-setting-bubble-content'; - content.setAttribute('controlled-by', this.controlledBy); + content.classList.add('controlled-setting-bubble-header'); content.textContent = text; if (this.controlledBy == 'hasRecommendation' && this.resetHandler_ && @@ -169,13 +164,15 @@ cr.define('options', function() { var manageLink = extensionContainer.querySelector( '.controlled-setting-bubble-extension-manage-link'); + var extensionId = this.extensionId; manageLink.onclick = function() { uber.invokeMethodOnWindow( - window.top, 'showPage', {pageId: 'extensions'}); + window.top, 'showPage', {pageId: 'extensions', + path: '?id=' + extensionId}); }; - var disableButton = extensionContainer.querySelector('button'); - var extensionId = this.extensionId; + var disableButton = extensionContainer.querySelector( + '.controlled-setting-bubble-extension-disable-button'); disableButton.onclick = function() { chrome.send('disableExtension', [extensionId]); }; @@ -223,6 +220,10 @@ cr.define('options', function() { * override this recommendation but has not done so. * - 'hasRecommendation': A value is recommended by policy. The user has * overridden this recommendation. + * - 'owner': A value is controlled by the owner of the device + * (Chrome OS only). + * - 'shared': A value belongs to the primary user but can be + * modified (Chrome OS only). * - unset: The value is controlled by the user alone. * @type {string} */ diff --git a/chromium/chrome/browser/resources/options/cookies_view.js b/chromium/chrome/browser/resources/options/cookies_view.js index 4d496684c42..a6af2978005 100644 --- a/chromium/chrome/browser/resources/options/cookies_view.js +++ b/chromium/chrome/browser/resources/options/cookies_view.js @@ -88,6 +88,10 @@ cr.define('options', function() { * @private */ handleSearchQueryChange_: function(e) { + var stringId = document.querySelector('.cookies-search-box').value ? + 'remove_all_shown_cookie' : 'remove_all_cookie'; + document.querySelector('.remove-all-cookies-button').innerHTML = + loadTimeData.getString(stringId); if (this.queryDelayTimerId_) window.clearTimeout(this.queryDelayTimerId_); diff --git a/chromium/chrome/browser/resources/options/deletable_item_list.js b/chromium/chrome/browser/resources/options/deletable_item_list.js index 403dc0fc1dc..4f223bad578 100644 --- a/chromium/chrome/browser/resources/options/deletable_item_list.js +++ b/chromium/chrome/browser/resources/options/deletable_item_list.js @@ -54,6 +54,8 @@ cr.define('options', function() { this.handleMouseDownUpOnClose_); this.closeButtonElement_.addEventListener('focus', this.handleFocus_.bind(this)); + this.closeButtonElement_.title = + loadTimeData.getString('deletableItemDeleteButtonTitle'); this.appendChild(this.closeButtonElement_); }, diff --git a/chromium/chrome/browser/resources/options/do_not_track_confirm_overlay.html b/chromium/chrome/browser/resources/options/do_not_track_confirm_overlay.html index e39d00f0af1..2c6ec530945 100644 --- a/chromium/chrome/browser/resources/options/do_not_track_confirm_overlay.html +++ b/chromium/chrome/browser/resources/options/do_not_track_confirm_overlay.html @@ -5,19 +5,23 @@ <span id="do-not-track-confirm-text" i18n-content="doNotTrackConfirmMessage"> </span> - <a target="_blank" i18n-content="learnMore" - i18n-values="href:doNotTrackLearnMoreURL"> - </a> </div> <div class="action-area"> - <div class="button-strip"> - <button id="do-not-track-confirm-ok" class="default-button" - i18n-content="doNotTrackConfirmEnable"> - </button> - <button id="do-not-track-confirm-cancel" - i18n-content="doNotTrackConfirmDisable" - class="cancel-button"> - </button> + <div class="hbox stretch"> + <a target="_blank" i18n-content="learnMore" + i18n-values="href:doNotTrackLearnMoreURL"> + </a> + </div> + <div class="action-area-right"> + <div class="button-strip"> + <button id="do-not-track-confirm-ok" class="default-button" + i18n-content="doNotTrackConfirmEnable"> + </button> + <button id="do-not-track-confirm-cancel" + i18n-content="doNotTrackConfirmDisable" + class="cancel-button"> + </button> + </div> </div> </div> </div> diff --git a/chromium/chrome/browser/resources/options/font_settings.js b/chromium/chrome/browser/resources/options/font_settings.js index 0b3f3f70a9b..1d09f5ae8fb 100644 --- a/chromium/chrome/browser/resources/options/font_settings.js +++ b/chromium/chrome/browser/resources/options/font_settings.js @@ -34,6 +34,8 @@ cr.define('options', function() { 22, 24, 26, 28, 30, 32, 34, 36, 40, 44, 48, 56, 64, 72]; standardFontRange.addEventListener( 'change', this.standardRangeChanged_.bind(this, standardFontRange)); + standardFontRange.addEventListener( + 'input', this.standardRangeChanged_.bind(this, standardFontRange)); standardFontRange.customChangeHandler = this.standardFontSizeChanged_.bind(standardFontRange); @@ -42,6 +44,8 @@ cr.define('options', function() { 18, 20, 22, 24]; minimumFontRange.addEventListener( 'change', this.minimumRangeChanged_.bind(this, minimumFontRange)); + minimumFontRange.addEventListener( + 'input', this.minimumRangeChanged_.bind(this, minimumFontRange)); minimumFontRange.customChangeHandler = this.minimumFontSizeChanged_.bind(minimumFontRange); diff --git a/chromium/chrome/browser/resources/options/handler_options.html b/chromium/chrome/browser/resources/options/handler_options.html index 4f45f018a3a..4b4e8e55b13 100644 --- a/chromium/chrome/browser/resources/options/handler_options.html +++ b/chromium/chrome/browser/resources/options/handler_options.html @@ -29,10 +29,16 @@ </div> </div> <div class="action-area"> - <div class="button-strip"> - <button id="handler-options-overlay-confirm" class="default-button" - i18n-content="done"> - </button> + <div class="hbox stretch"> + <a target="_blank" i18n-content="learnMore" + i18n-values="href:handlers_learn_more_url"></a> + </div> + <div class="action-area-right"> + <div class="button-strip"> + <button id="handler-options-overlay-confirm" class="default-button" + i18n-content="done"> + </button> + </div> </div> </div> </div> diff --git a/chromium/chrome/browser/resources/options/handler_options.js b/chromium/chrome/browser/resources/options/handler_options.js index 894e13f72c0..0918e0f2889 100644 --- a/chromium/chrome/browser/resources/options/handler_options.js +++ b/chromium/chrome/browser/resources/options/handler_options.js @@ -27,7 +27,7 @@ cr.define('options', function() { /** * The handlers list. - * @type {DeletableItemList} + * @type {options.HandlersList} * @private */ handlersList_: null, diff --git a/chromium/chrome/browser/resources/options/handler_options_list.js b/chromium/chrome/browser/resources/options/handler_options_list.js index 5572a55445f..12129a89a25 100644 --- a/chromium/chrome/browser/resources/options/handler_options_list.js +++ b/chromium/chrome/browser/resources/options/handler_options_list.js @@ -6,7 +6,6 @@ cr.define('options', function() { /** @const */ var ArrayDataModel = cr.ui.ArrayDataModel; /** @const */ var List = cr.ui.List; /** @const */ var ListItem = cr.ui.ListItem; - /** @const */ var HandlerOptions = options.HandlerOptions; /** @const */ var DeletableItem = options.DeletableItem; /** @const */ var DeletableItemList = options.DeletableItemList; @@ -14,7 +13,7 @@ cr.define('options', function() { * Creates a new ignored protocol / content handler list item. * * Accepts values in the form - * ['mailto', 'http://www.thesite.com/%s', 'The title of the protocol'], + * ['mailto', 'http://www.thesite.com/%s', 'www.thesite.com'], * @param {Object} entry A dictionary describing the handlers for a given * protocol. * @constructor @@ -41,12 +40,12 @@ cr.define('options', function() { protocolElement.className = 'handlers-type-column'; this.contentElement_.appendChild(protocolElement); - // Site title. - var titleElement = document.createElement('div'); - titleElement.textContent = this.dataItem[2]; - titleElement.className = 'handlers-site-column'; - titleElement.title = this.dataItem[1]; - this.contentElement_.appendChild(titleElement); + // Host name. + var hostElement = document.createElement('div'); + hostElement.textContent = this.dataItem[2]; + hostElement.className = 'handlers-site-column'; + hostElement.title = this.dataItem[1]; + this.contentElement_.appendChild(hostElement); }, }; @@ -91,7 +90,7 @@ cr.define('options', function() { * Accepts values in the form * { protocol: 'mailto', * handlers: [ - * ['mailto', 'http://www.thesite.com/%s', 'The title of the protocol'], + * ['mailto', 'http://www.thesite.com/%s', 'www.thesite.com'], * ..., * ], * } @@ -168,7 +167,6 @@ cr.define('options', function() { decorate: function() { ListItem.prototype.decorate.call(this); - var self = this; var delegate = { removeHandler: function(index, handler) { chrome.send('removeHandler', [handler]); diff --git a/chromium/chrome/browser/resources/options/home_page_overlay.html b/chromium/chrome/browser/resources/options/home_page_overlay.html index 7fc78398d50..a51016813ad 100644 --- a/chromium/chrome/browser/resources/options/home_page_overlay.html +++ b/chromium/chrome/browser/resources/options/home_page_overlay.html @@ -31,7 +31,7 @@ <input id="homepage-url-field" type="url" data-type="url" class="weakrtl favicon-cell stretch" pref="homepage" aria-labelledby="homepage-use-url-label" - dialog-pref> + metric="Options_Homepage_URL" dialog-pref> </input> <span id="homepage-url-field-indicator" class="controlled-setting-indicator" pref="homepage" diff --git a/chromium/chrome/browser/resources/options/hotword_confirm_overlay.css b/chromium/chrome/browser/resources/options/hotword_confirm_overlay.css new file mode 100644 index 00000000000..6fc7648e239 --- /dev/null +++ b/chromium/chrome/browser/resources/options/hotword_confirm_overlay.css @@ -0,0 +1,12 @@ +/* Copyright 2014 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. + */ + +#hotword-confirm-overlay { + width: 500px; +} + +#audio-logging-bar input { + bottom: 6px; +} diff --git a/chromium/chrome/browser/resources/options/hotword_confirm_overlay.html b/chromium/chrome/browser/resources/options/hotword_confirm_overlay.html new file mode 100644 index 00000000000..25a61b3719d --- /dev/null +++ b/chromium/chrome/browser/resources/options/hotword_confirm_overlay.html @@ -0,0 +1,38 @@ +<div id="hotword-confirm-overlay" class="page" hidden> + <div class="close-button"></div> + <h1 i18n-content="hotwordConfirmOverlay"></h1> + <div class="content-area"> + <span id="hotword-confirm-text" i18n-content="hotwordConfirmMessage"> + </span> + </div> + <div class="action-area"> + <div class="hbox stretch"> + <a target="_blank" i18n-content="learnMore" + i18n-values="href:hotwordLearnMoreURL"> + </a> + </div> + <div class="action-area-right"> + <div class="button-strip"> + <button id="hotword-confirm-cancel" + i18n-content="hotwordConfirmDisable"> + </button> + <button id="hotword-confirm-ok" class="default-button" + i18n-content="hotwordConfirmEnable"> + </button> + </div> + </div> + </div> + <div id="audio-logging-bar" class="gray-bottom-bar checkbox"> + <span class="controlled-setting-with-label"> + <input id="hotword-audio-logging-enable" + pref="hotword.audio_logging_enabled" + metric="Options_Hotword_AudioLogging_Checkbox" + type="checkbox" dialog-pref checked> + <span> + <label for="hotword-audio-logging-enable" + i18n-content="hotwordAudioLoggingEnable"> + </label> + </span> + </span> + </div> +</div> diff --git a/chromium/chrome/browser/resources/options/hotword_search_setting_indicator.css b/chromium/chrome/browser/resources/options/hotword_search_setting_indicator.css new file mode 100644 index 00000000000..1abdeb6a076 --- /dev/null +++ b/chromium/chrome/browser/resources/options/hotword_search_setting_indicator.css @@ -0,0 +1,10 @@ +/* Copyright 2014 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. */ + +/* Hotword extension-specific controlled setting indicator and bubble. */ + +#hotword-search-setting-indicator > div { + background: url('chrome://theme/IDR_WARNING') left top no-repeat; + background-size: 18px; +} diff --git a/chromium/chrome/browser/resources/options/hotword_search_setting_indicator.js b/chromium/chrome/browser/resources/options/hotword_search_setting_indicator.js new file mode 100644 index 00000000000..035a1d317ab --- /dev/null +++ b/chromium/chrome/browser/resources/options/hotword_search_setting_indicator.js @@ -0,0 +1,115 @@ +// Copyright 2014 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. + +cr.define('options', function() { + /** @const */ var ControlledSettingIndicator = + options.ControlledSettingIndicator; + + /** + * A variant of the {@link ControlledSettingIndicator} that shows the status + * of the hotword search setting, including a bubble to show setup errors + * (such as failures to download extension resources). + * @constructor + * @extends {HTMLSpanElement} + */ + var HotwordSearchSettingIndicator = cr.ui.define('span'); + + HotwordSearchSettingIndicator.prototype = { + __proto__: ControlledSettingIndicator.prototype, + + /** + * Decorates the base element to show the proper icon. + * @override + */ + decorate: function() { + ControlledSettingIndicator.prototype.decorate.call(this); + this.hidden = true; + }, + + /* Handle changes to the associated pref by hiding any currently visible + * bubble. + * @param {Event} event Pref change event. + * @override + */ + handlePrefChange: function(event) { + OptionsPage.hideBubble(); + }, + + /** + * Sets the variable tracking thesection which becomes disabled if an + * error exists. + * @param {HTMLElement} section The section to disable. + */ + set disabledOnErrorSection(section) { + this.disabledOnErrorSection_ = section; + }, + + /** + * Assigns a value to the error message and updates the hidden state + * and whether the disabled section is disabled or not. + * @param {string} errorMsg The error message to be displayed. If none, + * there is no error. + */ + set errorText(errorMsg) { + this.setAttribute('controlled-by', 'policy'); + this.errorText_ = errorMsg; + if (errorMsg) + this.hidden = false; + if (this.disabledOnErrorSection_) + this.disabledOnErrorSection_.disabled = (errorMsg ? true : false); + }, + + /** + * Assigns a value to the help link variable. + * @param {string} helpLink The text that links to a troubleshooting page. + */ + set helpLink(helpLinkText) { + this.helpLink_ = helpLinkText; + }, + + /** + * Toggles showing and hiding the error message bubble. An empty + * |errorText_| indicates that there is no error message. So the bubble + * only be shown if |errorText_| has a value. + */ + toggleBubble_: function() { + if (this.showingBubble) { + OptionsPage.hideBubble(); + return; + } + + if (!this.errorText_) + return; + + var self = this; + // Create the DOM tree for the bubble content. + var closeButton = document.createElement('div'); + closeButton.classList.add('close-button'); + + var text = document.createElement('p'); + text.innerHTML = this.errorText_; + + var help = document.createElement('p'); + help.innerHTML = this.helpLink_; + + var textDiv = document.createElement('div'); + textDiv.appendChild(text); + textDiv.appendChild(help); + + var container = document.createElement('div'); + container.appendChild(closeButton); + container.appendChild(textDiv); + + var content = document.createElement('div'); + content.appendChild(container); + + OptionsPage.showBubble(content, this.image, this, this.location); + }, + }; + + // Export + return { + HotwordSearchSettingIndicator: HotwordSearchSettingIndicator + }; +}); diff --git a/chromium/chrome/browser/resources/options/import_data_overlay.html b/chromium/chrome/browser/resources/options/import_data_overlay.html index 57215089b87..4aca7cfcb4c 100644 --- a/chromium/chrome/browser/resources/options/import_data_overlay.html +++ b/chromium/chrome/browser/resources/options/import_data_overlay.html @@ -116,7 +116,9 @@ </div> </div> </div> +<if expr="is_macosx"> <div id="mac-password-keychain" class="gray-bottom-bar"> <span i18n-content="macPasswordKeychain"></span> </div> +</if> </div> diff --git a/chromium/chrome/browser/resources/options/import_data_overlay.js b/chromium/chrome/browser/resources/options/import_data_overlay.js index 16b8cca6ff2..f6fb061af30 100644 --- a/chromium/chrome/browser/resources/options/import_data_overlay.js +++ b/chromium/chrome/browser/resources/options/import_data_overlay.js @@ -62,13 +62,6 @@ cr.define('options', function() { chrome.send('chooseBookmarksFile'); }; - $('import-data-show-bookmarks-bar').onchange = function() { - // Note: The callback 'toggleShowBookmarksBar' is handled within the - // browser options handler -- rather than the import data handler -- - // as the implementation is shared by several clients. - chrome.send('toggleShowBookmarksBar'); - } - $('import-data-confirm').onclick = function() { ImportDataOverlay.dismiss(); }; @@ -100,7 +93,9 @@ cr.define('options', function() { this.setUpCheckboxState_(checkboxes[i], enabled); $('import-data-commit').disabled = !enabled; $('import-choose-file').hidden = !enabled; +<if expr="is_macosx"> $('mac-password-keychain').hidden = !enabled; +</if> }, /** @@ -147,7 +142,9 @@ cr.define('options', function() { if (this.browserProfiles.length > index) browserProfile = this.browserProfiles[index]; var enable = browserProfile && browserProfile['show_bottom_bar']; +<if expr="is_macosx"> $('mac-password-keychain').hidden = !enable; +</if> }, /** diff --git a/chromium/chrome/browser/resources/options/language_options.css b/chromium/chrome/browser/resources/options/language_options.css index 4e86bbbe02b..07f968f1ccb 100644 --- a/chromium/chrome/browser/resources/options/language_options.css +++ b/chromium/chrome/browser/resources/options/language_options.css @@ -2,6 +2,10 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ +#languagePage .content-area { + width: 660px; +} + .language-options { display: -webkit-box; margin: 10px 0; @@ -25,7 +29,8 @@ padding: 0 12px 4px; } -.language-options-contents > span:not(.input-method-label) { +.language-options-contents > + span:not(.input-method-label):not(.controlled-setting-indicator) { display: inline-block; margin: 1px; padding: 0.42em 10px; @@ -59,9 +64,10 @@ } #language-options-details { + -webkit-box-flex: 1; /* To share the center line with the left pane. */ -webkit-margin-start: -1px; - width: 360px; + overflow-y: auto; } #language-options-details h3:not(:first-of-type) { diff --git a/chromium/chrome/browser/resources/options/language_options.html b/chromium/chrome/browser/resources/options/language_options.html index e2d420cb61a..cc8ef30d698 100644 --- a/chromium/chrome/browser/resources/options/language_options.html +++ b/chromium/chrome/browser/resources/options/language_options.html @@ -7,10 +7,12 @@ <span class="link"><span class="link-color"></span></span> </div> <div class="language-options-header"> - <div i18n-content="addLanguageInstructions"></div> -<if expr="pp_ifdef('chromeos')"> - <div i18n-content="inputMethodInstructions"></div> + <span i18n-content="addLanguageInstructions"></span> +<if expr="chromeos"> + <span i18n-content="inputMethodInstructions"></span> </if> + <a target="_blank" i18n-content="learnMore" + i18n-values="href:languagesLearnMoreURL"></a> </div> <div class="language-options"> <div id="language-options-languages"> @@ -25,11 +27,12 @@ </div> <div id="language-options-details"> <h3 id="language-options-language-name"></h3> -<if expr="os == 'win32' or pp_ifdef('chromeos')"> +<if expr="os == 'win32' or chromeos"> <div class="language-options-contents"> <button id="language-options-ui-language-button" i18n-content="displayInThisLanguage"> </button> + <span class="controlled-setting-indicator"></span> <span id="language-options-ui-language-message" hidden></span> </div> </if> @@ -59,7 +62,7 @@ <div id="language-options-ui-notification-bar" class="language-options-notification" hidden> <div i18n-content="restartRequired"></div> -<if expr="pp_ifdef('chromeos')"> +<if expr="chromeos"> <button id="language-options-ui-restart-button" i18n-content="restartButton"> </button> @@ -78,7 +81,7 @@ <span id="cannot-translate-in-this-language" i18n-content="cannotTranslateInThisLanguage" hidden></span> </div> -<if expr="pp_ifdef('chromeos')"> +<if expr="chromeos"> <h3 i18n-content="inputMethod"></h3> <div id="language-options-input-method-template" class="input-method" hidden> @@ -99,14 +102,14 @@ </div> </div> <div class="language-options-footer"> -<if expr="pp_ifdef('chromeos')"> +<if expr="chromeos"> <div i18n-content="switchInputMethodsHint"></div> <div i18n-content="selectPreviousInputMethodHint"></div> <button id="edit-dictionary-button" class="link-button standalone-link-button" i18n-content="languageDictionaryOverlayTitle"></button> </if> -<if expr="not pp_ifdef('chromeos') and not is_macosx"> +<if expr="not chromeos and not is_macosx"> <div id="spell-check-option" class="checkbox"> <label> <input id="enable-spell-check" pref="browser.enable_spellchecking" diff --git a/chromium/chrome/browser/resources/options/language_options.js b/chromium/chrome/browser/resources/options/language_options.js index 3ebf7d2665b..f8801975253 100644 --- a/chromium/chrome/browser/resources/options/language_options.js +++ b/chromium/chrome/browser/resources/options/language_options.js @@ -8,6 +8,8 @@ cr.define('options', function() { /** @const */ var OptionsPage = options.OptionsPage; /** @const */ var LanguageList = options.LanguageList; + /** @const */ var ThirdPartyImeConfirmOverlay = + options.ThirdPartyImeConfirmOverlay; /** * Spell check dictionary download status. @@ -318,6 +320,7 @@ cr.define('options', function() { var input = element.querySelector('input'); input.inputMethodId = inputMethod.id; + input.imeProvider = inputMethod.extensionName; var span = element.querySelector('span'); span.textContent = inputMethod.displayName; @@ -426,14 +429,6 @@ cr.define('options', function() { }, /** - * Happens when a user changes back to the language they're currently using. - */ - currentLocaleWasReselected: function() { - this.updateUiLanguageButton_( - loadTimeData.getString('currentUiLanguageCode')); - }, - - /** * Handles languageOptionsList's save event. * @param {Event} e Save event. * @private @@ -557,6 +552,11 @@ cr.define('options', function() { // hidden by a language change. uiLanguageButton.hidden = false; + // Hide the controlled setting indicator. + var uiLanguageIndicator = document.querySelector( + '.language-options-contents .controlled-setting-indicator'); + uiLanguageIndicator.removeAttribute('controlled-by'); + if (languageCode == this.prospectiveUiLanguageCode_) { uiLanguageMessage.textContent = loadTimeData.getString('isDisplayedInThisLanguage'); @@ -571,11 +571,18 @@ cr.define('options', function() { } else { uiLanguageButton.textContent = loadTimeData.getString('displayInThisLanguage'); + + if (loadTimeData.valueExists('secondaryUser') && + loadTimeData.getBoolean('secondaryUser')) { + uiLanguageButton.disabled = true; + uiLanguageIndicator.setAttribute('controlled-by', 'shared'); + } else { + uiLanguageButton.onclick = function(e) { + chrome.send('uiLanguageChange', [languageCode]); + }; + } showMutuallyExclusiveNodes( [uiLanguageButton, uiLanguageMessage, uiLanguageNotification], 0); - uiLanguageButton.onclick = function(e) { - chrome.send('uiLanguageChange', [languageCode]); - }; } } else { uiLanguageMessage.textContent = @@ -819,6 +826,31 @@ cr.define('options', function() { handleCheckboxClick_: function(e) { var checkbox = e.target; + // Third party IMEs require additional confirmation prior to enabling due + // to privacy risk. + if (/^_ext_ime_/.test(checkbox.inputMethodId) && checkbox.checked) { + var confirmationCallback = this.handleCheckboxUpdate_.bind(this, + checkbox); + var cancellationCallback = function() { + checkbox.checked = false; + }; + ThirdPartyImeConfirmOverlay.showConfirmationDialog({ + extension: checkbox.imeProvider, + confirm: confirmationCallback, + cancel: cancellationCallback + }); + } else { + this.handleCheckboxUpdate_(checkbox); + } + }, + + /** + * Updates active IMEs based on change in state of a checkbox for an input + * method. + * @param {!Element} checkbox Updated checkbox element. + * @private + */ + handleCheckboxUpdate_: function(checkbox) { if (checkbox.inputMethodId.match(/^_ext_ime_/)) { this.updateEnabledExtensionsFromCheckboxes_(); this.saveEnabledExtensionPref_(); @@ -842,7 +874,12 @@ cr.define('options', function() { this.savePreloadEnginesPref_(); }, - handleAddLanguageOkButtonClick_: function() { + /** + * Handles clicks on the "OK" button of the "Add language" dialog. + * @param {Event} e Click event. + * @private + */ + handleAddLanguageOkButtonClick_: function(e) { var languagesSelect = $('add-language-overlay-language-list'); var selectedIndex = languagesSelect.selectedIndex; if (selectedIndex >= 0) { @@ -1181,6 +1218,39 @@ cr.define('options', function() { delayedHide(); }, + /** + * Chrome callback for when the UI language preference is saved. + * @param {string} languageCode The newly selected language to use. + * @private + */ + uiLanguageSaved_: function(languageCode) { + this.prospectiveUiLanguageCode_ = languageCode; + + // If the user is no longer on the same language code, ignore. + if ($('language-options-list').getSelectedLanguageCode() != languageCode) + return; + + // Special case for when a user changes to a different language, and + // changes back to the same language without having restarted Chrome or + // logged in/out of ChromeOS. + if (languageCode == loadTimeData.getString('currentUiLanguageCode')) { + this.updateUiLanguageButton_(languageCode); + return; + } + + // Otherwise, show a notification telling the user that their changes will + // only take effect after restart. + showMutuallyExclusiveNodes([$('language-options-ui-language-button'), + $('language-options-ui-notification-bar')], + 1); + }, + + /** + * A handler for when dictionary for |languageCode| begins downloading. + * @param {string} languageCode The language of the dictionary that just + * began downloading. + * @private + */ onDictionaryDownloadBegin_: function(languageCode) { this.spellcheckDictionaryDownloadStatus_[languageCode] = DOWNLOAD_STATUS.IN_PROGRESS; @@ -1191,6 +1261,12 @@ cr.define('options', function() { } }, + /** + * A handler for when dictionary for |languageCode| successfully downloaded. + * @param {string} languageCode The language of the dictionary that + * succeeded downloading. + * @private + */ onDictionaryDownloadSuccess_: function(languageCode) { delete this.spellcheckDictionaryDownloadStatus_[languageCode]; this.spellcheckDictionaryDownloadFailures_ = 0; @@ -1201,6 +1277,12 @@ cr.define('options', function() { } }, + /** + * A handler for when dictionary for |languageCode| fails to download. + * @param {string} languageCode The language of the dictionary that failed + * to download. + * @private + */ onDictionaryDownloadFailure_: function(languageCode) { this.spellcheckDictionaryDownloadStatus_[languageCode] = DOWNLOAD_STATUS.FAILED; @@ -1256,29 +1338,8 @@ cr.define('options', function() { } } - /** - * Chrome callback for when the UI language preference is saved. - * @param {string} languageCode The newly selected language to use. - */ LanguageOptions.uiLanguageSaved = function(languageCode) { - this.prospectiveUiLanguageCode_ = languageCode; - - // If the user is no longer on the same language code, ignore. - if ($('language-options-list').getSelectedLanguageCode() != languageCode) - return; - - // Special case for when a user changes to a different language, and changes - // back to the same language without having restarted Chrome or logged - // in/out of ChromeOS. - if (languageCode == loadTimeData.getString('currentUiLanguageCode')) { - LanguageOptions.getInstance().currentLocaleWasReselected(); - return; - } - - // Otherwise, show a notification telling the user that their changes will - // only take effect after restart. - showMutuallyExclusiveNodes([$('language-options-ui-language-button'), - $('language-options-ui-notification-bar')], 1); + LanguageOptions.getInstance().uiLanguageSaved_(languageCode); }; LanguageOptions.onDictionaryDownloadBegin = function(languageCode) { diff --git a/chromium/chrome/browser/resources/options/manage_profile_overlay.css b/chromium/chrome/browser/resources/options/manage_profile_overlay.css index 760030db3d2..1c2ed4416f8 100644 --- a/chromium/chrome/browser/resources/options/manage_profile_overlay.css +++ b/chromium/chrome/browser/resources/options/manage_profile_overlay.css @@ -23,6 +23,10 @@ margin-top: 5px; } +#create-profile-name-input-container { + margin-bottom: 5px; +} + #create-profile-name, #manage-profile-name { margin-left: 10px; @@ -33,6 +37,19 @@ background-color: pink; } +#disconnect-managed-profile-domain-name { + font-weight: bold; +} + +#disconnect-managed-profile-domain-information { + background-color: #f0f0f0; + padding: 14px 0 14px 17px; +} + +#disconnect-managed-profile-message { + padding-top: 9px; +} + #create-profile-error-bubble, #manage-profile-error-bubble { -webkit-transition: max-height 200ms, padding 200ms; @@ -43,11 +60,21 @@ margin-right: auto; max-height: 50px; overflow: hidden; - padding: 1px 10px; + padding: 10px 10px; text-align: center; width: 80%; } +html[dir='ltr'] #create-profile-error-bubble { + margin-left: 20px; + width: 90%; +} + +html[dir='rtl'] #create-profile-error-bubble { + margin-right: 20px; + width: 90%; +} + #create-profile-error-bubble[hidden], #manage-profile-error-bubble[hidden] { display: block !important; @@ -121,10 +148,15 @@ html[dir='rtl'] #delete-profile-icon { } #create-profile-managed-content-area { - padding-top: 0; + padding-top: 5px; } #import-existing-managed-user-link { left: 17px; position: absolute; } + +#supervised-user-import { + margin: 0; + padding: 0; +} diff --git a/chromium/chrome/browser/resources/options/manage_profile_overlay.html b/chromium/chrome/browser/resources/options/manage_profile_overlay.html index 42ccfb21cae..e8a6515c92e 100644 --- a/chromium/chrome/browser/resources/options/manage_profile_overlay.html +++ b/chromium/chrome/browser/resources/options/manage_profile_overlay.html @@ -52,6 +52,29 @@ i18n-content="deleteProfileOK"></button> </div> </div> + <!-- Dialog for disconnecting enterprise managed profiles. --> + <div id="manage-profile-overlay-disconnect-managed" hidden> + <h1 i18n-content="disconnectManagedProfileTitle"></h1> + <div class="content-area" + id="disconnect-managed-profile-domain-information" + i18n-values=".innerHTML:disconnectManagedProfileDomainInformation"> + </div> + <div class="content-area"> + <div id="disconnect-managed-profile-message"> + <div id="disconnect-managed-profile-text" + i18n-values=".innerHTML:disconnectManagedProfileText"> + </div> + </div> + </div> + <div class="action-area"> + <div class="button-strip"> + <button id="disconnect-managed-profile-ok" + i18n-content="disconnectManagedProfileOK"></button> + <button id="disconnect-managed-profile-cancel" class="default-button" + i18n-content="cancel"></button> + </div> + </div> + </div> <!-- Dialog for creating profiles. --> <div id="manage-profile-overlay-create" hidden> <h1 i18n-content="createProfileTitle"></h1> @@ -66,7 +89,6 @@ <input id="create-profile-name" type="text" required> </label> </div> - <div id="create-profile-error-bubble" hidden></div> </div> <div id="create-profile-managed-content-area" class="content-area"> <div id="create-shortcut-container" class="checkbox" hidden> @@ -107,11 +129,12 @@ class="bubble-button controlled-setting-indicator"> </span> </div> + <div id="create-profile-error-bubble" hidden></div> </div> <div class="action-area"> <div id="create-profile-throbber" class="throbber"></div> <button id="import-existing-managed-user-link" class="link-button" - i18n-content="importExistingManagedUserLink"> + i18n-content="importExistingManagedUserLink" hidden> </button> <div class="button-strip"> <button id="create-profile-cancel" i18n-content="cancel"></button> diff --git a/chromium/chrome/browser/resources/options/manage_profile_overlay.js b/chromium/chrome/browser/resources/options/manage_profile_overlay.js index 2d6e64c717f..723d6cd1cc8 100644 --- a/chromium/chrome/browser/resources/options/manage_profile_overlay.js +++ b/chromium/chrome/browser/resources/options/manage_profile_overlay.js @@ -27,8 +27,16 @@ cr.define('options', function() { // Info about the currently managed/deleted profile. profileInfo_: null, - // An object containing all known profile names. - profileNames_: {}, + // Whether the currently chosen name for a new profile was assigned + // automatically by choosing an avatar. Set on receiveNewProfileDefaults; + // cleared on first edit (in onNameChanged_). + profileNameIsDefault_: false, + + // List of default profile names corresponding to the respective icons. + defaultProfileNames_: [], + + // An object containing all names of existing profiles. + existingProfileNames_: {}, // The currently selected icon in the icon grid. iconGridSelectedURL_: null, @@ -58,10 +66,8 @@ cr.define('options', function() { CreateProfileOverlay.cancelCreateProfile(); }; - $('import-existing-managed-user-link').hidden = - !loadTimeData.getBoolean('allowCreateExistingManagedUsers'); - $('manage-profile-cancel').onclick = + $('disconnect-managed-profile-cancel').onclick = $('delete-profile-cancel').onclick = function(event) { OptionsPage.closeOverlay(); }; @@ -70,6 +76,7 @@ cr.define('options', function() { if (BrowserOptions.getCurrentProfile().isManaged) return; chrome.send('deleteProfile', [self.profileInfo_.filePath]); + options.ManagedUserListData.resetPromise(); }; $('add-shortcut-button').onclick = function(event) { chrome.send('addProfileShortcut', [self.profileInfo_.filePath]); @@ -78,6 +85,12 @@ cr.define('options', function() { chrome.send('removeProfileShortcut', [self.profileInfo_.filePath]); }; + $('disconnect-managed-profile-ok').onclick = function(event) { + OptionsPage.closeOverlay(); + chrome.send('deleteProfile', + [BrowserOptions.getCurrentProfile().filePath]); + } + $('create-profile-managed-signed-in-learn-more-link').onclick = function(event) { OptionsPage.navigateToPage('managedUserLearnMore'); @@ -100,14 +113,17 @@ cr.define('options', function() { }; $('import-existing-managed-user-link').onclick = function(event) { - OptionsPage.closeOverlay(); + // Hide the import button to trigger a cursor update. The import button + // is shown again when the import overlay loads. TODO(akuegel): Remove + // this temporary fix when crbug/246304 is resolved. + $('import-existing-managed-user-link').hidden = true; OptionsPage.navigateToPage('managedUserImport'); }; }, /** @override */ didShowPage: function() { - chrome.send('requestDefaultProfileIcons'); + chrome.send('requestDefaultProfileIcons', ['manage']); // Just ignore the manage profile dialog on Chrome OS, they use /accounts. if (!cr.isChromeOS && window.location.pathname == '/manageProfile') @@ -130,13 +146,14 @@ cr.define('options', function() { $('manage-profile-ok').focus(); else manageNameField.focus(); + + this.profileNameIsDefault_ = false; }, /** * Registers event handlers that are common between create and manage modes. - * @param {string} mode A label that specifies the type of dialog - * box which is currently being viewed (i.e. 'create' or - * 'manage'). + * @param {string} mode A label that specifies the type of dialog box which + * is currently being viewed (i.e. 'create' or 'manage'). * @param {function()} submitFunction The function that should be called * when the user chooses to submit (e.g. by clicking the OK button). * @private @@ -147,7 +164,7 @@ cr.define('options', function() { self.onIconGridSelectionChanged_(mode); }); $(mode + '-profile-name').oninput = function(event) { - self.onNameChanged_(event, mode); + self.onNameChanged_(mode); }; $(mode + '-profile-ok').onclick = function(event) { OptionsPage.closeOverlay(); @@ -165,9 +182,8 @@ cr.define('options', function() { * isCurrentProfile: false, * isManaged: false * }; - * @param {string} mode A label that specifies the type of dialog - * box which is currently being viewed (i.e. 'create' or - * 'manage'). + * @param {string} mode A label that specifies the type of dialog box which + * is currently being viewed (i.e. 'create' or 'manage'). * @private */ setProfileInfo_: function(profileInfo, mode) { @@ -178,28 +194,38 @@ cr.define('options', function() { }, /** - * Sets the name of the currently edited profile. + * Sets the name of the profile being edited or created. + * @param {string} name New profile name. + * @param {string} mode A label that specifies the type of dialog box which + * is currently being viewed (i.e. 'create' or 'manage'). * @private */ - setProfileName_: function(name) { + setProfileName_: function(name, mode) { if (this.profileInfo_) this.profileInfo_.name = name; - $('manage-profile-name').value = name; + $(mode + '-profile-name').value = name; }, /** * Set an array of default icon URLs. These will be added to the grid that * the user will use to choose their profile icon. + * @param {string} mode A label that specifies the type of dialog box which + * is currently being viewed (i.e. 'create' or 'manage'). * @param {Array.<string>} iconURLs An array of icon URLs. + * @param {Array.<string>} names An array of default names + * corresponding to the icons. * @private */ - receiveDefaultProfileIcons_: function(iconGrid, iconURLs) { - $(iconGrid).dataModel = new ArrayDataModel(iconURLs); + receiveDefaultProfileIconsAndNames_: function(mode, iconURLs, names) { + this.defaultProfileNames_ = names; + + var grid = $(mode + '-profile-icon-grid'); + + grid.dataModel = new ArrayDataModel(iconURLs); if (this.profileInfo_) - $(iconGrid).selectedItem = this.profileInfo_.iconURL; + grid.selectedItem = this.profileInfo_.iconURL; - var grid = $(iconGrid); // Recalculate the measured item size. grid.measured_ = null; grid.columns = 0; @@ -217,6 +243,7 @@ cr.define('options', function() { */ receiveNewProfileDefaults_: function(profileInfo) { ManageProfileOverlay.setProfileInfo(profileInfo, 'create'); + this.profileNameIsDefault_ = true; $('create-profile-name-label').hidden = false; $('create-profile-name').hidden = false; // Trying to change the focus if this isn't the topmost overlay can @@ -239,8 +266,8 @@ cr.define('options', function() { * @param {Object} profileNames A dictionary of profile names. * @private */ - receiveProfileNames_: function(profileNames) { - this.profileNames_ = profileNames; + receiveExistingProfileNames_: function(profileNames) { + this.existingProfileNames_ = profileNames; }, /** @@ -256,20 +283,19 @@ cr.define('options', function() { }, /** - * Display the error bubble, with |errorText| in the bubble. - * @param {string} errorText The string to display as an error. - * @param {string} mode A label that specifies the type of dialog - * box which is currently being viewed (i.e. 'create' or - * 'manage'). + * Display the error bubble, with |errorHtml| in the bubble. + * @param {string} errorHtml The html string to display as an error. + * @param {string} mode A label that specifies the type of dialog box which + * is currently being viewed (i.e. 'create' or 'manage'). * @param {boolean} disableOKButton True if the dialog's OK button should be * disabled when the error bubble is shown. It will be (re-)enabled when * the error bubble is hidden. * @private */ - showErrorBubble_: function(errorText, mode, disableOKButton) { + showErrorBubble_: function(errorHtml, mode, disableOKButton) { var nameErrorEl = $(mode + '-profile-error-bubble'); nameErrorEl.hidden = false; - nameErrorEl.textContent = errorText; + nameErrorEl.innerHTML = errorHtml; if (disableOKButton) $(mode + '-profile-ok').disabled = true; @@ -277,34 +303,123 @@ cr.define('options', function() { /** * Hide the error bubble. - * @param {string} mode A label that specifies the type of dialog - * box which is currently being viewed (i.e. 'create' or - * 'manage'). + * @param {string} mode A label that specifies the type of dialog box which + * is currently being viewed (i.e. 'create' or 'manage'). * @private */ hideErrorBubble_: function(mode) { + $(mode + '-profile-error-bubble').innerHTML = ''; $(mode + '-profile-error-bubble').hidden = true; $(mode + '-profile-ok').disabled = false; }, /** * oninput callback for <input> field. - * @param {Event} event The event object. - * @param {string} mode A label that specifies the type of dialog - * box which is currently being viewed (i.e. 'create' or - * 'manage'). + * @param {string} mode A label that specifies the type of dialog box which + * is currently being viewed (i.e. 'create' or 'manage'). * @private */ - onNameChanged_: function(event, mode) { - var newName = event.target.value; - var oldName = this.profileInfo_.name; + onNameChanged_: function(mode) { + this.profileNameIsDefault_ = false; + this.updateCreateOrImport_(mode); + }, - if (newName == oldName) { - this.hideErrorBubble_(mode); - } else if (this.profileNames_[newName] != undefined) { - var errorText = + /** + * Called when the profile name is changed or the 'create managed' checkbox + * is toggled. Updates the 'ok' button and the 'import existing supervised + * user' link. + * @param {string} mode A label that specifies the type of dialog box which + * is currently being viewed (i.e. 'create' or 'manage'). + * @private + */ + updateCreateOrImport_: function(mode) { + // In 'create' mode, check for existing managed users with the same name. + if (mode == 'create' && $('create-profile-managed').checked) { + options.ManagedUserListData.requestExistingManagedUsers().then( + this.receiveExistingManagedUsers_.bind(this), + this.onSigninError_.bind(this)); + } else { + this.updateOkButton_(mode); + } + }, + + /** + * Callback which receives the list of existing managed users. Checks if the + * currently entered name is the name of an already existing managed user. + * If yes, the user is prompted to import the existing managed user, and the + * create button is disabled. + * @param {Array.<Object>} The list of existing managed users. + * @private + */ + receiveExistingManagedUsers_: function(managedUsers) { + var newName = $('create-profile-name').value; + var i; + for (i = 0; i < managedUsers.length; ++i) { + if (managedUsers[i].name == newName && + !managedUsers[i].onCurrentDevice) { + var errorHtml = loadTimeData.getStringF( + 'manageProfilesExistingSupervisedUser', + HTMLEscape(elide(newName, /* maxLength */ 50))); + this.showErrorBubble_(errorHtml, 'create', true); + + // Check if another supervised user also exists with that name. + var nameIsUnique = true; + var j; + for (j = i + 1; j < managedUsers.length; ++j) { + if (managedUsers[j].name == newName) { + nameIsUnique = false; + break; + } + } + var self = this; + function getImportHandler(managedUser, nameIsUnique) { + return function() { + if (managedUser.needAvatar || !nameIsUnique) { + OptionsPage.navigateToPage('managedUserImport'); + } else { + self.hideErrorBubble_('create'); + CreateProfileOverlay.updateCreateInProgress(true); + chrome.send('createProfile', + [managedUser.name, managedUser.iconURL, false, true, + managedUser.id]); + } + } + }; + $('supervised-user-import').onclick = + getImportHandler(managedUsers[i], nameIsUnique); + $('create-profile-ok').disabled = true; + return; + } + } + this.updateOkButton_('create'); + }, + + /** + * Called in case the request for the list of managed users fails because of + * a signin error. + * @private + */ + onSigninError_: function() { + this.updateImportExistingManagedUserLink_(false); + }, + + /** + * Called to update the state of the ok button depending if the name is + * already used or not. + * @param {string} mode A label that specifies the type of dialog box which + * is currently being viewed (i.e. 'create' or 'manage'). + * @private + */ + updateOkButton_: function(mode) { + var oldName = this.profileInfo_.name; + var newName = $(mode + '-profile-name').value; + var nameIsDuplicate = this.existingProfileNames_[newName] != undefined; + if (mode == 'manage' && oldName == newName) + nameIsDuplicate = false; + if (nameIsDuplicate) { + var errorHtml = loadTimeData.getString('manageProfilesDuplicateNameError'); - this.showErrorBubble_(errorText, mode, true); + this.showErrorBubble_(errorHtml, mode, true); } else { this.hideErrorBubble_(mode); @@ -324,6 +439,8 @@ cr.define('options', function() { chrome.send('setProfileIconAndName', [this.profileInfo_.filePath, iconURL, name]); + if (name != this.profileInfo_.name) + options.ManagedUserListData.resetPromise(); }, /** @@ -356,9 +473,8 @@ cr.define('options', function() { /** * Called when the selected icon in the icon grid changes. - * @param {string} mode A label that specifies the type of dialog - * box which is currently being viewed (i.e. 'create' or - * 'manage'). + * @param {string} mode A label that specifies the type of dialog box which + * is currently being viewed (i.e. 'create' or 'manage'). * @private */ onIconGridSelectionChanged_: function(mode) { @@ -366,6 +482,13 @@ cr.define('options', function() { if (!iconURL || iconURL == this.iconGridSelectedURL_) return; this.iconGridSelectedURL_ = iconURL; + if (this.profileNameIsDefault_) { + var index = $(mode + '-profile-icon-grid').selectionModel.selectedIndex; + var name = this.defaultProfileNames_[index]; + if (name) { + this.setProfileName_(name, mode); + } + } if (this.profileInfo_ && this.profileInfo_.filePath) { chrome.send('profileIconSelectionChanged', [this.profileInfo_.filePath, iconURL]); @@ -378,11 +501,13 @@ cr.define('options', function() { * @private */ prepareForManageDialog_: function() { + chrome.send('refreshGaiaPicture'); var profileInfo = BrowserOptions.getCurrentProfile(); ManageProfileOverlay.setProfileInfo(profileInfo, 'manage'); $('manage-profile-overlay-create').hidden = true; $('manage-profile-overlay-manage').hidden = false; $('manage-profile-overlay-delete').hidden = true; + $('manage-profile-overlay-disconnect-managed').hidden = true; $('manage-profile-name').disabled = profileInfo.isManaged; this.hideErrorBubble_('manage'); }, @@ -409,10 +534,12 @@ cr.define('options', function() { $('manage-profile-overlay-create').hidden = true; $('manage-profile-overlay-manage').hidden = true; $('manage-profile-overlay-delete').hidden = false; + $('manage-profile-overlay-disconnect-managed').hidden = true; $('delete-profile-icon').style.content = - imageset(profileInfo.iconURL + '@scalefactorx'); + getProfileAvatarIcon(profileInfo.iconURL); $('delete-profile-text').textContent = - loadTimeData.getStringF('deleteProfileMessage', profileInfo.name); + loadTimeData.getStringF('deleteProfileMessage', + elide(profileInfo.name, /* maxLength */ 50)); $('delete-managed-profile-addendum').hidden = !profileInfo.isManaged; // Because this dialog isn't useful when refreshing or as part of the @@ -421,6 +548,26 @@ cr.define('options', function() { }, /** + * Display the "Disconnect Managed Profile" dialog. + * @private + */ + showDisconnectManagedProfileDialog_: function(replacements) { + loadTimeData.overrideValues(replacements); + $('manage-profile-overlay-create').hidden = true; + $('manage-profile-overlay-manage').hidden = true; + $('manage-profile-overlay-delete').hidden = true; + $('disconnect-managed-profile-domain-information').innerHTML = + loadTimeData.getString('disconnectManagedProfileDomainInformation'); + $('disconnect-managed-profile-text').innerHTML = + loadTimeData.getString('disconnectManagedProfileText'); + $('manage-profile-overlay-disconnect-managed').hidden = false; + + // Because this dialog isn't useful when refreshing or as part of the + // history, don't create a history entry for it when showing. + OptionsPage.showPageByName('manageProfile', false); + }, + + /** * Display the "Create Profile" dialog. * @private */ @@ -431,14 +578,15 @@ cr.define('options', function() { // Forward public APIs to private implementations. [ - 'receiveDefaultProfileIcons', + 'receiveDefaultProfileIconsAndNames', 'receiveNewProfileDefaults', - 'receiveProfileNames', + 'receiveExistingProfileNames', 'receiveHasProfileShortcuts', 'setProfileInfo', 'setProfileName', 'showManageDialog', 'showDeleteDialog', + 'showDisconnectManagedProfileDialog', 'showCreateDialog', ].forEach(function(name) { ManageProfileOverlay[name] = function() { @@ -474,12 +622,13 @@ cr.define('options', function() { */ didShowPage: function() { chrome.send('requestCreateProfileUpdate'); - chrome.send('requestDefaultProfileIcons'); + chrome.send('requestDefaultProfileIcons', ['create']); chrome.send('requestNewProfileDefaults'); $('manage-profile-overlay-create').hidden = false; $('manage-profile-overlay-manage').hidden = true; $('manage-profile-overlay-delete').hidden = true; + $('manage-profile-overlay-disconnect-managed').hidden = true; $('create-profile-instructions').textContent = loadTimeData.getStringF('createProfileInstructions'); this.hideErrorBubble_(); @@ -494,9 +643,15 @@ cr.define('options', function() { $('create-profile-ok').disabled = true; $('create-profile-managed').checked = false; + $('import-existing-managed-user-link').hidden = true; + $('create-profile-managed').onchange = function() { + ManageProfileOverlay.getInstance().updateCreateOrImport_('create'); + }; $('create-profile-managed-signed-in').disabled = true; $('create-profile-managed-signed-in').hidden = true; $('create-profile-managed-not-signed-in').hidden = true; + + this.profileNameIsDefault_ = false; }, /** @override */ @@ -505,8 +660,8 @@ cr.define('options', function() { }, /** @override */ - showErrorBubble_: function(errorText) { - ManageProfileOverlay.getInstance().showErrorBubble_(errorText, + showErrorBubble_: function(errorHtml) { + ManageProfileOverlay.getInstance().showErrorBubble_(errorHtml, 'create', false); }, @@ -532,6 +687,7 @@ cr.define('options', function() { $('create-profile-name').disabled = inProgress; $('create-shortcut').disabled = inProgress; $('create-profile-ok').disabled = inProgress; + $('import-existing-managed-user-link').disabled = inProgress; $('create-profile-throbber').hidden = !inProgress; }, @@ -585,6 +741,7 @@ cr.define('options', function() { this.updateCreateInProgress_(false); OptionsPage.closeOverlay(); if (profileInfo.isManaged) { + options.ManagedUserListData.resetPromise(); profileInfo.custodianEmail = this.signedInEmail_; ManagedUserCreateConfirmOverlay.setProfileInfo(profileInfo); OptionsPage.showPageByName('managedUserCreateConfirm', false); @@ -638,7 +795,8 @@ cr.define('options', function() { */ updateImportExistingManagedUserLink_: function(enable) { var importManagedUserElement = $('import-existing-managed-user-link'); - importManagedUserElement.disabled = !enable; + importManagedUserElement.hidden = false; + importManagedUserElement.disabled = !enable || this.createInProgress_; importManagedUserElement.textContent = enable ? loadTimeData.getString('importExistingManagedUserLink') : loadTimeData.getString('signInToImportManagedUsers'); diff --git a/chromium/chrome/browser/resources/options/managed_user_create_confirm.js b/chromium/chrome/browser/resources/options/managed_user_create_confirm.js index de91bf9be9d..84bce024659 100644 --- a/chromium/chrome/browser/resources/options/managed_user_create_confirm.js +++ b/chromium/chrome/browser/resources/options/managed_user_create_confirm.js @@ -64,23 +64,9 @@ cr.define('options', function() { * @private */ setProfileInfo_: function(info) { - function HTMLEscape(original) { - return original.replace(/&/g, '&') - .replace(/</g, '<') - .replace(/>/g, '>') - .replace(/"/g, '"') - .replace(/'/g, '''); - } - - var MAX_LENGTH = 50; - function elide(original) { - if (original.length <= MAX_LENGTH) - return original; - return original.substring(0, MAX_LENGTH - 3) + '...'; - } - this.profileInfo_ = info; - var elidedName = elide(info.name); + var MAX_LENGTH = 50; + var elidedName = elide(info.name, MAX_LENGTH); $('managed-user-created-title').textContent = loadTimeData.getStringF('managedUserCreatedTitle', elidedName); $('managed-user-created-switch').textContent = @@ -92,7 +78,8 @@ cr.define('options', function() { $('managed-user-created-text').innerHTML = loadTimeData.getStringF('managedUserCreatedText', HTMLEscape(elidedName), - HTMLEscape(elide(info.custodianEmail))); + HTMLEscape(elide(info.custodianEmail, + MAX_LENGTH))); }, /** @override */ diff --git a/chromium/chrome/browser/resources/options/managed_user_import.css b/chromium/chrome/browser/resources/options/managed_user_import.css index 9dae8f1db4e..b0f94f571f8 100644 --- a/chromium/chrome/browser/resources/options/managed_user_import.css +++ b/chromium/chrome/browser/resources/options/managed_user_import.css @@ -2,15 +2,12 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ -#create-new-user-link { - position: absolute; -} - #managed-user-import { width: 612px; } -#managed-user-import-text { +#managed-user-import-text, +#managed-user-select-avatar-text { padding-bottom: 10px; padding-left: 17px; white-space: pre-wrap; diff --git a/chromium/chrome/browser/resources/options/managed_user_import.html b/chromium/chrome/browser/resources/options/managed_user_import.html index db2674dc953..377002c5eba 100644 --- a/chromium/chrome/browser/resources/options/managed_user_import.html +++ b/chromium/chrome/browser/resources/options/managed_user_import.html @@ -1,24 +1,38 @@ <div id="managed-user-import" class="page" hidden> <div class="close-button"></div> <!-- Overlay to import an existing managed user during user creation --> - <h1 id="managed-user-import-title"></h1> - <div id="managed-user-import-text"> + <h1 id="managed-user-import-title" i18n-content="managedUserImportTitle" + class="managed-user-import"> + </h1> + <h1 id="managed-user-select-avatar-title" + i18n-content="managedUserSelectAvatarTitle" + class="managed-user-select-avatar" hidden> + </h1> + <div id="managed-user-import-text" i18n-content="managedUserImportText" + class="managed-user-import"> + </div> + <div id="managed-user-select-avatar-text" + i18n-content="managedUserSelectAvatarText" + class="managed-user-select-avatar" hidden> </div> <div id="managed-user-import-content-area" class="content-area"> - <list id="managed-user-list" class="settings-list"></list> - <grid id="select-avatar-grid" hidden></grid> + <list id="managed-user-list" class="settings-list managed-user-import"> + </list> + <grid id="select-avatar-grid" class="managed-user-select-avatar" hidden></grid> </div> <div id="managed-user-import-error-bubble" hidden></div> <div id="managed-user-import-action-area" class="action-area"> - <button id="create-new-user-link" class="link-button" - i18n-content="createNewUserLink"> - </button> <div class="button-strip"> <div id="managed-user-import-throbber" class="throbber"></div> <button id="managed-user-import-cancel" i18n-content="cancel"> </button> - <button id="managed-user-import-ok" class="default-button"> + <button id="managed-user-import-ok" i18n-content="managedUserImportOk" + class="default-button managed-user-import"> + </button> + <button id="managed-user-select-avatar-ok" + i18n-content="managedUserSelectAvatarOk" + class="default-button managed-user-select-avatar" hidden> </button> </div> </div> -</div>
\ No newline at end of file +</div> diff --git a/chromium/chrome/browser/resources/options/managed_user_import.js b/chromium/chrome/browser/resources/options/managed_user_import.js index 70a54dd2cab..f37e2209598 100644 --- a/chromium/chrome/browser/resources/options/managed_user_import.js +++ b/chromium/chrome/browser/resources/options/managed_user_import.js @@ -55,40 +55,65 @@ cr.define('options', function() { var self = this; $('managed-user-import-cancel').onclick = function(event) { - OptionsPage.closeOverlay(); - self.updateImportInProgress_(false); + if (self.inProgress_) { + self.updateImportInProgress_(false); - // 'cancelCreateProfile' is handled by CreateProfileHandler. - chrome.send('cancelCreateProfile'); + // 'cancelCreateProfile' is handled by CreateProfileHandler. + chrome.send('cancelCreateProfile'); + } + OptionsPage.closeOverlay(); }; $('managed-user-import-ok').onclick = this.showAvatarGridOrSubmit_.bind(this); - - $('create-new-user-link').onclick = function(event) { - OptionsPage.closeOverlay(); - OptionsPage.navigateToPage('createProfile'); - }; + $('managed-user-select-avatar-ok').onclick = + this.showAvatarGridOrSubmit_.bind(this); }, /** * @override */ didShowPage: function() { - chrome.send('requestManagedUserImportUpdate'); + // When the import link is clicked to open this overlay, it is hidden in + // order to trigger a cursor update. We can show the import link again + // now. TODO(akuegel): Remove this temporary fix when crbug/246304 is + // resolved. + $('import-existing-managed-user-link').hidden = false; + + options.ManagedUserListData.requestExistingManagedUsers().then( + this.receiveExistingManagedUsers_, this.onSigninError_.bind(this)); + options.ManagedUserListData.addObserver(this); this.updateImportInProgress_(false); $('managed-user-import-error-bubble').hidden = true; $('managed-user-import-ok').disabled = true; - $('select-avatar-grid').hidden = true; - $('managed-user-list').hidden = false; - - $('managed-user-import-ok').textContent = - loadTimeData.getString('managedUserImportOk'); - $('managed-user-import-text').textContent = - loadTimeData.getString('managedUserImportText'); - $('managed-user-import-title').textContent = - loadTimeData.getString('managedUserImportTitle'); + this.showAppropriateElements_(/* isSelectAvatarMode */ false); + }, + + /** + * @override + */ + didClosePage: function() { + options.ManagedUserListData.removeObserver(this); + }, + + /** + * Shows either the managed user import dom elements or the select avatar + * dom elements. + * @param {boolean} isSelectAvatarMode True if the overlay should show the + * select avatar grid, and false if the overlay should show the managed + * user list. + * @private + */ + showAppropriateElements_: function(isSelectAvatarMode) { + var avatarElements = + this.pageDiv.querySelectorAll('.managed-user-select-avatar'); + for (var i = 0; i < avatarElements.length; i++) + avatarElements[i].hidden = !isSelectAvatarMode; + var importElements = + this.pageDiv.querySelectorAll('.managed-user-import'); + for (var i = 0; i < importElements.length; i++) + importElements[i].hidden = isSelectAvatarMode; }, /** @@ -128,18 +153,10 @@ cr.define('options', function() { * @private */ showAvatarGridHelper_: function() { - $('managed-user-list').hidden = true; - $('select-avatar-grid').hidden = false; + this.showAppropriateElements_(/* isSelectAvatarMode */ true); $('select-avatar-grid').redraw(); $('select-avatar-grid').selectedItem = loadTimeData.getValue('avatarIcons')[0]; - - $('managed-user-import-ok').textContent = - loadTimeData.getString('managedUserSelectAvatarOk'); - $('managed-user-import-text').textContent = - loadTimeData.getString('managedUserSelectAvatarText'); - $('managed-user-import-title').textContent = - loadTimeData.getString('managedUserSelectAvatarTitle'); }, /** @@ -149,16 +166,16 @@ cr.define('options', function() { * @private */ updateImportInProgress_: function(inProgress) { + this.inProgress_ = inProgress; $('managed-user-import-ok').disabled = inProgress; + $('managed-user-select-avatar-ok').disabled = inProgress; $('managed-user-list').disabled = inProgress; $('select-avatar-grid').disabled = inProgress; - $('create-new-user-link').disabled = inProgress; $('managed-user-import-throbber').hidden = !inProgress; }, /** - * Adds all the existing |managedUsers| to the list. If |managedUsers| - * is undefined, then the list is cleared. + * Sets the data model of the managed user list to |managedUsers|. * @param {Array.<Object>} managedUsers An array of managed user objects. * Each object is of the form: * managedUser = { @@ -171,12 +188,9 @@ cr.define('options', function() { * @private */ receiveExistingManagedUsers_: function(managedUsers) { - if (!managedUsers) { - $('managed-user-list').dataModel = null; - return; - } - managedUsers.sort(function(a, b) { + if (a.onCurrentDevice != b.onCurrentDevice) + return a.onCurrentDevice ? 1 : -1; return a.name.localeCompare(b.name); }); @@ -184,14 +198,15 @@ cr.define('options', function() { if (managedUsers.length == 0) { this.onError_(loadTimeData.getString('noExistingManagedUsers')); $('managed-user-import-ok').disabled = true; + } else { + // Hide the error bubble. + $('managed-user-import-error-bubble').hidden = true; } }, - /** - * @private - */ - hideErrorBubble_: function() { - $('managed-user-import-error-bubble').hidden = true; + onSigninError_: function() { + $('managed-user-list').dataModel = null; + this.onError_(loadTimeData.getString('managedUserImportSigninError')); }, /** @@ -209,21 +224,21 @@ cr.define('options', function() { }, /** - * Closes the overlay if importing the managed user was successful. + * Closes the overlay if importing the managed user was successful. Also + * reset the cached list of managed users in order to get an updated list + * when the overlay is reopened. * @private */ onSuccess_: function() { this.updateImportInProgress_(false); - OptionsPage.closeOverlay(); + options.ManagedUserListData.resetPromise(); + OptionsPage.closeAllOverlays(); }, }; // Forward public APIs to private implementations. [ - 'hideErrorBubble', - 'onError', 'onSuccess', - 'receiveExistingManagedUsers', ].forEach(function(name) { ManagedUserImportOverlay[name] = function() { var instance = ManagedUserImportOverlay.getInstance(); diff --git a/chromium/chrome/browser/resources/options/managed_user_list.js b/chromium/chrome/browser/resources/options/managed_user_list.js index 4af84c64c14..2d4ec61d2e9 100644 --- a/chromium/chrome/browser/resources/options/managed_user_list.js +++ b/chromium/chrome/browser/resources/options/managed_user_list.js @@ -62,8 +62,7 @@ cr.define('options.managedUserOptions', function() { // Add the avatar. var iconElement = this.ownerDocument.createElement('img'); iconElement.className = 'profile-img'; - iconElement.style.content = - imageset(managedUser.iconURL + '@scalefactorx'); + iconElement.style.content = getProfileAvatarIcon(managedUser.iconURL); this.appendChild(iconElement); // Add the profile name. diff --git a/chromium/chrome/browser/resources/options/managed_user_list_data.js b/chromium/chrome/browser/resources/options/managed_user_list_data.js new file mode 100644 index 00000000000..91619ede6a8 --- /dev/null +++ b/chromium/chrome/browser/resources/options/managed_user_list_data.js @@ -0,0 +1,152 @@ +// Copyright 2014 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. + +cr.define('options', function() { + /** + * ManagedUserListData class. + * Handles requests for retrieving a list of existing managed users which are + * supervised by the current profile. For each request a promise is returned, + * which is cached in order to reuse the retrieved managed users for future + * requests. The first request will be handled asynchronously. + * @constructor + * @class + */ + function ManagedUserListData() { + this.observers_ = []; + }; + + cr.addSingletonGetter(ManagedUserListData); + + /** + * Receives a list of managed users and resolves the promise. + * @param {Array.<Object>} managedUsers An array of managed user objects. + * Each object is of the form: + * managedUser = { + * id: "Managed User ID", + * name: "Managed User Name", + * iconURL: "chrome://path/to/icon/image", + * onCurrentDevice: true or false, + * needAvatar: true or false + * } + * @private + */ + ManagedUserListData.prototype.receiveExistingManagedUsers_ = function( + managedUsers) { + if (!this.promise_) { + this.onDataChanged_(managedUsers); + return; + } + this.resolve_(managedUsers); + }; + + /** + * Called when there is a signin error when retrieving the list of managed + * users. Rejects the promise and resets the cached promise to null. + * @private + */ + ManagedUserListData.prototype.onSigninError_ = function() { + assert(this.promise_); + this.reject_(); + this.resetPromise_(); + }; + + /** + * Handles the request for the list of existing managed users by returning a + * promise for the requested data. If there is no cached promise yet, a new + * one will be created. + * @return {Promise} The promise containing the list of managed users. + * @private + */ + ManagedUserListData.prototype.requestExistingManagedUsers_ = function() { + if (this.promise_) + return this.promise_; + this.promise_ = this.createPromise_(); + chrome.send('requestManagedUserImportUpdate'); + return this.promise_; + }; + + /** + * Creates the promise containing the list of managed users. The promise is + * resolved in receiveExistingManagedUsers_() or rejected in + * onSigninError_(). The promise is cached, so that for future requests it can + * be resolved immediately. + * @return {Promise} The promise containing the list of managed users. + * @private + */ + ManagedUserListData.prototype.createPromise_ = function() { + var self = this; + return new Promise(function(resolve, reject) { + self.resolve_ = resolve; + self.reject_ = reject; + }); + }; + + /** + * Resets the promise to null in order to avoid stale data. For the next + * request, a new promise will be created. + * @private + */ + ManagedUserListData.prototype.resetPromise_ = function() { + this.promise_ = null; + }; + + /** + * Initializes |promise| with the new data and also passes the new data to + * observers. + * @param {Array.<Object>} managedUsers An array of managed user objects. + * For the format of the objects, see receiveExistingManagedUsers_(). + * @private + */ + ManagedUserListData.prototype.onDataChanged_ = function(managedUsers) { + this.promise_ = this.createPromise_(); + this.resolve_(managedUsers); + for (var i = 0; i < this.observers_.length; ++i) + this.observers_[i].receiveExistingManagedUsers_(managedUsers); + }; + + /** + * Adds an observer to the list of observers. + * @param {Object} observer The observer to be added. + * @private + */ + ManagedUserListData.prototype.addObserver_ = function(observer) { + for (var i = 0; i < this.observers_.length; ++i) + assert(this.observers_[i] != observer); + this.observers_.push(observer); + }; + + /** + * Removes an observer from the list of observers. + * @param {Object} observer The observer to be removed. + * @private + */ + ManagedUserListData.prototype.removeObserver_ = function(observer) { + for (var i = 0; i < this.observers_.length; ++i) { + if (this.observers_[i] == observer) { + this.observers_.splice(i, 1); + return; + } + } + }; + + // Forward public APIs to private implementations. + [ + 'addObserver', + 'onSigninError', + 'receiveExistingManagedUsers', + 'removeObserver', + 'requestExistingManagedUsers', + 'resetPromise', + ].forEach(function(name) { + ManagedUserListData[name] = function() { + var instance = ManagedUserListData.getInstance(); + return instance[name + '_'].apply(instance, arguments); + }; + }); + + // Export + return { + ManagedUserListData: ManagedUserListData, + }; +}); diff --git a/chromium/chrome/browser/resources/options/media_galleries_list.js b/chromium/chrome/browser/resources/options/media_galleries_list.js deleted file mode 100644 index 8d892bcdd00..00000000000 --- a/chromium/chrome/browser/resources/options/media_galleries_list.js +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (c) 2012 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. - -cr.define('options', function() { - /** @const */ var DeletableItem = options.DeletableItem; - /** @const */ var DeletableItemList = options.DeletableItemList; - - /** - * @constructor - * @extends {DeletableItem} - */ - function MediaGalleriesListItem(galleryInfo) { - var el = cr.doc.createElement('div'); - el.galleryInfo_ = galleryInfo; - el.__proto__ = MediaGalleriesListItem.prototype; - el.decorate(); - return el; - } - - MediaGalleriesListItem.prototype = { - __proto__: DeletableItem.prototype, - - decorate: function() { - DeletableItem.prototype.decorate.call(this); - - var span = this.ownerDocument.createElement('span'); - span.textContent = this.galleryInfo_.displayName; - this.contentElement.appendChild(span); - this.contentElement.title = this.galleryInfo_.path; - }, - }; - - var MediaGalleriesList = cr.ui.define('list'); - - MediaGalleriesList.prototype = { - __proto__: DeletableItemList.prototype, - - /** @override */ - decorate: function() { - DeletableItemList.prototype.decorate.call(this); - this.autoExpands_ = true; - }, - - /** @override */ - createItem: function(galleryInfo) { - return new MediaGalleriesListItem(galleryInfo); - }, - - /** @override */ - deleteItemAtIndex: function(index) { - chrome.send('forgetGallery', [this.dataModel.item(index).id]); - }, - }; - - return { - MediaGalleriesList: MediaGalleriesList - }; -}); diff --git a/chromium/chrome/browser/resources/options/media_galleries_manager_overlay.html b/chromium/chrome/browser/resources/options/media_galleries_manager_overlay.html deleted file mode 100644 index 05c4db1c6af..00000000000 --- a/chromium/chrome/browser/resources/options/media_galleries_manager_overlay.html +++ /dev/null @@ -1,19 +0,0 @@ -<div id="manage-media-galleries-overlay" class="page" hidden> - <div class="close-button"></div> - <h1 i18n-content="manageMediaGalleries"></h1> - <div class="content-area"> - <list id="available-galleries-list"></list> - </div> - <div class="action-area"> - <div class="stretch"> - <button id="new-media-gallery" i18n-content="addNewGalleryButton" - disabled></button> - </div> - </stretch> - <div class="button-strip"> - <button id="manage-media-confirm" class="default-button" - i18n-content="done"> - </button> - </div> - </div> -</div> diff --git a/chromium/chrome/browser/resources/options/media_galleries_manager_overlay.js b/chromium/chrome/browser/resources/options/media_galleries_manager_overlay.js deleted file mode 100644 index ac8e5271580..00000000000 --- a/chromium/chrome/browser/resources/options/media_galleries_manager_overlay.js +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright (c) 2012 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. - -cr.define('options', function() { - /** @const */ var ArrayDataModel = cr.ui.ArrayDataModel; - /** @const */ var OptionsPage = options.OptionsPage; - - /** - * This class is an overlay which allows the user to add or remove media - * galleries, and displays known media galleries. - * @constructor - * @extends {OptionsPage} - */ - function MediaGalleriesManager() { - OptionsPage.call(this, 'manageGalleries', - loadTimeData.getString('manageMediaGalleriesTabTitle'), - 'manage-media-galleries-overlay'); - } - - cr.addSingletonGetter(MediaGalleriesManager); - - MediaGalleriesManager.prototype = { - __proto__: OptionsPage.prototype, - - /** - * Decorate the overlay and set up event handlers. - */ - initializePage: function() { - OptionsPage.prototype.initializePage.call(this); - - this.availableGalleriesList_ = $('available-galleries-list'); - options.MediaGalleriesList.decorate(this.availableGalleriesList_); - - $('new-media-gallery').addEventListener('click', function() { - chrome.send('addNewGallery'); - }); - - $('manage-media-confirm').addEventListener( - 'click', OptionsPage.closeOverlay.bind(OptionsPage)); - - this.addEventListener('visibleChange', this.handleVisibleChange_); - }, - - /** @private */ - handleVisibleChange_: function() { - if (!this.visible) - return; - - chrome.send('initializeMediaGalleries'); - - if (this.availableGalleriesList_) - this.availableGalleriesList_.redraw(); - }, - - /** - * @param {Array} galleries List of structs describibing galleries. - * @private - */ - setAvailableMediaGalleries_: function(galleries) { - $('available-galleries-list').dataModel = new ArrayDataModel(galleries); - $('new-media-gallery').disabled = false; - $('media-galleries-section').hidden = false; - }, - }, - - // Forward public APIs to private implementations. - [ - 'setAvailableMediaGalleries', - ].forEach(function(name) { - MediaGalleriesManager[name] = function() { - var instance = MediaGalleriesManager.getInstance(); - return instance[name + '_'].apply(instance, arguments); - }; - }); - - // Export - return { - MediaGalleriesManager: MediaGalleriesManager - }; -}); diff --git a/chromium/chrome/browser/resources/options/options.html b/chromium/chrome/browser/resources/options/options.html index 0d1f0cbb896..f6fcfd48aa3 100644 --- a/chromium/chrome/browser/resources/options/options.html +++ b/chromium/chrome/browser/resources/options/options.html @@ -17,7 +17,7 @@ <link rel="stylesheet" href="autofill_edit_overlay.css"> <link rel="stylesheet" href="autofill_options.css"> <link rel="stylesheet" href="browser_options.css"> -<if expr="pp_ifdef('chromeos')"> +<if expr="chromeos"> <link rel="stylesheet" href="chromeos/browser_options.css"> </if> <link rel="stylesheet" href="clear_browser_data_overlay.css"> @@ -28,6 +28,8 @@ <link rel="stylesheet" href="font_settings.css"> <link rel="stylesheet" href="handler_options.css"> <link rel="stylesheet" href="home_page_overlay.css"> +<link rel="stylesheet" href="hotword_confirm_overlay.css"> +<link rel="stylesheet" href="hotword_search_setting_indicator.css"> <link rel="stylesheet" href="import_data_overlay.css"> <if expr="not is_macosx"> <link rel="stylesheet" href="language_dictionary_overlay.css"> @@ -39,15 +41,16 @@ <link rel="stylesheet" href="managed_user_learn_more.css"> <link rel="stylesheet" href="password_manager.css"> <link rel="stylesheet" href="password_manager_list.css"> -<link rel="stylesheet" href="reset_profile_settings_banner.css"> <link rel="stylesheet" href="reset_profile_settings_overlay.css"> <link rel="stylesheet" href="search_engine_manager.css"> <link rel="stylesheet" href="search_page.css"> +<link rel="stylesheet" href="settings_banner.css"> <link rel="stylesheet" href="spelling_confirm_overlay.css"> <link rel="stylesheet" href="subpages_tab_controls.css"> <link rel="stylesheet" href="startup_overlay.css"> <link rel="stylesheet" href="../sync_setup_overlay.css"> -<if expr="pp_ifdef('chromeos')"> +<if expr="chromeos"> +<link rel="stylesheet" href="chromeos/third_party_ime_confirm_overlay.css"> <link rel="stylesheet" href="chromeos/accounts_options_page.css"> <link rel="stylesheet" href="chromeos/bluetooth.css"> <link rel="stylesheet" href="chromeos/change_picture_options.css"> @@ -58,11 +61,11 @@ <link rel="stylesheet" href="chromeos/pointer_overlay.css"> <link rel="stylesheet" href="factory_reset_overlay.css"> </if> -<if expr="pp_ifdef('use_nss')"> +<if expr="use_nss"> <link rel="stylesheet" href="certificate_manager.css"> <link rel="stylesheet" href="certificate_tree.css"> </if> -<if expr="pp_ifdef('enable_settings_app')"> +<if expr="enable_settings_app"> <link rel="stylesheet" href="options_settings_app.css"> </if> <script src="chrome://resources/css/tree.css.js"></script> @@ -91,6 +94,7 @@ <script src="chrome://resources/js/cr/ui/repeating_button.js"></script> <script src="chrome://resources/js/cr/ui/tree.js"></script> <script src="chrome://resources/js/load_time_data.js"></script> +<script src="chrome://resources/js/parse_html_subset.js"></script> <script src="chrome://resources/js/util.js"></script> <script src="chrome://settings-frame/strings.js"></script> @@ -103,22 +107,21 @@ <include src="autofill_options.html"> <include src="clear_browser_data_overlay.html"> <include src="content_settings.html"> - <include src="content_settings2.html"> <include src="do_not_track_confirm_overlay.html"> <include src="font_settings.html"> <include src="home_page_overlay.html"> + <include src="hotword_confirm_overlay.html"> <include src="import_data_overlay.html"> <include src="language_options.html"> <include src="manage_profile_overlay.html"> <include src="managed_user_create_confirm.html"> - <include src="managed_user_import.html"> <include src="password_manager.html"> <include src="reset_profile_settings_overlay.html"> <include src="search_engine_manager.html"> <include src="spelling_confirm_overlay.html"> <include src="startup_overlay.html"> <include src="../sync_setup_overlay.html"> -<if expr="pp_ifdef('chromeos')"> +<if expr="chromeos"> <include src="chromeos/accounts_options.html"> <include src="chromeos/bluetooth_add_device_overlay.html"> <include src="chromeos/bluetooth_pair_device_overlay.html"> @@ -128,7 +131,7 @@ <include src="chromeos/pointer_overlay.html"> <include src="factory_reset_overlay.html"> </if> -<if expr="pp_ifdef('use_nss')"> +<if expr="use_nss"> <include src="certificate_manager.html"> </if> </div> @@ -140,15 +143,16 @@ <include src="cookies_view.html"> <include src="handler_options.html"> <include src="language_add_language_overlay.html"> + <include src="managed_user_import.html"> <include src="managed_user_learn_more.html"> <if expr="not is_macosx"> <include src="language_dictionary_overlay.html"> </if> - <include src="media_galleries_manager_overlay.html"> -<if expr="pp_ifdef('chromeos')"> +<if expr="chromeos"> <include src="chromeos/display_overscan.html"> <include src="chromeos/internet_detail.html"> <include src="chromeos/preferred_networks.html"> + <include src="chromeos/third_party_ime_confirm_overlay.html"> </if> <if expr="not is_win and not is_macosx"> <include src="certificate_restore_overlay.html"> @@ -164,13 +168,19 @@ <div class="controlled-setting-bubble-extension-name"></div> </div> <div class="controlled-setting-bubble-content-row"> - <div class="controlled-setting-bubble-extension-manage-link link-button" - i18n-content="controlledSettingManageExtensions"></div> + <button class="controlled-setting-bubble-extension-manage-link link-button" + i18n-content="controlledSettingManageExtension"></button> <button class='controlled-setting-bubble-extension-disable-button' i18n-content="controlledSettingDisableExtension"></button> </div> </div> +<div id="extension-controlled-warning-template" + class="extension-controlled-warning-box" hidden> + <div class="extension-controlled-warning"></div> + <button i18n-content="extensionDisable"></button> +</div> + <div id="main-content"> <div id="mainview"> <div id="mainview-content"> diff --git a/chromium/chrome/browser/resources/options/options.js b/chromium/chrome/browser/resources/options/options.js index 1aeb352c218..dea67ba23ff 100644 --- a/chromium/chrome/browser/resources/options/options.js +++ b/chromium/chrome/browser/resources/options/options.js @@ -7,6 +7,7 @@ var AlertOverlay = options.AlertOverlay; var AutofillEditAddressOverlay = options.AutofillEditAddressOverlay; var AutofillEditCreditCardOverlay = options.AutofillEditCreditCardOverlay; var AutofillOptions = options.AutofillOptions; +var AutomaticSettingsResetBanner = options.AutomaticSettingsResetBanner; var BrowserOptions = options.BrowserOptions; var ClearBrowserDataOverlay = options.ClearBrowserDataOverlay; var ConfirmDialog = options.ConfirmDialog; @@ -17,7 +18,7 @@ var CookiesView = options.CookiesView; var CreateProfileOverlay = options.CreateProfileOverlay; var EditDictionaryOverlay = cr.IsMac ? null : options.EditDictionaryOverlay; var FactoryResetOverlay = options.FactoryResetOverlay; -<if expr="pp_ifdef('enable_google_now')"> +<if expr="enable_google_now"> var GeolocationOptions = options.GeolocationOptions; </if> var FontSettings = options.FontSettings; @@ -29,7 +30,6 @@ var ManageProfileOverlay = options.ManageProfileOverlay; var ManagedUserCreateConfirmOverlay = options.ManagedUserCreateConfirmOverlay; var ManagedUserImportOverlay = options.ManagedUserImportOverlay; var ManagedUserLearnMoreOverlay = options.ManagedUserLearnMoreOverlay; -var MediaGalleriesManager = options.MediaGalleriesManager; var OptionsFocusManager = options.OptionsFocusManager; var OptionsPage = options.OptionsPage; var PasswordManager = options.PasswordManager; @@ -41,6 +41,7 @@ var SearchEngineManager = options.SearchEngineManager; var SearchPage = options.SearchPage; var StartupOverlay = options.StartupOverlay; var SyncSetupOverlay = options.SyncSetupOverlay; +var ThirdPartyImeConfirmOverlay = options.ThirdPartyImeConfirmOverlay; /** * DOMContentLoaded handler, sets up the page. @@ -104,6 +105,16 @@ function load() { $('spelling-enabled-control').metric), BrowserOptions.getInstance()); } + OptionsPage.registerOverlay( + new ConfirmDialog( + 'hotwordConfirm', + loadTimeData.getString('hotwordConfirmOverlayTabTitle'), + 'hotword-confirm-overlay', + $('hotword-confirm-ok'), + $('hotword-confirm-cancel'), + $('hotword-search-enable').pref, + $('hotword-search-enable').metric), + BrowserOptions.getInstance()); OptionsPage.registerOverlay(ContentSettings.getInstance(), BrowserOptions.getInstance(), [$('privacyContentSettingsButton')]); @@ -142,16 +153,11 @@ function load() { if (!cr.isChromeOS) { OptionsPage.registerOverlay(ManagedUserCreateConfirmOverlay.getInstance(), BrowserOptions.getInstance()); - if (loadTimeData.getBoolean('allowCreateExistingManagedUsers')) { - OptionsPage.registerOverlay(ManagedUserImportOverlay.getInstance(), - BrowserOptions.getInstance()); - } + OptionsPage.registerOverlay(ManagedUserImportOverlay.getInstance(), + CreateProfileOverlay.getInstance()); OptionsPage.registerOverlay(ManagedUserLearnMoreOverlay.getInstance(), CreateProfileOverlay.getInstance()); } - OptionsPage.registerOverlay(MediaGalleriesManager.getInstance(), - ContentSettings.getInstance(), - [$('manage-galleries-button')]); OptionsPage.registerOverlay(PasswordManager.getInstance(), BrowserOptions.getInstance(), [$('manage-passwords')]); @@ -196,6 +202,8 @@ function load() { [$('pointer-settings-button')]); OptionsPage.registerOverlay(PreferredNetworks.getInstance(), BrowserOptions.getInstance()); + OptionsPage.registerOverlay(ThirdPartyImeConfirmOverlay.getInstance(), + LanguageOptions.getInstance()); } if (!cr.isWindows && !cr.isMac) { @@ -216,17 +224,14 @@ function load() { OptionsFocusManager.getInstance().initialize(); Preferences.getInstance().initialize(); ResetProfileSettingsBanner.getInstance().initialize(); + AutomaticSettingsResetBanner.getInstance().initialize(); OptionsPage.initialize(); - var path = document.location.pathname; - - if (path.length > 1) { - // Skip starting slash and remove trailing slash (if any). - var pageName = path.slice(1).replace(/\/$/, ''); - OptionsPage.showPageByName(pageName, true, {replaceState: true}); - } else { - OptionsPage.showDefaultPage(); - } + var pageName = OptionsPage.getPageNameFromPath(); + // Still update history so that chrome://settings/nonexistant redirects + // appropriately to chrome://settings/. If the URL matches, updateHistory_ + // will avoid the extra replaceState. + OptionsPage.showPageByName(pageName, true, {replaceState: true}); var subpagesNavTabs = document.querySelectorAll('.subpages-nav-tabs'); for (var i = 0; i < subpagesNavTabs.length; i++) { @@ -237,6 +242,7 @@ function load() { window.setTimeout(function() { document.documentElement.classList.remove('loading'); + chrome.send('onFinishedLoadingOptions'); }); } @@ -255,5 +261,6 @@ window.onbeforeunload = function() { * @param {Event} e The |popstate| event. */ window.onpopstate = function(e) { - options.OptionsPage.setState(e.state); + var pageName = options.OptionsPage.getPageNameFromPath(); + options.OptionsPage.setState(pageName, e.state); }; diff --git a/chromium/chrome/browser/resources/options/options_bundle.js b/chromium/chrome/browser/resources/options/options_bundle.js index 8f450648e5a..24c1c6c31a7 100644 --- a/chromium/chrome/browser/resources/options/options_bundle.js +++ b/chromium/chrome/browser/resources/options/options_bundle.js @@ -9,11 +9,13 @@ <include src="controlled_setting.js"></include> <include src="deletable_item_list.js"></include> <include src="editable_text_field.js"></include> +<include src="hotword_search_setting_indicator.js"></include> <include src="inline_editable_list.js"></include> <include src="options_page.js"></include> <include src="pref_ui.js"></include> <include src="settings_dialog.js"></include> -<if expr="pp_ifdef('chromeos')"> +<include src="settings_banner.js"></include> +<if expr="chromeos"> <include src="../chromeos/user_images_grid.js"></include> // DO NOT BREAK THE FOLLOWING INCLUDE LINE INTO SEPARATE LINES! // Even though the include line spans more than 80 characters, @@ -36,6 +38,7 @@ <include src="chromeos/display_overscan.js"></include> <include src="chromeos/keyboard_overlay.js"></include> <include src="chromeos/pointer_overlay.js"></include> +<include src="chromeos/third_party_ime_confirm_overlay.js"></include> var AccountsOptions = options.AccountsOptions; var ChangePictureOptions = options.ChangePictureOptions; var DetailsInternetPage = options.internet.DetailsInternetPage; @@ -47,7 +50,7 @@ var KeyboardOverlay = options.KeyboardOverlay; var PointerOverlay = options.PointerOverlay; var UIAccountTweaks = uiAccountTweaks.UIAccountTweaks; </if> -<if expr="pp_ifdef('use_nss')"> +<if expr="use_nss"> <include src="certificate_tree.js"></include> <include src="certificate_manager.js"></include> <include src="certificate_restore_overlay.js"></include> @@ -65,20 +68,20 @@ var CertificateImportErrorOverlay = options.CertificateImportErrorOverlay; <include src="autofill_edit_creditcard_overlay.js"></include> <include src="autofill_options_list.js"></include> <include src="autofill_options.js"></include> +<include src="automatic_settings_reset_banner.js"></include> <include src="browser_options.js"></include> <include src="browser_options_profile_list.js"></include> <include src="browser_options_startup_page_list.js"></include> <include src="clear_browser_data_overlay.js"></include> <include src="confirm_dialog.js"></include> <include src="content_settings.js"></include> -<include src="content_settings2.js"></include> <include src="content_settings_exceptions_area.js"></include> <include src="content_settings_ui.js"></include> <include src="cookies_list.js"></include> <include src="cookies_view.js"></include> <include src="factory_reset_overlay.js"></include> <include src="font_settings.js"></include> -<if expr="pp_ifdef('enable_google_now')"> +<if expr="enable_google_now"> <include src="geolocation_options.js"></include> </if> <include src="handler_options.js"></include> @@ -97,8 +100,7 @@ var CertificateImportErrorOverlay = options.CertificateImportErrorOverlay; <include src="managed_user_import.js"></include> <include src="managed_user_learn_more.js"</include> <include src="managed_user_list.js"></include> -<include src="media_galleries_list.js"></include> -<include src="media_galleries_manager_overlay.js"></include> +<include src="managed_user_list_data.js"></include> <include src="options_focus_manager.js"></include> <include src="password_manager.js"></include> <include src="password_manager_list.js"></include> @@ -112,6 +114,6 @@ var CertificateImportErrorOverlay = options.CertificateImportErrorOverlay; <include src="../sync_setup_overlay.js"></include> <include src="../uber/uber_utils.js"></include> <include src="options.js"></include> -<if expr="pp_ifdef('enable_settings_app')"> +<if expr="enable_settings_app"> <include src="options_settings_app.js"></include> </if> diff --git a/chromium/chrome/browser/resources/options/options_page.css b/chromium/chrome/browser/resources/options/options_page.css index b4223ec7e32..f8efff87805 100644 --- a/chromium/chrome/browser/resources/options/options_page.css +++ b/chromium/chrome/browser/resources/options/options_page.css @@ -213,38 +213,38 @@ list:not([disabled]) > :hover { * these rules can be simplified (since they wont need to override other rules). */ -list:not([hasElementFocus]) > [selected], -list:not([hasElementFocus]) > [lead][selected] { +list:not([has-element-focus]) > [selected], +list:not([has-element-focus]) > [lead][selected] { background-color: #d0d0d0; background-image: none; } -list[hasElementFocus] > [selected], -list[hasElementFocus] > [lead][selected], -list:not([hasElementFocus]) > [selected]:hover, -list:not([hasElementFocus]) > [selected][lead]:hover { +list[has-element-focus] > [selected], +list[has-element-focus] > [lead][selected], +list:not([has-element-focus]) > [selected]:hover, +list:not([has-element-focus]) > [selected][lead]:hover { background-color: rgb(187, 206, 233); background-image: none; } -list[hasElementFocus] > [lead], -list[hasElementFocus] > [lead][selected] { +.settings-list[has-element-focus] > [lead], +.settings-list[has-element-focus] > [lead][selected] { border-bottom: 1px solid rgb(120, 146, 180); border-top: 1px solid rgb(120, 146, 180); } -list[hasElementFocus] > [lead]:nth-child(2), -list[hasElementFocus] > [lead][selected]:nth-child(2) { +.settings-list[has-element-focus] > [lead]:nth-child(2), +.settings-list[has-element-focus] > [lead][selected]:nth-child(2) { border-top: 1px solid transparent; } -list[hasElementFocus] > [lead]:nth-last-child(2), -list[hasElementFocus] > [lead][selected]:nth-last-child(2) { +.settings-list[has-element-focus] > [lead]:nth-last-child(2), +.settings-list[has-element-focus] > [lead][selected]:nth-last-child(2) { border-bottom: 1px solid transparent; } -list[disabled] > [lead][selected], -list[disabled]:focus > [lead][selected] { +.settings-list[disabled] > [lead][selected], +.settings-list[disabled]:focus > [lead][selected] { border: none; } @@ -287,7 +287,8 @@ list .row-delete-button { } list > *:not(:hover):not([selected]):not([lead]) .row-delete-button, -list:not([hasElementFocus]) > *:not(:hover):not([selected]) .row-delete-button, +list:not([has-element-focus]) > *:not(:hover):not([selected]) + .row-delete-button, list[disabled] .row-delete-button, list .row-delete-button[disabled] { opacity: 0; @@ -334,10 +335,9 @@ list > :not([editing]) [displaymode='edit'] { list > [editing] [displaymode='static'] { /* Don't use display:none because we need to keep an element focusable. */ left: 0; - opacity: 0; pointer-events: none; position: absolute; - top: -10em; + visibility: hidden; } list > [editing] input:invalid { @@ -404,7 +404,7 @@ html[enable-background-mode=false] #background-mode-section { /* UI Controls */ /* LIST */ -list[hasElementFocus] { +.settings-list[has-element-focus] { <if expr="not is_macosx"> outline: 1px solid rgba(0, 128, 256, 0.5); outline-offset: -2px; @@ -436,8 +436,8 @@ list.autocomplete-suggestions > div { height: auto; } -list.autocomplete-suggestions:not([hasElementFocus]) > [selected], -list.autocomplete-suggestions:not([hasElementFocus]) > [lead][selected] { +list.autocomplete-suggestions:not([has-element-focus]) > [selected], +list.autocomplete-suggestions:not([has-element-focus]) > [lead][selected] { background-color: rgb(187, 206, 233); } diff --git a/chromium/chrome/browser/resources/options/options_page.js b/chromium/chrome/browser/resources/options/options_page.js index befb7c81398..968bb4794a0 100644 --- a/chromium/chrome/browser/resources/options/options_page.js +++ b/chromium/chrome/browser/resources/options/options_page.js @@ -58,6 +58,11 @@ cr.define('options', function() { OptionsPage.registeredOverlayPages = {}; /** + * True if options page is served from a dialog. + */ + OptionsPage.isDialog = false; + + /** * Gets the default page (to be shown on initial load). */ OptionsPage.getDefaultPage = function() { @@ -115,6 +120,7 @@ cr.define('options', function() { if (!targetPage && this.showOverlay_(pageName, rootPage)) { if (updateHistory) this.updateHistoryState_(!!opt_propertyBag.replaceState); + this.updateTitle_(); return; } else { targetPage = this.getDefaultPage(); @@ -161,9 +167,6 @@ cr.define('options', function() { if (updateHistory) this.updateHistoryState_(!!opt_propertyBag.replaceState); - // Update tab title. - this.setTitle_(targetPage.title); - // Update focus if any other control was focused on the previous page, // or the previous page is not known. if (document.activeElement != document.body && @@ -183,16 +186,10 @@ cr.define('options', function() { page.didShowPage(); } } - }; - /** - * Sets the title of the page. This is accomplished by calling into the - * parent page API. - * @param {string} title The title string. - * @private - */ - OptionsPage.setTitle_ = function(title) { - uber.invokeMethodOnParent('setTitle', {title: title}); + // Update the document title. Do this after didShowPage was called, in case + // a page decides to change its title. + this.updateTitle_(); }; /** @@ -208,42 +205,40 @@ cr.define('options', function() { }; /** - * Pushes the current page onto the history stack, overriding the last page - * if it is the generic chrome://settings/. + * Updates the title to title of the current page. + * @private + */ + OptionsPage.updateTitle_ = function() { + var page = this.getTopmostVisiblePage(); + uber.setTitle(page.title); + }; + + /** + * Pushes the current page onto the history stack, replacing the current entry + * if appropriate. * @param {boolean} replace If true, allow no history events to be created. * @param {object=} opt_params A bag of optional params, including: * {boolean} ignoreHash Whether to include the hash or not. * @private */ OptionsPage.updateHistoryState_ = function(replace, opt_params) { + if (OptionsPage.isDialog) + return; + var page = this.getTopmostVisiblePage(); var path = window.location.pathname + window.location.hash; if (path) path = path.slice(1).replace(/\/(?:#|$)/, ''); // Remove trailing slash. - // Update tab title. - this.setTitle_(page.title); - - // The page is already in history (the user may have clicked the same link - // twice). Do nothing. - if (path == page.name && !OptionsPage.isLoading()) - return; - + // If the page is already in history (the user may have clicked the same + // link twice, or this is the initial load), do nothing. var hash = opt_params && opt_params.ignoreHash ? '' : window.location.hash; + var newPath = (page == this.getDefaultPage() ? '' : page.name) + hash; + if (path == newPath) + return; - // If settings are embedded, tell the outer page to set its "path" to the - // inner frame's path. - var outerPath = (page == this.getDefaultPage() ? '' : page.name) + hash; - uber.invokeMethodOnParent('setPath', {path: outerPath}); - - // If there is no path, the current location is chrome://settings/. - // Override this with the new page. - var historyFunction = path && !replace ? window.history.pushState : - window.history.replaceState; - historyFunction.call(window.history, - {pageName: page.name}, - page.title, - '/' + page.name + hash); + var historyFunction = replace ? uber.replaceState : uber.pushState; + historyFunction.call(uber, {}, newPath); }; /** @@ -273,9 +268,6 @@ cr.define('options', function() { if (overlay.didShowPage) overlay.didShowPage(); } - // Update tab title. - this.setTitle_(overlay.title); - // Change focus to the overlay if any other control was focused by keyboard // before. Otherwise, no one should have focus. if (document.activeElement != document.body) { @@ -286,7 +278,7 @@ cr.define('options', function() { } } - if ($('search-field').value == '') { + if ($('search-field') && $('search-field').value == '') { var section = overlay.associatedSection; if (section) options.BrowserOptions.scrollToSection(section); @@ -342,11 +334,21 @@ cr.define('options', function() { if (overlay.didClosePage) overlay.didClosePage(); this.updateHistoryState_(false, {ignoreHash: true}); + this.updateTitle_(); this.restoreLastFocusedElement_(); }; /** + * Closes all overlays and updates the history after each closed overlay. + */ + OptionsPage.closeAllOverlays = function() { + while (this.isOverlayVisible_()) { + this.closeOverlay(); + } + }; + + /** * Cancels (closes) the overlay, due to the user pressing <Esc>. */ OptionsPage.cancelOverlay = function() { @@ -534,9 +536,9 @@ cr.define('options', function() { } } - // Reverse the button strip for views. See the documentation of + // Reverse the button strip for Windows and CrOS. See the documentation of // reverseButtonStripIfNecessary_() for an explanation of why this is done. - if (cr.isViews) + if (cr.isWindows || cr.isChromeOS) this.reverseButtonStripIfNecessary_(overlay); overlay.tab = undefined; @@ -570,22 +572,33 @@ cr.define('options', function() { }; /** + * Returns the name of the page from the current path. + */ + OptionsPage.getPageNameFromPath = function() { + var path = location.pathname; + if (path.length <= 1) + return this.getDefaultPage().name; + + // Skip starting slash and remove trailing slash (if any). + return path.slice(1).replace(/\/$/, ''); + }; + + /** * Callback for window.onpopstate to handle back/forward navigations. + * @param {string} pageName The current page name. * @param {Object} data State data pushed into history. */ - OptionsPage.setState = function(data) { - if (data && data.pageName) { - var currentOverlay = this.getVisibleOverlay_(); - var lowercaseName = data.pageName.toLowerCase(); - var newPage = this.registeredPages[lowercaseName] || - this.registeredOverlayPages[lowercaseName] || - this.getDefaultPage(); - if (currentOverlay && !currentOverlay.isAncestorOfPage(newPage)) { - currentOverlay.visible = false; - if (currentOverlay.didClosePage) currentOverlay.didClosePage(); - } - this.showPageByName(data.pageName, false); + OptionsPage.setState = function(pageName, data) { + var currentOverlay = this.getVisibleOverlay_(); + var lowercaseName = pageName.toLowerCase(); + var newPage = this.registeredPages[lowercaseName] || + this.registeredOverlayPages[lowercaseName] || + this.getDefaultPage(); + if (currentOverlay && !currentOverlay.isAncestorOfPage(newPage)) { + currentOverlay.visible = false; + if (currentOverlay.didClosePage) currentOverlay.didClosePage(); } + this.showPageByName(pageName, false); }; /** @@ -887,11 +900,16 @@ cr.define('options', function() { // TODO(flackr): Use an event delegate to avoid having to subscribe and // unsubscribe for webkitTransitionEnd events. container.addEventListener('webkitTransitionEnd', function f(e) { - if (e.target != e.currentTarget || e.propertyName != 'opacity') + var propName = e.propertyName; + if (e.target != e.currentTarget || + (propName && propName != 'opacity')) { return; + } container.removeEventListener('webkitTransitionEnd', f); self.fadeCompleted_(); }); + // -webkit-transition is 200ms. Let's wait for 400ms. + ensureTransitionEndEvent(container, 400); } if (visible) { diff --git a/chromium/chrome/browser/resources/options/options_settings_app.js b/chromium/chrome/browser/resources/options/options_settings_app.js index 02ab5569aaa..c556340d8e6 100644 --- a/chromium/chrome/browser/resources/options/options_settings_app.js +++ b/chromium/chrome/browser/resources/options/options_settings_app.js @@ -22,7 +22,6 @@ 'downloads-section', 'handlers-section', 'languages-section', - 'media-galleries-section', 'network-section', 'notifications-section', 'sync-section' diff --git a/chromium/chrome/browser/resources/options/password_manager_list.js b/chromium/chrome/browser/resources/options/password_manager_list.js index 9442dee28a5..2a77ea3281a 100644 --- a/chromium/chrome/browser/resources/options/password_manager_list.js +++ b/chromium/chrome/browser/resources/options/password_manager_list.js @@ -56,6 +56,7 @@ cr.define('options.passwordManager', function() { var usernameLabel = this.ownerDocument.createElement('div'); usernameLabel.className = 'name'; usernameLabel.textContent = this.username; + usernameLabel.title = this.username; this.contentElement.appendChild(usernameLabel); // The stored password. diff --git a/chromium/chrome/browser/resources/options/pref_ui.js b/chromium/chrome/browser/resources/options/pref_ui.js index 0775306d776..b4f28308bf8 100644 --- a/chromium/chrome/browser/resources/options/pref_ui.js +++ b/chromium/chrome/browser/resources/options/pref_ui.js @@ -160,6 +160,11 @@ cr.define('options', function() { decorate: function() { PrefInputElement.prototype.decorate.call(this); this.type = 'checkbox'; + + // Consider a checked dialog checkbox as a 'suggestion' which is committed + // once the user confirms the dialog. + if (this.dialogPref && this.checked) + this.updatePrefFromState_(); }, /** diff --git a/chromium/chrome/browser/resources/options/preferences.js b/chromium/chrome/browser/resources/options/preferences.js index 6f8cc829417..ef1ed18cf90 100644 --- a/chromium/chrome/browser/resources/options/preferences.js +++ b/chromium/chrome/browser/resources/options/preferences.js @@ -214,12 +214,11 @@ cr.define('options', function() { var event = new Event(name); // Decorate pref value as CoreOptionsHandler::CreateValueForPref() does. - event.value = { - value: value, - recommendedValue: pref.orig.recommendedValue, - disabled: pref.orig.disabled, - uncommitted: true, - }; + event.value = {value: value, uncommitted: true}; + if (pref.orig) { + event.value.recommendedValue = pref.orig.recommendedValue; + event.value.disabled = pref.orig.disabled; + } this.dispatchEvent(event); }, diff --git a/chromium/chrome/browser/resources/options/profiles_icon_grid.js b/chromium/chrome/browser/resources/options/profiles_icon_grid.js index a35b23fe436..f8e7b61d13b 100644 --- a/chromium/chrome/browser/resources/options/profiles_icon_grid.js +++ b/chromium/chrome/browser/resources/options/profiles_icon_grid.js @@ -37,7 +37,7 @@ cr.define('options', function() { ListItem.prototype.decorate.call(this); var imageEl = cr.doc.createElement('img'); imageEl.className = 'profile-icon'; - imageEl.style.content = imageset(this.iconURL_ + '@scalefactorx'); + imageEl.style.content = getProfileAvatarIcon(this.iconURL_); this.appendChild(imageEl); this.className = 'profile-icon-grid-item'; @@ -65,4 +65,3 @@ cr.define('options', function() { ProfilesIconGrid: ProfilesIconGrid }; }); - diff --git a/chromium/chrome/browser/resources/options/reset_profile_settings_banner.html b/chromium/chrome/browser/resources/options/reset_profile_settings_banner.html index 77b6d592eca..fd95c3c7ec9 100644 --- a/chromium/chrome/browser/resources/options/reset_profile_settings_banner.html +++ b/chromium/chrome/browser/resources/options/reset_profile_settings_banner.html @@ -1,4 +1,4 @@ -<div id="reset-profile-settings-banner" hidden> +<div id="reset-profile-settings-banner" class="settings-banner" hidden> <div id="reset-profile-settings-banner-close" class="close-button"></div> <div class="content-area"> <div class="badge"></div> diff --git a/chromium/chrome/browser/resources/options/reset_profile_settings_banner.js b/chromium/chrome/browser/resources/options/reset_profile_settings_banner.js index 4517e9151c7..ffa2b07c1c5 100644 --- a/chromium/chrome/browser/resources/options/reset_profile_settings_banner.js +++ b/chromium/chrome/browser/resources/options/reset_profile_settings_banner.js @@ -6,6 +6,7 @@ cr.define('options', function() { /** @const */ var OptionsPage = options.OptionsPage; + /** @const */ var SettingsBannerBase = options.SettingsBannerBase; /** * ResetProfileSettingsBanner class @@ -17,28 +18,19 @@ cr.define('options', function() { cr.addSingletonGetter(ResetProfileSettingsBanner); ResetProfileSettingsBanner.prototype = { - /** - * Whether or not the banner has already been dismissed. - * - * This is needed because of the surprising ordering of asynchronous - * JS<->native calls when the settings page is opened with specifying a - * given sub-page, e.g. chrome://settings/resetProfileSettings. - * - * In such a case, ResetProfileSettingsOverlay's didShowPage(), which calls - * our dismiss() method, would be called before the native Handlers' - * InitalizePage() methods have an effect in the JS, which includes calling - * our show() method. This would mean that the banner would be first - * dismissed, then shown. We want to prevent this. - * - * @type {boolean} - * @private - */ - hadBeenDismissed_: false, + __proto__: SettingsBannerBase.prototype, /** * Initializes the banner's event handlers. */ initialize: function() { + this.showMetricName_ = 'AutomaticReset_WebUIBanner_BannerShown'; + + this.dismissNativeCallbackName_ = + 'onDismissedResetProfileSettingsBanner'; + + this.setVisibilibyDomElement_ = $('reset-profile-settings-banner'); + $('reset-profile-settings-banner-close').onclick = function(event) { chrome.send('metricsHandler:recordAction', ['AutomaticReset_WebUIBanner_ManuallyClosed']); @@ -50,39 +42,6 @@ cr.define('options', function() { OptionsPage.navigateToPage('resetProfileSettings'); }; }, - - /** - * Called by the native code to show the banner if needed. - * @private - */ - show_: function() { - if (!this.hadBeenDismissed_) { - chrome.send('metricsHandler:recordAction', - ['AutomaticReset_WebUIBanner_BannerShown']); - this.setVisibility_(true); - } - }, - - /** - * Called when the banner should be closed as a result of something taking - * place on the WebUI page, i.e. when its close button is pressed, or when - * the confirmation dialog for the profile settings reset feature is opened. - * @private - */ - dismiss_: function() { - chrome.send('onDismissedResetProfileSettingsBanner'); - this.hadBeenDismissed_ = true; - this.setVisibility_(false); - }, - - /** - * Sets whether or not the reset profile settings banner shall be visible. - * @param {boolean} show Whether or not to show the banner. - * @private - */ - setVisibility_: function(show) { - $('reset-profile-settings-banner').hidden = !show; - } }; // Forward public APIs to private implementations. diff --git a/chromium/chrome/browser/resources/options/reset_profile_settings_overlay.html b/chromium/chrome/browser/resources/options/reset_profile_settings_overlay.html index e348c818d91..98d5248bf82 100644 --- a/chromium/chrome/browser/resources/options/reset_profile_settings_overlay.html +++ b/chromium/chrome/browser/resources/options/reset_profile_settings_overlay.html @@ -1,4 +1,4 @@ -<div id="reset-profile-settings-overlay" class="page" hidden> +<div id="reset-profile-settings-overlay" class="page not-resizable" hidden> <div class="close-button"></div> <h1 i18n-content="resetProfileSettingsOverlay"></h1> <div id="reset-profile-settings-content-area" class="content-area"> @@ -42,4 +42,4 @@ </div> </div> </div> -<script src="chrome://resources/js/jstemplate_compiled.js"></script>
\ No newline at end of file +<script src="chrome://resources/js/jstemplate_compiled.js"></script> diff --git a/chromium/chrome/browser/resources/options/reset_profile_settings_overlay.js b/chromium/chrome/browser/resources/options/reset_profile_settings_overlay.js index ab4d830b714..30a6d44f4b2 100644 --- a/chromium/chrome/browser/resources/options/reset_profile_settings_overlay.js +++ b/chromium/chrome/browser/resources/options/reset_profile_settings_overlay.js @@ -49,6 +49,11 @@ cr.define('options', function() { ResetProfileSettingsBanner.dismiss(); chrome.send('onShowResetProfileDialog'); }, + + /** @override */ + didClosePage: function() { + chrome.send('onHideResetProfileDialog'); + }, }; /** @@ -67,12 +72,7 @@ cr.define('options', function() { * operation has terminated. */ ResetProfileSettingsOverlay.doneResetting = function() { - // The delay gives the user some feedback that the resetting - // actually worked. Otherwise the dialog just vanishes instantly in most - // cases. - window.setTimeout(function() { - ResetProfileSettingsOverlay.dismiss(); - }, 200); + ResetProfileSettingsOverlay.dismiss(); }; /** diff --git a/chromium/chrome/browser/resources/options/search_engine_manager.css b/chromium/chrome/browser/resources/options/search_engine_manager.css index c19734da4e4..68ad445ab7f 100644 --- a/chromium/chrome/browser/resources/options/search_engine_manager.css +++ b/chromium/chrome/browser/resources/options/search_engine_manager.css @@ -78,4 +78,12 @@ display: none; } +#default-search-engine-list { + z-index: 2; +} + +#other-search-engine-list { + z-index: 1; +} + /* End temporary Make Default button styling */ diff --git a/chromium/chrome/browser/resources/options/search_engine_manager_engine_list.js b/chromium/chrome/browser/resources/options/search_engine_manager_engine_list.js index 9bc12b9f8b6..0be060294d4 100644 --- a/chromium/chrome/browser/resources/options/search_engine_manager_engine_list.js +++ b/chromium/chrome/browser/resources/options/search_engine_manager_engine_list.js @@ -186,9 +186,8 @@ cr.define('options.search_engines', function() { // CoreOptionsHandler::CreateValueForPref() does. var event = new Event(this.contentType); if (engine.extension) { - event.value = { controlledBy: 'extension' }; - // TODO(mad): add id, name, and icon once we solved the issue with the - // search engine manager in http://crbug.com/314507. + event.value = { controlledBy: 'extension', + extension: engine.extension }; } else { event.value = { controlledBy: 'policy' }; } diff --git a/chromium/chrome/browser/resources/options/search_page.js b/chromium/chrome/browser/resources/options/search_page.js index 234399d7af2..cd72ba5f383 100644 --- a/chromium/chrome/browser/resources/options/search_page.js +++ b/chromium/chrome/browser/resources/options/search_page.js @@ -272,8 +272,7 @@ cr.define('options', function() { // Set the hash on the current page, and the enclosing uber page var hash = text ? '#' + encodeURIComponent(text) : ''; var path = text ? this.name : ''; - window.location.hash = hash; - uber.invokeMethodOnParent('setPath', {path: path + hash}); + uber.pushState({}, path + hash); // Toggle the search page if necessary. if (text) { @@ -505,7 +504,7 @@ cr.define('options', function() { /** * Builds a list of sub-pages (and overlay pages) to search. Ignore pages - * that have no associated controls. + * that have no associated controls, or whose controls are hidden. * @return {Array} An array of pages to search. * @private */ @@ -513,13 +512,19 @@ cr.define('options', function() { var name, pageInfo, page, pages = []; for (name in OptionsPage.registeredPages) { page = OptionsPage.registeredPages[name]; - if (page.parentPage && page.associatedSection) + if (page.parentPage && + page.associatedSection && + !page.associatedSection.hidden) { pages.push(page); + } } for (name in OptionsPage.registeredOverlayPages) { page = OptionsPage.registeredOverlayPages[name]; - if (page.associatedSection && page.pageDiv != undefined) + if (page.associatedSection && + !page.associatedSection.hidden && + page.pageDiv != undefined) { pages.push(page); + } } return pages; }, diff --git a/chromium/chrome/browser/resources/options/secondary_user_banner.html b/chromium/chrome/browser/resources/options/secondary_user_banner.html new file mode 100644 index 00000000000..84da4273451 --- /dev/null +++ b/chromium/chrome/browser/resources/options/secondary_user_banner.html @@ -0,0 +1,11 @@ +<div id="secondary-user-banner" class="settings-banner" hidden> + <div class="content-area"> + <div class="badge"></div> + <div class="text"> + <p> + <span i18n-values=".innerHTML:secondaryUserBannerText"> + </span> + </p> + </div> + </div> +</div> diff --git a/chromium/chrome/browser/resources/options/reset_profile_settings_banner.css b/chromium/chrome/browser/resources/options/settings_banner.css index 21087f8aebd..44add992f64 100644 --- a/chromium/chrome/browser/resources/options/reset_profile_settings_banner.css +++ b/chromium/chrome/browser/resources/options/settings_banner.css @@ -1,8 +1,11 @@ -/* Copyright 2013 The Chromium Authors. All rights reserved. +/* Copyright 2014 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. */ -#reset-profile-settings-banner { +/* These styles are used bby both reset_profile_settings_banner.html and + * automatic_settings_reset_banner.html. */ + +.settings-banner { background-color: #f5f5f5; border-color: #c8c8c8; border-radius: 3px; @@ -10,11 +13,11 @@ border-width: 1px; margin-bottom: 24px; margin-top: 20px; + max-width: 716px; position: relative; - width: 716px; } -#reset-profile-settings-banner > .close-button { +.settings-banner > .close-button { background-image: url('chrome://theme/IDR_CLOSE_DIALOG'); background-position: center; background-repeat: no-repeat; @@ -26,26 +29,26 @@ width: 14px; } -html[dir='rtl'] #reset-profile-settings-banner > .close-button { +html[dir='rtl'] .settings-banner > .close-button { left: 4px; right: auto; } -#reset-profile-settings-banner > .close-button:hover { +.settings-banner > .close-button:hover { background-image: url('chrome://theme/IDR_CLOSE_DIALOG_H'); } -#reset-profile-settings-banner > .close-button:active { +.settings-banner > .close-button:active { background-image: url('chrome://theme/IDR_CLOSE_DIALOG_P'); } -#reset-profile-settings-banner .content-area { +.settings-banner .content-area { -webkit-box-align: center; display: -webkit-box; padding: 17px; } -#reset-profile-settings-banner .content-area .badge { +.settings-banner .content-area .badge { background-image: url(yellow_gear.png); background-position: center; background-repeat: no-repeat; @@ -53,25 +56,30 @@ html[dir='rtl'] #reset-profile-settings-banner > .close-button { width: 58px; } -#reset-profile-settings-banner .content-area .text { +.settings-banner .content-area .text { -webkit-box-flex: 1.0; -webkit-margin-start: 18px; } -#reset-profile-settings-banner .content-area .text p { +.settings-banner .content-area .text p { -webkit-margin-after: 0; -webkit-margin-before: 0; } -#reset-profile-settings-banner .content-area .button-area { +.settings-banner .content-area .button-area { -webkit-margin-start: 54px; } -#reset-profile-settings-banner .nowrap { +.settings-banner .nowrap { white-space: nowrap; } -#reset-profile-settings-banner button { +.settings-banner button { margin-bottom: 1px; margin-right: 0; } + +#secondary-user-banner .content-area .badge { + background-color: rgb(210, 210, 212); + background-image: url(chrome://theme/IDR_SECONDARY_USER_SETTINGS); +} diff --git a/chromium/chrome/browser/resources/options/settings_banner.js b/chromium/chrome/browser/resources/options/settings_banner.js new file mode 100644 index 00000000000..1b253187e8c --- /dev/null +++ b/chromium/chrome/browser/resources/options/settings_banner.js @@ -0,0 +1,86 @@ +// Copyright 2014 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. + +cr.define('options', function() { + + /** + * Base class for banners that appear at the top of the settings page. + */ + function SettingsBannerBase() {} + + cr.addSingletonGetter(SettingsBannerBase); + + SettingsBannerBase.prototype = { + /** + * Whether or not the banner has already been dismissed. + * + * This is needed because of the surprising ordering of asynchronous + * JS<->native calls when the settings page is opened with specifying a + * given sub-page, e.g. chrome://settings/AutomaticSettingsReset. + * + * In such a case, AutomaticSettingsResetOverlay's didShowPage(), which + * calls our dismiss() method, would be called before the native Handlers' + * InitalizePage() methods have an effect in the JS, which includes calling + * our show() method. This would mean that the banner would be first + * dismissed, then shown. We want to prevent this. + * + * @type {boolean} + * @private + */ + hadBeenDismissed_: false, + + /** + * Metric name to send when a show event occurs. + */ + showMetricName_: '', + + /** + * Name of the native callback invoked when the banner is dismised. + */ + dismissNativeCallbackName_: '', + + /** + * DOM element whose visibility is set when setVisibility_ is called. + */ + setVisibilibyDomElement_: null, + + /** + * Called by the native code to show the banner if needed. + * @private + */ + show_: function() { + if (!this.hadBeenDismissed_) { + chrome.send('metricsHandler:recordAction', [this.showMetricName_]); + this.setVisibility_(true); + } + }, + + /** + * Called when the banner should be closed as a result of something taking + * place on the WebUI page, i.e. when its close button is pressed, or when + * the confirmation dialog for the profile settings reset feature is opened. + * @private + */ + dismiss_: function() { + chrome.send(this.dismissNativeCallbackName_); + this.hadBeenDismissed_ = true; + this.setVisibility_(false); + }, + + /** + * Sets whether or not the reset profile settings banner shall be visible. + * @param {boolean} show Whether or not to show the banner. + * @private + */ + setVisibility_: function(show) { + this.setVisibilibyDomElement_.hidden = !show; + }, + + }; + + // Export + return { + SettingsBannerBase: SettingsBannerBase + }; +}); diff --git a/chromium/chrome/browser/resources/options/startup_section.html b/chromium/chrome/browser/resources/options/startup_section.html index 2eaea81c0bf..41a34ecb47b 100644 --- a/chromium/chrome/browser/resources/options/startup_section.html +++ b/chromium/chrome/browser/resources/options/startup_section.html @@ -1,7 +1,7 @@ <section id="startup-section" guest-visibility="hidden"> <h3 i18n-content="sectionTitleStartup"></h3> - <div> - <div class="radio"> + <div id="startup-section-content"> + <div class="radio" id="newtab-section-content"> <span class="controlled-setting-with-label"> <input id="startup-newtab" type="radio" name="startup" value="5" pref="session.restore_on_startup" diff --git a/chromium/chrome/browser/resources/options/subpages_tab_controls.css b/chromium/chrome/browser/resources/options/subpages_tab_controls.css index c49c07715fe..c8b6c970b0c 100644 --- a/chromium/chrome/browser/resources/options/subpages_tab_controls.css +++ b/chromium/chrome/browser/resources/options/subpages_tab_controls.css @@ -50,14 +50,12 @@ html[dir=rtl] .subpages-nav-tabs .tab-label { } .subpages-nav-tabs { - background-image: -webkit-gradient( - linear, - left top, - left bottom, - color-stop(0, rgb(255,255,255)), - color-stop(0.6, rgb(255,255,255)), - color-stop(0.8, rgb(250, 250, 250)), - color-stop(1.0, rgb(242,242,242)) + background-image: linear-gradient( + to bottom, + rgb(255,255,255), + rgb(255,255,255) 60%, + rgb(250, 250, 250) 80%, + rgb(242,242,242) ); border-bottom: 1px solid #ddd; padding: 4px 20px; diff --git a/chromium/chrome/browser/resources/options/sync_section.html b/chromium/chrome/browser/resources/options/sync_section.html index fdf89885921..fea00770681 100644 --- a/chromium/chrome/browser/resources/options/sync_section.html +++ b/chromium/chrome/browser/resources/options/sync_section.html @@ -1,8 +1,8 @@ -<if expr="not pp_ifdef('chromeos')"> +<if expr="not chromeos"> <section id="sync-section"> <h3 i18n-content="sectionTitleSync"></h3> </if> -<if expr="pp_ifdef('chromeos')"> +<if expr="chromeos"> <div id="sync-section"> </if> @@ -12,7 +12,7 @@ target="_blank"></a> </div> -<if expr="pp_ifdef('chromeos')"> +<if expr="chromeos"> <div id="account-picture-wrapper"> <div id="account-picture-control"> <input type="image" id="account-picture" tabindex="0" @@ -23,17 +23,18 @@ </span> </div> <div id="sync-general"> -</if> <!-- pp_ifdef('chromeos') --> +</if> <!-- chromeos --> <div id="sync-status" class="settings-row" hidden> <span id="sync-status-text"></span> <button id="sync-action-link" class="link-button"></button> </div> -<if expr="pp_ifdef('chromeos')"> +<if expr="chromeos"> <div class="checkbox"> <span class="controlled-setting-with-label"> <input id="enable-screen-lock" type="checkbox" + metric="Options_ScreenLock" pref="settings.enable_screen_lock"> <span> <label for="enable-screen-lock" i18n-content="enableScreenlock"> @@ -45,7 +46,7 @@ </span> </div> </div> -</if> <!-- pp_ifdef('chromeos') --> +</if> <!-- chromeos --> <div id="sync-buttons" class="settings-row"> <button id="start-stop-sync" hidden></button> @@ -55,23 +56,16 @@ <button id="customize-sync" i18n-content="customizeSync" pref="sync.managed" hidden> </button> -<if expr="pp_ifdef('chromeos')"> +<if expr="chromeos"> <button id="manage-accounts-button" i18n-content="manageAccountsButtonTitle"> </button> -</if> <!-- pp_ifdef('chromeos') --> - <div id="enable-auto-login-checkbox" class="checkbox" hidden> - <label> - <input id="enable-auto-login" pref="autologin.enabled" - metric="Options_Autologin" type="checkbox"> - <span i18n-content="autologinEnabled"></span> - </label> - </div> +</if> <!-- chromeos --> </div> -<if expr="not pp_ifdef('chromeos')"> +<if expr="not chromeos"> </section> </if> -<if expr="pp_ifdef('chromeos')"> +<if expr="chromeos"> </div> </if> |