Home | History | Annotate | Download | only in ui
      1 // Copyright (c) 2012 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 'use strict';
      6 
      7 /**
      8  * @fileoverview Simple list view.
      9  */
     10 base.requireStylesheet('ui.list_view');
     11 
     12 base.require('base.events');
     13 base.require('ui');
     14 base.require('ui.container_that_decorates_its_children');
     15 
     16 base.exportTo('ui', function() {
     17   /**
     18    * @constructor
     19    */
     20   var ListView = ui.define('x-list-view', ui.ContainerThatDecoratesItsChildren);
     21 
     22   ListView.prototype = {
     23     __proto__: ui.ContainerThatDecoratesItsChildren.prototype,
     24 
     25     decorate: function() {
     26       ui.ContainerThatDecoratesItsChildren.prototype.decorate.call(this);
     27 
     28       this.classList.add('x-list-view');
     29       this.onItemClicked_ = this.onItemClicked_.bind(this);
     30       this.onKeyDown_ = this.onKeyDown_.bind(this);
     31       this.tabIndex = 0;
     32       this.addEventListener('keydown', this.onKeyDown_);
     33 
     34       this.selectionChanged_ = false;
     35     },
     36 
     37     decorateChild_: function(item) {
     38       item.classList.add('list-item');
     39       item.addEventListener('click', this.onItemClicked_, true);
     40 
     41       var listView = this;
     42       Object.defineProperty(
     43           item,
     44           'selected', {
     45             configurable: true,
     46             set: function(value) {
     47               var oldSelection = listView.selectedElement;
     48               if (oldSelection && oldSelection != this && value)
     49                 listView.selectedElement.removeAttribute('selected');
     50               if (value)
     51                 this.setAttribute('selected', 'selected');
     52               else
     53                 this.removeAttribute('selected');
     54               var newSelection = listView.selectedElement;
     55               if (newSelection != oldSelection)
     56                 base.dispatchSimpleEvent(listView, 'selection-changed', false);
     57             },
     58             get: function() {
     59               return this.hasAttribute('selected');
     60             }
     61           });
     62     },
     63 
     64     undecorateChild_: function(item) {
     65       this.selectionChanged_ |= item.selected;
     66 
     67       item.classList.remove('list-item');
     68       item.removeEventListener('click', this.onItemClicked_);
     69       delete item.selected;
     70     },
     71 
     72     beginDecorating_: function() {
     73       this.selectionChanged_ = false;
     74     },
     75 
     76     doneDecoratingForNow_: function() {
     77       if (this.selectionChanged_)
     78         base.dispatchSimpleEvent(this, 'selection-changed', false);
     79     },
     80 
     81     get selectedElement() {
     82       var el = this.querySelector('.list-item[selected]');
     83       if (!el)
     84         return undefined;
     85       return el;
     86     },
     87 
     88     set selectedElement(el) {
     89       if (!el) {
     90         if (this.selectedElement)
     91           this.selectedElement.selected = false;
     92         return;
     93       }
     94 
     95       if (el.parentElement != this)
     96         throw new Error(
     97             'Can only select elements that are children of this list view');
     98       el.selected = true;
     99     },
    100 
    101     clear: function() {
    102       var changed = this.selectedElement !== undefined;
    103       ui.ContainerThatDecoratesItsChildren.prototype.clear.call(this);
    104       if (changed)
    105         base.dispatchSimpleEvent(this, 'selection-changed', false);
    106     },
    107 
    108     onItemClicked_: function(e) {
    109       var currentSelectedElement = this.selectedElement;
    110       if (currentSelectedElement)
    111         currentSelectedElement.removeAttribute('selected');
    112       var element = e.target;
    113       while (element.parentElement != this)
    114         element = element.parentElement;
    115       element.setAttribute('selected', 'selected');
    116       base.dispatchSimpleEvent(this, 'selection-changed', false);
    117     },
    118 
    119     onKeyDown_: function(e) {
    120       if (e.keyCode == 38) { // Up arrow.
    121         var prev = this.selectedElement.previousSibling;
    122         if (prev) {
    123           prev.selected = true;
    124           prev.scrollIntoView(false);
    125           e.preventDefault();
    126           return true;
    127         }
    128       } else if (e.keyCode == 40) { // Down arrow.
    129         var next = this.selectedElement.nextSibling;
    130         if (next) {
    131           next.selected = true;
    132           next.scrollIntoView(false);
    133           e.preventDefault();
    134           return true;
    135         }
    136       }
    137     },
    138 
    139     addItem: function(textContent) {
    140       var item = document.createElement('div');
    141       item.textContent = textContent;
    142       this.appendChild(item);
    143       return item;
    144     }
    145 
    146   };
    147 
    148   return {
    149     ListView: ListView
    150   };
    151 
    152 });
    153