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

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

Issue 2254113002: MD Settings: reduce complexity and overhead of prefs singleton (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@SimplifyLanguages
Patch Set: test fix Created 4 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
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 * 'settings-prefs' exposes a singleton model of Chrome settings and 7 * 'settings-prefs' exposes a singleton model of Chrome settings and
8 * preferences, which listens to changes to Chrome prefs whitelisted in 8 * preferences, which listens to changes to Chrome prefs whitelisted in
9 * chrome.settingsPrivate. When changing prefs in this element's 'prefs' 9 * chrome.settingsPrivate. When changing prefs in this element's 'prefs'
10 * property via the UI, the singleton model tries to set those preferences in 10 * property via the UI, the singleton model tries to set those preferences in
11 * Chrome. Whether or not the calls to settingsPrivate.setPref succeed, 'prefs' 11 * Chrome. Whether or not the calls to settingsPrivate.setPref succeed, 'prefs'
12 * is eventually consistent with the Chrome pref store. 12 * is eventually consistent with the Chrome pref store.
13 *
14 * Example:
15 *
16 * <settings-prefs prefs="{{prefs}}"></settings-prefs>
17 * <settings-checkbox pref="{{prefs.homepage_is_newtabpage}}">
18 * </settings-checkbox>
19 */ 13 */
20 14
21 (function() { 15 (function() {
22 'use strict'; 16 'use strict';
23 17
24 /** 18 /**
25 * Checks whether two values are recursively equal. Only compares serializable 19 * Checks whether two values are recursively equal. Only compares serializable
26 * data (primitives, serializable arrays and serializable objects). 20 * data (primitives, serializable arrays and serializable objects).
27 * @param {*} val1 Value to compare. 21 * @param {*} val1 Value to compare.
28 * @param {*} val2 Value to compare with val1. 22 * @param {*} val2 Value to compare with val1.
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after
120 } 114 }
121 return copy; 115 return copy;
122 } 116 }
123 117
124 Polymer({ 118 Polymer({
125 is: 'settings-prefs', 119 is: 'settings-prefs',
126 120
127 properties: { 121 properties: {
128 /** 122 /**
129 * Object containing all preferences, for use by Polymer controls. 123 * Object containing all preferences, for use by Polymer controls.
130 */
131 prefs: {
132 type: Object,
133 notify: true,
134 },
135
136 /**
137 * Singleton element created at startup which provides the prefs model.
138 * @type {!Element}
139 */
140 singleton_: {
141 type: Object,
142 value: document.createElement('settings-prefs-singleton'),
143 },
144 },
145
146 observers: [
147 'prefsChanged_(prefs.*)',
148 ],
149
150 /** @override */
151 ready: function() {
152 // Register a callback on CrSettingsPrefs.initialized immediately so prefs
153 // is set as soon as the settings API returns. This enables other elements
154 // dependent on |prefs| to add their own callbacks to
155 // CrSettingsPrefs.initialized.
156 this.startListening_();
157 if (!CrSettingsPrefs.deferInitialization)
158 this.initialize();
159 },
160
161 /**
162 * Binds this.prefs to the settings-prefs-singleton's shared prefs once
163 * preferences are initialized.
164 * @private
165 */
166 startListening_: function() {
167 CrSettingsPrefs.initialized.then(function() {
168 // Ignore changes to prevent prefsChanged_ from notifying singleton_.
169 this.runWhileIgnoringChanges_(function() {
170 this.prefs = this.singleton_.prefs;
171 this.stopListening_();
172 this.listen(
173 this.singleton_, 'prefs-changed', 'singletonPrefsChanged_');
174 });
175 }.bind(this));
176 },
177
178 /**
179 * Stops listening for changes to settings-prefs-singleton's shared
180 * prefs.
181 * @private
182 */
183 stopListening_: function() {
184 this.unlisten(
185 this.singleton_, 'prefs-changed', 'singletonPrefsChanged_');
186 },
187
188 /**
189 * Handles changes reported by singleton_ by forwarding them to the host.
190 * @private
191 */
192 singletonPrefsChanged_: function(e) {
193 // Ignore changes because we've defeated Polymer's dirty-checking.
194 this.runWhileIgnoringChanges_(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 settings-prefs-singleton.
202 * @private
203 */
204 prefsChanged_: function(info) {
205 // Ignore changes that came from singleton_ so we don't re-process
206 // changes made in other instances of this element.
207 if (!this.ignoreChanges_)
208 this.singleton_.fire('shared-prefs-changed', info, {bubbles: false});
209 },
210
211 /**
212 * Sets ignoreChanged_ before calling the function to suppress change
213 * events that are manually handled.
214 * @param {!function()} fn
215 * @private
216 */
217 runWhileIgnoringChanges_: function(fn) {
218 assert(!this.ignoreChanges_,
219 'Nested calls to runWhileIgnoringChanges_ are not supported');
220 this.ignoreChanges_ = true;
221 fn.call(this);
222 // We can unset ignoreChanges_ now because change notifications
223 // are synchronous.
224 this.ignoreChanges_ = false;
225 },
226
227 /** Initializes the singleton, which will fetch the prefs. */
228 initialize: function() {
229 this.singleton_.initialize();
230 },
231
232 /**
233 * Used to initialize the singleton with a fake SettingsPrivate.
234 * @param {SettingsPrivate} settingsApi Fake implementation to use.
235 */
236 initializeForTesting: function(settingsApi) {
237 this.singleton_.initialize(settingsApi);
238 },
239
240 /**
241 * Uninitializes this element to remove it from tests. Also resets
242 * settings-prefs-singleton, allowing newly created elements to
243 * re-initialize it.
244 */
245 resetForTesting: function() {
246 this.singleton_.resetForTesting();
247 },
248 });
249
250 /**
251 * Privately used element that contains, listens to and updates the shared
252 * prefs state.
253 */
254 Polymer({
255 is: 'settings-prefs-singleton',
256
257 properties: {
258 /**
259 * Object containing all preferences, for use by Polymer controls.
260 * @type {Object|undefined} 124 * @type {Object|undefined}
261 */ 125 */
262 prefs: { 126 prefs: {
263 type: Object, 127 type: Object,
264 notify: true, 128 notify: true,
265 }, 129 },
266 130
267 /** 131 /**
268 * Map of pref keys to values representing the state of the Chrome 132 * Map of pref keys to values representing the state of the Chrome
269 * pref store as of the last update from the API. 133 * pref store as of the last update from the API.
270 * @type {Object<*>} 134 * @type {Object<*>}
271 * @private 135 * @private
272 */ 136 */
273 lastPrefValues_: { 137 lastPrefValues_: {
274 type: Object, 138 type: Object,
275 value: function() { return {}; }, 139 value: function() { return {}; },
276 }, 140 },
277 }, 141 },
278 142
279 // Listen for the manually fired shared-prefs-changed event, fired when 143 observers: [
280 // a shared-prefs instance is changed by another element. 144 'prefsChanged_(prefs.*)',
281 listeners: { 145 ],
282 'shared-prefs-changed': 'sharedPrefsChanged_',
283 },
284 146
285 /** @type {SettingsPrivate} */ 147 /** @type {SettingsPrivate} */
286 settingsApi_: /** @type {SettingsPrivate} */(chrome.settingsPrivate), 148 settingsApi_: /** @type {SettingsPrivate} */(chrome.settingsPrivate),
287 149
150 created: function() {
151 if (!CrSettingsPrefs.deferInitialization)
152 this.initialize();
153 },
154
288 /** 155 /**
289 * @param {SettingsPrivate=} opt_settingsApi SettingsPrivate implementation 156 * @param {SettingsPrivate=} opt_settingsApi SettingsPrivate implementation
290 * to use (chrome.settingsPrivate by default). 157 * to use (chrome.settingsPrivate by default).
291 */ 158 */
292 initialize: function(opt_settingsApi) { 159 initialize: function(opt_settingsApi) {
293 // Only initialize once (or after resetForTesting() is called). 160 // Only initialize once (or after resetForTesting() is called).
294 if (this.initialized_) 161 if (this.initialized_)
295 return; 162 return;
296 this.initialized_ = true; 163 this.initialized_ = true;
297 164
298 if (opt_settingsApi) 165 if (opt_settingsApi)
299 this.settingsApi_ = opt_settingsApi; 166 this.settingsApi_ = opt_settingsApi;
300 167
301 /** @private {function(!Array<!chrome.settingsPrivate.PrefObject>)} */ 168 /** @private {function(!Array<!chrome.settingsPrivate.PrefObject>)} */
302 this.boundPrefsChanged_ = this.onSettingsPrivatePrefsChanged_.bind(this); 169 this.boundPrefsChanged_ = this.onSettingsPrivatePrefsChanged_.bind(this);
303 this.settingsApi_.onPrefsChanged.addListener(this.boundPrefsChanged_); 170 this.settingsApi_.onPrefsChanged.addListener(this.boundPrefsChanged_);
304 this.settingsApi_.getAllPrefs( 171 this.settingsApi_.getAllPrefs(
305 this.onSettingsPrivatePrefsFetched_.bind(this)); 172 this.onSettingsPrivatePrefsFetched_.bind(this));
306 }, 173 },
307 174
308 /** 175 /**
309 * Polymer callback for changes to prefs.* from a shared-prefs element. 176 * @param {!{path: string}} e
310 * @param {!CustomEvent} e
311 * @param {!{path: string}} change
312 * @private 177 * @private
313 */ 178 */
314 sharedPrefsChanged_: function(e, change) { 179 prefsChanged_: function(e) {
315 if (!CrSettingsPrefs.isInitialized) 180 if (!CrSettingsPrefs.isInitialized)
316 return; 181 return;
182 // Prefs can be set directly in tests.
183 if (e.path == 'prefs')
Dan Beam 2016/08/18 05:00:12 nit: maybe combine with above?
michaelpg 2016/08/19 17:25:24 Done.
184 return;
317 185
318 var key = this.getPrefKeyFromPath_(change.path); 186 var key = this.getPrefKeyFromPath_(e.path);
319 var prefStoreValue = this.lastPrefValues_[key]; 187 var prefStoreValue = this.lastPrefValues_[key];
320 188
321 var prefObj = /** @type {chrome.settingsPrivate.PrefObject} */( 189 var prefObj = /** @type {chrome.settingsPrivate.PrefObject} */(
322 this.get(key, this.prefs)); 190 this.get(key, this.prefs));
323 191
324 // If settingsPrivate already has this value, ignore it. (Otherwise, 192 // If settingsPrivate already has this value, ignore it. (Otherwise,
325 // a change event from settingsPrivate could make us call 193 // a change event from settingsPrivate could make us call
326 // settingsPrivate.setPref and potentially trigger an IPC loop.) 194 // settingsPrivate.setPref and potentially trigger an IPC loop.)
327 if (!deepEqual(prefStoreValue, prefObj.value)) { 195 if (!deepEqual(prefStoreValue, prefObj.value)) {
328 this.settingsApi_.setPref( 196 this.settingsApi_.setPref(
329 key, 197 key,
330 prefObj.value, 198 prefObj.value,
331 /* pageId */ '', 199 /* pageId */ '',
332 /* callback */ this.setPrefCallback_.bind(this, key)); 200 /* callback */ this.setPrefCallback_.bind(this, key));
333 } 201 }
334
335 // Package the event as a prefs-changed event for other elements.
336 this.fire('prefs-changed', change);
337 }, 202 },
338 203
339 /** 204 /**
340 * Called when prefs in the underlying Chrome pref store are changed. 205 * Called when prefs in the underlying Chrome pref store are changed.
341 * @param {!Array<!chrome.settingsPrivate.PrefObject>} prefs 206 * @param {!Array<!chrome.settingsPrivate.PrefObject>} prefs
342 * The prefs that changed. 207 * The prefs that changed.
343 * @private 208 * @private
344 */ 209 */
345 onSettingsPrivatePrefsChanged_: function(prefs) { 210 onSettingsPrivatePrefsChanged_: function(prefs) {
346 if (CrSettingsPrefs.isInitialized) 211 if (CrSettingsPrefs.isInitialized)
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after
431 this.prefs = undefined; 296 this.prefs = undefined;
432 this.lastPrefValues_ = {}; 297 this.lastPrefValues_ = {};
433 this.initialized_ = false; 298 this.initialized_ = false;
434 // Remove the listener added in initialize(). 299 // Remove the listener added in initialize().
435 this.settingsApi_.onPrefsChanged.removeListener(this.boundPrefsChanged_); 300 this.settingsApi_.onPrefsChanged.removeListener(this.boundPrefsChanged_);
436 this.settingsApi_ = 301 this.settingsApi_ =
437 /** @type {SettingsPrivate} */(chrome.settingsPrivate); 302 /** @type {SettingsPrivate} */(chrome.settingsPrivate);
438 }, 303 },
439 }); 304 });
440 })(); 305 })();
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698