Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(667)

Side by Side Diff: chrome/browser/resources/options/autofill_edit_address_overlay.js

Issue 243013004: i18n address editing in chrome://settings/autofillEditAddress. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix windows build. Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 cr.define('options', function() { 5 cr.define('options', function() {
6 /** @const */ var OptionsPage = options.OptionsPage; 6 /** @const */ var OptionsPage = options.OptionsPage;
7 /** @const */ var ArrayDataModel = cr.ui.ArrayDataModel; 7 /** @const */ var ArrayDataModel = cr.ui.ArrayDataModel;
8 8
9 // The GUID of the loaded address. 9 // The GUID of the loaded address.
10 var guid; 10 var guid;
11 11
12 // The BCP 47 language code for the layout of input fields.
13 var languageCode;
Dan Beam 2014/05/06 03:51:09 ^ i'm confused, where is this used? looks like de
14
12 /** 15 /**
13 * AutofillEditAddressOverlay class 16 * AutofillEditAddressOverlay class
14 * Encapsulated handling of the 'Add Page' overlay page. 17 * Encapsulated handling of the 'Add Page' overlay page.
15 * @class 18 * @class
16 */ 19 */
17 function AutofillEditAddressOverlay() { 20 function AutofillEditAddressOverlay() {
18 OptionsPage.call(this, 'autofillEditAddress', 21 OptionsPage.call(this, 'autofillEditAddress',
19 loadTimeData.getString('autofillEditAddressTitle'), 22 loadTimeData.getString('autofillEditAddressTitle'),
20 'autofill-edit-address-overlay'); 23 'autofill-edit-address-overlay');
21 } 24 }
(...skipping 17 matching lines...) Expand all
39 }; 42 };
40 43
41 // TODO(jhawkins): Investigate other possible solutions. 44 // TODO(jhawkins): Investigate other possible solutions.
42 $('autofill-edit-address-apply-button').onclick = function(event) { 45 $('autofill-edit-address-apply-button').onclick = function(event) {
43 // Blur active element to ensure that pending changes are committed. 46 // Blur active element to ensure that pending changes are committed.
44 if (document.activeElement) 47 if (document.activeElement)
45 document.activeElement.blur(); 48 document.activeElement.blur();
46 // Blurring is delayed for list elements. Queue save and close to 49 // Blurring is delayed for list elements. Queue save and close to
47 // ensure that pending changes have been applied. 50 // ensure that pending changes have been applied.
48 setTimeout(function() { 51 setTimeout(function() {
49 $('phone-list').doneValidating().then(function() { 52 self.pageDiv.querySelector('[field=phone]').doneValidating().then(
50 self.saveAddress_(); 53 function() {
51 self.dismissOverlay_(); 54 self.saveAddress_();
52 }); 55 self.dismissOverlay_();
56 });
53 }, 0); 57 }, 0);
54 }; 58 };
55 59
56 // Prevent 'blur' events on the OK and cancel buttons, which can trigger 60 // Prevent 'blur' events on the OK and cancel buttons, which can trigger
57 // insertion of new placeholder elements. The addition of placeholders 61 // insertion of new placeholder elements. The addition of placeholders
58 // affects layout, which interferes with being able to click on the 62 // affects layout, which interferes with being able to click on the
59 // buttons. 63 // buttons.
60 $('autofill-edit-address-apply-button').onmousedown = function(event) { 64 $('autofill-edit-address-apply-button').onmousedown = function(event) {
61 event.preventDefault(); 65 event.preventDefault();
62 }; 66 };
63 $('autofill-edit-address-cancel-button').onmousedown = function(event) { 67 $('autofill-edit-address-cancel-button').onmousedown = function(event) {
64 event.preventDefault(); 68 event.preventDefault();
65 }; 69 };
66 70
67 self.guid = ''; 71 this.guid = '';
68 self.populateCountryList_(); 72 this.populateCountryList_();
69 self.clearInputFields_(); 73 this.rebuildInputFields_(
70 self.connectInputEvents_(); 74 loadTimeData.getValue('autofillDefaultCountryComponents'));
75 this.languageCode =
76 loadTimeData.getString('autofillDefaultCountryLanguageCode');
77 this.connectInputEvents_();
78 this.setInputFields_({});
79 this.getCountrySelector_().onchange = function(event) {
80 self.countryChanged_();
81 };
71 }, 82 },
72 83
73 /** 84 /**
74 * Specifically catch the situations in which the overlay is cancelled 85 * Specifically catch the situations in which the overlay is cancelled
75 * externally (e.g. by pressing <Esc>), so that the input fields and 86 * externally (e.g. by pressing <Esc>), so that the input fields and
76 * GUID can be properly cleared. 87 * GUID can be properly cleared.
77 * @override 88 * @override
78 */ 89 */
79 handleCancel: function() { 90 handleCancel: function() {
80 this.dismissOverlay_(); 91 this.dismissOverlay_();
81 }, 92 },
82 93
83 /** 94 /**
84 * Creates, decorates and initializes the multi-value lists for full name, 95 * Creates, decorates and initializes the multi-value lists for phone and
85 * phone, and email. 96 * email.
86 * @private 97 * @private
87 */ 98 */
88 createMultiValueLists_: function() { 99 createMultiValueLists_: function() {
89 var list = $('full-name-list'); 100 var list = this.pageDiv.querySelector('[field=phone]');
90 options.autofillOptions.AutofillNameValuesList.decorate(list);
91 list.autoExpands = true;
92
93 list = $('phone-list');
94 options.autofillOptions.AutofillPhoneValuesList.decorate(list); 101 options.autofillOptions.AutofillPhoneValuesList.decorate(list);
95 list.autoExpands = true; 102 list.autoExpands = true;
96 103
97 list = $('email-list'); 104 list = this.pageDiv.querySelector('[field=email]');
98 options.autofillOptions.AutofillValuesList.decorate(list); 105 options.autofillOptions.AutofillValuesList.decorate(list);
99 list.autoExpands = true; 106 list.autoExpands = true;
100 }, 107 },
101 108
102 /** 109 /**
103 * Updates the data model for the list named |listName| with the values from 110 * Updates the data model for the |list| with the values from |entries|.
104 * |entries|. 111 * @param {element} list The list to update.
Dan Beam 2014/05/06 03:51:09 !Element
105 * @param {string} listName The id of the list.
106 * @param {Array} entries The list of items to be added to the list. 112 * @param {Array} entries The list of items to be added to the list.
113 * @private
107 */ 114 */
108 setMultiValueList_: function(listName, entries) { 115 setMultiValueList_: function(list, entries) {
109 // Add data entries.
110 var list = $(listName);
111
112 // Add special entry for adding new values. 116 // Add special entry for adding new values.
113 var augmentedList = entries.slice(); 117 var augmentedList = entries.slice();
114 augmentedList.push(null); 118 augmentedList.push(null);
115 list.dataModel = new ArrayDataModel(augmentedList); 119 list.dataModel = new ArrayDataModel(augmentedList);
116 120
117 // Update the status of the 'OK' button. 121 // Update the status of the 'OK' button.
118 this.inputFieldChanged_(); 122 this.inputFieldChanged_();
119 123
120 list.dataModel.addEventListener('splice', 124 list.dataModel.addEventListener('splice',
121 this.inputFieldChanged_.bind(this)); 125 this.inputFieldChanged_.bind(this));
122 list.dataModel.addEventListener('change', 126 list.dataModel.addEventListener('change',
123 this.inputFieldChanged_.bind(this)); 127 this.inputFieldChanged_.bind(this));
124 }, 128 },
125 129
126 /** 130 /**
127 * Clears any uncommitted input, resets the stored GUID and dismisses the 131 * Clears any uncommitted input, resets the stored GUID and dismisses the
128 * overlay. 132 * overlay.
129 * @private 133 * @private
130 */ 134 */
131 dismissOverlay_: function() { 135 dismissOverlay_: function() {
132 this.clearInputFields_(); 136 this.setInputFields_({});
137 this.inputFieldChanged_();
133 this.guid = ''; 138 this.guid = '';
139 this.languageCode = '';
134 OptionsPage.closeOverlay(); 140 OptionsPage.closeOverlay();
135 }, 141 },
136 142
137 /** 143 /**
144 * Returns the country selector element.
145 * @return {element} The country selector.
Dan Beam 2014/05/06 03:51:09 Element
146 * @private
147 */
148 getCountrySelector_: function() {
Dan Beam 2014/05/06 03:51:09 nit: getCountrySwitcher as calling something a "se
149 return this.pageDiv.querySelector('[field=country]');
150 },
151
152 /**
153 * Returns all list elements.
154 * @return {NodeList} The list elements.
155 * @private
156 */
157 getLists_: function() {
158 return this.pageDiv.querySelectorAll('list[field]');
159 },
160
161 /**
162 * Returns all text input elements.
163 * @return {NodeList} The text input elements.
Dan Beam 2014/05/06 03:51:09 !NodeList in both cases (here and above)
164 * @private
165 */
166 getTextFields_: function() {
167 return this.pageDiv.querySelectorAll(
168 ':-webkit-any(textarea, input)[field]');
169 },
170
171 /**
172 * Aggregates the values in the input fields into an object.
173 * @return {object} The mapping from field names to values.
Dan Beam 2014/05/06 03:51:09 !Object
174 * @private
175 */
176 getInputFields_: function() {
177 var address = {};
178 address['country'] = this.getCountrySelector_().value;
Dan Beam 2014/05/06 03:51:09 why not: var address = {country: this.getCountr
179
180 var lists = this.getLists_();
181 for (var i = 0; i < lists.length; i++) {
182 address[lists[i].getAttribute('field')] =
183 lists[i].dataModel.slice(0, lists[i].dataModel.length - 1);
Dan Beam 2014/05/06 03:51:09 you can usually do .slice(0) if you want the whole
184 }
185
186 var fields = this.getTextFields_();
187 for (var i = 0; i < fields.length; i++) {
188 address[fields[i].getAttribute('field')] = fields[i].value;
189 }
190
191 return address;
192 },
193
194 /**
195 * Sets the value of each input field according to |address|.
196 * @param {object} address The object with values to use.
Dan Beam 2014/05/06 03:51:09 !Object
197 * @private
198 */
199 setInputFields_: function(address) {
200 this.getCountrySelector_().value = address['country'] || '';
Dan Beam 2014/05/06 03:51:09 it's preferable to use .prop rather than ['prop']
201
202 var lists = this.getLists_();
203 for (var i = 0; i < lists.length; i++) {
204 this.setMultiValueList_(
205 lists[i], address[lists[i].getAttribute('field')] || []);
206 }
207
208 var fields = this.getTextFields_();
209 for (var i = 0; i < fields.length; i++) {
210 fields[i].value = address[fields[i].getAttribute('field')] || '';
211 }
212 },
213
214 /**
138 * Aggregates the values in the input fields into an array and sends the 215 * Aggregates the values in the input fields into an array and sends the
139 * array to the Autofill handler. 216 * array to the Autofill handler.
140 * @private 217 * @private
141 */ 218 */
142 saveAddress_: function() { 219 saveAddress_: function() {
220 var inputFields = this.getInputFields_();
143 var address = new Array(); 221 var address = new Array();
144 address[0] = this.guid; 222 var argCounter = 0;
145 var list = $('full-name-list'); 223 address[argCounter++] = this.guid;
146 address[1] = list.dataModel.slice(0, list.dataModel.length - 1); 224 address[argCounter++] = inputFields['fullName'] || [];
147 address[2] = $('company-name').value; 225 address[argCounter++] = inputFields['companyName'] || '';
148 address[3] = $('addr-line-1').value; 226 address[argCounter++] = inputFields['addrLines'] || '';
149 address[4] = $('addr-line-2').value; 227 address[argCounter++] = inputFields['dependentLocality'] || '';
150 address[5] = $('city').value; 228 address[argCounter++] = inputFields['city'] || '';
151 address[6] = $('state').value; 229 address[argCounter++] = inputFields['state'] || '';
152 address[7] = $('postal-code').value; 230 address[argCounter++] = inputFields['postalCode'] || '';
153 address[8] = $('country').value; 231 address[argCounter++] = inputFields['sortingCode'] || '';
154 list = $('phone-list'); 232 address[argCounter++] = inputFields['country'] || '';
155 address[9] = list.dataModel.slice(0, list.dataModel.length - 1); 233 address[argCounter++] = inputFields['phone'] || [];
156 list = $('email-list'); 234 address[argCounter++] = inputFields['email'] || [];
157 address[10] = list.dataModel.slice(0, list.dataModel.length - 1); 235 address[argCounter++] = this.languageCode;
Dan Beam 2014/05/06 03:51:09 confused, why not: var address = [ this.gui
158 236
159 chrome.send('setAddress', address); 237 chrome.send('setAddress', address);
160 }, 238 },
161 239
162 /** 240 /**
163 * Connects each input field to the inputFieldChanged_() method that enables 241 * Connects each input field to the inputFieldChanged_() method that enables
164 * or disables the 'Ok' button based on whether all the fields are empty or 242 * or disables the 'Ok' button based on whether all the fields are empty or
165 * not. 243 * not.
166 * @private 244 * @private
167 */ 245 */
168 connectInputEvents_: function() { 246 connectInputEvents_: function() {
169 var self = this; 247 var self = this;
170 $('company-name').oninput = $('addr-line-1').oninput = 248 var fields = this.getTextFields_();
171 $('addr-line-2').oninput = $('city').oninput = $('state').oninput = 249 for (var i = 0; i < fields.length; i++) {
172 $('postal-code').oninput = function(event) { 250 fields[i].oninput = function(event) { self.inputFieldChanged_(); };
Dan Beam 2014/05/06 03:51:09 fields[i].oninput = this.inputFieldChanged_.bind(t
173 self.inputFieldChanged_(); 251 }
174 };
175
176 $('country').onchange = function(event) {
177 self.countryChanged_();
178 };
179 }, 252 },
180 253
181 /** 254 /**
182 * Checks the values of each of the input fields and disables the 'Ok' 255 * Disables the 'Ok' button if all of the fields are empty.
183 * button if all of the fields are empty.
184 * @private 256 * @private
185 */ 257 */
186 inputFieldChanged_: function() { 258 inputFieldChanged_: function() {
187 // Length of lists are tested for <= 1 due to the "add" placeholder item 259 var disabled = true;
Dan Beam 2014/05/06 03:51:09 var disabled = !this.getCountrySelector_().value;
188 // in the list. 260 if (this.getCountrySelector_().value)
189 var disabled = 261 disabled = false;
190 $('full-name-list').items.length <= 1 && 262
191 !$('company-name').value && 263 if (disabled) {
192 !$('addr-line-1').value && !$('addr-line-2').value && 264 // Length of lists are tested for > 1 due to the "add" placeholder item
193 !$('city').value && !$('state').value && !$('postal-code').value && 265 // in the list.
194 !$('country').value && $('phone-list').items.length <= 1 && 266 var lists = this.getLists_();
195 $('email-list').items.length <= 1; 267 for (var i = 0; i < lists.length; i++) {
268 if (lists[i].items.length > 1) {
269 disabled = false;
270 break;
271 }
272 }
273 }
274
275 if (disabled) {
276 var fields = this.getTextFields_();
277 for (var i = 0; i < fields.length; i++) {
278 if (fields[i].value) {
279 disabled = false;
280 break;
281 }
282 }
283 }
284
196 $('autofill-edit-address-apply-button').disabled = disabled; 285 $('autofill-edit-address-apply-button').disabled = disabled;
197 }, 286 },
198 287
199 /** 288 /**
200 * Updates the postal code and state field labels appropriately for the 289 * Updates the address fields appropriately for the selected country.
201 * selected country.
202 * @private 290 * @private
203 */ 291 */
204 countryChanged_: function() { 292 countryChanged_: function() {
205 var countryCode = $('country').value || 293 var countryCode = this.getCountrySelector_().value;
206 loadTimeData.getString('defaultCountryCode'); 294 if (countryCode)
207 295 chrome.send('loadAddressEditorComponents', [countryCode]);
208 var details = loadTimeData.getValue('autofillCountryData')[countryCode]; 296 else
209 var postal = $('postal-code-label'); 297 this.inputFieldChanged_();
210 postal.textContent = details.postalCodeLabel;
211 $('state-label').textContent = details.stateLabel;
212
213 // Also update the 'Ok' button as needed.
214 this.inputFieldChanged_();
215 }, 298 },
216 299
217 /** 300 /**
218 * Populates the country <select> list. 301 * Populates the country <select> list.
219 * @private 302 * @private
220 */ 303 */
221 populateCountryList_: function() { 304 populateCountryList_: function() {
222 var countryList = loadTimeData.getValue('autofillCountrySelectList'); 305 var countryList = loadTimeData.getValue('autofillCountrySelectList');
223 306
224 // Add the countries to the country <select> list. 307 // Add the countries to the country <select> list.
225 var countrySelect = $('country'); 308 var countrySelect = this.getCountrySelector_();
226 // Add an empty option. 309 // Add an empty option.
227 countrySelect.appendChild(new Option('', '')); 310 countrySelect.appendChild(new Option('', ''));
228 for (var i = 0; i < countryList.length; i++) { 311 for (var i = 0; i < countryList.length; i++) {
229 var option = new Option(countryList[i].name, 312 var option = new Option(countryList[i].name,
230 countryList[i].value); 313 countryList[i].value);
231 option.disabled = countryList[i].value == 'separator'; 314 option.disabled = countryList[i].value == 'separator';
232 countrySelect.appendChild(option); 315 countrySelect.appendChild(option);
233 } 316 }
234 }, 317 },
235 318
236 /** 319 /**
237 * Clears the value of each input field.
238 * @private
239 */
240 clearInputFields_: function() {
241 this.setMultiValueList_('full-name-list', []);
242 $('company-name').value = '';
243 $('addr-line-1').value = '';
244 $('addr-line-2').value = '';
245 $('city').value = '';
246 $('state').value = '';
247 $('postal-code').value = '';
248 $('country').value = '';
249 this.setMultiValueList_('phone-list', []);
250 this.setMultiValueList_('email-list', []);
251
252 this.countryChanged_();
253 },
254
255 /**
256 * Loads the address data from |address|, sets the input fields based on 320 * Loads the address data from |address|, sets the input fields based on
257 * this data and stores the GUID of the address. 321 * this data, and stores the GUID and language code of the address.
258 * @private 322 * @private
259 */ 323 */
260 loadAddress_: function(address) { 324 loadAddress_: function(address) {
325 this.rebuildInputFields_(address.components);
261 this.setInputFields_(address); 326 this.setInputFields_(address);
262 this.inputFieldChanged_(); 327 this.inputFieldChanged_();
328 this.connectInputEvents_();
263 this.guid = address.guid; 329 this.guid = address.guid;
330 this.languageCode = address.languageCode;
264 }, 331 },
265 332
266 /** 333 /**
267 * Sets the value of each input field according to |address| 334 * Takes a snapshot of the input values, clears the input values, loads the
335 * address input layout from |input.components|, restores the input values
336 * from snapshot, and stores the |input.languageCode| for the address.
268 * @private 337 * @private
269 */ 338 */
270 setInputFields_: function(address) { 339 loadAddressComponents_: function(input) {
271 this.setMultiValueList_('full-name-list', address.fullName); 340 var address = this.getInputFields_();
Dan Beam 2014/05/06 03:51:09 why is this named address?
272 $('company-name').value = address.companyName; 341 this.rebuildInputFields_(input.components);
273 $('addr-line-1').value = address.addrLine1; 342 this.setInputFields_(address);
274 $('addr-line-2').value = address.addrLine2; 343 this.inputFieldChanged_();
275 $('city').value = address.city; 344 this.connectInputEvents_();
276 $('state').value = address.state; 345 this.languageCode = input.languageCode;
277 $('postal-code').value = address.postalCode; 346 },
278 $('country').value = address.country;
279 this.setMultiValueList_('phone-list', address.phone);
280 this.setMultiValueList_('email-list', address.email);
281 347
282 this.countryChanged_(); 348 /**
349 * Clears address inputs and rebuilds the input fields according to
350 * |components|.
Dan Beam 2014/05/06 03:51:09 @param {<some_type>} components
351 * @private
352 */
353 rebuildInputFields_: function(components) {
354 var content = $('autofill-edit-address-fields');
355 while (content.firstChild) {
356 content.removeChild(content.firstChild);
357 }
Dan Beam 2014/05/06 03:51:09 content.innerHTML = '';
358
359 var customContainerElements = {'fullName': 'div'};
360 var customInputElements = {'fullName': 'list', 'addrLines': 'textarea'};
Dan Beam 2014/05/06 03:51:09 opt nit: don't need ' around keys in this case
361
362 for (var i in components) {
363 var row = document.createElement('div');
364 row.classList.add('input-group', 'settings-row');
365 content.appendChild(row);
366
367 for (var j in components[i]) {
368 if (components[i][j].field == 'country')
369 continue;
370
371 var fieldContainer = document.createElement(
372 customContainerElements[components[i][j].field] || 'label');
373 row.appendChild(fieldContainer);
374
375 var fieldName = document.createElement('div');
376 fieldName.textContent = components[i][j].name;
377 fieldContainer.appendChild(fieldName);
378
379 var input = document.createElement(
380 customInputElements[components[i][j].field] || 'input');
381 input.setAttribute('field', components[i][j].field);
382 input.classList.add(components[i][j].length);
383 input.setAttribute('placeholder', components[i][j].placeholder || '');
384 fieldContainer.appendChild(input);
385
386 if (input.tagName == 'LIST') {
387 options.autofillOptions.AutofillValuesList.decorate(input);
388 input.autoExpands = true;
389 }
390 }
391 }
283 }, 392 },
284 }; 393 };
285 394
286 AutofillEditAddressOverlay.loadAddress = function(address) { 395 AutofillEditAddressOverlay.loadAddress = function(address) {
287 AutofillEditAddressOverlay.getInstance().loadAddress_(address); 396 AutofillEditAddressOverlay.getInstance().loadAddress_(address);
288 }; 397 };
289 398
399 AutofillEditAddressOverlay.loadAddressComponents = function(input) {
400 AutofillEditAddressOverlay.getInstance().loadAddressComponents_(input);
401 };
402
290 AutofillEditAddressOverlay.setTitle = function(title) { 403 AutofillEditAddressOverlay.setTitle = function(title) {
291 $('autofill-address-title').textContent = title; 404 $('autofill-address-title').textContent = title;
292 }; 405 };
293 406
294 AutofillEditAddressOverlay.setValidatedPhoneNumbers = function(numbers) { 407 AutofillEditAddressOverlay.setValidatedPhoneNumbers = function(numbers) {
295 AutofillEditAddressOverlay.getInstance().setMultiValueList_('phone-list', 408 var instance = AutofillEditAddressOverlay.getInstance();
296 numbers); 409 var phoneList = instance.pageDiv.querySelector('[field=phone]');
297 $('phone-list').didReceiveValidationResult(); 410 instance.setMultiValueList_(phoneList, numbers);
411 phoneList.didReceiveValidationResult();
298 }; 412 };
299 413
300 // Export 414 // Export
301 return { 415 return {
302 AutofillEditAddressOverlay: AutofillEditAddressOverlay 416 AutofillEditAddressOverlay: AutofillEditAddressOverlay
303 }; 417 };
304 }); 418 });
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698