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

Side by Side Diff: chrome/browser/resources/settings/prefs/prefs.js

Issue 1333473002: Support lists in <cr-settings-pref> (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@PrefsTests
Patch Set: Created 5 years, 3 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
« no previous file with comments | « no previous file | chrome/test/data/webui/settings/prefs_test_cases.js » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* Copyright 2015 The Chromium Authors. All rights reserved. 1 /* Copyright 2015 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 * @fileoverview 6 * @fileoverview
7 * 'cr-settings-prefs' models Chrome settings and preferences, listening for 7 * 'cr-settings-prefs' models Chrome settings and preferences, listening for
8 * changes to Chrome prefs whitelisted in chrome.settingsPrivate. 8 * changes to Chrome prefs whitelisted in chrome.settingsPrivate.
9 * When changing prefs in this element's 'prefs' property via the UI, this 9 * When changing prefs in this element's 'prefs' property via the UI, this
10 * element tries to set those preferences in Chrome. Whether or not the calls to 10 * element tries to set those preferences in Chrome. Whether or not the calls to
11 * settingsPrivate.setPref succeed, 'prefs' is eventually consistent with the 11 * settingsPrivate.setPref succeed, 'prefs' is eventually consistent with the
12 * Chrome pref store. 12 * Chrome pref store.
13 * 13 *
14 * Example: 14 * Example:
15 * 15 *
16 * <cr-settings-prefs prefs="{{prefs}}"></cr-settings-prefs> 16 * <cr-settings-prefs prefs="{{prefs}}"></cr-settings-prefs>
17 * <cr-settings-a11y-page prefs="{{prefs}}"></cr-settings-a11y-page> 17 * <cr-settings-a11y-page prefs="{{prefs}}"></cr-settings-a11y-page>
18 * 18 *
19 * @group Chrome Settings Elements 19 * @group Chrome Settings Elements
20 * @element cr-settings-prefs 20 * @element cr-settings-prefs
21 */ 21 */
22 22
23 /**
24 * Pref state object. Copies values of PrefObjects received from
25 * settingsPrivate to determine when pref values have changed.
26 * This prototype works for primitive types, but more complex types should
27 * override these functions.
28 * @constructor
29 * @param {!chrome.settingsPrivate.PrefObject} prefObj
30 */
31 function PrefWrapper(prefObj) {
32 this.key_ = prefObj.key;
33 this.value_ = prefObj.value;
34 }
35
36 /**
37 * Checks if other's value equals this.value_. Both prefs wrapped by the
38 * PrefWrappers should have the same keys.
39 * @param {PrefWrapper} other
40 * @return {boolean}
41 */
42 PrefWrapper.prototype.equals = function(other) {
43 assert(this.key_ == other.key_);
44 return this.value_ == other.value_;
45 };
46
47 /**
48 * @constructor
49 * @extends {PrefWrapper}
50 * @param {!chrome.settingsPrivate.PrefObject} prefObj
51 */
52 function ListPrefWrapper(prefObj) {
53 // Copy the array so changes to prefObj aren't reflected in this.value_.
54 // TODO(michaelpg): Do a deep copy to support nested lists and objects.
55 this.value_ = prefObj.value.slice();
56 }
57
58 ListPrefWrapper.prototype = {
59 __proto__: PrefWrapper.prototype,
60
61 /**
62 * Tests whether two ListPrefWrapper values contain the same list items.
63 * @override
64 */
65 equals: function(other) {
66 'use strict';
67 assert(this.key_ == other.key_);
68 if (this.value_.length != other.value_.length)
69 return false;
70 for (let i = 0; i < this.value_.length; i++) {
71 if (this.value_[i] != other.value_[i])
72 return false;
73 }
74 return true;
75 },
76 };
77
78 (function() { 23 (function() {
79 'use strict'; 24 'use strict';
80 25
26 /**
27 * Checks whether two values are recursively equal. Only compares serializable
28 * data (primitives, serializable arrays and serializable objects).
29 * @param {*} val1 Value to compare.
30 * @param {*} val2 Value to compare with val1.
31 * @return {boolean} True if the values are recursively equal.
32 */
33 function deepEqual(val1, val2) {
34 if (val1 === val2)
35 return true;
36
37 if (val1 == null || val2 == null)
Dan Beam 2015/09/18 01:54:16 you should probably use === just to make sure
michaelpg 2015/09/18 02:03:22 actually this line is superfluous because null and
Dan Beam 2015/09/18 02:05:18 super
38 return false;
39
40 if (Array.isArray(val1) || Array.isArray(val2)) {
41 if (!Array.isArray(val1) || !Array.isArray(val2))
42 return false;
43 return arraysEqual(/** @type {!Array} */(val1),
44 /** @type {!Array} */(val2));
45 }
46
47 if (val1 instanceof Object && val2 instanceof Object)
48 return objectsEqual(val1, val2);
49
50 return false;
51 }
52
53 /**
54 * @param {!Array} arr1
55 * @param {!Array} arr2
56 * @return {boolean} True if the arrays are recursively equal.
57 */
58 function arraysEqual(arr1, arr2) {
59 if (arr1.length != arr2.length)
60 return false;
61
62 for (var i = 0; i < arr1.length; i++) {
63 if (!deepEqual(arr1[i], arr2[i]))
64 return false;
65 }
66
67 return true;
68 }
69
70 /**
71 * @param {!Object} obj1
72 * @param {!Object} obj2
73 * @return {boolean} True if the objects are recursively equal.
74 */
75 function objectsEqual(obj1, obj2) {
76 var keys1 = Object.keys(obj1);
77 var keys2 = Object.keys(obj2);
78 if (keys1.length != keys2.length)
79 return false;
80
81 for (var i = 0; i < keys1.length; i++) {
82 var key = keys1[i];
83 if (!deepEqual(obj1[key], obj2[key]))
84 return false;
85 }
86
87 return true;
88 }
89
90 /**
91 * Returns a recursive copy of the value.
92 * @param {*} val Value to copy. Should be a primitive or only contain
93 * serializable data (primitives, serializable arrays and
94 * serializable objects).
95 * @return {*} A deep copy of the value.
96 */
97 function deepCopy(val) {
98 if (!(val instanceof Object))
99 return val;
100 return Array.isArray(val) ? deepCopyArray(/** @type {!Array} */(val)) :
101 deepCopyObject(val);
102 };
103
104 /**
105 * @param {!Array} arr
106 * @return {!Array} Deep copy of the array.
107 */
108 function deepCopyArray(arr) {
109 var copy = [];
110 for (var i = 0; i < arr.length; i++)
111 copy.push(deepCopy(arr[i]));
112 return copy;
113 }
114
115 /**
116 * @param {!Object} obj
117 * @return {!Object} Deep copy of the object.
118 */
119 function deepCopyObject(obj) {
120 var copy = {};
121 var keys = Object.keys(obj);
122 for (var i = 0; i < keys.length; i++) {
123 var key = keys[i];
124 copy[key] = deepCopy(obj[key]);
125 }
126 return copy;
127 }
128
81 Polymer({ 129 Polymer({
82 is: 'cr-settings-prefs', 130 is: 'cr-settings-prefs',
83 131
84 properties: { 132 properties: {
85 /** 133 /**
86 * Object containing all preferences, for use by Polymer controls. 134 * Object containing all preferences, for use by Polymer controls.
87 */ 135 */
88 prefs: { 136 prefs: {
89 type: Object, 137 type: Object,
90 notify: true, 138 notify: true,
91 }, 139 },
92 140
93 /** 141 /**
94 * Map of pref keys to PrefWrapper objects representing the state of the 142 * Map of pref keys to values representing the state of the Chrome
95 * Chrome pref store. 143 * pref store as of the last update from the API.
96 * @type {Object<PrefWrapper>} 144 * @type {Object<*>}
97 * @private 145 * @private
98 */ 146 */
99 prefWrappers_: { 147 lastPrefValues_: {
100 type: Object, 148 type: Object,
101 value: function() { return {}; }, 149 value: function() { return {}; },
102 }, 150 },
103 }, 151 },
104 152
105 observers: [ 153 observers: [
106 'prefsChanged_(prefs.*)', 154 'prefsChanged_(prefs.*)',
107 ], 155 ],
108 156
109 settingsApi_: chrome.settingsPrivate, 157 settingsApi_: chrome.settingsPrivate,
(...skipping 15 matching lines...) Expand all
125 /** 173 /**
126 * Polymer callback for changes to this.prefs. 174 * Polymer callback for changes to this.prefs.
127 * @param {!{path: string, value: *}} change 175 * @param {!{path: string, value: *}} change
128 * @private 176 * @private
129 */ 177 */
130 prefsChanged_: function(change) { 178 prefsChanged_: function(change) {
131 if (!CrSettingsPrefs.isInitialized) 179 if (!CrSettingsPrefs.isInitialized)
132 return; 180 return;
133 181
134 var key = this.getPrefKeyFromPath_(change.path); 182 var key = this.getPrefKeyFromPath_(change.path);
135 var prefWrapper = this.prefWrappers_[key]; 183 var prefStoreValue = this.lastPrefValues_[key];
136 if (!prefWrapper)
137 return;
138 184
139 var prefObj = /** @type {chrome.settingsPrivate.PrefObject} */( 185 var prefObj = /** @type {chrome.settingsPrivate.PrefObject} */(
140 this.get(key, this.prefs)); 186 this.get(key, this.prefs));
141 187
142 // If settingsPrivate already has this value, do nothing. (Otherwise, 188 // If settingsPrivate already has this value, do nothing. (Otherwise,
143 // a change event from settingsPrivate could make us call 189 // a change event from settingsPrivate could make us call
144 // settingsPrivate.setPref and potentially trigger an IPC loop.) 190 // settingsPrivate.setPref and potentially trigger an IPC loop.)
145 if (prefWrapper.equals(this.createPrefWrapper_(prefObj))) 191 if (deepEqual(prefStoreValue, prefObj.value))
146 return; 192 return;
147 193
148 this.settingsApi_.setPref( 194 this.settingsApi_.setPref(
149 key, 195 key,
150 prefObj.value, 196 prefObj.value,
151 /* pageId */ '', 197 /* pageId */ '',
152 /* callback */ this.setPrefCallback_.bind(this, key)); 198 /* callback */ this.setPrefCallback_.bind(this, key));
153 }, 199 },
154 200
155 /** 201 /**
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
194 240
195 /** 241 /**
196 * Updates the prefs model with the given prefs. 242 * Updates the prefs model with the given prefs.
197 * @param {!Array<!chrome.settingsPrivate.PrefObject>} newPrefs 243 * @param {!Array<!chrome.settingsPrivate.PrefObject>} newPrefs
198 * @private 244 * @private
199 */ 245 */
200 updatePrefs_: function(newPrefs) { 246 updatePrefs_: function(newPrefs) {
201 // Use the existing prefs object or create it. 247 // Use the existing prefs object or create it.
202 var prefs = this.prefs || {}; 248 var prefs = this.prefs || {};
203 newPrefs.forEach(function(newPrefObj) { 249 newPrefs.forEach(function(newPrefObj) {
204 // Use the PrefObject from settingsPrivate to create a PrefWrapper in 250 // Use the PrefObject from settingsPrivate to create a copy in
205 // prefWrappers_ at the pref's key. 251 // lastPrefValues_ at the pref's key.
206 this.prefWrappers_[newPrefObj.key] = 252 this.lastPrefValues_[newPrefObj.key] = deepCopy(newPrefObj.value);
207 this.createPrefWrapper_(newPrefObj);
208 253
209 // Add the pref to |prefs|. 254 // Add the pref to |prefs|.
210 cr.exportPath(newPrefObj.key, newPrefObj, prefs); 255 cr.exportPath(newPrefObj.key, newPrefObj, prefs);
211 // If this.prefs already exists, notify listeners of the change. 256 // If this.prefs already exists, notify listeners of the change.
212 if (prefs == this.prefs) 257 if (prefs == this.prefs)
213 this.notifyPath('prefs.' + newPrefObj.key, newPrefObj); 258 this.notifyPath('prefs.' + newPrefObj.key, newPrefObj);
214 }, this); 259 }, this);
215 if (!this.prefs) 260 if (!this.prefs)
216 this.prefs = prefs; 261 this.prefs = prefs;
217 }, 262 },
218 263
219 /** 264 /**
220 * Given a 'property-changed' path, returns the key of the preference the 265 * Given a 'property-changed' path, returns the key of the preference the
221 * path refers to. E.g., if the path of the changed property is 266 * path refers to. E.g., if the path of the changed property is
222 * 'prefs.search.suggest_enabled.value', the key of the pref that changed is 267 * 'prefs.search.suggest_enabled.value', the key of the pref that changed is
223 * 'search.suggest_enabled'. 268 * 'search.suggest_enabled'.
224 * @param {string} path 269 * @param {string} path
225 * @return {string} 270 * @return {string}
226 * @private 271 * @private
227 */ 272 */
228 getPrefKeyFromPath_: function(path) { 273 getPrefKeyFromPath_: function(path) {
229 // Skip the first token, which refers to the member variable (this.prefs). 274 // Skip the first token, which refers to the member variable (this.prefs).
230 var parts = path.split('.'); 275 var parts = path.split('.');
231 assert(parts.shift() == 'prefs'); 276 assert(parts.shift() == 'prefs');
232 277
233 for (let i = 1; i <= parts.length; i++) { 278 for (let i = 1; i <= parts.length; i++) {
234 let key = parts.slice(0, i).join('.'); 279 let key = parts.slice(0, i).join('.');
235 // The prefWrappers_ keys match the pref keys. 280 // The lastPrefValues_ keys match the pref keys.
236 if (this.prefWrappers_[key] != undefined) 281 if (this.lastPrefValues_.hasOwnProperty(key))
237 return key; 282 return key;
238 } 283 }
239 return ''; 284 return '';
240 }, 285 },
241
242 /**
243 * Creates a PrefWrapper object from a chrome.settingsPrivate pref.
244 * @param {!chrome.settingsPrivate.PrefObject} prefObj
245 * PrefObject received from chrome.settingsPrivate.
246 * @return {PrefWrapper} An object containing a copy of the PrefObject's
247 * value.
248 * @private
249 */
250 createPrefWrapper_: function(prefObj) {
251 return prefObj.type == chrome.settingsPrivate.PrefType.LIST ?
252 new ListPrefWrapper(prefObj) : new PrefWrapper(prefObj);
253 },
254 }); 286 });
255 })(); 287 })();
OLDNEW
« no previous file with comments | « no previous file | chrome/test/data/webui/settings/prefs_test_cases.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698