Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(3)

Side by Side Diff: chrome/browser/resources/file_manager/js/drag_selector.js

Issue 15643006: Files.app: Added DragSelector class. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Addressed Yoshiki's comments. Created 7 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2013 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 * Drag selector used on the file list or the grid table.
9 * TODO(hirono): Support drag selection for grid view. crbug.com/224832
10 * @constructor
11 */
12 function DragSelector() {
13 /**
14 * Target list of drag selection.
15 * @type {cr.ui.List}
16 * @private
17 */
18 this.target_ = null;
19
20 /**
21 * Border element of drag handle.
22 * @type {HtmlElement}
23 * @private
24 */
25 this.border_ = null;
26
27 /**
28 * Start point of dragging.
29 * @type {number?}
30 * @private
31 */
32 this.startX_ = null;
33
34 /**
35 * Start point of dragging.
36 * @type {number?}
37 * @private
38 */
39 this.startY_ = null;
40
41 /**
42 * Indexes of selected items by dragging at the last update.
43 * @type {Array.<number>!}
44 * @private
45 */
46 this.lastSelection_ = [];
47
48 /**
49 * Indexes of selected items at the start of dragging.
50 * @type {Array.<number>!}
51 * @private
52 */
53 this.originalSelection_ = [];
54
55 // Bind handlers to make them removable.
56 this.onMouseMoveBound_ = this.onMouseMove_.bind(this);
57 this.onMouseUpBound_ = this.onMouseUp_.bind(this);
58 }
59
60 /**
61 * Flag that shows whether the item is included in the selection or not.
62 * @enum {number}
63 * @private
64 */
65 DragSelector.SelectionFlag_ = {
66 IN_LAST_SELECTION: 1 << 0,
67 IN_CURRENT_SELECTION: 1 << 1
68 };
69
70 /**
71 * Starts drag selection by reacting dragstart event.
72 * This function must be called from handlers of dragstart event.
73 *
74 * @this {DragSelector}
75 * @param {cr.ui.List} list List where the drag selection starts.
76 * @param {Event} event The dragstart event.
77 */
78 DragSelector.prototype.startDragSelection = function(list, event) {
79 // Precondition check
80 if (!list.selectionModel_.multiple || this.target_)
81 return;
82
83 // Set the target of the drag selection
84 this.target_ = list;
85
86 // Create and add the border element
87 if (!this.border_) {
88 this.border_ = this.target_.ownerDocument.createElement('div');
89 this.border_.className = 'drag-selection-border';
90 }
91 list.appendChild(this.border_);
92
93 // Prevent default action.
94 event.preventDefault();
95
96 // If no modifier key is pressed, clear the original selection.
97 if (!event.shiftKey && !event.ctrlKey) {
98 this.target_.selectionModel_.unselectAll();
99 }
100
101 // Save the start state.
102 var rect = list.getBoundingClientRect();
103 this.startX_ = event.clientX - rect.left + list.scrollLeft;
104 this.startY_ = event.clientY - rect.top + list.scrollTop;
105 this.border_.style.left = this.startX_ + 'px';
106 this.border_.style.top = this.startY_ + 'px';
107 this.lastSelection_ = [];
108 this.originalSelection_ = this.target_.selectionModel_.selectedIndexes;
109
110 // Register event handlers.
111 // The handlers are bounded at the constructor.
112 this.target_.ownerDocument.addEventListener(
113 'mousemove', this.onMouseMoveBound_, true);
114 this.target_.ownerDocument.addEventListener(
115 'mouseup', this.onMouseUpBound_, true);
116 };
117
118 /**
119 * Handle the mousemove event.
120 * @private
121 * @param {MouseEvent} event The mousemove event.
122 */
123 DragSelector.prototype.onMouseMove_ = function(event) {
124 // Get the selection bounds.
125 var inRect = this.target_.getBoundingClientRect();
126 var x = event.clientX - inRect.left + this.target_.scrollLeft;
127 var y = event.clientY - inRect.top + this.target_.scrollTop;
128 var borderBounds = {
129 left: Math.max(Math.min(this.startX_, x), 0),
130 top: Math.max(Math.min(this.startY_, y), 0),
131 right: Math.min(Math.max(this.startX_, x), this.target_.scrollWidth),
132 bottom: Math.min(Math.max(this.startY_, y), this.target_.scrollHeight)
133 };
134 borderBounds.width = borderBounds.right - borderBounds.left;
135 borderBounds.height = borderBounds.bottom - borderBounds.top;
136
137 // Collect items within the selection rect.
138 var currentSelection = [];
139 var leadIndex = -1;
140 for (var i = 0; i < this.target_.selectionModel_.length; i++) {
141 // TODO(hirono): Stop to use the private method. crbug.com/246459
142 var itemMetrics = this.target_.getHeightsForIndex_(i);
143 itemMetrics.bottom = itemMetrics.top + itemMetrics.height;
144 if (itemMetrics.top < borderBounds.bottom &&
145 itemMetrics.bottom >= borderBounds.top) {
146 currentSelection.push(i);
147 }
148 var pointed = itemMetrics.top <= y && y < itemMetrics.bottom;
149 if (pointed)
150 leadIndex = i;
151 }
152
153 // Diff the selection between currentSelection and this.lastSelection_.
154 var selectionFlag = [];
155 for (var i = 0; i < this.lastSelection_.length; i++) {
156 var index = this.lastSelection_[i];
157 // Bit operator can be used for undefined value.
158 selectionFlag[index] =
159 selectionFlag[index] | DragSelector.SelectionFlag_.IN_LAST_SELECTION;
160 }
161 for (var i = 0; i < currentSelection.length; i++) {
162 var index = currentSelection[i];
163 // Bit operator can be used for undefined value.
164 selectionFlag[index] =
165 selectionFlag[index] | DragSelector.SelectionFlag_.IN_CURRENT_SELECTION;
166 }
167
168 // Update the selection
169 this.target_.selectionModel_.beginChange();
170 for (var name in selectionFlag) {
171 var index = parseInt(name);
172 var flag = selectionFlag[name];
173 // The flag may be one of followings:
174 // - IN_LAST_SELECTION | IN_CURRENT_SELECTION
175 // - IN_LAST_SELECTION
176 // - IN_CURRENT_SELECTION
177 // - undefined
178
179 // If the flag equals to (IN_LAST_SELECTION | IN_CURRENT_SELECTION),
180 // this is included in both the last selection and the current selection.
181 // We have nothing to do for this item.
182
183 if (flag == DragSelector.SelectionFlag_.IN_LAST_SELECTION) {
184 // If the flag equals to IN_LAST_SELECTION,
185 // then the item is included in lastSelection but not in currentSelection.
186 // Revert the selection state to this.originalSelection_.
187 this.target_.selectionModel_.setIndexSelected(
188 index, this.originalSelection_.indexOf(index) != -1);
189 } else if (flag == DragSelector.SelectionFlag_.IN_CURRENT_SELECTION) {
190 // If the flag equals to IN_CURRENT_SELECTION,
191 // this is included in currentSelection but not in lastSelection.
192 this.target_.selectionModel_.setIndexSelected(index, true);
193 }
194 }
195 if (leadIndex != -1) {
196 this.target_.selectionModel_.leadIndex = leadIndex;
197 this.target_.selectionModel_.anchorIndex = leadIndex;
198 }
199 this.target_.selectionModel_.endChange();
200 this.lastSelection_ = currentSelection;
201
202 // Update the size of border
203 this.border_.style.left = borderBounds.left + 'px';
204 this.border_.style.top = borderBounds.top + 'px';
205 this.border_.style.width = borderBounds.width + 'px';
206 this.border_.style.height = borderBounds.height + 'px';
207 };
208
209 /**
210 * Handle the mouseup event.
211 * @private
212 * @param {MouseEvent} event The mouseup event.
213 */
214 DragSelector.prototype.onMouseUp_ = function(event) {
215 this.onMouseMove_(event);
216 this.target_.removeChild(this.border_);
217 this.target_.ownerDocument.removeEventListener(
218 'mousemove', this.onMouseMoveBound_, true);
219 this.target_.ownerDocument.removeEventListener(
220 'mouseup', this.onMouseUpBound_, true);
221 event.stopPropagation();
222 this.target_ = null;
223 };
OLDNEW
« no previous file with comments | « chrome/browser/resources/file_manager/css/file_manager.css ('k') | chrome/browser/resources/file_manager/js/main_scripts.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698