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

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

Issue 1357183002: MD-Settings: convert cr-settings-prefs to a singleton model (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: unnecessary parens 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
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' exposes a sinlgeton model of Chrome settings and
8 * changes to Chrome prefs whitelisted in chrome.settingsPrivate. 8 * preferences, which listens to changes to Chrome prefs whitelisted in
9 * When changing prefs in this element's 'prefs' property via the UI, this 9 * chrome.settingsPrivate. When changing prefs in this element's 'prefs'
10 * element tries to set those preferences in Chrome. Whether or not the calls to 10 * property via the UI, the model tries to set those preferences in Chrome.
11 * settingsPrivate.setPref succeed, 'prefs' is eventually consistent with the 11 * Whether or not the calls to settingsPrivate.setPref succeed, 'prefs'
12 * Chrome pref store. 12 * is eventually consistent with the 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
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after
129 properties: { 129 properties: {
130 /** 130 /**
131 * Object containing all preferences, for use by Polymer controls. 131 * Object containing all preferences, for use by Polymer controls.
132 */ 132 */
133 prefs: { 133 prefs: {
134 type: Object, 134 type: Object,
135 notify: true, 135 notify: true,
136 }, 136 },
137 137
138 /** 138 /**
139 * Shared private state.
140 * @type {!Element}
141 */
142 prefsPrivate_: {
143 type: Object,
144 value: document.createElement('cr-settings-prefs-private'),
145 },
146 },
147
148 observers: [
149 'prefsChanged_(prefs.*)',
150 ],
151
152 /** @override */
153 ready: function() {
154 this.prefsPrivate_.initialize();
155 this.startListening_();
156 },
157
158 /**
159 * Binds this.prefs to the cr-settings-prefs-private's shared prefs once
160 * preferences are initialized.
161 * @private
162 */
163 startListening_: function() {
164 CrSettingsPrefs.initialized.then(function() {
165 // Ignore changes to prevent prefsChanged_ from notifying prefsPrivate_.
166 this.runWhileIgnoringChanges_(function() {
167 this.prefs = this.prefsPrivate_.prefs;
168 this.stopListening_();
169 this.listen(
170 this.prefsPrivate_, 'prefs-changed', 'prefsPrivateChanged_');
171 });
172 }.bind(this));
173 },
174
175 /**
176 * Stops listening for changes to cr-settings-prefs-private's shared prefs.
177 * @private
178 */
179 stopListening_: function() {
180 this.unlisten(
181 this.prefsPrivate_, 'prefs-changed', 'prefsPrivateChanged_');
182 },
183
184 /**
185 * Handles changes reported by prefsPrivate_.
186 * @private
187 */
188 prefsPrivateChanged_: function(e) {
189 // Ignore changes because we've defeated Polymer's dirty-checking.
190 this.runWhileIgnoringChanges_(function() {
191 // Forward notification to host.
192 this.fire(e.type, e.detail, {bubbles: false});
193 });
194 },
195
196 /**
197 * Forwards changes to this.prefs to cr-settings-prefs-private.
198 * @private
199 */
200 prefsChanged_: function(info) {
201 // Ignore prefsPrivate_ of changes that came from it so we don't
202 // re-processing changes made in other instances of this element.
203 if (!this.ignoreChanges_)
204 this.prefsPrivate_.fire('prefs-changed', info, {bubbles: false});
205 },
206
207 /**
208 * Sets ignoreChanged_ before calling the function to suppress change
209 * events that are manually handled.
210 * @param {!function()} fn
211 * @private
212 */
213 runWhileIgnoringChanges_: function(fn) {
Dan Beam 2015/09/22 06:12:31 assert(!this.ignoreChanges_, 'update the code to s
michaelpg 2015/09/22 21:38:36 Done.
214 this.ignoreChanges_ = true;
215 fn.call(this);
216 // We can unset ignoreChanges_ now because change notifications
217 // are synchronous.
218 this.ignoreChanges_ = false;
219 },
220
221 /**
222 * Uninitializes this element to remove it from tests. Also resets
223 * cr-settings-prefs-private, allowing newly created elements to
224 * re-initialize it.
225 */
226 resetForTesting: function() {
227 this.stopListening_();
228 this.prefsPrivate_.resetForTesting();
229 },
230 });
231
232 /**
233 * Privately used element that contains, listens to and updates the shared
234 * prefs state.
235 */
236 Polymer({
237 is: 'cr-settings-prefs-private',
238
239 properties: {
240 /**
241 * Object containing all preferences, for use by Polymer controls.
242 * @type {Object|undefined}
243 */
244 prefs: {
245 type: Object,
246 notify: true,
247 },
248
249 /**
139 * Map of pref keys to values representing the state of the Chrome 250 * Map of pref keys to values representing the state of the Chrome
140 * pref store as of the last update from the API. 251 * pref store as of the last update from the API.
141 * @type {Object<*>} 252 * @type {Object<*>}
142 * @private 253 * @private
143 */ 254 */
144 lastPrefValues_: { 255 lastPrefValues_: {
145 type: Object, 256 type: Object,
146 value: function() { return {}; }, 257 value: function() { return {}; },
147 }, 258 },
148 }, 259 },
149 260
150 observers: [ 261 // Listen for the manually fired prefs-changed event.
151 'prefsChanged_(prefs.*)', 262 listeners: {
152 ], 263 'prefs-changed': 'prefsChanged_',
264 },
153 265
154 settingsApi_: chrome.settingsPrivate, 266 settingsApi_: chrome.settingsPrivate,
155 267
156 /** @override */ 268 initialize: function() {
157 ready: function() { 269 // Only initialize once (or after resetForTesting() is called).
270 if (this.initialized_)
271 return;
272 this.initialized_ = true;
273
158 // Set window.mockApi to pass a custom settings API, i.e. for tests. 274 // Set window.mockApi to pass a custom settings API, i.e. for tests.
159 // TODO(michaelpg): don't use a global. 275 // TODO(michaelpg): don't use a global.
160 if (window.mockApi) 276 if (window.mockApi)
161 this.settingsApi_ = window.mockApi; 277 this.settingsApi_ = window.mockApi;
162 CrSettingsPrefs.isInitialized = false;
163 278
164 this.settingsApi_.onPrefsChanged.addListener( 279 this.settingsApi_.onPrefsChanged.addListener(
165 this.onSettingsPrivatePrefsChanged_.bind(this)); 280 this.onSettingsPrivatePrefsChanged_.bind(this));
166 this.settingsApi_.getAllPrefs( 281 this.settingsApi_.getAllPrefs(
167 this.onSettingsPrivatePrefsFetched_.bind(this)); 282 this.onSettingsPrivatePrefsFetched_.bind(this));
168 }, 283 },
169 284
170 /** 285 /**
171 * Polymer callback for changes to this.prefs. 286 * Polymer callback for changes to this.prefs.
172 * @param {!{path: string, value: *}} change 287 * @param {!CustomEvent} e
288 * @param {!{path: string}} change
173 * @private 289 * @private
174 */ 290 */
175 prefsChanged_: function(change) { 291 prefsChanged_: function(e, change) {
176 if (!CrSettingsPrefs.isInitialized) 292 if (!CrSettingsPrefs.isInitialized)
177 return; 293 return;
178 294
179 var key = this.getPrefKeyFromPath_(change.path); 295 var key = this.getPrefKeyFromPath_(change.path);
180 var prefStoreValue = this.lastPrefValues_[key]; 296 var prefStoreValue = this.lastPrefValues_[key];
181 297
182 var prefObj = /** @type {chrome.settingsPrivate.PrefObject} */( 298 var prefObj = /** @type {chrome.settingsPrivate.PrefObject} */(
183 this.get(key, this.prefs)); 299 this.get(key, this.prefs));
184 300
185 // If settingsPrivate already has this value, do nothing. (Otherwise, 301 // If settingsPrivate already has this value, do nothing. (Otherwise,
(...skipping 20 matching lines...) Expand all
206 this.updatePrefs_(prefs); 322 this.updatePrefs_(prefs);
207 }, 323 },
208 324
209 /** 325 /**
210 * Called when prefs are fetched from settingsPrivate. 326 * Called when prefs are fetched from settingsPrivate.
211 * @param {!Array<!chrome.settingsPrivate.PrefObject>} prefs 327 * @param {!Array<!chrome.settingsPrivate.PrefObject>} prefs
212 * @private 328 * @private
213 */ 329 */
214 onSettingsPrivatePrefsFetched_: function(prefs) { 330 onSettingsPrivatePrefsFetched_: function(prefs) {
215 this.updatePrefs_(prefs); 331 this.updatePrefs_(prefs);
216 332 // Prefs are now initialized.
Dan Beam 2015/09/22 06:12:31 nit: useless comment
michaelpg 2015/09/22 21:38:37 Done.
217 CrSettingsPrefs.isInitialized = true; 333 CrSettingsPrefs.setInitialized();
218 document.dispatchEvent(new Event(CrSettingsPrefs.INITIALIZED));
219 }, 334 },
220 335
221 /** 336 /**
222 * Checks the result of calling settingsPrivate.setPref. 337 * Checks the result of calling settingsPrivate.setPref.
223 * @param {string} key The key used in the call to setPref. 338 * @param {string} key The key used in the call to setPref.
224 * @param {boolean} success True if setting the pref succeeded. 339 * @param {boolean} success True if setting the pref succeeded.
225 * @private 340 * @private
226 */ 341 */
227 setPrefCallback_: function(key, success) { 342 setPrefCallback_: function(key, success) {
228 if (success) 343 if (success)
(...skipping 12 matching lines...) Expand all
241 * @private 356 * @private
242 */ 357 */
243 updatePrefs_: function(newPrefs) { 358 updatePrefs_: function(newPrefs) {
244 // Use the existing prefs object or create it. 359 // Use the existing prefs object or create it.
245 var prefs = this.prefs || {}; 360 var prefs = this.prefs || {};
246 newPrefs.forEach(function(newPrefObj) { 361 newPrefs.forEach(function(newPrefObj) {
247 // Use the PrefObject from settingsPrivate to create a copy in 362 // Use the PrefObject from settingsPrivate to create a copy in
248 // lastPrefValues_ at the pref's key. 363 // lastPrefValues_ at the pref's key.
249 this.lastPrefValues_[newPrefObj.key] = deepCopy(newPrefObj.value); 364 this.lastPrefValues_[newPrefObj.key] = deepCopy(newPrefObj.value);
250 365
251 // Add the pref to |prefs|. 366 if (!deepEqual(this.get(newPrefObj.key, prefs), newPrefObj)) {
252 cr.exportPath(newPrefObj.key, newPrefObj, prefs); 367 // Add the pref to |prefs|.
253 // If this.prefs already exists, notify listeners of the change. 368 cr.exportPath(newPrefObj.key, newPrefObj, prefs);
254 if (prefs == this.prefs) 369 // If this.prefs already exists, notify listeners of the change.
255 this.notifyPath('prefs.' + newPrefObj.key, newPrefObj); 370 if (prefs == this.prefs)
371 this.notifyPath('prefs.' + newPrefObj.key, newPrefObj);
372 }
256 }, this); 373 }, this);
257 if (!this.prefs) 374 if (!this.prefs)
258 this.prefs = prefs; 375 this.prefs = prefs;
259 }, 376 },
260 377
261 /** 378 /**
262 * Given a 'property-changed' path, returns the key of the preference the 379 * Given a 'property-changed' path, returns the key of the preference the
263 * path refers to. E.g., if the path of the changed property is 380 * path refers to. E.g., if the path of the changed property is
264 * 'prefs.search.suggest_enabled.value', the key of the pref that changed is 381 * 'prefs.search.suggest_enabled.value', the key of the pref that changed is
265 * 'search.suggest_enabled'. 382 * 'search.suggest_enabled'.
266 * @param {string} path 383 * @param {string} path
267 * @return {string} 384 * @return {string}
268 * @private 385 * @private
269 */ 386 */
270 getPrefKeyFromPath_: function(path) { 387 getPrefKeyFromPath_: function(path) {
271 // Skip the first token, which refers to the member variable (this.prefs). 388 // Skip the first token, which refers to the member variable (this.prefs).
272 var parts = path.split('.'); 389 var parts = path.split('.');
273 assert(parts.shift() == 'prefs'); 390 assert(parts.shift() == 'prefs');
274 391
275 for (let i = 1; i <= parts.length; i++) { 392 for (let i = 1; i <= parts.length; i++) {
276 let key = parts.slice(0, i).join('.'); 393 let key = parts.slice(0, i).join('.');
277 // The lastPrefValues_ keys match the pref keys. 394 // The lastPrefValues_ keys match the pref keys.
278 if (this.lastPrefValues_.hasOwnProperty(key)) 395 if (this.lastPrefValues_.hasOwnProperty(key))
279 return key; 396 return key;
280 } 397 }
281 return ''; 398 return '';
282 }, 399 },
400
401 /**
402 * Resets the element so it can be re-initialized with a new prefs state.
403 */
404 resetForTesting: function() {
405 this.prefs = undefined;
406 this.lastPrefValues_ = {};
407 this.initialized_ = false;
408 },
283 }); 409 });
284 })(); 410 })();
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698