1// Copyright (c) 2011 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. 4 5cr.define('options.autofillOptions', function() { 6 const DeletableItem = options.DeletableItem; 7 const DeletableItemList = options.DeletableItemList; 8 const InlineEditableItem = options.InlineEditableItem; 9 const InlineEditableItemList = options.InlineEditableItemList; 10 11 /** 12 * Creates a new address list item. 13 * @param {Array} entry An array of the form [guid, label]. 14 * @constructor 15 * @extends {options.DeletableItem} 16 */ 17 function AddressListItem(entry) { 18 var el = cr.doc.createElement('div'); 19 el.guid = entry[0]; 20 el.label = entry[1]; 21 el.__proto__ = AddressListItem.prototype; 22 el.decorate(); 23 24 return el; 25 } 26 27 AddressListItem.prototype = { 28 __proto__: DeletableItem.prototype, 29 30 /** @inheritDoc */ 31 decorate: function() { 32 DeletableItem.prototype.decorate.call(this); 33 34 // The stored label. 35 var label = this.ownerDocument.createElement('div'); 36 label.className = 'autofill-list-item'; 37 label.textContent = this.label; 38 this.contentElement.appendChild(label); 39 }, 40 }; 41 42 /** 43 * Creates a new credit card list item. 44 * @param {Array} entry An array of the form [guid, label, icon]. 45 * @constructor 46 * @extends {options.DeletableItem} 47 */ 48 function CreditCardListItem(entry) { 49 var el = cr.doc.createElement('div'); 50 el.guid = entry[0]; 51 el.label = entry[1]; 52 el.icon = entry[2]; 53 el.description = entry[3]; 54 el.__proto__ = CreditCardListItem.prototype; 55 el.decorate(); 56 57 return el; 58 } 59 60 CreditCardListItem.prototype = { 61 __proto__: DeletableItem.prototype, 62 63 /** @inheritDoc */ 64 decorate: function() { 65 DeletableItem.prototype.decorate.call(this); 66 67 // The stored label. 68 var label = this.ownerDocument.createElement('div'); 69 label.className = 'autofill-list-item'; 70 label.textContent = this.label; 71 this.contentElement.appendChild(label); 72 73 // The credit card icon. 74 var icon = this.ownerDocument.createElement('image'); 75 icon.src = this.icon; 76 icon.alt = this.description; 77 this.contentElement.appendChild(icon); 78 }, 79 }; 80 81 /** 82 * Creates a new value list item. 83 * @param {AutofillValuesList} list The parent list of this item. 84 * @param {String} entry A string value. 85 * @constructor 86 * @extends {options.InlineEditableItem} 87 */ 88 function ValuesListItem(list, entry) { 89 var el = cr.doc.createElement('div'); 90 el.list = list; 91 el.value = entry; 92 el.__proto__ = ValuesListItem.prototype; 93 el.decorate(); 94 95 return el; 96 } 97 98 ValuesListItem.prototype = { 99 __proto__: InlineEditableItem.prototype, 100 101 /** @inheritDoc */ 102 decorate: function() { 103 InlineEditableItem.prototype.decorate.call(this); 104 105 this.isPlaceholder = !this.value; 106 107 // The stored value. 108 var cell = this.createEditableTextCell(this.value); 109 this.contentElement.appendChild(cell); 110 this.input = cell.querySelector('input'); 111 112 this.addEventListener('commitedit', this.onEditCommitted_); 113 }, 114 115 /** 116 * Called when committing an edit. 117 * @param {Event} e The end event. 118 * @private 119 */ 120 onEditCommitted_: function(e) { 121 var i = this.list.items.indexOf(this); 122 if (this.input.value == this.list.dataModel.item(i)) 123 return; 124 125 if (this.input.value && 126 this.list.dataModel.indexOf(this.input.value) == -1) { 127 // Update with new value. 128 this.list.dataModel.splice(i, 1, this.input.value); 129 } else { 130 // Reject empty values and duplicates. 131 this.list.dataModel.splice(i, 1); 132 } 133 }, 134 }; 135 136 /** 137 * Creates a new list item for the Add New Item row, which doesn't represent 138 * an actual entry in the values list but allows the user to add new 139 * values. 140 * @param {AutofillValuesList} entry The parent list of this item. 141 * @constructor 142 * @extends {cr.ui.ValuesListItem} 143 */ 144 function ValuesAddRowListItem(list) { 145 var el = cr.doc.createElement('div'); 146 el.list = list; 147 el.__proto__ = ValuesAddRowListItem.prototype; 148 el.decorate(); 149 150 return el; 151 } 152 153 ValuesAddRowListItem.prototype = { 154 __proto__: ValuesListItem.prototype, 155 156 decorate: function() { 157 ValuesListItem.prototype.decorate.call(this); 158 this.input.value = ''; 159 this.input.placeholder = this.list.getAttribute('placeholder'); 160 this.deletable = false; 161 }, 162 163 /** 164 * Called when committing an edit. Committing a non-empty value adds it 165 * to the end of the values list, leaving this "AddRow" in place. 166 * @param {Event} e The end event. 167 * @extends {options.ValuesListItem} 168 * @private 169 */ 170 onEditCommitted_: function(e) { 171 var i = this.list.items.indexOf(this); 172 if (i < 0 || i >= this.list.dataModel.length) 173 return; 174 175 if (this.input.value && 176 this.list.dataModel.indexOf(this.input.value) == -1) { 177 this.list.dataModel.splice(i, 0, this.input.value); 178 } else { 179 this.input.value = ''; 180 this.list.dataModel.updateIndex(i); 181 } 182 }, 183 }; 184 185 /** 186 * Create a new address list. 187 * @constructor 188 * @extends {options.DeletableItemList} 189 */ 190 var AutofillAddressList = cr.ui.define('list'); 191 192 AutofillAddressList.prototype = { 193 __proto__: DeletableItemList.prototype, 194 195 decorate: function() { 196 DeletableItemList.prototype.decorate.call(this); 197 198 this.addEventListener('blur', this.onBlur_); 199 }, 200 201 /** 202 * When the list loses focus, unselect all items in the list. 203 * @private 204 */ 205 onBlur_: function() { 206 this.selectionModel.unselectAll(); 207 }, 208 209 /** @inheritDoc */ 210 createItem: function(entry) { 211 return new AddressListItem(entry); 212 }, 213 214 /** @inheritDoc */ 215 activateItemAtIndex: function(index) { 216 AutofillOptions.loadAddressEditor(this.dataModel.item(index)[0]); 217 }, 218 219 /** @inheritDoc */ 220 deleteItemAtIndex: function(index) { 221 AutofillOptions.removeAddress(this.dataModel.item(index)[0]); 222 }, 223 }; 224 225 /** 226 * Create a new credit card list. 227 * @constructor 228 * @extends {options.DeletableItemList} 229 */ 230 var AutofillCreditCardList = cr.ui.define('list'); 231 232 AutofillCreditCardList.prototype = { 233 __proto__: DeletableItemList.prototype, 234 235 decorate: function() { 236 DeletableItemList.prototype.decorate.call(this); 237 238 this.addEventListener('blur', this.onBlur_); 239 }, 240 241 /** 242 * When the list loses focus, unselect all items in the list. 243 * @private 244 */ 245 onBlur_: function() { 246 this.selectionModel.unselectAll(); 247 }, 248 249 /** @inheritDoc */ 250 createItem: function(entry) { 251 return new CreditCardListItem(entry); 252 }, 253 254 /** @inheritDoc */ 255 activateItemAtIndex: function(index) { 256 AutofillOptions.loadCreditCardEditor(this.dataModel.item(index)[0]); 257 }, 258 259 /** @inheritDoc */ 260 deleteItemAtIndex: function(index) { 261 AutofillOptions.removeCreditCard(this.dataModel.item(index)[0]); 262 }, 263 }; 264 265 /** 266 * Create a new value list. 267 * @constructor 268 * @extends {options.InlineEditableItemList} 269 */ 270 var AutofillValuesList = cr.ui.define('list'); 271 272 AutofillValuesList.prototype = { 273 __proto__: InlineEditableItemList.prototype, 274 275 decorate: function() { 276 InlineEditableItemList.prototype.decorate.call(this); 277 278 var self = this; 279 function handleBlur(e) { 280 // When the blur event happens we do not know who is getting focus so we 281 // delay this a bit until we know if the new focus node is outside the 282 // list. 283 var doc = e.target.ownerDocument; 284 window.setTimeout(function() { 285 var activeElement = doc.activeElement; 286 if (!self.contains(activeElement)) 287 self.selectionModel.unselectAll(); 288 }, 50); 289 } 290 291 this.addEventListener('blur', handleBlur, true); 292 }, 293 294 /** @inheritDoc */ 295 createItem: function(entry) { 296 if (entry != null) 297 return new ValuesListItem(this, entry); 298 else 299 return new ValuesAddRowListItem(this); 300 }, 301 302 /** @inheritDoc */ 303 deleteItemAtIndex: function(index) { 304 this.dataModel.splice(index, 1); 305 }, 306 }; 307 308 return { 309 AddressListItem: AddressListItem, 310 CreditCardListItem: CreditCardListItem, 311 ValuesListItem: ValuesListItem, 312 ValuesAddRowListItem: ValuesAddRowListItem, 313 AutofillAddressList: AutofillAddressList, 314 AutofillCreditCardList: AutofillCreditCardList, 315 AutofillValuesList: AutofillValuesList, 316 }; 317}); 318