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

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: remove redundant check 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 (Array.isArray(val1) || Array.isArray(val2)) {
38 if (!Array.isArray(val1) || !Array.isArray(val2))
39 return false;
40 return arraysEqual(/** @type {!Array} */(val1),
41 /** @type {!Array} */(val2));
42 }
43
44 if (val1 instanceof Object && val2 instanceof Object)
45 return objectsEqual(val1, val2);
46
47 return false;
48 }
49
50 /**
51 * @param {!Array} arr1
52 * @param {!Array} arr2
53 * @return {boolean} True if the arrays are recursively equal.
54 */
55 function arraysEqual(arr1, arr2) {
56 if (arr1.length != arr2.length)
57 return false;
58
59 for (var i = 0; i < arr1.length; i++) {
60 if (!deepEqual(arr1[i], arr2[i]))
61 return false;
62 }
63
64 return true;
65 }
66
67 /**
68 * @param {!Object} obj1
69 * @param {!Object} obj2
70 * @return {boolean} True if the objects are recursively equal.
71 */
72 function objectsEqual(obj1, obj2) {
73 var keys1 = Object.keys(obj1);
74 var keys2 = Object.keys(obj2);
75 if (keys1.length != keys2.length)
76 return false;
77
78 for (var i = 0; i < keys1.length; i++) {
79 var key = keys1[i];
80 if (!deepEqual(obj1[key], obj2[key]))
81 return false;
82 }
83
84 return true;
85 }
86
87 /**
88 * Returns a recursive copy of the value.
89 * @param {*} val Value to copy. Should be a primitive or only contain
90 * serializable data (primitives, serializable arrays and
91 * serializable objects).
92 * @return {*} A deep copy of the value.
93 */
94 function deepCopy(val) {
95 if (!(val instanceof Object))
96 return val;
97 return Array.isArray(val) ? deepCopyArray(/** @type {!Array} */(val)) :
98 deepCopyObject(val);
99 };
100
101 /**
102 * @param {!Array} arr
103 * @return {!Array} Deep copy of the array.
104 */
105 function deepCopyArray(arr) {
106 var copy = [];
107 for (var i = 0; i < arr.length; i++)
108 copy.push(deepCopy(arr[i]));
109 return copy;
110 }
111
112 /**
113 * @param {!Object} obj
114 * @return {!Object} Deep copy of the object.
115 */
116 function deepCopyObject(obj) {
117 var copy = {};
118 var keys = Object.keys(obj);
119 for (var i = 0; i < keys.length; i++) {
120 var key = keys[i];
121 copy[key] = deepCopy(obj[key]);
122 }
123 return copy;
124 }
125
81 Polymer({ 126 Polymer({
82 is: 'cr-settings-prefs', 127 is: 'cr-settings-prefs',
83 128
84 properties: { 129 properties: {
85 /** 130 /**
86 * Object containing all preferences, for use by Polymer controls. 131 * Object containing all preferences, for use by Polymer controls.
87 */ 132 */
88 prefs: { 133 prefs: {
89 type: Object, 134 type: Object,
90 notify: true, 135 notify: true,
91 }, 136 },
92 137
93 /** 138 /**
94 * Map of pref keys to PrefWrapper objects representing the state of the 139 * Map of pref keys to values representing the state of the Chrome
95 * Chrome pref store. 140 * pref store as of the last update from the API.
96 * @type {Object<PrefWrapper>} 141 * @type {Object<*>}
97 * @private 142 * @private
98 */ 143 */
99 prefWrappers_: { 144 lastPrefValues_: {
100 type: Object, 145 type: Object,
101 value: function() { return {}; }, 146 value: function() { return {}; },
102 }, 147 },
103 }, 148 },
104 149
105 observers: [ 150 observers: [
106 'prefsChanged_(prefs.*)', 151 'prefsChanged_(prefs.*)',
107 ], 152 ],
108 153
109 settingsApi_: chrome.settingsPrivate, 154 settingsApi_: chrome.settingsPrivate,
(...skipping 15 matching lines...) Expand all
125 /** 170 /**
126 * Polymer callback for changes to this.prefs. 171 * Polymer callback for changes to this.prefs.
127 * @param {!{path: string, value: *}} change 172 * @param {!{path: string, value: *}} change
128 * @private 173 * @private
129 */ 174 */
130 prefsChanged_: function(change) { 175 prefsChanged_: function(change) {
131 if (!CrSettingsPrefs.isInitialized) 176 if (!CrSettingsPrefs.isInitialized)
132 return; 177 return;
133 178
134 var key = this.getPrefKeyFromPath_(change.path); 179 var key = this.getPrefKeyFromPath_(change.path);
135 var prefWrapper = this.prefWrappers_[key]; 180 var prefStoreValue = this.lastPrefValues_[key];
136 if (!prefWrapper)
137 return;
138 181
139 var prefObj = /** @type {chrome.settingsPrivate.PrefObject} */( 182 var prefObj = /** @type {chrome.settingsPrivate.PrefObject} */(
140 this.get(key, this.prefs)); 183 this.get(key, this.prefs));
141 184
142 // If settingsPrivate already has this value, do nothing. (Otherwise, 185 // If settingsPrivate already has this value, do nothing. (Otherwise,
143 // a change event from settingsPrivate could make us call 186 // a change event from settingsPrivate could make us call
144 // settingsPrivate.setPref and potentially trigger an IPC loop.) 187 // settingsPrivate.setPref and potentially trigger an IPC loop.)
145 if (prefWrapper.equals(this.createPrefWrapper_(prefObj))) 188 if (deepEqual(prefStoreValue, prefObj.value))
146 return; 189 return;
147 190
148 this.settingsApi_.setPref( 191 this.settingsApi_.setPref(
149 key, 192 key,
150 prefObj.value, 193 prefObj.value,
151 /* pageId */ '', 194 /* pageId */ '',
152 /* callback */ this.setPrefCallback_.bind(this, key)); 195 /* callback */ this.setPrefCallback_.bind(this, key));
153 }, 196 },
154 197
155 /** 198 /**
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
194 237
195 /** 238 /**
196 * Updates the prefs model with the given prefs. 239 * Updates the prefs model with the given prefs.
197 * @param {!Array<!chrome.settingsPrivate.PrefObject>} newPrefs 240 * @param {!Array<!chrome.settingsPrivate.PrefObject>} newPrefs
198 * @private 241 * @private
199 */ 242 */
200 updatePrefs_: function(newPrefs) { 243 updatePrefs_: function(newPrefs) {
201 // Use the existing prefs object or create it. 244 // Use the existing prefs object or create it.
202 var prefs = this.prefs || {}; 245 var prefs = this.prefs || {};
203 newPrefs.forEach(function(newPrefObj) { 246 newPrefs.forEach(function(newPrefObj) {
204 // Use the PrefObject from settingsPrivate to create a PrefWrapper in 247 // Use the PrefObject from settingsPrivate to create a copy in
205 // prefWrappers_ at the pref's key. 248 // lastPrefValues_ at the pref's key.
206 this.prefWrappers_[newPrefObj.key] = 249 this.lastPrefValues_[newPrefObj.key] = deepCopy(newPrefObj.value);
207 this.createPrefWrapper_(newPrefObj);
208 250
209 // Add the pref to |prefs|. 251 // Add the pref to |prefs|.
210 cr.exportPath(newPrefObj.key, newPrefObj, prefs); 252 cr.exportPath(newPrefObj.key, newPrefObj, prefs);
211 // If this.prefs already exists, notify listeners of the change. 253 // If this.prefs already exists, notify listeners of the change.
212 if (prefs == this.prefs) 254 if (prefs == this.prefs)
213 this.notifyPath('prefs.' + newPrefObj.key, newPrefObj); 255 this.notifyPath('prefs.' + newPrefObj.key, newPrefObj);
214 }, this); 256 }, this);
215 if (!this.prefs) 257 if (!this.prefs)
216 this.prefs = prefs; 258 this.prefs = prefs;
217 }, 259 },
218 260
219 /** 261 /**
220 * Given a 'property-changed' path, returns the key of the preference the 262 * 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 263 * 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 264 * 'prefs.search.suggest_enabled.value', the key of the pref that changed is
223 * 'search.suggest_enabled'. 265 * 'search.suggest_enabled'.
224 * @param {string} path 266 * @param {string} path
225 * @return {string} 267 * @return {string}
226 * @private 268 * @private
227 */ 269 */
228 getPrefKeyFromPath_: function(path) { 270 getPrefKeyFromPath_: function(path) {
229 // Skip the first token, which refers to the member variable (this.prefs). 271 // Skip the first token, which refers to the member variable (this.prefs).
230 var parts = path.split('.'); 272 var parts = path.split('.');
231 assert(parts.shift() == 'prefs'); 273 assert(parts.shift() == 'prefs');
232 274
233 for (let i = 1; i <= parts.length; i++) { 275 for (let i = 1; i <= parts.length; i++) {
234 let key = parts.slice(0, i).join('.'); 276 let key = parts.slice(0, i).join('.');
235 // The prefWrappers_ keys match the pref keys. 277 // The lastPrefValues_ keys match the pref keys.
236 if (this.prefWrappers_[key] != undefined) 278 if (this.lastPrefValues_.hasOwnProperty(key))
237 return key; 279 return key;
238 } 280 }
239 return ''; 281 return '';
240 }, 282 },
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 }); 283 });
255 })(); 284 })();
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