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