OLD | NEW |
| (Empty) |
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. | |
4 | |
5 cr.define('options.autofillOptions', function() { | |
6 /** @const */ var DeletableItem = options.DeletableItem; | |
7 /** @const */ var DeletableItemList = options.DeletableItemList; | |
8 /** @const */ var InlineEditableItem = options.InlineEditableItem; | |
9 /** @const */ var InlineEditableItemList = options.InlineEditableItemList; | |
10 | |
11 function AutofillEditProfileButton(guid, edit) { | |
12 var editButtonEl = document.createElement('button'); | |
13 editButtonEl.className = 'list-inline-button custom-appearance'; | |
14 editButtonEl.textContent = | |
15 loadTimeData.getString('autofillEditProfileButton'); | |
16 editButtonEl.onclick = function(e) { edit(guid); }; | |
17 | |
18 // Don't select the row when clicking the button. | |
19 editButtonEl.onmousedown = function(e) { | |
20 e.stopPropagation(); | |
21 }; | |
22 | |
23 return editButtonEl; | |
24 } | |
25 | |
26 /** | |
27 * Creates a new address list item. | |
28 * @param {Array} entry An array of the form [guid, label]. | |
29 * @constructor | |
30 * @extends {options.DeletableItem} | |
31 */ | |
32 function AddressListItem(entry) { | |
33 var el = cr.doc.createElement('div'); | |
34 el.guid = entry[0]; | |
35 el.label = entry[1]; | |
36 el.__proto__ = AddressListItem.prototype; | |
37 el.decorate(); | |
38 | |
39 return el; | |
40 } | |
41 | |
42 AddressListItem.prototype = { | |
43 __proto__: DeletableItem.prototype, | |
44 | |
45 /** @inheritDoc */ | |
46 decorate: function() { | |
47 DeletableItem.prototype.decorate.call(this); | |
48 | |
49 // The stored label. | |
50 var label = this.ownerDocument.createElement('div'); | |
51 label.className = 'autofill-list-item'; | |
52 label.textContent = this.label; | |
53 this.contentElement.appendChild(label); | |
54 | |
55 // The 'Edit' button. | |
56 var editButtonEl = new AutofillEditProfileButton( | |
57 this.guid, | |
58 AutofillOptions.loadAddressEditor); | |
59 this.contentElement.appendChild(editButtonEl); | |
60 }, | |
61 }; | |
62 | |
63 /** | |
64 * Creates a new credit card list item. | |
65 * @param {Array} entry An array of the form [guid, label, icon]. | |
66 * @constructor | |
67 * @extends {options.DeletableItem} | |
68 */ | |
69 function CreditCardListItem(entry) { | |
70 var el = cr.doc.createElement('div'); | |
71 el.guid = entry[0]; | |
72 el.label = entry[1]; | |
73 el.icon = entry[2]; | |
74 el.description = entry[3]; | |
75 el.__proto__ = CreditCardListItem.prototype; | |
76 el.decorate(); | |
77 | |
78 return el; | |
79 } | |
80 | |
81 CreditCardListItem.prototype = { | |
82 __proto__: DeletableItem.prototype, | |
83 | |
84 /** @inheritDoc */ | |
85 decorate: function() { | |
86 DeletableItem.prototype.decorate.call(this); | |
87 | |
88 // The stored label. | |
89 var label = this.ownerDocument.createElement('div'); | |
90 label.className = 'autofill-list-item'; | |
91 label.textContent = this.label; | |
92 this.contentElement.appendChild(label); | |
93 | |
94 // The credit card icon. | |
95 var icon = this.ownerDocument.createElement('image'); | |
96 icon.src = this.icon; | |
97 icon.alt = this.description; | |
98 this.contentElement.appendChild(icon); | |
99 | |
100 // The 'Edit' button. | |
101 var editButtonEl = new AutofillEditProfileButton( | |
102 this.guid, | |
103 AutofillOptions.loadCreditCardEditor); | |
104 this.contentElement.appendChild(editButtonEl); | |
105 }, | |
106 }; | |
107 | |
108 /** | |
109 * Creates a new value list item. | |
110 * @param {AutofillValuesList} list The parent list of this item. | |
111 * @param {String} entry A string value. | |
112 * @constructor | |
113 * @extends {options.InlineEditableItem} | |
114 */ | |
115 function ValuesListItem(list, entry) { | |
116 var el = cr.doc.createElement('div'); | |
117 el.list = list; | |
118 el.value = entry ? entry : ''; | |
119 el.__proto__ = ValuesListItem.prototype; | |
120 el.decorate(); | |
121 | |
122 return el; | |
123 } | |
124 | |
125 ValuesListItem.prototype = { | |
126 __proto__: InlineEditableItem.prototype, | |
127 | |
128 /** @inheritDoc */ | |
129 decorate: function() { | |
130 InlineEditableItem.prototype.decorate.call(this); | |
131 | |
132 // Note: This must be set prior to calling |createEditableTextCell|. | |
133 this.isPlaceholder = !this.value; | |
134 | |
135 // The stored value. | |
136 var cell = this.createEditableTextCell(this.value); | |
137 this.contentElement.appendChild(cell); | |
138 this.input = cell.querySelector('input'); | |
139 | |
140 if (this.isPlaceholder) { | |
141 this.input.placeholder = this.list.getAttribute('placeholder'); | |
142 this.deletable = false; | |
143 } | |
144 | |
145 this.addEventListener('commitedit', this.onEditCommitted_); | |
146 }, | |
147 | |
148 /** | |
149 * @return {string} This item's value. | |
150 * @protected | |
151 */ | |
152 value_: function() { | |
153 return this.input.value; | |
154 }, | |
155 | |
156 /** | |
157 * @param {Object} value The value to test. | |
158 * @return {boolean} True if the given value is non-empty. | |
159 * @protected | |
160 */ | |
161 valueIsNonEmpty_: function(value) { | |
162 return !!value; | |
163 }, | |
164 | |
165 /** | |
166 * @return {boolean} True if value1 is logically equal to value2. | |
167 */ | |
168 valuesAreEqual_: function(value1, value2) { | |
169 return value1 === value2; | |
170 }, | |
171 | |
172 /** | |
173 * Clears the item's value. | |
174 * @protected | |
175 */ | |
176 clearValue_: function() { | |
177 this.input.value = ''; | |
178 }, | |
179 | |
180 /** | |
181 * Called when committing an edit. | |
182 * If this is an "Add ..." item, committing a non-empty value adds that | |
183 * value to the end of the values list, but also leaves this "Add ..." item | |
184 * in place. | |
185 * @param {Event} e The end event. | |
186 * @private | |
187 */ | |
188 onEditCommitted_: function(e) { | |
189 var value = this.value_(); | |
190 var i = this.list.items.indexOf(this); | |
191 if (i < this.list.dataModel.length && | |
192 this.valuesAreEqual_(value, this.list.dataModel.item(i))) { | |
193 return; | |
194 } | |
195 | |
196 var entries = this.list.dataModel.slice(); | |
197 if (this.valueIsNonEmpty_(value) && | |
198 !entries.some(this.valuesAreEqual_.bind(this, value))) { | |
199 // Update with new value. | |
200 if (this.isPlaceholder) { | |
201 // It is important that updateIndex is done before validateAndSave. | |
202 // Otherwise we can not be sure about AddRow index. | |
203 this.list.dataModel.updateIndex(i); | |
204 this.list.validateAndSave(i, 0, value); | |
205 } else { | |
206 this.list.validateAndSave(i, 1, value); | |
207 } | |
208 } else { | |
209 // Reject empty values and duplicates. | |
210 if (!this.isPlaceholder) | |
211 this.list.dataModel.splice(i, 1); | |
212 else | |
213 this.clearValue_(); | |
214 } | |
215 }, | |
216 }; | |
217 | |
218 /** | |
219 * Creates a new name value list item. | |
220 * @param {AutofillNameValuesList} list The parent list of this item. | |
221 * @param {array} entry An array of [first, middle, last] names. | |
222 * @constructor | |
223 * @extends {options.ValuesListItem} | |
224 */ | |
225 function NameListItem(list, entry) { | |
226 var el = cr.doc.createElement('div'); | |
227 el.list = list; | |
228 el.first = entry ? entry[0] : ''; | |
229 el.middle = entry ? entry[1] : ''; | |
230 el.last = entry ? entry[2] : ''; | |
231 el.__proto__ = NameListItem.prototype; | |
232 el.decorate(); | |
233 | |
234 return el; | |
235 } | |
236 | |
237 NameListItem.prototype = { | |
238 __proto__: ValuesListItem.prototype, | |
239 | |
240 /** @inheritDoc */ | |
241 decorate: function() { | |
242 InlineEditableItem.prototype.decorate.call(this); | |
243 | |
244 // Note: This must be set prior to calling |createEditableTextCell|. | |
245 this.isPlaceholder = !this.first && !this.middle && !this.last; | |
246 | |
247 // The stored value. | |
248 // For the simulated static "input element" to display correctly, the | |
249 // value must not be empty. We use a space to force the UI to render | |
250 // correctly when the value is logically empty. | |
251 var cell = this.createEditableTextCell(this.first); | |
252 this.contentElement.appendChild(cell); | |
253 this.firstNameInput = cell.querySelector('input'); | |
254 | |
255 cell = this.createEditableTextCell(this.middle); | |
256 this.contentElement.appendChild(cell); | |
257 this.middleNameInput = cell.querySelector('input'); | |
258 | |
259 cell = this.createEditableTextCell(this.last); | |
260 this.contentElement.appendChild(cell); | |
261 this.lastNameInput = cell.querySelector('input'); | |
262 | |
263 if (this.isPlaceholder) { | |
264 this.firstNameInput.placeholder = | |
265 loadTimeData.getString('autofillAddFirstNamePlaceholder'); | |
266 this.middleNameInput.placeholder = | |
267 loadTimeData.getString('autofillAddMiddleNamePlaceholder'); | |
268 this.lastNameInput.placeholder = | |
269 loadTimeData.getString('autofillAddLastNamePlaceholder'); | |
270 this.deletable = false; | |
271 } | |
272 | |
273 this.addEventListener('commitedit', this.onEditCommitted_); | |
274 }, | |
275 | |
276 /** @inheritDoc */ | |
277 value_: function() { | |
278 return [this.firstNameInput.value, | |
279 this.middleNameInput.value, | |
280 this.lastNameInput.value]; | |
281 }, | |
282 | |
283 /** @inheritDoc */ | |
284 valueIsNonEmpty_: function(value) { | |
285 return value[0] || value[1] || value[2]; | |
286 }, | |
287 | |
288 /** @inheritDoc */ | |
289 valuesAreEqual_: function(value1, value2) { | |
290 // First, check for null values. | |
291 if (!value1 || !value2) | |
292 return value1 == value2; | |
293 | |
294 return value1[0] === value2[0] && | |
295 value1[1] === value2[1] && | |
296 value1[2] === value2[2]; | |
297 }, | |
298 | |
299 /** @inheritDoc */ | |
300 clearValue_: function() { | |
301 this.firstNameInput.value = ''; | |
302 this.middleNameInput.value = ''; | |
303 this.lastNameInput.value = ''; | |
304 }, | |
305 }; | |
306 | |
307 /** | |
308 * Base class for shared implementation between address and credit card lists. | |
309 * @constructor | |
310 * @extends {options.DeletableItemList} | |
311 */ | |
312 var AutofillProfileList = cr.ui.define('list'); | |
313 | |
314 AutofillProfileList.prototype = { | |
315 __proto__: DeletableItemList.prototype, | |
316 | |
317 decorate: function() { | |
318 DeletableItemList.prototype.decorate.call(this); | |
319 | |
320 this.addEventListener('blur', this.onBlur_); | |
321 }, | |
322 | |
323 /** | |
324 * When the list loses focus, unselect all items in the list. | |
325 * @private | |
326 */ | |
327 onBlur_: function() { | |
328 this.selectionModel.unselectAll(); | |
329 }, | |
330 }; | |
331 | |
332 /** | |
333 * Create a new address list. | |
334 * @constructor | |
335 * @extends {options.AutofillProfileList} | |
336 */ | |
337 var AutofillAddressList = cr.ui.define('list'); | |
338 | |
339 AutofillAddressList.prototype = { | |
340 __proto__: AutofillProfileList.prototype, | |
341 | |
342 decorate: function() { | |
343 AutofillProfileList.prototype.decorate.call(this); | |
344 }, | |
345 | |
346 /** @inheritDoc */ | |
347 activateItemAtIndex: function(index) { | |
348 AutofillOptions.loadAddressEditor(this.dataModel.item(index)[0]); | |
349 }, | |
350 | |
351 /** @inheritDoc */ | |
352 createItem: function(entry) { | |
353 return new AddressListItem(entry); | |
354 }, | |
355 | |
356 /** @inheritDoc */ | |
357 deleteItemAtIndex: function(index) { | |
358 AutofillOptions.removeAddress(this.dataModel.item(index)[0]); | |
359 }, | |
360 }; | |
361 | |
362 /** | |
363 * Create a new credit card list. | |
364 * @constructor | |
365 * @extends {options.DeletableItemList} | |
366 */ | |
367 var AutofillCreditCardList = cr.ui.define('list'); | |
368 | |
369 AutofillCreditCardList.prototype = { | |
370 __proto__: AutofillProfileList.prototype, | |
371 | |
372 decorate: function() { | |
373 AutofillProfileList.prototype.decorate.call(this); | |
374 }, | |
375 | |
376 /** @inheritDoc */ | |
377 activateItemAtIndex: function(index) { | |
378 AutofillOptions.loadCreditCardEditor(this.dataModel.item(index)[0]); | |
379 }, | |
380 | |
381 /** @inheritDoc */ | |
382 createItem: function(entry) { | |
383 return new CreditCardListItem(entry); | |
384 }, | |
385 | |
386 /** @inheritDoc */ | |
387 deleteItemAtIndex: function(index) { | |
388 AutofillOptions.removeCreditCard(this.dataModel.item(index)[0]); | |
389 }, | |
390 }; | |
391 | |
392 /** | |
393 * Create a new value list. | |
394 * @constructor | |
395 * @extends {options.InlineEditableItemList} | |
396 */ | |
397 var AutofillValuesList = cr.ui.define('list'); | |
398 | |
399 AutofillValuesList.prototype = { | |
400 __proto__: InlineEditableItemList.prototype, | |
401 | |
402 /** @inheritDoc */ | |
403 createItem: function(entry) { | |
404 return new ValuesListItem(this, entry); | |
405 }, | |
406 | |
407 /** @inheritDoc */ | |
408 deleteItemAtIndex: function(index) { | |
409 this.dataModel.splice(index, 1); | |
410 }, | |
411 | |
412 /** @inheritDoc */ | |
413 shouldFocusPlaceholder: function() { | |
414 return false; | |
415 }, | |
416 | |
417 /** | |
418 * Called when the list hierarchy as a whole loses or gains focus. | |
419 * If the list was focused in response to a mouse click, call into the | |
420 * superclass's implementation. If the list was focused in response to a | |
421 * keyboard navigation, focus the first item. | |
422 * If the list loses focus, unselect all the elements. | |
423 * @param {Event} e The change event. | |
424 * @private | |
425 */ | |
426 handleListFocusChange_: function(e) { | |
427 // We check to see whether there is a selected item as a proxy for | |
428 // distinguishing between mouse- and keyboard-originated focus events. | |
429 var selectedItem = this.selectedItem; | |
430 if (selectedItem) | |
431 InlineEditableItemList.prototype.handleListFocusChange_.call(this, e); | |
432 | |
433 if (!e.newValue) { | |
434 // When the list loses focus, unselect all the elements. | |
435 this.selectionModel.unselectAll(); | |
436 } else { | |
437 // When the list gains focus, select the first item if nothing else is | |
438 // selected. | |
439 var firstItem = this.getListItemByIndex(0); | |
440 if (!selectedItem && firstItem && e.newValue) | |
441 firstItem.handleFocus_(); | |
442 } | |
443 }, | |
444 | |
445 /** | |
446 * Called when a new list item should be validated; subclasses are | |
447 * responsible for implementing if validation is required. | |
448 * @param {number} index The index of the item that was inserted or changed. | |
449 * @param {number} remove The number items to remove. | |
450 * @param {string} value The value of the item to insert. | |
451 */ | |
452 validateAndSave: function(index, remove, value) { | |
453 this.dataModel.splice(index, remove, value); | |
454 }, | |
455 }; | |
456 | |
457 /** | |
458 * Create a new value list for phone number validation. | |
459 * @constructor | |
460 * @extends {options.AutofillValuesList} | |
461 */ | |
462 var AutofillNameValuesList = cr.ui.define('list'); | |
463 | |
464 AutofillNameValuesList.prototype = { | |
465 __proto__: AutofillValuesList.prototype, | |
466 | |
467 /** @inheritDoc */ | |
468 createItem: function(entry) { | |
469 return new NameListItem(this, entry); | |
470 }, | |
471 }; | |
472 | |
473 /** | |
474 * Create a new value list for phone number validation. | |
475 * @constructor | |
476 * @extends {options.AutofillValuesList} | |
477 */ | |
478 var AutofillPhoneValuesList = cr.ui.define('list'); | |
479 | |
480 AutofillPhoneValuesList.prototype = { | |
481 __proto__: AutofillValuesList.prototype, | |
482 | |
483 /** @inheritDoc */ | |
484 validateAndSave: function(index, remove, value) { | |
485 var numbers = this.dataModel.slice(0, this.dataModel.length - 1); | |
486 numbers.splice(index, remove, value); | |
487 var info = new Array(); | |
488 info[0] = index; | |
489 info[1] = numbers; | |
490 info[2] = $('country').value; | |
491 chrome.send('validatePhoneNumbers', info); | |
492 }, | |
493 }; | |
494 | |
495 return { | |
496 AddressListItem: AddressListItem, | |
497 CreditCardListItem: CreditCardListItem, | |
498 ValuesListItem: ValuesListItem, | |
499 NameListItem: NameListItem, | |
500 AutofillAddressList: AutofillAddressList, | |
501 AutofillCreditCardList: AutofillCreditCardList, | |
502 AutofillValuesList: AutofillValuesList, | |
503 AutofillNameValuesList: AutofillNameValuesList, | |
504 AutofillPhoneValuesList: AutofillPhoneValuesList, | |
505 }; | |
506 }); | |
OLD | NEW |