chromium/third_party/polymer/v3_0/components-chromium/iron-selector/iron-multi-selectable.js

/**
@license
Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
This code may only be used under the BSD style license found at
http://polymer.github.io/LICENSE.txt The complete set of authors may be found at
http://polymer.github.io/AUTHORS.txt The complete set of contributors may be
found at http://polymer.github.io/CONTRIBUTORS.txt Code distributed by Google as
part of the polymer project is also subject to an additional IP rights grant
found at http://polymer.github.io/PATENTS.txt
*/
import '../polymer/polymer_bundled.min.js';

import {IronSelectableBehavior} from './iron-selectable.js';

/**
 * @polymerBehavior IronMultiSelectableBehavior
 */
export const IronMultiSelectableBehaviorImpl = {
  properties: {

    /**
     * If true, multiple selections are allowed.
     */
    multi: {type: Boolean, value: false, observer: 'multiChanged'},

    /**
     * Gets or sets the selected elements. This is used instead of `selected`
     * when `multi` is true.
     */
    selectedValues: {
      type: Array,
      notify: true,
      value: function() {
        return [];
      }
    },

    /**
     * Returns an array of currently selected items.
     */
    selectedItems: {
      type: Array,
      readOnly: true,
      notify: true,
      value: function() {
        return [];
      }
    },

  },

  observers: ['_updateSelected(selectedValues.splices)'],

  /**
   * Selects the given value. If the `multi` property is true, then the selected
   * state of the `value` will be toggled; otherwise the `value` will be
   * selected.
   *
   * @method select
   * @param {string|number} value the value to select.
   */
  select: function(value) {
    if (this.multi) {
      this._toggleSelected(value);
    } else {
      this.selected = value;
    }
  },

  multiChanged: function(multi) {
    this._selection.multi = multi;
    this._updateSelected();
  },

  // UNUSED, FOR API COMPATIBILITY
  get _shouldUpdateSelection() {
    return this.selected != null ||
        (this.selectedValues != null && this.selectedValues.length);
  },

  _updateAttrForSelected: function() {
    if (!this.multi) {
      IronSelectableBehavior._updateAttrForSelected.apply(this);
    } else if (this.selectedItems && this.selectedItems.length > 0) {
      this.selectedValues =
          this.selectedItems
              .map(
                  function(selectedItem) {
                    return this._indexToValue(this.indexOf(selectedItem));
                  },
                  this)
              .filter(function(unfilteredValue) {
                return unfilteredValue != null;
              }, this);
    }
  },

  _updateSelected: function() {
    if (this.multi) {
      this._selectMulti(this.selectedValues);
    } else {
      this._selectSelected(this.selected);
    }
  },

  _selectMulti: function(values) {
    values = values || [];

    var selectedItems =
        (this._valuesToItems(values) || []).filter(function(item) {
          return item !== null && item !== undefined;
        });

    // clear all but the current selected items
    this._selection.clear(selectedItems);

    // select only those not selected yet
    for (var i = 0; i < selectedItems.length; i++) {
      this._selection.setItemSelected(selectedItems[i], true);
    }

    // Check for items, since this array is populated only when attached
    if (this.fallbackSelection && !this._selection.get().length) {
      var fallback = this._valueToItem(this.fallbackSelection);
      if (fallback) {
        this.select(this.fallbackSelection);
      }
    }
  },

  _selectionChange: function() {
    var s = this._selection.get();
    if (this.multi) {
      this._setSelectedItems(s);
      this._setSelectedItem(s.length ? s[0] : null);
    } else {
      if (s !== null && s !== undefined) {
        this._setSelectedItems([s]);
        this._setSelectedItem(s);
      } else {
        this._setSelectedItems([]);
        this._setSelectedItem(null);
      }
    }
  },

  _toggleSelected: function(value) {
    var i = this.selectedValues.indexOf(value);
    var unselected = i < 0;
    if (unselected) {
      this.push('selectedValues', value);
    } else {
      this.splice('selectedValues', i, 1);
    }
  },

  _valuesToItems: function(values) {
    return (values == null) ? null : values.map(function(value) {
      return this._valueToItem(value);
    }, this);
  }
};

/** @polymerBehavior */
export const IronMultiSelectableBehavior =
    [IronSelectableBehavior, IronMultiSelectableBehaviorImpl];