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

Side by Side Diff: chrome/browser/resources/options2/pref_ui.js

Issue 10809005: Options: Rename chrome/browser/resources/options2 -> chrome/browser/resources/options. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix. Created 8 years, 4 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
(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 // TODO(jhawkins): Add dialog-pref support to all preference controls.
6
7 cr.define('options', function() {
8
9 var Preferences = options.Preferences;
10
11 /**
12 * Allows an element to be disabled for several reasons.
13 * The element is disabled if at least one reason is true, and the reasons
14 * can be set separately.
15 * @private
16 * @param {!HTMLElement} el The element to update.
17 * @param {string} reason The reason for disabling the element.
18 * @param {boolean} disabled Whether the element should be disabled or enabled
19 * for the given |reason|.
20 */
21 function updateDisabledState_(el, reason, disabled) {
22 if (!el.disabledReasons)
23 el.disabledReasons = {};
24 if (el.disabled && (Object.keys(el.disabledReasons).length == 0)) {
25 // The element has been previously disabled without a reason, so we add
26 // one to keep it disabled.
27 el.disabledReasons['other'] = true;
28 }
29 if (!el.disabled) {
30 // If the element is not disabled, there should be no reason, except for
31 // 'other'.
32 delete el.disabledReasons['other'];
33 if (Object.keys(el.disabledReasons).length > 0)
34 console.error('Element is not disabled but should be');
35 }
36 if (disabled) {
37 el.disabledReasons[reason] = true;
38 } else {
39 delete el.disabledReasons[reason];
40 }
41 el.disabled = Object.keys(el.disabledReasons).length > 0;
42 }
43
44 /**
45 * Helper function to update element's state from pref change event.
46 * @private
47 * @param {!HTMLElement} el The element to update.
48 * @param {!Event} event The pref change event.
49 */
50 function updateElementState_(el, event) {
51 el.controlledBy = null;
52
53 if (!event.value)
54 return;
55
56 updateDisabledState_(el, 'notUserModifiable', event.value.disabled);
57
58 el.controlledBy = event.value.controlledBy;
59
60 OptionsPage.updateManagedBannerVisibility();
61 }
62
63 /////////////////////////////////////////////////////////////////////////////
64 // PrefCheckbox class:
65 // TODO(jhawkins): Refactor all this copy-pasted code!
66
67 // Define a constructor that uses an input element as its underlying element.
68 var PrefCheckbox = cr.ui.define('input');
69
70 PrefCheckbox.prototype = {
71 // Set up the prototype chain
72 __proto__: HTMLInputElement.prototype,
73
74 /**
75 * The stored value of the preference that this checkbox controls.
76 * @type {boolean}
77 */
78 prefValue_: null,
79
80 /**
81 * Initialization function for the cr.ui framework.
82 */
83 decorate: function() {
84 this.type = 'checkbox';
85 var self = this;
86
87 self.initializeValueType(self.getAttribute('value-type'));
88
89 // Listen to pref changes.
90 Preferences.getInstance().addEventListener(this.pref, function(event) {
91 self.prefValue_ = Boolean(event.value.value);
92 self.resetPrefState();
93
94 updateElementState_(self, event);
95 });
96
97 // Listen to user events.
98 this.addEventListener('change', function(e) {
99 if (self.customChangeHandler(e))
100 return;
101
102 if (!this.dialogPref)
103 this.updatePreferenceValue_();
104 });
105 },
106
107 /**
108 * Update the preference value based on the checkbox state.
109 * @private
110 */
111 updatePreferenceValue_: function() {
112 var value = this.inverted_pref ? !this.checked : this.checked;
113 switch (this.valueType) {
114 case 'number':
115 Preferences.setIntegerPref(this.pref, Number(value), this.metric);
116 break;
117 case 'boolean':
118 Preferences.setBooleanPref(this.pref, value, this.metric);
119 break;
120 }
121 },
122
123 /**
124 * Called by SettingsDialog to save the preference.
125 */
126 savePrefState: function() {
127 this.updatePreferenceValue_();
128 },
129
130 /**
131 * Called by SettingsDialog to reset the UI to match the current preference
132 * value.
133 */
134 resetPrefState: function() {
135 this.checked = this.inverted_pref ? !this.prefValue_ : this.prefValue_;
136 },
137
138 /**
139 * Sets up options in checkbox element.
140 * @param {String} valueType The preference type for this checkbox.
141 */
142 initializeValueType: function(valueType) {
143 this.valueType = valueType || 'boolean';
144 },
145
146 /**
147 * See |updateDisabledState_| above.
148 */
149 setDisabled: function(reason, disabled) {
150 updateDisabledState_(this, reason, disabled);
151 },
152
153 /**
154 * This method is called first while processing an onchange event. If it
155 * returns false, regular onchange processing continues (setting the
156 * associated pref, etc). If it returns true, the rest of the onchange is
157 * not performed. I.e., this works like stopPropagation or cancelBubble.
158 * @param {Event} event Change event.
159 */
160 customChangeHandler: function(event) {
161 return false;
162 },
163 };
164
165 /**
166 * The preference name.
167 * @type {string}
168 */
169 cr.defineProperty(PrefCheckbox, 'pref', cr.PropertyKind.ATTR);
170
171 /**
172 * A special preference type specific to dialogs. These preferences are reset
173 * when the dialog is shown and are not saved until the user confirms the
174 * dialog.
175 * @type {boolean}
176 */
177 cr.defineProperty(PrefCheckbox, 'dialogPref', cr.PropertyKind.BOOL_ATTR);
178
179 /**
180 * Whether the preference is controlled by something else than the user's
181 * settings (either 'policy' or 'extension').
182 * @type {string}
183 */
184 cr.defineProperty(PrefCheckbox, 'controlledBy', cr.PropertyKind.ATTR);
185
186 /**
187 * The user metric string.
188 * @type {string}
189 */
190 cr.defineProperty(PrefCheckbox, 'metric', cr.PropertyKind.ATTR);
191
192 /**
193 * Whether to use inverted pref value.
194 * @type {boolean}
195 */
196 cr.defineProperty(PrefCheckbox, 'inverted_pref', cr.PropertyKind.BOOL_ATTR);
197
198 /////////////////////////////////////////////////////////////////////////////
199 // PrefRadio class:
200
201 //Define a constructor that uses an input element as its underlying element.
202 var PrefRadio = cr.ui.define('input');
203
204 PrefRadio.prototype = {
205 // Set up the prototype chain
206 __proto__: HTMLInputElement.prototype,
207
208 // Stores the initialized value of the preference used to reset the input
209 // in resetPrefState().
210 storedValue_: null,
211
212 /**
213 * Initialization function for the cr.ui framework.
214 */
215 decorate: function() {
216 this.type = 'radio';
217 var self = this;
218
219 // Listen to preference changes.
220 Preferences.getInstance().addEventListener(this.pref,
221 function(event) {
222 if (self.customChangeHandler(event))
223 return;
224 self.checked = String(event.value.value) == self.value;
225 self.storedValue_ = self.checked;
226
227 updateElementState_(self, event);
228 });
229
230 // Dialog preferences are not saved until savePrefState() is explicitly
231 // called.
232 if (!this.dialogPref)
233 this.onchange = this.savePrefState.bind(this);
234 },
235
236 /**
237 * Resets the input to the stored value.
238 */
239 resetPrefState: function() {
240 this.checked = this.storedValue_;
241 },
242
243 /**
244 * Saves the value of the input back into the preference. May be called
245 * directly to save dialog preferences.
246 */
247 savePrefState: function() {
248 this.storedValue_ = this.checked;
249 if (this.value == 'true' || this.value == 'false') {
250 var value = String(this.value);
251 Preferences.setBooleanPref(this.pref, value == String(this.checked),
252 this.metric);
253 } else {
254 Preferences.setIntegerPref(this.pref, parseInt(this.value, 10),
255 this.metric);
256 }
257 },
258
259 /**
260 * See |updateDisabledState_| above.
261 */
262 setDisabled: function(reason, disabled) {
263 updateDisabledState_(this, reason, disabled);
264 },
265
266 /**
267 * This method is called first while processing an onchange event. If it
268 * returns false, regular onchange processing continues (setting the
269 * associated pref, etc). If it returns true, the rest of the onchange is
270 * not performed. I.e., this works like stopPropagation or cancelBubble.
271 * @param {Event} event Change event.
272 */
273 customChangeHandler: function(event) {
274 return false;
275 },
276 };
277
278 /**
279 * The preference name.
280 * @type {string}
281 */
282 cr.defineProperty(PrefRadio, 'pref', cr.PropertyKind.ATTR);
283
284 /**
285 * A special preference type specific to dialogs. These preferences are reset
286 * when the dialog is shown and are not saved until the user confirms the
287 * dialog.
288 * @type {boolean}
289 */
290 cr.defineProperty(PrefRadio, 'dialogPref', cr.PropertyKind.BOOL_ATTR);
291
292 /**
293 * Whether the preference is controlled by something else than the user's
294 * settings (either 'policy' or 'extension').
295 * @type {string}
296 */
297 cr.defineProperty(PrefRadio, 'controlledBy', cr.PropertyKind.ATTR);
298
299 /**
300 * The user metric string.
301 * @type {string}
302 */
303 cr.defineProperty(PrefRadio, 'metric', cr.PropertyKind.ATTR);
304
305 /////////////////////////////////////////////////////////////////////////////
306 // PrefNumeric class:
307
308 // Define a constructor that uses an input element as its underlying element.
309 var PrefNumeric = function() {};
310 PrefNumeric.prototype = {
311 // Set up the prototype chain
312 __proto__: HTMLInputElement.prototype,
313
314 /**
315 * Initialization function for the cr.ui framework.
316 */
317 decorate: function() {
318 var self = this;
319
320 // Listen to pref changes.
321 Preferences.getInstance().addEventListener(this.pref,
322 function(event) {
323 self.value = event.value.value;
324
325 updateElementState_(self, event);
326 });
327
328 // Listen to user events.
329 this.addEventListener('change',
330 function(e) {
331 if (this.validity.valid) {
332 Preferences.setIntegerPref(self.pref, self.value, self.metric);
333 }
334 });
335 },
336
337 /**
338 * See |updateDisabledState_| above.
339 */
340 setDisabled: function(reason, disabled) {
341 updateDisabledState_(this, reason, disabled);
342 },
343 };
344
345 /**
346 * The preference name.
347 * @type {string}
348 */
349 cr.defineProperty(PrefNumeric, 'pref', cr.PropertyKind.ATTR);
350
351 /**
352 * Whether the preference is controlled by something else than the user's
353 * settings (either 'policy' or 'extension').
354 * @type {string}
355 */
356 cr.defineProperty(PrefNumeric, 'controlledBy', cr.PropertyKind.ATTR);
357
358 /**
359 * The user metric string.
360 * @type {string}
361 */
362 cr.defineProperty(PrefNumeric, 'metric', cr.PropertyKind.ATTR);
363
364 /////////////////////////////////////////////////////////////////////////////
365 // PrefNumber class:
366
367 // Define a constructor that uses an input element as its underlying element.
368 var PrefNumber = cr.ui.define('input');
369
370 PrefNumber.prototype = {
371 // Set up the prototype chain
372 __proto__: PrefNumeric.prototype,
373
374 /**
375 * Initialization function for the cr.ui framework.
376 */
377 decorate: function() {
378 this.type = 'number';
379 PrefNumeric.prototype.decorate.call(this);
380
381 // Listen to user events.
382 this.addEventListener('input',
383 function(e) {
384 if (this.validity.valid) {
385 Preferences.setIntegerPref(self.pref, self.value, self.metric);
386 }
387 });
388 },
389
390 /**
391 * See |updateDisabledState_| above.
392 */
393 setDisabled: function(reason, disabled) {
394 updateDisabledState_(this, reason, disabled);
395 },
396 };
397
398 /////////////////////////////////////////////////////////////////////////////
399 // PrefRange class:
400
401 // Define a constructor that uses an input element as its underlying element.
402 var PrefRange = cr.ui.define('input');
403
404 PrefRange.prototype = {
405 // Set up the prototype chain
406 __proto__: HTMLInputElement.prototype,
407
408 /**
409 * The map from input range value to the corresponding preference value.
410 */
411 valueMap: undefined,
412
413 /**
414 * If true, the associated pref will be modified on each onchange event;
415 * otherwise, the pref will only be modified on the onmouseup event after
416 * the drag.
417 */
418 continuous: true,
419
420 /**
421 * Initialization function for the cr.ui framework.
422 */
423 decorate: function() {
424 this.type = 'range';
425
426 // Update the UI when the pref changes.
427 Preferences.getInstance().addEventListener(
428 this.pref, this.onPrefChange_.bind(this));
429
430 // Listen to user events.
431 // TODO(jhawkins): Add onmousewheel handling once the associated WK bug is
432 // fixed.
433 // https://bugs.webkit.org/show_bug.cgi?id=52256
434 this.onchange = this.onChange_.bind(this);
435 this.onkeyup = this.onmouseup = this.onInputUp_.bind(this);
436 },
437
438 /**
439 * Event listener that updates the UI when the underlying pref changes.
440 * @param {Event} event The event that details the pref change.
441 * @private
442 */
443 onPrefChange_: function(event) {
444 var value = event.value.value;
445 if (value != undefined)
446 this.value = this.valueMap ? this.valueMap.indexOf(value) : value;
447 },
448
449 /**
450 * onchange handler that sets the pref when the user changes the value of
451 * the input element.
452 * @private
453 */
454 onChange_: function(event) {
455 if (this.continuous)
456 this.setRangePref_();
457
458 if (this.notifyChange)
459 this.notifyChange(this, this.mapValueToRange_(this.value));
460 },
461
462 /**
463 * Sets the integer value of |pref| to the value of this element.
464 * @private
465 */
466 setRangePref_: function() {
467 Preferences.setIntegerPref(
468 this.pref, this.mapValueToRange_(this.value), this.metric);
469
470 if (this.notifyPrefChange)
471 this.notifyPrefChange(this, this.mapValueToRange_(this.value));
472 },
473
474 /**
475 * onkeyup/onmouseup handler that modifies the pref if |continuous| is
476 * false.
477 * @private
478 */
479 onInputUp_: function(event) {
480 if (!this.continuous)
481 this.setRangePref_();
482 },
483
484 /**
485 * Maps the value of this element into the range provided by the client,
486 * represented by |valueMap|.
487 * @param {number} value The value to map.
488 * @private
489 */
490 mapValueToRange_: function(value) {
491 return this.valueMap ? this.valueMap[value] : value;
492 },
493
494 /**
495 * Called when the client has specified non-continuous mode and the value of
496 * the range control changes.
497 * @param {Element} el This element.
498 * @param {number} value The value of this element.
499 */
500 notifyChange: function(el, value) {
501 },
502
503 /**
504 * See |updateDisabledState_| above.
505 */
506 setDisabled: function(reason, disabled) {
507 updateDisabledState_(this, reason, disabled);
508 },
509 };
510
511 /**
512 * The preference name.
513 * @type {string}
514 */
515 cr.defineProperty(PrefRange, 'pref', cr.PropertyKind.ATTR);
516
517 /**
518 * Whether the preference is controlled by something else than the user's
519 * settings (either 'policy' or 'extension').
520 * @type {string}
521 */
522 cr.defineProperty(PrefRange, 'controlledBy', cr.PropertyKind.ATTR);
523
524 /**
525 * The user metric string.
526 * @type {string}
527 */
528 cr.defineProperty(PrefRange, 'metric', cr.PropertyKind.ATTR);
529
530 /////////////////////////////////////////////////////////////////////////////
531 // PrefSelect class:
532
533 // Define a constructor that uses a select element as its underlying element.
534 var PrefSelect = cr.ui.define('select');
535
536 PrefSelect.prototype = {
537 // Set up the prototype chain
538 __proto__: HTMLSelectElement.prototype,
539
540 /**
541 * @type {string} The stored value of the preference that this select
542 * controls.
543 */
544 prefValue_: null,
545
546 /**
547 * Initialization function for the cr.ui framework.
548 */
549 decorate: function() {
550 var self = this;
551
552 // Listen to pref changes.
553 Preferences.getInstance().addEventListener(this.pref, function(event) {
554 // Make sure |value| is a string, because the value is stored as a
555 // string in the HTMLOptionElement.
556 value = event.value.value.toString();
557
558 updateElementState_(self, event);
559 self.prefValue_ = value;
560 self.resetPrefState();
561 });
562
563 // Listen to user events.
564 this.addEventListener('change', function(event) {
565 if (!self.dialogPref)
566 self.updatePreference_(self.prefValue_);
567 });
568 },
569
570 /**
571 * Resets the input to the stored value.
572 */
573 resetPrefState: function() {
574 var found = false;
575 for (var i = 0; i < this.options.length; i++) {
576 if (this.options[i].value == this.prefValue_) {
577 this.selectedIndex = i;
578 found = true;
579 }
580 }
581
582 // Item not found, select first item.
583 if (!found)
584 this.selectedIndex = 0;
585
586 if (this.onchange)
587 this.onchange(event);
588 },
589
590 /**
591 * Updates the preference to the currently selected value.
592 */
593 updatePreference_: function() {
594 if (!this.dataType) {
595 console.error('undefined data type for <select> pref');
596 return;
597 }
598
599 var prefValue = this.options[this.selectedIndex].value;
600 switch (this.dataType) {
601 case 'number':
602 Preferences.setIntegerPref(this.pref, prefValue, this.metric);
603 break;
604 case 'double':
605 Preferences.setDoublePref(this.pref, prefValue, this.metric);
606 break;
607 case 'boolean':
608 var value = (prefValue == 'true');
609 Preferences.setBooleanPref(this.pref, value, this.metric);
610 break;
611 case 'string':
612 Preferences.setStringPref(this.pref, prefValue, this.metric);
613 break;
614 default:
615 console.error('unknown data type for <select> pref: ' +
616 this.dataType);
617 }
618 },
619
620 /**
621 * Called by SettingsDialog to save the stored value to preferences.
622 */
623 savePrefState: function() {
624 this.updatePreference_();
625 },
626
627 /**
628 * See |updateDisabledState_| above.
629 */
630 setDisabled: function(reason, disabled) {
631 updateDisabledState_(this, reason, disabled);
632 },
633 };
634
635 /**
636 * The preference name.
637 * @type {string}
638 */
639 cr.defineProperty(PrefSelect, 'pref', cr.PropertyKind.ATTR);
640
641 /**
642 * Whether the preference is controlled by something else than the user's
643 * settings (either 'policy' or 'extension').
644 * @type {string}
645 */
646 cr.defineProperty(PrefSelect, 'controlledBy', cr.PropertyKind.ATTR);
647
648 /**
649 * A special preference type specific to dialogs. These preferences are reset
650 * when the dialog is shown and are not saved until the user confirms the
651 * dialog.
652 * @type {boolean}
653 */
654 cr.defineProperty(PrefSelect, 'dialogPref', cr.PropertyKind.BOOL_ATTR);
655
656 /**
657 * The user metric string.
658 * @type {string}
659 */
660 cr.defineProperty(PrefSelect, 'metric', cr.PropertyKind.ATTR);
661
662 /**
663 * The data type for the preference options.
664 * @type {string}
665 */
666 cr.defineProperty(PrefSelect, 'dataType', cr.PropertyKind.ATTR);
667
668 /////////////////////////////////////////////////////////////////////////////
669 // PrefTextField class:
670
671 // Define a constructor that uses an input element as its underlying element.
672 var PrefTextField = cr.ui.define('input');
673
674 PrefTextField.prototype = {
675 // Set up the prototype chain
676 __proto__: HTMLInputElement.prototype,
677
678 /**
679 * @type {string} The stored value of the preference that this text field
680 * controls.
681 */
682 prefValue_: null,
683
684 /**
685 * Saves the value of the input back into the preference. May be called
686 * directly to save dialog preferences.
687 */
688 savePrefState: function() {
689 switch (this.dataType) {
690 case 'number':
691 Preferences.setIntegerPref(this.pref, this.value, this.metric);
692 break;
693 case 'double':
694 Preferences.setDoublePref(this.pref, this.value, this.metric);
695 break;
696 case 'url':
697 Preferences.setURLPref(this.pref, this.value, this.metric);
698 break;
699 default:
700 Preferences.setStringPref(this.pref, this.value, this.metric);
701 break;
702 }
703 },
704
705 /**
706 * Resets the input to the stored value.
707 */
708 resetPrefState: function() {
709 this.value = this.prefValue_;
710 },
711
712 /**
713 * Initialization function for the cr.ui framework.
714 */
715 decorate: function() {
716 var self = this;
717
718 // Listen to pref changes.
719 Preferences.getInstance().addEventListener(this.pref,
720 function(event) {
721 self.value = event.value.value;
722
723 updateElementState_(self, event);
724
725 self.prefValue_ = self.value;
726 });
727
728 // Listen to user events.
729 if (!this.dialogPref)
730 this.addEventListener('change', this.savePrefState.bind(this));
731
732 window.addEventListener('unload',
733 function() {
734 if (document.activeElement == self)
735 self.blur();
736 });
737 },
738
739 /**
740 * See |updateDisabledState_| above.
741 */
742 setDisabled: function(reason, disabled) {
743 updateDisabledState_(this, reason, disabled);
744 },
745 };
746
747 /**
748 * The preference name.
749 * @type {string}
750 */
751 cr.defineProperty(PrefTextField, 'pref', cr.PropertyKind.ATTR);
752
753 /**
754 * A special preference type specific to dialogs. These preferences are reset
755 * when the dialog is shown and are not saved until the user confirms the
756 * dialog.
757 * @type {boolean}
758 */
759 cr.defineProperty(PrefTextField, 'dialogPref', cr.PropertyKind.BOOL_ATTR);
760
761 /**
762 * Whether the preference is controlled by something else than the user's
763 * settings (either 'policy' or 'extension').
764 * @type {string}
765 */
766 cr.defineProperty(PrefTextField, 'controlledBy', cr.PropertyKind.ATTR);
767
768 /**
769 * The user metric string.
770 * @type {string}
771 */
772 cr.defineProperty(PrefTextField, 'metric', cr.PropertyKind.ATTR);
773
774 /**
775 * The data type for the preference options.
776 * @type {string}
777 */
778 cr.defineProperty(PrefTextField, 'dataType', cr.PropertyKind.ATTR);
779
780 /////////////////////////////////////////////////////////////////////////////
781 // PrefButton class:
782
783 // Define a constructor that uses a button element as its underlying element.
784 var PrefButton = cr.ui.define('button');
785
786 PrefButton.prototype = {
787 // Set up the prototype chain
788 __proto__: HTMLButtonElement.prototype,
789
790 /**
791 * Initialization function for the cr.ui framework.
792 */
793 decorate: function() {
794 var self = this;
795
796 // Listen to pref changes. This element behaves like a normal button and
797 // doesn't affect the underlying preference; it just becomes disabled
798 // when the preference is managed, and its value is false.
799 // This is useful for buttons that should be disabled when the underlying
800 // boolean preference is set to false by a policy or extension.
801 Preferences.getInstance().addEventListener(this.pref,
802 function(event) {
803 var e = {
804 value: {
805 'disabled': event.value.disabled && !event.value.value,
806 'controlledBy': event.value.controlledBy
807 }
808 };
809 updateElementState_(self, e);
810 });
811 },
812
813 /**
814 * See |updateDisabledState_| above.
815 */
816 setDisabled: function(reason, disabled) {
817 updateDisabledState_(this, reason, disabled);
818 },
819 };
820
821 /**
822 * The preference name.
823 * @type {string}
824 */
825 cr.defineProperty(PrefButton, 'pref', cr.PropertyKind.ATTR);
826
827 /**
828 * Whether the preference is controlled by something else than the user's
829 * settings (either 'policy' or 'extension').
830 * @type {string}
831 */
832 cr.defineProperty(PrefButton, 'controlledBy', cr.PropertyKind.ATTR);
833
834 // Export
835 return {
836 PrefCheckbox: PrefCheckbox,
837 PrefNumber: PrefNumber,
838 PrefNumeric: PrefNumeric,
839 PrefRadio: PrefRadio,
840 PrefRange: PrefRange,
841 PrefSelect: PrefSelect,
842 PrefTextField: PrefTextField,
843 PrefButton: PrefButton
844 };
845
846 });
OLDNEW
« no previous file with comments | « chrome/browser/resources/options2/password_manager_list.js ('k') | chrome/browser/resources/options2/preferences.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698