Home | History | Annotate | Download | only in options
      1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 cr.define('options', function() {
      6   const List = cr.ui.List;
      7   const ListItem = cr.ui.ListItem;
      8 
      9   /**
     10    * Creates a deletable list item, which has a button that will trigger a call
     11    * to deleteItemAtIndex(index) in the list.
     12    */
     13   var DeletableItem = cr.ui.define('li');
     14 
     15   DeletableItem.prototype = {
     16     __proto__: ListItem.prototype,
     17 
     18     /**
     19      * The element subclasses should populate with content.
     20      * @type {HTMLElement}
     21      * @private
     22      */
     23     contentElement_: null,
     24 
     25     /**
     26      * The close button element.
     27      * @type {HTMLElement}
     28      * @private
     29      */
     30     closeButtonElement_: null,
     31 
     32     /**
     33      * Whether or not this item can be deleted.
     34      * @type {boolean}
     35      * @private
     36      */
     37     deletable_: true,
     38 
     39     /** @inheritDoc */
     40     decorate: function() {
     41       ListItem.prototype.decorate.call(this);
     42 
     43       this.classList.add('deletable-item');
     44 
     45       this.contentElement_ = this.ownerDocument.createElement('div');
     46       this.appendChild(this.contentElement_);
     47 
     48       this.closeButtonElement_ = this.ownerDocument.createElement('button');
     49       this.closeButtonElement_.classList.add('raw-button');
     50       this.closeButtonElement_.classList.add('close-button');
     51       this.closeButtonElement_.addEventListener('mousedown',
     52                                                 this.handleMouseDownUpOnClose_);
     53       this.closeButtonElement_.addEventListener('mouseup',
     54                                                 this.handleMouseDownUpOnClose_);
     55       this.appendChild(this.closeButtonElement_);
     56     },
     57 
     58     /**
     59      * Returns the element subclasses should add content to.
     60      * @return {HTMLElement} The element subclasses should popuplate.
     61      */
     62     get contentElement() {
     63       return this.contentElement_;
     64     },
     65 
     66     /* Gets/sets the deletable property. An item that is not deletable doesn't
     67      * show the delete button (although space is still reserved for it).
     68      */
     69     get deletable() {
     70       return this.deletable_;
     71     },
     72     set deletable(value) {
     73       this.deletable_ = value;
     74       this.closeButtonElement_.disabled = !value;
     75     },
     76 
     77     /**
     78      * Don't let the list have a crack at the event. We don't want clicking the
     79      * close button to change the selection of the list.
     80      * @param {Event} e The mouse down/up event object.
     81      * @private
     82      */
     83     handleMouseDownUpOnClose_: function(e) {
     84       if (!e.target.disabled)
     85         e.stopPropagation();
     86     },
     87   };
     88 
     89   var DeletableItemList = cr.ui.define('list');
     90 
     91   DeletableItemList.prototype = {
     92     __proto__: List.prototype,
     93 
     94     /** @inheritDoc */
     95     decorate: function() {
     96       List.prototype.decorate.call(this);
     97       this.addEventListener('click', this.handleClick_);
     98       this.addEventListener('keydown', this.handleKeyDown_);
     99     },
    100 
    101     /**
    102      * Callback for onclick events.
    103      * @param {Event} e The click event object.
    104      * @private
    105      */
    106     handleClick_: function(e) {
    107       if (this.disabled)
    108         return;
    109 
    110       var target = e.target;
    111       if (target.classList.contains('close-button')) {
    112         var listItem = this.getListItemAncestor(target);
    113         var selected = this.selectionModel.selectedIndexes;
    114 
    115         // Check if the list item that contains the close button being clicked
    116         // is not in the list of selected items. Only delete this item in that
    117         // case.
    118         var idx = this.getIndexOfListItem(listItem);
    119         if (selected.indexOf(idx) == -1) {
    120           this.deleteItemAtIndex(idx);
    121         } else {
    122           this.deleteSelectedItems_();
    123         }
    124       }
    125     },
    126 
    127     /**
    128      * Callback for keydown events.
    129      * @param {Event} e The keydown event object.
    130      * @private
    131      */
    132     handleKeyDown_: function(e) {
    133       // Map delete (and backspace on Mac) to item deletion (unless focus is
    134       // in an input field, where it's intended for text editing).
    135       if ((e.keyCode == 46 || (e.keyCode == 8 && cr.isMac)) &&
    136           e.target.tagName != 'INPUT') {
    137         this.deleteSelectedItems_();
    138         // Prevent the browser from going back.
    139         e.preventDefault();
    140       }
    141     },
    142 
    143     /**
    144      * Deletes all the currently selected items that are deletable.
    145      * @private
    146      */
    147     deleteSelectedItems_: function() {
    148       var selected = this.selectionModel.selectedIndexes;
    149       // Reverse through the list of selected indexes to maintain the
    150       // correct index values after deletion.
    151       for (var j = selected.length - 1; j >= 0; j--) {
    152         var index = selected[j];
    153         if (this.getListItemByIndex(index).deletable)
    154           this.deleteItemAtIndex(index);
    155       }
    156     },
    157 
    158     /**
    159      * Called when an item should be deleted; subclasses are responsible for
    160      * implementing.
    161      * @param {number} index The index of the item that is being deleted.
    162      */
    163     deleteItemAtIndex: function(index) {
    164     },
    165   };
    166 
    167   return {
    168     DeletableItemList: DeletableItemList,
    169     DeletableItem: DeletableItem,
    170   };
    171 });
    172