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

Powered by Google App Engine
This is Rietveld 408576698