| Index: Tools/GardeningServer/lib/update-util.html
|
| diff --git a/Tools/GardeningServer/lib/update-util.html b/Tools/GardeningServer/lib/update-util.html
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..1d3f191db959dd94752d75897c5497133c61b227
|
| --- /dev/null
|
| +++ b/Tools/GardeningServer/lib/update-util.html
|
| @@ -0,0 +1,105 @@
|
| +<!--
|
| +Copyright 2014 The Chromium Authors. All rights reserved.
|
| +Use of this source code is governed by a BSD-style license that can be
|
| +found in the LICENSE file.
|
| +-->
|
| +
|
| +<link rel="import" href="sugar.html">
|
| +
|
| +<script>
|
| +
|
| +var updateUtil = updateUtil || {};
|
| +
|
| +(function () {
|
| +'use strict';
|
| +
|
| +// Returns true if |updateLeft| can do a field-wise merge from |source| to |target|.
|
| +// We assume |target| and |source| have the same type.
|
| +// If they're arrays, true if the elements have a |key| property.
|
| +// If they're objects, true if they're not null. (null should be assigned).
|
| +// Otherwise, false.
|
| +function canUpdateLeft(target, source) {
|
| + if (Array.isArray(target)) {
|
| + // If |source| is empty, we'll return an empty array regardless.
|
| + return source.length !== 0 && source[0].key !== undefined;
|
| + } else if (target === null || source === null) {
|
| + return false;
|
| + } else if (typeof target === 'object') {
|
| + return true;
|
| + }
|
| + return false;
|
| +};
|
| +
|
| +// |target| and |source| must have the same type, which must return true from
|
| +// canUpdateLeft() (see above). An array is treated like a dictionary where the
|
| +// key of an object is its |key| property, except that no effort is made to
|
| +// preserve the object identity of arrays. This function will:
|
| +//
|
| +// * Ignore elements listed in an object's constructor's |transientProperties| array.
|
| +// * Remove elements from |target| whose key isn't in |source|.
|
| +// * Copy elements from |source| whose key isn't in |target| or which are !canUpdateLeft().
|
| +// In particular, we copy |null| rather than trying to merge it.
|
| +// * If a matching element defines an |updateLeft| method, call that to let types customize the update process.
|
| +// This method must return the updated object.
|
| +// * Call updateLeft recursively for other matching elements.
|
| +//
|
| +// You have to call this as "target = updateLeft(target, source);" because it
|
| +// won't always update |target| in-place.
|
| +updateUtil.updateLeft = function(target, source)
|
| +{
|
| + if (!canUpdateLeft(target, source)) {
|
| + return source;
|
| + }
|
| +
|
| + if (target.updateLeft) {
|
| + return target.updateLeft(source);
|
| + }
|
| +
|
| + if (Array.isArray(target)) {
|
| + return updateLeftArray(target, source);
|
| + } else {
|
| + return updateLeftObject(target, source);
|
| + }
|
| +};
|
| +
|
| +// |target| and |source| must be arrays of objects with a |key| property.
|
| +function updateLeftArray(target, source) {
|
| + var oldElemByKey = {};
|
| + target.forEach(function(elem) {
|
| + oldElemByKey[elem.key] = elem;
|
| + })
|
| + // Polymer doesn't pay attention to array identity when deciding to recreate
|
| + // elements, just object identity.
|
| + return source.map(function(value) {
|
| + return updateUtil.updateLeft(oldElemByKey[value.key], value);
|
| + });
|
| +};
|
| +
|
| +// |target| and |source| must be objects. |target|'s properties will be updated
|
| +// to match |source|'s except for properties listed in its constructor's
|
| +// |transientProperties| array.
|
| +function updateLeftObject(target, source) {
|
| + // Prepare to filter out properties that reflect local UI
|
| + // state that wasn't loaded from the server.
|
| + var transientProperties = target.constructor.transientProperties;
|
| + function isTransientProperty(name) {
|
| + return transientProperties && transientProperties.indexOf(name) !== -1;
|
| + };
|
| +
|
| + // Remove elements from |target| that aren't in |source|.
|
| + Object.keys(target, function(key) {
|
| + if (!source.hasOwnProperty(key) && !isTransientProperty(key))
|
| + delete target[key];
|
| + });
|
| +
|
| + // Recursively update or assign properties that are in |source|.
|
| + Object.keys(source, function(key, sourceValue) {
|
| + if (!isTransientProperty(key))
|
| + target[key] = updateUtil.updateLeft(target[key], source[key]);
|
| + });
|
| + return target;
|
| +};
|
| +
|
| +})();
|
| +
|
| +</script>
|
|
|