chromium/ash/webui/common/resources/list_property_update_behavior.js

// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import {calculateSplices} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';

/**
 * @fileoverview |ListPropertyUpdateBehavior| is used to update an existing
 * polymer list property given the list after all the edits were made while
 * maintaining the reference to the original list. This allows
 * dom-repeat/iron-list elements bound to this list property to not fully
 * re-rendered from scratch.
 *
 * The minimal splices needed to transform the original list to the edited list
 * are calculated using |calculateSplices|. All the edits
 * are then applied to the original list. Once completed, a single notification
 * containing information about all the edits is sent to the polyer object.
 *
 * NOTE: This file is deprecated in favor of list_property_update_mixin.ts.
 * Don't use it in new code.
 */

/** @polymerBehavior */
export const ListPropertyUpdateBehavior = {
  /**
   * @param {string} propertyPath
   * @param {function(!Object): (!Object|string)} identityGetter
   * @param {!Array<!Object>} updatedList
   * @param {boolean=} identityBasedUpdate
   * @return {boolean} True if notifySplices was called.
   */
  updateList(
      propertyPath, identityGetter, updatedList, identityBasedUpdate = false) {
    const list = this.get(propertyPath);
    const splices = calculateSplices(
        updatedList.map(identityGetter), list.map(identityGetter));

    splices.forEach(splice => {
      const index = splice.index;
      const deleteCount = splice.removed.length;
      // Transform splices to the expected format of notifySplices().
      // Convert !Array<string> to !Array<!Object>.
      splice.removed = list.slice(index, index + deleteCount);
      splice.object = list;
      splice.type = 'splice';

      const added = updatedList.slice(index, index + splice.addedCount);
      const spliceParams = [index, deleteCount].concat(added);
      list.splice.apply(list, spliceParams);
    });

    let updated = splices.length > 0;
    if (!identityBasedUpdate) {
      list.forEach((item, index) => {
        const updatedItem = updatedList[index];
        if (JSON.stringify(item) !== JSON.stringify(updatedItem)) {
          this.set([propertyPath, index], updatedItem);
          updated = true;
        }
      });
    }

    if (splices.length > 0) {
      this.notifySplices(propertyPath, splices);
    }
    return updated;
  },
};

export class ListPropertyUpdateBehaviorInterface {
  /**
   * @param {string} propertyPath
   * @param {function(!Object): (!Object|string)} identityGetter
   * @param {!Array<!Object>} updatedList
   * @param {boolean=} identityBasedUpdate
   * @return {boolean} True if notifySplices was called.
   */
  updateList(
      propertyPath, identityGetter, updatedList, identityBasedUpdate = false) {}
}