1<!DOCTYPE html>
2<!--
3Copyright (c) 2014 The Chromium Authors. All rights reserved.
4Use of this source code is governed by a BSD-style license that can be
5found in the LICENSE file.
6-->
7
8<link rel="stylesheet" href="/tracing/ui/base/list_view.css">
9
10<link rel="import" href="/tracing/base/event.html">
11<link rel="import" href="/tracing/ui/base/container_that_decorates_its_children.html">
12<link rel="import" href="/tracing/ui/base/ui.html">
13<link rel="import" href="/tracing/ui/base/utils.html">
14
15<script>
16'use strict';
17
18/**
19 * @fileoverview Simple list view.
20 */
21tr.exportTo('tr.ui.b', function() {
22  /**
23   * @constructor
24   */
25  var ListView = tr.ui.b.define(
26      'x-list-view', tr.ui.b.ContainerThatDecoratesItsChildren);
27
28  ListView.prototype = {
29    __proto__: tr.ui.b.ContainerThatDecoratesItsChildren.prototype,
30
31    decorate: function() {
32      tr.ui.b.ContainerThatDecoratesItsChildren.prototype.decorate.call(this);
33
34      this.classList.add('x-list-view');
35      this.onItemClicked_ = this.onItemClicked_.bind(this);
36      this.onKeyDown_ = this.onKeyDown_.bind(this);
37      this.tabIndex = 0;
38      this.addEventListener('keydown', this.onKeyDown_);
39
40      this.selectionChanged_ = false;
41    },
42
43    decorateChild_: function(item) {
44      item.classList.add('list-item');
45      item.addEventListener('click', this.onItemClicked_, true);
46
47      var listView = this;
48      Object.defineProperty(
49          item,
50          'selected', {
51            configurable: true,
52            set: function(value) {
53              var oldSelection = listView.selectedElement;
54              if (oldSelection && oldSelection != this && value)
55                listView.selectedElement.removeAttribute('selected');
56              if (value)
57                this.setAttribute('selected', 'selected');
58              else
59                this.removeAttribute('selected');
60              var newSelection = listView.selectedElement;
61              if (newSelection != oldSelection)
62                tr.b.dispatchSimpleEvent(listView, 'selection-changed', false);
63            },
64            get: function() {
65              return this.hasAttribute('selected');
66            }
67          });
68    },
69
70    undecorateChild_: function(item) {
71      this.selectionChanged_ |= item.selected;
72
73      item.classList.remove('list-item');
74      item.removeEventListener('click', this.onItemClicked_);
75      delete item.selected;
76    },
77
78    beginDecorating_: function() {
79      this.selectionChanged_ = false;
80    },
81
82    doneDecoratingForNow_: function() {
83      if (this.selectionChanged_)
84        tr.b.dispatchSimpleEvent(this, 'selection-changed', false);
85    },
86
87    get selectedElement() {
88      var el = this.querySelector('.list-item[selected]');
89      if (!el)
90        return undefined;
91      return el;
92    },
93
94    set selectedElement(el) {
95      if (!el) {
96        if (this.selectedElement)
97          this.selectedElement.selected = false;
98        return;
99      }
100
101      if (el.parentElement != this)
102        throw new Error(
103            'Can only select elements that are children of this list view');
104      el.selected = true;
105    },
106
107    getElementByIndex: function(index) {
108      return this.querySelector('.list-item:nth-child(' + index + ')');
109    },
110
111    clear: function() {
112      var changed = this.selectedElement !== undefined;
113      tr.ui.b.ContainerThatDecoratesItsChildren.prototype.clear.call(this);
114      if (changed)
115        tr.b.dispatchSimpleEvent(this, 'selection-changed', false);
116    },
117
118    onItemClicked_: function(e) {
119      var currentSelectedElement = this.selectedElement;
120      if (currentSelectedElement)
121        currentSelectedElement.removeAttribute('selected');
122      var element = e.target;
123      while (element.parentElement != this)
124        element = element.parentElement;
125      if (element !== currentSelectedElement)
126        element.setAttribute('selected', 'selected');
127      tr.b.dispatchSimpleEvent(this, 'selection-changed', false);
128    },
129
130    onKeyDown_: function(e) {
131      if (this.selectedElement === undefined)
132        return;
133
134      if (e.keyCode == 38) { // Up arrow.
135        var prev = this.selectedElement.previousSibling;
136        if (prev) {
137          prev.selected = true;
138          tr.ui.b.scrollIntoViewIfNeeded(prev);
139          e.preventDefault();
140          return true;
141        }
142      } else if (e.keyCode == 40) { // Down arrow.
143        var next = this.selectedElement.nextSibling;
144        if (next) {
145          next.selected = true;
146          tr.ui.b.scrollIntoViewIfNeeded(next);
147          e.preventDefault();
148          return true;
149        }
150      }
151    },
152
153    addItem: function(textContent) {
154      var item = document.createElement('div');
155      item.textContent = textContent;
156      this.appendChild(item);
157      return item;
158    }
159
160  };
161
162  return {
163    ListView: ListView
164  };
165
166});
167</script>
168