| Index: chrome/browser/resources/options2/autofill_options_list.js
|
| diff --git a/chrome/browser/resources/options2/autofill_options_list.js b/chrome/browser/resources/options2/autofill_options_list.js
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..c9ed67ce9ff07d3aa0aaa37fa7ba5d20b3c142fd
|
| --- /dev/null
|
| +++ b/chrome/browser/resources/options2/autofill_options_list.js
|
| @@ -0,0 +1,506 @@
|
| +// Copyright (c) 2011 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.autofillOptions', function() {
|
| + const DeletableItem = options.DeletableItem;
|
| + const DeletableItemList = options.DeletableItemList;
|
| + const InlineEditableItem = options.InlineEditableItem;
|
| + const InlineEditableItemList = options.InlineEditableItemList;
|
| +
|
| + function AutofillEditProfileButton(guid, edit) {
|
| + var editButtonEl = document.createElement('button');
|
| + editButtonEl.className = 'raw-button custom-appearance';
|
| + editButtonEl.textContent =
|
| + templateData.autofillEditProfileButton;
|
| + editButtonEl.onclick = function(e) { edit(guid); };
|
| +
|
| + // Don't select the row when clicking the button.
|
| + editButtonEl.onmousedown = function(e) {
|
| + e.stopPropagation();
|
| + };
|
| +
|
| + return editButtonEl;
|
| + }
|
| +
|
| + /**
|
| + * Creates a new address list item.
|
| + * @param {Array} entry An array of the form [guid, label].
|
| + * @constructor
|
| + * @extends {options.DeletableItem}
|
| + */
|
| + function AddressListItem(entry) {
|
| + var el = cr.doc.createElement('div');
|
| + el.guid = entry[0];
|
| + el.label = entry[1];
|
| + el.__proto__ = AddressListItem.prototype;
|
| + el.decorate();
|
| +
|
| + return el;
|
| + }
|
| +
|
| + AddressListItem.prototype = {
|
| + __proto__: DeletableItem.prototype,
|
| +
|
| + /** @inheritDoc */
|
| + decorate: function() {
|
| + DeletableItem.prototype.decorate.call(this);
|
| +
|
| + // The stored label.
|
| + var label = this.ownerDocument.createElement('div');
|
| + label.className = 'autofill-list-item';
|
| + label.textContent = this.label;
|
| + this.contentElement.appendChild(label);
|
| +
|
| + // The 'Edit' button.
|
| + var editButtonEl = new AutofillEditProfileButton(
|
| + this.guid,
|
| + AutofillOptions.loadAddressEditor);
|
| + this.contentElement.appendChild(editButtonEl);
|
| + },
|
| + };
|
| +
|
| + /**
|
| + * Creates a new credit card list item.
|
| + * @param {Array} entry An array of the form [guid, label, icon].
|
| + * @constructor
|
| + * @extends {options.DeletableItem}
|
| + */
|
| + function CreditCardListItem(entry) {
|
| + var el = cr.doc.createElement('div');
|
| + el.guid = entry[0];
|
| + el.label = entry[1];
|
| + el.icon = entry[2];
|
| + el.description = entry[3];
|
| + el.__proto__ = CreditCardListItem.prototype;
|
| + el.decorate();
|
| +
|
| + return el;
|
| + }
|
| +
|
| + CreditCardListItem.prototype = {
|
| + __proto__: DeletableItem.prototype,
|
| +
|
| + /** @inheritDoc */
|
| + decorate: function() {
|
| + DeletableItem.prototype.decorate.call(this);
|
| +
|
| + // The stored label.
|
| + var label = this.ownerDocument.createElement('div');
|
| + label.className = 'autofill-list-item';
|
| + label.textContent = this.label;
|
| + this.contentElement.appendChild(label);
|
| +
|
| + // The credit card icon.
|
| + var icon = this.ownerDocument.createElement('image');
|
| + icon.src = this.icon;
|
| + icon.alt = this.description;
|
| + this.contentElement.appendChild(icon);
|
| +
|
| + // The 'Edit' button.
|
| + var editButtonEl = new AutofillEditProfileButton(
|
| + this.guid,
|
| + AutofillOptions.loadCreditCardEditor);
|
| + this.contentElement.appendChild(editButtonEl);
|
| + },
|
| + };
|
| +
|
| + /**
|
| + * Creates a new value list item.
|
| + * @param {AutofillValuesList} list The parent list of this item.
|
| + * @param {String} entry A string value.
|
| + * @constructor
|
| + * @extends {options.InlineEditableItem}
|
| + */
|
| + function ValuesListItem(list, entry) {
|
| + var el = cr.doc.createElement('div');
|
| + el.list = list;
|
| + el.value = entry ? entry : '';
|
| + el.__proto__ = ValuesListItem.prototype;
|
| + el.decorate();
|
| +
|
| + return el;
|
| + }
|
| +
|
| + ValuesListItem.prototype = {
|
| + __proto__: InlineEditableItem.prototype,
|
| +
|
| + /** @inheritDoc */
|
| + decorate: function() {
|
| + InlineEditableItem.prototype.decorate.call(this);
|
| +
|
| + // Note: This must be set prior to calling |createEditableTextCell|.
|
| + this.isPlaceholder = !this.value;
|
| +
|
| + // The stored value.
|
| + var cell = this.createEditableTextCell(this.value);
|
| + this.contentElement.appendChild(cell);
|
| + this.input = cell.querySelector('input');
|
| +
|
| + if (this.isPlaceholder) {
|
| + this.input.placeholder = this.list.getAttribute('placeholder');
|
| + this.deletable = false;
|
| + }
|
| +
|
| + this.addEventListener('commitedit', this.onEditCommitted_);
|
| + },
|
| +
|
| + /**
|
| + * @return This item's value.
|
| + * @protected
|
| + */
|
| + value_: function() {
|
| + return this.input.value;
|
| + },
|
| +
|
| + /**
|
| + * @param {Object} value The value to test.
|
| + * @return true if the given value is non-empty.
|
| + * @protected
|
| + */
|
| + valueIsNonEmpty_: function(value) {
|
| + return !!value;
|
| + },
|
| +
|
| + /**
|
| + * @return true if value1 is logically equal to value2.
|
| + */
|
| + valuesAreEqual_: function(value1, value2) {
|
| + return value1 === value2;
|
| + },
|
| +
|
| + /**
|
| + * Clears the item's value.
|
| + * @protected
|
| + */
|
| + clearValue_: function() {
|
| + this.input.value = '';
|
| + },
|
| +
|
| + /**
|
| + * Called when committing an edit.
|
| + * If this is an "Add ..." item, committing a non-empty value adds that
|
| + * value to the end of the values list, but also leaves this "Add ..." item
|
| + * in place.
|
| + * @param {Event} e The end event.
|
| + * @private
|
| + */
|
| + onEditCommitted_: function(e) {
|
| + var value = this.value_();
|
| + var i = this.list.items.indexOf(this);
|
| + if (i < this.list.dataModel.length &&
|
| + this.valuesAreEqual_(value, this.list.dataModel.item(i))) {
|
| + return;
|
| + }
|
| +
|
| + var entries = this.list.dataModel.slice();
|
| + if (this.valueIsNonEmpty_(value) &&
|
| + !entries.some(this.valuesAreEqual_.bind(this, value))) {
|
| + // Update with new value.
|
| + if (this.isPlaceholder) {
|
| + // It is important that updateIndex is done before validateAndSave.
|
| + // Otherwise we can not be sure about AddRow index.
|
| + this.list.dataModel.updateIndex(i);
|
| + this.list.validateAndSave(i, 0, value);
|
| + } else {
|
| + this.list.validateAndSave(i, 1, value);
|
| + }
|
| + } else {
|
| + // Reject empty values and duplicates.
|
| + if (!this.isPlaceholder)
|
| + this.list.dataModel.splice(i, 1);
|
| + else
|
| + this.clearValue_();
|
| + }
|
| + },
|
| + };
|
| +
|
| + /**
|
| + * Creates a new name value list item.
|
| + * @param {AutofillNameValuesList} list The parent list of this item.
|
| + * @param {array} entry An array of [first, middle, last] names.
|
| + * @constructor
|
| + * @extends {options.ValuesListItem}
|
| + */
|
| + function NameListItem(list, entry) {
|
| + var el = cr.doc.createElement('div');
|
| + el.list = list;
|
| + el.first = entry ? entry[0] : '';
|
| + el.middle = entry ? entry[1] : '';
|
| + el.last = entry ? entry[2] : '';
|
| + el.__proto__ = NameListItem.prototype;
|
| + el.decorate();
|
| +
|
| + return el;
|
| + }
|
| +
|
| + NameListItem.prototype = {
|
| + __proto__: ValuesListItem.prototype,
|
| +
|
| + /** @inheritDoc */
|
| + decorate: function() {
|
| + InlineEditableItem.prototype.decorate.call(this);
|
| +
|
| + // Note: This must be set prior to calling |createEditableTextCell|.
|
| + this.isPlaceholder = !this.first && !this.middle && !this.last;
|
| +
|
| + // The stored value.
|
| + // For the simulated static "input element" to display correctly, the
|
| + // value must not be empty. We use a space to force the UI to render
|
| + // correctly when the value is logically empty.
|
| + var cell = this.createEditableTextCell(this.first);
|
| + this.contentElement.appendChild(cell);
|
| + this.firstNameInput = cell.querySelector('input');
|
| +
|
| + cell = this.createEditableTextCell(this.middle);
|
| + this.contentElement.appendChild(cell);
|
| + this.middleNameInput = cell.querySelector('input');
|
| +
|
| + cell = this.createEditableTextCell(this.last);
|
| + this.contentElement.appendChild(cell);
|
| + this.lastNameInput = cell.querySelector('input');
|
| +
|
| + if (this.isPlaceholder) {
|
| + this.firstNameInput.placeholder =
|
| + templateData.autofillAddFirstNamePlaceholder;
|
| + this.middleNameInput.placeholder =
|
| + templateData.autofillAddMiddleNamePlaceholder;
|
| + this.lastNameInput.placeholder =
|
| + templateData.autofillAddLastNamePlaceholder;
|
| + this.deletable = false;
|
| + }
|
| +
|
| + this.addEventListener('commitedit', this.onEditCommitted_);
|
| + },
|
| +
|
| + /** @inheritDoc */
|
| + value_: function() {
|
| + return [ this.firstNameInput.value,
|
| + this.middleNameInput.value,
|
| + this.lastNameInput.value ];
|
| + },
|
| +
|
| + /** @inheritDoc */
|
| + valueIsNonEmpty_: function(value) {
|
| + return value[0] || value[1] || value[2];
|
| + },
|
| +
|
| + /** @inheritDoc */
|
| + valuesAreEqual_: function(value1, value2) {
|
| + // First, check for null values.
|
| + if (!value1 || !value2)
|
| + return value1 == value2;
|
| +
|
| + return value1[0] === value2[0] &&
|
| + value1[1] === value2[1] &&
|
| + value1[2] === value2[2];
|
| + },
|
| +
|
| + /** @inheritDoc */
|
| + clearValue_: function() {
|
| + this.firstNameInput.value = '';
|
| + this.middleNameInput.value = '';
|
| + this.lastNameInput.value = '';
|
| + },
|
| + };
|
| +
|
| + /**
|
| + * Base class for shared implementation between address and credit card lists.
|
| + * @constructor
|
| + * @extends {options.DeletableItemList}
|
| + */
|
| + var AutofillProfileList = cr.ui.define('list');
|
| +
|
| + AutofillProfileList.prototype = {
|
| + __proto__: DeletableItemList.prototype,
|
| +
|
| + decorate: function() {
|
| + DeletableItemList.prototype.decorate.call(this);
|
| +
|
| + this.addEventListener('blur', this.onBlur_);
|
| + },
|
| +
|
| + /**
|
| + * When the list loses focus, unselect all items in the list.
|
| + * @private
|
| + */
|
| + onBlur_: function() {
|
| + this.selectionModel.unselectAll();
|
| + },
|
| + };
|
| +
|
| + /**
|
| + * Create a new address list.
|
| + * @constructor
|
| + * @extends {options.AutofillProfileList}
|
| + */
|
| + var AutofillAddressList = cr.ui.define('list');
|
| +
|
| + AutofillAddressList.prototype = {
|
| + __proto__: AutofillProfileList.prototype,
|
| +
|
| + decorate: function() {
|
| + AutofillProfileList.prototype.decorate.call(this);
|
| + },
|
| +
|
| + /** @inheritDoc */
|
| + activateItemAtIndex: function(index) {
|
| + AutofillOptions.loadAddressEditor(this.dataModel.item(index)[0]);
|
| + },
|
| +
|
| + /** @inheritDoc */
|
| + createItem: function(entry) {
|
| + return new AddressListItem(entry);
|
| + },
|
| +
|
| + /** @inheritDoc */
|
| + deleteItemAtIndex: function(index) {
|
| + AutofillOptions.removeAddress(this.dataModel.item(index)[0]);
|
| + },
|
| + };
|
| +
|
| + /**
|
| + * Create a new credit card list.
|
| + * @constructor
|
| + * @extends {options.DeletableItemList}
|
| + */
|
| + var AutofillCreditCardList = cr.ui.define('list');
|
| +
|
| + AutofillCreditCardList.prototype = {
|
| + __proto__: AutofillProfileList.prototype,
|
| +
|
| + decorate: function() {
|
| + AutofillProfileList.prototype.decorate.call(this);
|
| + },
|
| +
|
| + /** @inheritDoc */
|
| + activateItemAtIndex: function(index) {
|
| + AutofillOptions.loadCreditCardEditor(this.dataModel.item(index)[0]);
|
| + },
|
| +
|
| + /** @inheritDoc */
|
| + createItem: function(entry) {
|
| + return new CreditCardListItem(entry);
|
| + },
|
| +
|
| + /** @inheritDoc */
|
| + deleteItemAtIndex: function(index) {
|
| + AutofillOptions.removeCreditCard(this.dataModel.item(index)[0]);
|
| + },
|
| + };
|
| +
|
| + /**
|
| + * Create a new value list.
|
| + * @constructor
|
| + * @extends {options.InlineEditableItemList}
|
| + */
|
| + var AutofillValuesList = cr.ui.define('list');
|
| +
|
| + AutofillValuesList.prototype = {
|
| + __proto__: InlineEditableItemList.prototype,
|
| +
|
| + /** @inheritDoc */
|
| + createItem: function(entry) {
|
| + return new ValuesListItem(this, entry);
|
| + },
|
| +
|
| + /** @inheritDoc */
|
| + deleteItemAtIndex: function(index) {
|
| + this.dataModel.splice(index, 1);
|
| + },
|
| +
|
| + /** @inheritDoc */
|
| + shouldFocusPlaceholder: function() {
|
| + return false;
|
| + },
|
| +
|
| + /**
|
| + * Called when the list hierarchy as a whole loses or gains focus.
|
| + * If the list was focused in response to a mouse click, call into the
|
| + * superclass's implementation. If the list was focused in response to a
|
| + * keyboard navigation, focus the first item.
|
| + * If the list loses focus, unselect all the elements.
|
| + * @param {Event} e The change event.
|
| + * @private
|
| + */
|
| + handleListFocusChange_: function(e) {
|
| + // We check to see whether there is a selected item as a proxy for
|
| + // distinguishing between mouse- and keyboard-originated focus events.
|
| + var selectedItem = this.selectedItem;
|
| + if (selectedItem)
|
| + InlineEditableItemList.prototype.handleListFocusChange_.call(this, e);
|
| +
|
| + if (!e.newValue) {
|
| + // When the list loses focus, unselect all the elements.
|
| + this.selectionModel.unselectAll();
|
| + } else {
|
| + // When the list gains focus, select the first item if nothing else is
|
| + // selected.
|
| + var firstItem = this.getListItemByIndex(0);
|
| + if (!selectedItem && firstItem && e.newValue)
|
| + firstItem.handleFocus_();
|
| + }
|
| + },
|
| +
|
| + /**
|
| + * Called when a new list item should be validated; subclasses are
|
| + * responsible for implementing if validation is required.
|
| + * @param {number} index The index of the item that was inserted or changed.
|
| + * @param {number} remove The number items to remove.
|
| + * @param {string} value The value of the item to insert.
|
| + */
|
| + validateAndSave: function(index, remove, value) {
|
| + this.dataModel.splice(index, remove, value);
|
| + },
|
| + };
|
| +
|
| + /**
|
| + * Create a new value list for phone number validation.
|
| + * @constructor
|
| + * @extends {options.AutofillValuesList}
|
| + */
|
| + var AutofillNameValuesList = cr.ui.define('list');
|
| +
|
| + AutofillNameValuesList.prototype = {
|
| + __proto__: AutofillValuesList.prototype,
|
| +
|
| + /** @inheritDoc */
|
| + createItem: function(entry) {
|
| + return new NameListItem(this, entry);
|
| + },
|
| + };
|
| +
|
| + /**
|
| + * Create a new value list for phone number validation.
|
| + * @constructor
|
| + * @extends {options.AutofillValuesList}
|
| + */
|
| + var AutofillPhoneValuesList = cr.ui.define('list');
|
| +
|
| + AutofillPhoneValuesList.prototype = {
|
| + __proto__: AutofillValuesList.prototype,
|
| +
|
| + /** @inheritDoc */
|
| + validateAndSave: function(index, remove, value) {
|
| + var numbers = this.dataModel.slice(0, this.dataModel.length - 1);
|
| + numbers.splice(index, remove, value);
|
| + var info = new Array();
|
| + info[0] = index;
|
| + info[1] = numbers;
|
| + info[2] = $('country').value;
|
| + chrome.send('validatePhoneNumbers', info);
|
| + },
|
| + };
|
| +
|
| + return {
|
| + AddressListItem: AddressListItem,
|
| + CreditCardListItem: CreditCardListItem,
|
| + ValuesListItem: ValuesListItem,
|
| + NameListItem: NameListItem,
|
| + AutofillAddressList: AutofillAddressList,
|
| + AutofillCreditCardList: AutofillCreditCardList,
|
| + AutofillValuesList: AutofillValuesList,
|
| + AutofillNameValuesList: AutofillNameValuesList,
|
| + AutofillPhoneValuesList: AutofillPhoneValuesList,
|
| + };
|
| +});
|
|
|