Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / ui / webui / resources / js / cr / ui / list_single_selection_model.js
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 cr.define('cr.ui', function() {
6   /** @const */ var EventTarget = cr.EventTarget;
7
8   /**
9    * Creates a new selection model that is to be used with lists. This only
10    * allows a single index to be selected.
11    *
12    * @param {number=} opt_length The number items in the selection.
13    *
14    * @constructor
15    * @extends {cr.EventTarget}
16    */
17   function ListSingleSelectionModel(opt_length) {
18     this.length_ = opt_length || 0;
19     this.selectedIndex = -1;
20
21     // True if any item could be lead or anchor. False if only selected ones.
22     this.independentLeadItem_ = !cr.isMac && !cr.isChromeOS;
23   }
24
25   ListSingleSelectionModel.prototype = {
26     __proto__: EventTarget.prototype,
27
28     /**
29      * The number of items in the model.
30      * @type {number}
31      */
32     get length() {
33       return this.length_;
34     },
35
36     /**
37      * @type {!Array} The selected indexes.
38      */
39     get selectedIndexes() {
40       var i = this.selectedIndex;
41       return i != -1 ? [this.selectedIndex] : [];
42     },
43     set selectedIndexes(indexes) {
44       this.selectedIndex = indexes.length ? indexes[0] : -1;
45     },
46
47     /**
48      * Convenience getter which returns the first selected index.
49      * Setter also changes lead and anchor indexes if value is nonegative.
50      * @type {number}
51      */
52     get selectedIndex() {
53       return this.selectedIndex_;
54     },
55     set selectedIndex(selectedIndex) {
56       var oldSelectedIndex = this.selectedIndex;
57       var i = Math.max(-1, Math.min(this.length_ - 1, selectedIndex));
58
59       if (i != oldSelectedIndex) {
60         this.beginChange();
61         this.selectedIndex_ = i;
62         this.leadIndex = i >= 0 ? i : this.leadIndex;
63         this.endChange();
64       }
65     },
66
67     /**
68      * Selects a range of indexes, starting with {@code start} and ends with
69      * {@code end}.
70      * @param {number} start The first index to select.
71      * @param {number} end The last index to select.
72      */
73     selectRange: function(start, end) {
74       // Only select first index.
75       this.selectedIndex = Math.min(start, end);
76     },
77
78     /**
79      * Selects all indexes.
80      */
81     selectAll: function() {
82       // Select all is not allowed on a single selection model
83     },
84
85     /**
86      * Clears the selection
87      */
88     clear: function() {
89       this.beginChange();
90       this.length_ = 0;
91       this.selectedIndex = this.anchorIndex = this.leadIndex = -1;
92       this.endChange();
93     },
94
95     /**
96      * Unselects all selected items.
97      */
98     unselectAll: function() {
99       this.selectedIndex = -1;
100     },
101
102     /**
103      * Sets the selected state for an index.
104      * @param {number} index The index to set the selected state for.
105      * @param {boolean} b Whether to select the index or not.
106      */
107     setIndexSelected: function(index, b) {
108       // Only allow selection
109       var oldSelected = index == this.selectedIndex_;
110       if (oldSelected == b)
111         return;
112
113       if (b)
114         this.selectedIndex = index;
115       else if (index == this.selectedIndex_)
116         this.selectedIndex = -1;
117     },
118
119     /**
120      * Whether a given index is selected or not.
121      * @param {number} index The index to check.
122      * @return {boolean} Whether an index is selected.
123      */
124     getIndexSelected: function(index) {
125       return index == this.selectedIndex_;
126     },
127
128     /**
129      * This is used to begin batching changes. Call {@code endChange} when you
130      * are done making changes.
131      */
132     beginChange: function() {
133       if (!this.changeCount_) {
134         this.changeCount_ = 0;
135         this.selectedIndexBefore_ = this.selectedIndex_;
136       }
137       this.changeCount_++;
138     },
139
140     /**
141      * Call this after changes are done and it will dispatch a change event if
142      * any changes were actually done.
143      */
144     endChange: function() {
145       this.changeCount_--;
146       if (!this.changeCount_) {
147         if (this.selectedIndexBefore_ != this.selectedIndex_) {
148           var beforeChange = this.createChangeEvent('beforeChange');
149           if (this.dispatchEvent(beforeChange))
150             this.dispatchEvent(this.createChangeEvent('change'));
151           else
152             this.selectedIndex_ = this.selectedIndexBefore_;
153         }
154       }
155     },
156
157     /**
158      * Creates event with specified name and fills its {changes} property.
159      * @param {string} eventName Event name.
160      */
161     createChangeEvent: function(eventName) {
162       var e = new Event(eventName);
163       var indexes = [this.selectedIndexBefore_, this.selectedIndex_];
164       e.changes = indexes.filter(function(index) {
165         return index != -1;
166       }).map(function(index) {
167         return {
168           index: index,
169           selected: index == this.selectedIndex_
170         };
171       }, this);
172
173       return e;
174     },
175
176     leadIndex_: -1,
177
178     /**
179      * The leadIndex is used with multiple selection and it is the index that
180      * the user is moving using the arrow keys.
181      * @type {number}
182      */
183     get leadIndex() {
184       return this.leadIndex_;
185     },
186     set leadIndex(leadIndex) {
187       var li = this.adjustIndex_(leadIndex);
188       if (li != this.leadIndex_) {
189         var oldLeadIndex = this.leadIndex_;
190         this.leadIndex_ = li;
191         cr.dispatchPropertyChange(this, 'leadIndex', li, oldLeadIndex);
192         cr.dispatchPropertyChange(this, 'anchorIndex', li, oldLeadIndex);
193       }
194     },
195
196     adjustIndex_: function(index) {
197       index = Math.max(-1, Math.min(this.length_ - 1, index));
198       if (!this.independentLeadItem_)
199         index = this.selectedIndex;
200       return index;
201     },
202
203     /**
204      * The anchorIndex is used with multiple selection.
205      * @type {number}
206      */
207     get anchorIndex() {
208       return this.leadIndex;
209     },
210     set anchorIndex(anchorIndex) {
211       this.leadIndex = anchorIndex;
212     },
213
214     /**
215      * Whether the selection model supports multiple selected items.
216      * @type {boolean}
217      */
218     get multiple() {
219       return false;
220     },
221
222     /**
223      * Adjusts the selection after reordering of items in the table.
224      * @param {!Array.<number>} permutation The reordering permutation.
225      */
226     adjustToReordering: function(permutation) {
227       if (this.leadIndex != -1)
228         this.leadIndex = permutation[this.leadIndex];
229
230       var oldSelectedIndex = this.selectedIndex;
231       if (oldSelectedIndex != -1) {
232         this.selectedIndex = permutation[oldSelectedIndex];
233       }
234     },
235
236     /**
237      * Adjusts selection model length.
238      * @param {number} length New selection model length.
239      */
240     adjustLength: function(length) {
241       this.length_ = length;
242     }
243   };
244
245   return {
246     ListSingleSelectionModel: ListSingleSelectionModel
247   };
248 });