Index: chrome/browser/resources/settings/prefs/prefs.js |
diff --git a/chrome/browser/resources/settings/prefs/prefs.js b/chrome/browser/resources/settings/prefs/prefs.js |
index 4d1e7062562064b78318f4a5ee21aeaf9ffe4b1d..ddb38be8ee478326abb67fec7a1cc1ffb9c149f1 100644 |
--- a/chrome/browser/resources/settings/prefs/prefs.js |
+++ b/chrome/browser/resources/settings/prefs/prefs.js |
@@ -20,63 +20,108 @@ |
* @element cr-settings-prefs |
*/ |
-/** |
- * Pref state object. Copies values of PrefObjects received from |
- * settingsPrivate to determine when pref values have changed. |
- * This prototype works for primitive types, but more complex types should |
- * override these functions. |
- * @constructor |
- * @param {!chrome.settingsPrivate.PrefObject} prefObj |
- */ |
-function PrefWrapper(prefObj) { |
- this.key_ = prefObj.key; |
- this.value_ = prefObj.value; |
-} |
+(function() { |
+ 'use strict'; |
-/** |
- * Checks if other's value equals this.value_. Both prefs wrapped by the |
- * PrefWrappers should have the same keys. |
- * @param {PrefWrapper} other |
- * @return {boolean} |
- */ |
-PrefWrapper.prototype.equals = function(other) { |
- assert(this.key_ == other.key_); |
- return this.value_ == other.value_; |
-}; |
+ /** |
+ * Checks whether two values are recursively equal. Only compares serializable |
+ * data (primitives, serializable arrays and serializable objects). |
+ * @param {*} val1 Value to compare. |
+ * @param {*} val2 Value to compare with val1. |
+ * @return {boolean} True if the values are recursively equal. |
+ */ |
+ function deepEqual(val1, val2) { |
+ if (val1 === val2) |
+ return true; |
-/** |
- * @constructor |
- * @extends {PrefWrapper} |
- * @param {!chrome.settingsPrivate.PrefObject} prefObj |
- */ |
-function ListPrefWrapper(prefObj) { |
- // Copy the array so changes to prefObj aren't reflected in this.value_. |
- // TODO(michaelpg): Do a deep copy to support nested lists and objects. |
- this.value_ = prefObj.value.slice(); |
-} |
+ if (Array.isArray(val1) || Array.isArray(val2)) { |
+ if (!Array.isArray(val1) || !Array.isArray(val2)) |
+ return false; |
+ return arraysEqual(/** @type {!Array} */(val1), |
+ /** @type {!Array} */(val2)); |
+ } |
+ |
+ if (val1 instanceof Object && val2 instanceof Object) |
+ return objectsEqual(val1, val2); |
- ListPrefWrapper.prototype = { |
- __proto__: PrefWrapper.prototype, |
+ return false; |
+ } |
/** |
- * Tests whether two ListPrefWrapper values contain the same list items. |
- * @override |
+ * @param {!Array} arr1 |
+ * @param {!Array} arr2 |
+ * @return {boolean} True if the arrays are recursively equal. |
*/ |
- equals: function(other) { |
- 'use strict'; |
- assert(this.key_ == other.key_); |
- if (this.value_.length != other.value_.length) |
+ function arraysEqual(arr1, arr2) { |
+ if (arr1.length != arr2.length) |
return false; |
- for (let i = 0; i < this.value_.length; i++) { |
- if (this.value_[i] != other.value_[i]) |
+ |
+ for (var i = 0; i < arr1.length; i++) { |
+ if (!deepEqual(arr1[i], arr2[i])) |
return false; |
} |
+ |
return true; |
- }, |
-}; |
+ } |
-(function() { |
- 'use strict'; |
+ /** |
+ * @param {!Object} obj1 |
+ * @param {!Object} obj2 |
+ * @return {boolean} True if the objects are recursively equal. |
+ */ |
+ function objectsEqual(obj1, obj2) { |
+ var keys1 = Object.keys(obj1); |
+ var keys2 = Object.keys(obj2); |
+ if (keys1.length != keys2.length) |
+ return false; |
+ |
+ for (var i = 0; i < keys1.length; i++) { |
+ var key = keys1[i]; |
+ if (!deepEqual(obj1[key], obj2[key])) |
+ return false; |
+ } |
+ |
+ return true; |
+ } |
+ |
+ /** |
+ * Returns a recursive copy of the value. |
+ * @param {*} val Value to copy. Should be a primitive or only contain |
+ * serializable data (primitives, serializable arrays and |
+ * serializable objects). |
+ * @return {*} A deep copy of the value. |
+ */ |
+ function deepCopy(val) { |
+ if (!(val instanceof Object)) |
+ return val; |
+ return Array.isArray(val) ? deepCopyArray(/** @type {!Array} */(val)) : |
+ deepCopyObject(val); |
+ }; |
+ |
+ /** |
+ * @param {!Array} arr |
+ * @return {!Array} Deep copy of the array. |
+ */ |
+ function deepCopyArray(arr) { |
+ var copy = []; |
+ for (var i = 0; i < arr.length; i++) |
+ copy.push(deepCopy(arr[i])); |
+ return copy; |
+ } |
+ |
+ /** |
+ * @param {!Object} obj |
+ * @return {!Object} Deep copy of the object. |
+ */ |
+ function deepCopyObject(obj) { |
+ var copy = {}; |
+ var keys = Object.keys(obj); |
+ for (var i = 0; i < keys.length; i++) { |
+ var key = keys[i]; |
+ copy[key] = deepCopy(obj[key]); |
+ } |
+ return copy; |
+ } |
Polymer({ |
is: 'cr-settings-prefs', |
@@ -91,12 +136,12 @@ function ListPrefWrapper(prefObj) { |
}, |
/** |
- * Map of pref keys to PrefWrapper objects representing the state of the |
- * Chrome pref store. |
- * @type {Object<PrefWrapper>} |
+ * Map of pref keys to values representing the state of the Chrome |
+ * pref store as of the last update from the API. |
+ * @type {Object<*>} |
* @private |
*/ |
- prefWrappers_: { |
+ lastPrefValues_: { |
type: Object, |
value: function() { return {}; }, |
}, |
@@ -132,9 +177,7 @@ function ListPrefWrapper(prefObj) { |
return; |
var key = this.getPrefKeyFromPath_(change.path); |
- var prefWrapper = this.prefWrappers_[key]; |
- if (!prefWrapper) |
- return; |
+ var prefStoreValue = this.lastPrefValues_[key]; |
var prefObj = /** @type {chrome.settingsPrivate.PrefObject} */( |
this.get(key, this.prefs)); |
@@ -142,7 +185,7 @@ function ListPrefWrapper(prefObj) { |
// If settingsPrivate already has this value, do nothing. (Otherwise, |
// a change event from settingsPrivate could make us call |
// settingsPrivate.setPref and potentially trigger an IPC loop.) |
- if (prefWrapper.equals(this.createPrefWrapper_(prefObj))) |
+ if (deepEqual(prefStoreValue, prefObj.value)) |
return; |
this.settingsApi_.setPref( |
@@ -201,10 +244,9 @@ function ListPrefWrapper(prefObj) { |
// Use the existing prefs object or create it. |
var prefs = this.prefs || {}; |
newPrefs.forEach(function(newPrefObj) { |
- // Use the PrefObject from settingsPrivate to create a PrefWrapper in |
- // prefWrappers_ at the pref's key. |
- this.prefWrappers_[newPrefObj.key] = |
- this.createPrefWrapper_(newPrefObj); |
+ // Use the PrefObject from settingsPrivate to create a copy in |
+ // lastPrefValues_ at the pref's key. |
+ this.lastPrefValues_[newPrefObj.key] = deepCopy(newPrefObj.value); |
// Add the pref to |prefs|. |
cr.exportPath(newPrefObj.key, newPrefObj, prefs); |
@@ -232,24 +274,11 @@ function ListPrefWrapper(prefObj) { |
for (let i = 1; i <= parts.length; i++) { |
let key = parts.slice(0, i).join('.'); |
- // The prefWrappers_ keys match the pref keys. |
- if (this.prefWrappers_[key] != undefined) |
+ // The lastPrefValues_ keys match the pref keys. |
+ if (this.lastPrefValues_.hasOwnProperty(key)) |
return key; |
} |
return ''; |
}, |
- |
- /** |
- * Creates a PrefWrapper object from a chrome.settingsPrivate pref. |
- * @param {!chrome.settingsPrivate.PrefObject} prefObj |
- * PrefObject received from chrome.settingsPrivate. |
- * @return {PrefWrapper} An object containing a copy of the PrefObject's |
- * value. |
- * @private |
- */ |
- createPrefWrapper_: function(prefObj) { |
- return prefObj.type == chrome.settingsPrivate.PrefType.LIST ? |
- new ListPrefWrapper(prefObj) : new PrefWrapper(prefObj); |
- }, |
}); |
})(); |