Only grant permissions to new extensions from sync if they have the expected version
[chromium-blink-merge.git] / chrome / browser / resources / options / autofill_edit_address_overlay.js
blob85675d57c1f26a6f96f69d23ec0bf78b187a67df
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 cr.define('options', function() {
6   /** @const */ var Page = cr.ui.pageManager.Page;
7   /** @const */ var PageManager = cr.ui.pageManager.PageManager;
8   /** @const */ var ArrayDataModel = cr.ui.ArrayDataModel;
10   /**
11    * AutofillEditAddressOverlay class
12    * Encapsulated handling of the 'Add Page' overlay page.
13    * @constructor
14    * @extends {cr.ui.pageManager.Page}
15    */
16   function AutofillEditAddressOverlay() {
17     Page.call(this, 'autofillEditAddress',
18               loadTimeData.getString('autofillEditAddressTitle'),
19               'autofill-edit-address-overlay');
20   }
22   cr.addSingletonGetter(AutofillEditAddressOverlay);
24   AutofillEditAddressOverlay.prototype = {
25     __proto__: Page.prototype,
27     /**
28      * The GUID of the loaded address.
29      * @type {string}
30      */
31     guid_: '',
33     /**
34      * The BCP 47 language code for the layout of input fields.
35      * @type {string}
36      */
37     languageCode_: '',
39     /**
40      * The saved field values for the address. For example, if the user changes
41      * from United States to Switzerland, then the State field will be hidden
42      * and its value will be stored here. If the user changes back to United
43      * States, then the State field will be restored to its previous value, as
44      * stored in this object.
45      * @type {Object}
46      */
47     savedFieldValues_: {},
49     /** @override */
50     initializePage: function() {
51       Page.prototype.initializePage.call(this);
53       var self = this;
54       $('autofill-edit-address-cancel-button').onclick = function(event) {
55         self.dismissOverlay_();
56       };
58       // TODO(jhawkins): Investigate other possible solutions.
59       $('autofill-edit-address-apply-button').onclick = function(event) {
60         // Blur active element to ensure that pending changes are committed.
61         if (document.activeElement)
62           document.activeElement.blur();
63         self.saveAddress_();
64         self.dismissOverlay_();
65       };
67       this.guid_ = '';
68       this.populateCountryList_();
69       this.rebuildInputFields_(
70           loadTimeData.getValue('autofillDefaultCountryComponents'));
71       this.languageCode_ =
72           loadTimeData.getString('autofillDefaultCountryLanguageCode');
73       this.connectInputEvents_();
74       this.setInputFields_({});
75       this.getCountrySwitcher_().onchange = function(event) {
76         self.countryChanged_();
77       };
78     },
80     /**
81     * Specifically catch the situations in which the overlay is cancelled
82     * externally (e.g. by pressing <Esc>), so that the input fields and
83     * GUID can be properly cleared.
84     * @override
85     */
86     handleCancel: function() {
87       this.dismissOverlay_();
88     },
90     /**
91      * Clears any uncommitted input, resets the stored GUID and dismisses the
92      * overlay.
93      * @private
94      */
95     dismissOverlay_: function() {
96       this.setInputFields_({});
97       this.inputFieldChanged_();
98       this.guid_ = '';
99       this.languageCode_ = '';
100       this.savedInputFields_ = {};
101       PageManager.closeOverlay();
102     },
104     /**
105      * @return {Element} The element used to switch countries.
106      * @private
107      */
108     getCountrySwitcher_: function() {
109       return this.pageDiv.querySelector('[field=country]');
110     },
112     /**
113      * Returns all text input elements.
114      * @return {!NodeList} The text input elements.
115      * @private
116      */
117     getTextFields_: function() {
118       return this.pageDiv.querySelectorAll('textarea[field], input[field]');
119     },
121     /**
122      * Creates a map from type => value for all text fields.
123      * @return {Object} The mapping from field names to values.
124      * @private
125      */
126     getInputFields_: function() {
127       var address = {country: this.getCountrySwitcher_().value};
129       var fields = this.getTextFields_();
130       for (var i = 0; i < fields.length; i++) {
131         address[fields[i].getAttribute('field')] = fields[i].value;
132       }
134       return address;
135     },
137     /**
138      * Sets the value of each input field according to |address|.
139      * @param {Object} address The object with values to use.
140      * @private
141      */
142     setInputFields_: function(address) {
143       this.getCountrySwitcher_().value = address.country || '';
145       var fields = this.getTextFields_();
146       for (var i = 0; i < fields.length; i++) {
147         fields[i].value = address[fields[i].getAttribute('field')] || '';
148       }
149     },
151     /**
152      * Aggregates the values in the input fields into an array and sends the
153      * array to the Autofill handler.
154      * @private
155      */
156     saveAddress_: function() {
157       var inputFields = this.getInputFields_();
158       var address = [
159         this.guid_,
160         inputFields['fullName'] || [],
161         inputFields['companyName'] || '',
162         inputFields['addrLines'] || '',
163         inputFields['dependentLocality'] || '',
164         inputFields['city'] || '',
165         inputFields['state'] || '',
166         inputFields['postalCode'] || '',
167         inputFields['sortingCode'] || '',
168         inputFields['country'] || loadTimeData.getString('defaultCountryCode'),
169         inputFields['phone'] || [],
170         inputFields['email'] || [],
171         this.languageCode_,
172       ];
173       chrome.send('setAddress', address);
175       // If the GUID is empty, this form is being used to add a new address,
176       // rather than edit an existing one.
177       if (!this.guid_.length) {
178         chrome.send('coreOptionsUserMetricsAction',
179                     ['Options_AutofillAddressAdded']);
180       }
181     },
183     /**
184      * Connects each input field to the inputFieldChanged_() method that enables
185      * or disables the 'Ok' button based on whether all the fields are empty or
186      * not.
187      * @private
188      */
189     connectInputEvents_: function() {
190       var fields = this.getTextFields_();
191       for (var i = 0; i < fields.length; i++) {
192         fields[i].oninput = this.inputFieldChanged_.bind(this);
193       }
194     },
196     /**
197      * Disables the 'Ok' button if all of the fields are empty.
198      * @private
199      */
200     inputFieldChanged_: function() {
201       var disabled = !this.getCountrySwitcher_().value;
202       if (disabled) {
203         var fields = this.getTextFields_();
204         for (var i = 0; i < fields.length; i++) {
205           if (fields[i].value) {
206             disabled = false;
207             break;
208           }
209         }
210       }
212       $('autofill-edit-address-apply-button').disabled = disabled;
213     },
215     /**
216      * Updates the address fields appropriately for the selected country.
217      * @private
218      */
219     countryChanged_: function() {
220       var countryCode = this.getCountrySwitcher_().value;
221       if (countryCode)
222         chrome.send('loadAddressEditorComponents', [countryCode]);
223       else
224         this.inputFieldChanged_();
225     },
227     /**
228      * Populates the country <select> list.
229      * @private
230      */
231     populateCountryList_: function() {
232       var countryList = loadTimeData.getValue('autofillCountrySelectList');
234       // Add the countries to the country <select>.
235       var countrySelect = this.getCountrySwitcher_();
236       // Add an empty option.
237       countrySelect.appendChild(new Option('', ''));
238       for (var i = 0; i < countryList.length; i++) {
239         var option = new Option(countryList[i].name,
240                                 countryList[i].value);
241         option.disabled = countryList[i].value == 'separator';
242         countrySelect.appendChild(option);
243       }
244     },
246     /**
247      * Called to prepare the overlay when a new address is being added.
248      * @private
249      */
250     prepForNewAddress_: function() {
251       // Focus the first element.
252       this.pageDiv.querySelector('input').focus();
253     },
255     /**
256      * Loads the address data from |address|, sets the input fields based on
257      * this data, and stores the GUID and language code of the address.
258      * @param {!Object} address Lots of info about an address from the browser.
259      * @private
260      */
261     loadAddress_: function(address) {
262       this.rebuildInputFields_(address.components);
263       this.setInputFields_(address);
264       this.inputFieldChanged_();
265       this.connectInputEvents_();
266       this.guid_ = address.guid;
267       this.languageCode_ = address.languageCode;
268     },
270     /**
271      * Takes a snapshot of the input values, clears the input values, loads the
272      * address input layout from |input.components|, restores the input values
273      * from snapshot, and stores the |input.languageCode| for the address.
274      * @param {{languageCode: string, components: Array<Array<Object>>}} input
275      *     Info about how to layout inputs fields in this dialog.
276      * @private
277      */
278     loadAddressComponents_: function(input) {
279       var inputFields = this.getInputFields_();
280       for (var fieldName in inputFields) {
281         if (inputFields.hasOwnProperty(fieldName))
282           this.savedFieldValues_[fieldName] = inputFields[fieldName];
283       }
284       this.rebuildInputFields_(input.components);
285       this.setInputFields_(this.savedFieldValues_);
286       this.inputFieldChanged_();
287       this.connectInputEvents_();
288       this.languageCode_ = input.languageCode;
289     },
291     /**
292      * Clears address inputs and rebuilds the input fields according to
293      * |components|.
294      * @param {Array<Array<Object>>} components A list of information about
295      *     each input field.
296      * @private
297      */
298     rebuildInputFields_: function(components) {
299       var content = $('autofill-edit-address-fields');
300       content.innerHTML = '';
302       var customInputElements = {addrLines: 'textarea'};
304       for (var i in components) {
305         var row = document.createElement('div');
306         row.classList.add('input-group', 'settings-row');
307         content.appendChild(row);
309         for (var j in components[i]) {
310           if (components[i][j].field == 'country')
311             continue;
313           var fieldContainer = document.createElement('label');
314           row.appendChild(fieldContainer);
316           var fieldName = document.createElement('div');
317           fieldName.textContent = components[i][j].name;
318           fieldContainer.appendChild(fieldName);
320           var input = document.createElement(
321               customInputElements[components[i][j].field] || 'input');
322           input.setAttribute('field', components[i][j].field);
323           input.classList.add(components[i][j].length);
324           fieldContainer.appendChild(input);
325         }
326       }
327     },
328   };
330   AutofillEditAddressOverlay.prepForNewAddress = function() {
331     AutofillEditAddressOverlay.getInstance().prepForNewAddress_();
332   };
334   AutofillEditAddressOverlay.loadAddress = function(address) {
335     AutofillEditAddressOverlay.getInstance().loadAddress_(address);
336   };
338   AutofillEditAddressOverlay.loadAddressComponents = function(input) {
339     AutofillEditAddressOverlay.getInstance().loadAddressComponents_(input);
340   };
342   AutofillEditAddressOverlay.setTitle = function(title) {
343     $('autofill-address-title').textContent = title;
344   };
346   // Export
347   return {
348     AutofillEditAddressOverlay: AutofillEditAddressOverlay
349   };