| OLD | NEW |
| 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 /** | 5 /** |
| 6 * @typedef {{ | 6 * @typedef {{ |
| 7 * guid: string, | 7 * guid: string, |
| 8 * label: string, | 8 * label: string, |
| 9 * sublabel: string, | 9 * sublabel: string, |
| 10 * isLocal: boolean, | 10 * isLocal: boolean, |
| (...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 176 */ | 176 */ |
| 177 loadCreditCardEditor: function() { | 177 loadCreditCardEditor: function() { |
| 178 if (this.metadata_.isLocal) | 178 if (this.metadata_.isLocal) |
| 179 chrome.send('loadCreditCardEditor', [this.metadata_.guid]); | 179 chrome.send('loadCreditCardEditor', [this.metadata_.guid]); |
| 180 else | 180 else |
| 181 window.open(loadTimeData.getString('manageWalletPaymentMethodsUrl')); | 181 window.open(loadTimeData.getString('manageWalletPaymentMethodsUrl')); |
| 182 }, | 182 }, |
| 183 }; | 183 }; |
| 184 | 184 |
| 185 /** | 185 /** |
| 186 * Creates a new value list item. | |
| 187 * @param {options.autofillOptions.AutofillValuesList} list The parent list of | |
| 188 * this item. | |
| 189 * @param {string} entry A string value. | |
| 190 * @constructor | |
| 191 * @extends {options.InlineEditableItem} | |
| 192 */ | |
| 193 function ValuesListItem(list, entry) { | |
| 194 var el = cr.doc.createElement('div'); | |
| 195 el.list = list; | |
| 196 el.value = entry ? entry : ''; | |
| 197 el.__proto__ = ValuesListItem.prototype; | |
| 198 el.decorate(); | |
| 199 | |
| 200 return el; | |
| 201 } | |
| 202 | |
| 203 ValuesListItem.prototype = { | |
| 204 __proto__: InlineEditableItem.prototype, | |
| 205 | |
| 206 /** @override */ | |
| 207 decorate: function() { | |
| 208 InlineEditableItem.prototype.decorate.call(this); | |
| 209 | |
| 210 // Note: This must be set prior to calling |createEditableTextCell|. | |
| 211 this.isPlaceholder = !this.value; | |
| 212 | |
| 213 // The stored value. | |
| 214 var cell = this.createEditableTextCell(String(this.value)); | |
| 215 this.contentElement.appendChild(cell); | |
| 216 this.input = cell.querySelector('input'); | |
| 217 | |
| 218 if (this.isPlaceholder) { | |
| 219 this.input.placeholder = this.list.getAttribute('placeholder'); | |
| 220 this.deletable = false; | |
| 221 } | |
| 222 | |
| 223 this.addEventListener('commitedit', this.onEditCommitted_); | |
| 224 this.closeButtonFocusAllowed = true; | |
| 225 this.setFocusableColumnIndex(this.input, 0); | |
| 226 this.setFocusableColumnIndex(this.closeButtonElement, 1); | |
| 227 }, | |
| 228 | |
| 229 /** | |
| 230 * @return {Array} This item's value. | |
| 231 * @protected | |
| 232 */ | |
| 233 value_: function() { | |
| 234 return this.input.value; | |
| 235 }, | |
| 236 | |
| 237 /** | |
| 238 * @param {*} value The value to test. | |
| 239 * @return {boolean} True if the given value is non-empty. | |
| 240 * @protected | |
| 241 */ | |
| 242 valueIsNonEmpty_: function(value) { | |
| 243 return !!value; | |
| 244 }, | |
| 245 | |
| 246 /** | |
| 247 * @return {boolean} True if value1 is logically equal to value2. | |
| 248 */ | |
| 249 valuesAreEqual_: function(value1, value2) { | |
| 250 return value1 === value2; | |
| 251 }, | |
| 252 | |
| 253 /** | |
| 254 * Clears the item's value. | |
| 255 * @protected | |
| 256 */ | |
| 257 clearValue_: function() { | |
| 258 this.input.value = ''; | |
| 259 }, | |
| 260 | |
| 261 /** | |
| 262 * Called when committing an edit. | |
| 263 * If this is an "Add ..." item, committing a non-empty value adds that | |
| 264 * value to the end of the values list, but also leaves this "Add ..." item | |
| 265 * in place. | |
| 266 * @param {Event} e The end event. | |
| 267 * @private | |
| 268 */ | |
| 269 onEditCommitted_: function(e) { | |
| 270 var value = this.value_(); | |
| 271 var i = this.list.items.indexOf(this); | |
| 272 if (i < this.list.dataModel.length && | |
| 273 this.valuesAreEqual_(value, this.list.dataModel.item(i))) { | |
| 274 return; | |
| 275 } | |
| 276 | |
| 277 var entries = this.list.dataModel.slice(); | |
| 278 if (this.valueIsNonEmpty_(value) && | |
| 279 !entries.some(this.valuesAreEqual_.bind(this, value))) { | |
| 280 // Update with new value. | |
| 281 if (this.isPlaceholder) { | |
| 282 // It is important that updateIndex is done before validateAndSave. | |
| 283 // Otherwise we can not be sure about AddRow index. | |
| 284 this.list.ignoreChangeEvents(function() { | |
| 285 this.list.dataModel.updateIndex(i); | |
| 286 }.bind(this)); | |
| 287 this.list.validateAndSave(i, 0, value); | |
| 288 } else { | |
| 289 this.list.validateAndSave(i, 1, value); | |
| 290 } | |
| 291 } else { | |
| 292 // Reject empty values and duplicates. | |
| 293 if (!this.isPlaceholder) { | |
| 294 this.list.ignoreChangeEvents(function() { | |
| 295 this.list.dataModel.splice(i, 1); | |
| 296 }.bind(this)); | |
| 297 this.list.selectIndexWithoutFocusing(i); | |
| 298 } else { | |
| 299 this.clearValue_(); | |
| 300 } | |
| 301 } | |
| 302 }, | |
| 303 }; | |
| 304 | |
| 305 /** | |
| 306 * Creates a new name value list item. | |
| 307 * @param {options.autofillOptions.AutofillNameValuesList} list The parent | |
| 308 * list of this item. | |
| 309 * @param {Array<string>} entry An array of [first, middle, last] names. | |
| 310 * @constructor | |
| 311 * @extends {options.autofillOptions.ValuesListItem} | |
| 312 */ | |
| 313 function NameListItem(list, entry) { | |
| 314 var el = cr.doc.createElement('div'); | |
| 315 el.list = list; | |
| 316 el.first = entry ? entry[0] : ''; | |
| 317 el.middle = entry ? entry[1] : ''; | |
| 318 el.last = entry ? entry[2] : ''; | |
| 319 el.__proto__ = NameListItem.prototype; | |
| 320 el.decorate(); | |
| 321 | |
| 322 return el; | |
| 323 } | |
| 324 | |
| 325 NameListItem.prototype = { | |
| 326 __proto__: ValuesListItem.prototype, | |
| 327 | |
| 328 /** @override */ | |
| 329 decorate: function() { | |
| 330 InlineEditableItem.prototype.decorate.call(this); | |
| 331 | |
| 332 // Note: This must be set prior to calling |createEditableTextCell|. | |
| 333 this.isPlaceholder = !this.first && !this.middle && !this.last; | |
| 334 | |
| 335 // The stored value. | |
| 336 // For the simulated static "input element" to display correctly, the | |
| 337 // value must not be empty. We use a space to force the UI to render | |
| 338 // correctly when the value is logically empty. | |
| 339 var cell = this.createEditableTextCell(this.first); | |
| 340 this.contentElement.appendChild(cell); | |
| 341 this.firstNameInput = cell.querySelector('input'); | |
| 342 | |
| 343 cell = this.createEditableTextCell(this.middle); | |
| 344 this.contentElement.appendChild(cell); | |
| 345 this.middleNameInput = cell.querySelector('input'); | |
| 346 | |
| 347 cell = this.createEditableTextCell(this.last); | |
| 348 this.contentElement.appendChild(cell); | |
| 349 this.lastNameInput = cell.querySelector('input'); | |
| 350 | |
| 351 if (this.isPlaceholder) { | |
| 352 this.firstNameInput.placeholder = | |
| 353 loadTimeData.getString('autofillAddFirstNamePlaceholder'); | |
| 354 this.middleNameInput.placeholder = | |
| 355 loadTimeData.getString('autofillAddMiddleNamePlaceholder'); | |
| 356 this.lastNameInput.placeholder = | |
| 357 loadTimeData.getString('autofillAddLastNamePlaceholder'); | |
| 358 this.deletable = false; | |
| 359 } | |
| 360 | |
| 361 this.addEventListener('commitedit', this.onEditCommitted_); | |
| 362 }, | |
| 363 | |
| 364 /** @override */ | |
| 365 value_: function() { | |
| 366 return [this.firstNameInput.value, | |
| 367 this.middleNameInput.value, | |
| 368 this.lastNameInput.value]; | |
| 369 }, | |
| 370 | |
| 371 /** @override */ | |
| 372 valueIsNonEmpty_: function(value) { | |
| 373 return value[0] || value[1] || value[2]; | |
| 374 }, | |
| 375 | |
| 376 /** @override */ | |
| 377 valuesAreEqual_: function(value1, value2) { | |
| 378 // First, check for null values. | |
| 379 if (!value1 || !value2) | |
| 380 return value1 == value2; | |
| 381 | |
| 382 return value1[0] === value2[0] && | |
| 383 value1[1] === value2[1] && | |
| 384 value1[2] === value2[2]; | |
| 385 }, | |
| 386 | |
| 387 /** @override */ | |
| 388 clearValue_: function() { | |
| 389 this.firstNameInput.value = ''; | |
| 390 this.middleNameInput.value = ''; | |
| 391 this.lastNameInput.value = ''; | |
| 392 }, | |
| 393 }; | |
| 394 | |
| 395 /** | |
| 396 * Base class for shared implementation between address and credit card lists. | 186 * Base class for shared implementation between address and credit card lists. |
| 397 * @constructor | 187 * @constructor |
| 398 * @extends {options.DeletableItemList} | 188 * @extends {options.DeletableItemList} |
| 399 */ | 189 */ |
| 400 var AutofillProfileList = cr.ui.define('list'); | 190 var AutofillProfileList = cr.ui.define('list'); |
| 401 | 191 |
| 402 AutofillProfileList.prototype = { | 192 AutofillProfileList.prototype = { |
| 403 __proto__: DeletableItemList.prototype, | 193 __proto__: DeletableItemList.prototype, |
| 404 | 194 |
| 405 decorate: function() { | 195 decorate: function() { |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 478 return new CreditCardListItem(metadata); | 268 return new CreditCardListItem(metadata); |
| 479 }, | 269 }, |
| 480 | 270 |
| 481 /** @override */ | 271 /** @override */ |
| 482 deleteItemAtIndex: function(index) { | 272 deleteItemAtIndex: function(index) { |
| 483 AutofillOptions.removeData(this.dataModel.item(index).guid, | 273 AutofillOptions.removeData(this.dataModel.item(index).guid, |
| 484 'Options_AutofillCreditCardDeleted'); | 274 'Options_AutofillCreditCardDeleted'); |
| 485 }, | 275 }, |
| 486 }; | 276 }; |
| 487 | 277 |
| 488 /** | |
| 489 * Create a new value list. | |
| 490 * @constructor | |
| 491 * @extends {options.InlineEditableItemList} | |
| 492 */ | |
| 493 var AutofillValuesList = cr.ui.define('list'); | |
| 494 | |
| 495 AutofillValuesList.prototype = { | |
| 496 __proto__: InlineEditableItemList.prototype, | |
| 497 | |
| 498 /** @override */ | |
| 499 createItem: function(entry) { | |
| 500 assert(entry === null || typeof entry == 'string'); | |
| 501 return new ValuesListItem(this, entry); | |
| 502 }, | |
| 503 | |
| 504 /** @override */ | |
| 505 deleteItemAtIndex: function(index) { | |
| 506 this.dataModel.splice(index, 1); | |
| 507 }, | |
| 508 | |
| 509 /** @override */ | |
| 510 shouldFocusPlaceholderOnEditCommit: function() { | |
| 511 return false; | |
| 512 }, | |
| 513 | |
| 514 /** | |
| 515 * Called when a new list item should be validated; subclasses are | |
| 516 * responsible for implementing if validation is required. | |
| 517 * @param {number} index The index of the item that was inserted or changed. | |
| 518 * @param {number} remove The number items to remove. | |
| 519 * @param {string} value The value of the item to insert. | |
| 520 */ | |
| 521 validateAndSave: function(index, remove, value) { | |
| 522 this.ignoreChangeEvents(function() { | |
| 523 this.dataModel.splice(index, remove, value); | |
| 524 }.bind(this)); | |
| 525 this.selectIndexWithoutFocusing(index); | |
| 526 }, | |
| 527 }; | |
| 528 | |
| 529 /** | |
| 530 * Create a new value list for phone number validation. | |
| 531 * @constructor | |
| 532 * @extends {options.autofillOptions.AutofillValuesList} | |
| 533 */ | |
| 534 var AutofillNameValuesList = cr.ui.define('list'); | |
| 535 | |
| 536 AutofillNameValuesList.prototype = { | |
| 537 __proto__: AutofillValuesList.prototype, | |
| 538 | |
| 539 /** | |
| 540 * @override | |
| 541 * @param {?string|Array<string>} entry | |
| 542 */ | |
| 543 createItem: function(entry) { | |
| 544 var arrayOrNull = entry ? assertInstanceof(entry, Array) : null; | |
| 545 return new NameListItem(this, arrayOrNull); | |
| 546 }, | |
| 547 }; | |
| 548 | |
| 549 /** | |
| 550 * Create a new value list for phone number validation. | |
| 551 * @constructor | |
| 552 * @extends {options.autofillOptions.AutofillValuesList} | |
| 553 */ | |
| 554 var AutofillPhoneValuesList = cr.ui.define('list'); | |
| 555 | |
| 556 AutofillPhoneValuesList.prototype = { | |
| 557 __proto__: AutofillValuesList.prototype, | |
| 558 | |
| 559 /** @override */ | |
| 560 validateAndSave: function(index, remove, value) { | |
| 561 var numbers = this.dataModel.slice(0, this.dataModel.length - 1); | |
| 562 numbers.splice(index, remove, value); | |
| 563 var info = new Array(); | |
| 564 info[0] = index; | |
| 565 info[1] = numbers; | |
| 566 info[2] = document.querySelector( | |
| 567 '#autofill-edit-address-overlay [field=country]').value; | |
| 568 this.validationRequests_++; | |
| 569 chrome.send('validatePhoneNumbers', info); | |
| 570 }, | |
| 571 | |
| 572 /** | |
| 573 * The number of ongoing validation requests. | |
| 574 * @type {number} | |
| 575 * @private | |
| 576 */ | |
| 577 validationRequests_: 0, | |
| 578 | |
| 579 /** | |
| 580 * Pending Promise resolver functions. | |
| 581 * @type {Array<!Function>} | |
| 582 * @private | |
| 583 */ | |
| 584 validationPromiseResolvers_: [], | |
| 585 | |
| 586 /** | |
| 587 * This should be called when a reply of chrome.send('validatePhoneNumbers') | |
| 588 * is received. | |
| 589 */ | |
| 590 didReceiveValidationResult: function() { | |
| 591 this.validationRequests_--; | |
| 592 assert(this.validationRequests_ >= 0); | |
| 593 if (this.validationRequests_ <= 0) { | |
| 594 while (this.validationPromiseResolvers_.length) { | |
| 595 this.validationPromiseResolvers_.pop()(); | |
| 596 } | |
| 597 } | |
| 598 }, | |
| 599 | |
| 600 /** | |
| 601 * Returns a Promise which is fulfilled when all of validation requests are | |
| 602 * completed. | |
| 603 * @return {!Promise} A promise. | |
| 604 */ | |
| 605 doneValidating: function() { | |
| 606 if (this.validationRequests_ <= 0) | |
| 607 return Promise.resolve(); | |
| 608 return new Promise(function(resolve) { | |
| 609 this.validationPromiseResolvers_.push(resolve); | |
| 610 }.bind(this)); | |
| 611 } | |
| 612 }; | |
| 613 | |
| 614 return { | 278 return { |
| 615 AutofillProfileList: AutofillProfileList, | 279 AutofillProfileList: AutofillProfileList, |
| 616 AddressListItem: AddressListItem, | 280 AddressListItem: AddressListItem, |
| 617 CreditCardListItem: CreditCardListItem, | 281 CreditCardListItem: CreditCardListItem, |
| 618 ValuesListItem: ValuesListItem, | |
| 619 NameListItem: NameListItem, | |
| 620 AutofillAddressList: AutofillAddressList, | 282 AutofillAddressList: AutofillAddressList, |
| 621 AutofillCreditCardList: AutofillCreditCardList, | 283 AutofillCreditCardList: AutofillCreditCardList, |
| 622 AutofillValuesList: AutofillValuesList, | |
| 623 AutofillNameValuesList: AutofillNameValuesList, | |
| 624 AutofillPhoneValuesList: AutofillPhoneValuesList, | |
| 625 }; | 284 }; |
| 626 }); | 285 }); |
| OLD | NEW |