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

Side by Side Diff: ui/file_manager/file_manager/audio_player/elements/track_list.js

Issue 641283002: Separate the audio player app from Files.app Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Clean up Created 6 years, 2 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
OLDNEW
(Empty)
1 // Copyright 2014 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 (function() {
6 'use strict';
7
8 Polymer('track-list', {
9 /**
10 * Initializes an element. This method is called automatically when the
11 * element is ready.
12 */
13 ready: function() {
14 this.tracksObserver_ = new ArrayObserver(
15 this.tracks,
16 this.tracksValueChanged_.bind(this));
17
18 window.addEventListener('resize', this.onWindowResize_.bind(this));
19 },
20
21 /**
22 * Registers handlers for changing of external variables
23 */
24 observe: {
25 'model.shuffle': 'onShuffleChanged',
26 },
27
28 /**
29 * Model object of the Audio Player.
30 * @type {AudioPlayerModel}
31 */
32 model: null,
33
34 /**
35 * List of tracks.
36 * @type {Array.<AudioPlayer.TrackInfo>}
37 */
38 tracks: [],
39
40 /**
41 * Play order of the tracks. Each value is the index of 'this.tracks'.
42 * @type {Array.<number>}
43 */
44 playOrder: [],
45
46 /**
47 * Track index of the current track.
48 * If the tracks property is empty, it should be -1. Otherwise, be a valid
49 * track number.
50 *
51 * @type {number}
52 */
53 currentTrackIndex: -1,
54
55 /**
56 * Invoked when 'shuffle' property is changed.
57 * @param {boolean} oldValue Old value.
58 * @param {boolean} newValue New value.
59 */
60 onShuffleChanged: function(oldValue, newValue) {
61 this.generatePlayOrder(true /* keep the current track */);
62 },
63
64 /**
65 * Invoked when the current track index is changed.
66 * @param {number} oldValue old value.
67 * @param {number} newValue new value.
68 */
69 currentTrackIndexChanged: function(oldValue, newValue) {
70 if (oldValue === newValue)
71 return;
72
73 if (!isNaN(oldValue) && 0 <= oldValue && oldValue < this.tracks.length)
74 this.tracks[oldValue].active = false;
75
76 if (0 <= newValue && newValue < this.tracks.length) {
77 var currentPlayOrder = this.playOrder.indexOf(newValue);
78 if (currentPlayOrder !== -1) {
79 // Success
80 this.tracks[newValue].active = true;
81
82 this.ensureTrackInViewport_(newValue /* trackIndex */);
83 return;
84 }
85 }
86
87 // Invalid index
88 if (this.tracks.length === 0)
89 this.currentTrackIndex = -1;
90 else
91 this.generatePlayOrder(false /* no need to keep the current track */);
92 },
93
94 /**
95 * Invoked when 'tracks' property is changed.
96 * @param {Array.<TrackInfo>} oldValue Old value.
97 * @param {Array.<TrackInfo>} newValue New value.
98 */
99 tracksChanged: function(oldValue, newValue) {
100 // Note: Sometimes both oldValue and newValue are null though the actual
101 // values are not null. Maybe it's a bug of Polymer.
102
103 // Re-register the observer of 'this.tracks'.
104 this.tracksObserver_.close();
105 this.tracksObserver_ = new ArrayObserver(this.tracks);
106 this.tracksObserver_.open(this.tracksValueChanged_.bind(this));
107
108 if (this.tracks.length !== 0) {
109 // Restore the active track.
110 if (this.currentTrackIndex !== -1 &&
111 this.currentTrackIndex < this.tracks.length) {
112 this.tracks[this.currentTrackIndex].active = true;
113 }
114
115 // Reset play order and current index.
116 this.generatePlayOrder(false /* no need to keep the current track */);
117 } else {
118 this.playOrder = [];
119 this.currentTrackIndex = -1;
120 }
121 },
122
123 /**
124 * Invoked when the value in the 'tracks' is changed.
125 * @param {Array.<Object>} splices The detail of the change.
126 */
127 tracksValueChanged_: function(splices) {
128 if (this.tracks.length === 0)
129 this.currentTrackIndex = -1;
130 else
131 this.tracks[this.currentTrackIndex].active = true;
132 },
133
134 /**
135 * Invoked when the track element is clicked.
136 * @param {Event} event Click event.
137 */
138 trackClicked: function(event) {
139 var index = ~~event.currentTarget.getAttribute('index');
140 var track = this.tracks[index];
141 if (track)
142 this.selectTrack(track);
143 },
144
145 /**
146 * Invoked when the window is resized.
147 * @private
148 */
149 onWindowResize_: function() {
150 this.ensureTrackInViewport_(this.currentTrackIndex);
151 },
152
153 /**
154 * Scrolls the track list to ensure the given track in the viewport.
155 * @param {number} trackIndex The index of the track to be in the viewport.
156 * @private
157 */
158 ensureTrackInViewport_: function(trackIndex) {
159 var trackSelector = '::shadow .track[index="' + trackIndex + '"]';
160 var trackElement = this.querySelector(trackSelector);
161 if (trackElement) {
162 var viewTop = this.scrollTop;
163 var viewHeight = this.clientHeight;
164 var elementTop = trackElement.offsetTop;
165 var elementHeight = trackElement.offsetHeight;
166
167 if (elementTop < viewTop) {
168 // Adjust the tops.
169 this.scrollTop = elementTop;
170 } else if (elementTop + elementHeight <= viewTop + viewHeight) {
171 // The entire element is in the viewport. Do nothing.
172 } else {
173 // Adjust the bottoms.
174 this.scrollTop = Math.max(0,
175 (elementTop + elementHeight - viewHeight));
176 }
177 }
178 },
179
180 /**
181 * Invoked when the track element is clicked.
182 * @param {boolean} keepCurrentTrack Keep the current track or not.
183 */
184 generatePlayOrder: function(keepCurrentTrack) {
185 console.assert((keepCurrentTrack !== undefined),
186 'The argument "forward" is undefined');
187
188 if (this.tracks.length === 0) {
189 this.playOrder = [];
190 return;
191 }
192
193 // Creates sequenced array.
194 this.playOrder =
195 this.tracks.
196 map(function(unused, index) { return index; });
197
198 if (this.model && this.model.shuffle) {
199 // Randomizes the play order array (Schwarzian-transform algorithm).
200 this.playOrder = this.playOrder
201 .map(function(a) {
202 return {weight: Math.random(), index: a};
203 })
204 .sort(function(a, b) { return a.weight - b.weight })
205 .map(function(a) { return a.index });
206
207 if (keepCurrentTrack) {
208 // Puts the current track at the beginning of the play order.
209 this.playOrder = this.playOrder
210 .filter(function(value) {
211 return this.currentTrackIndex !== value;
212 }, this);
213 this.playOrder.splice(0, 0, this.currentTrackIndex);
214 }
215 }
216
217 if (!keepCurrentTrack)
218 this.currentTrackIndex = this.playOrder[0];
219 },
220
221 /**
222 * Sets the current track.
223 * @param {AudioPlayer.TrackInfo} track TrackInfo to be set as the current
224 * track.
225 */
226 selectTrack: function(track) {
227 var index = -1;
228 for (var i = 0; i < this.tracks.length; i++) {
229 if (this.tracks[i].url === track.url) {
230 index = i;
231 break;
232 }
233 }
234 if (index >= 0) {
235 // TODO(yoshiki): Clean up the flow and the code around here.
236 if (this.currentTrackIndex == index)
237 this.replayCurrentTrack();
238 else
239 this.currentTrackIndex = index;
240 }
241 },
242
243 /**
244 * Request to replay the current music.
245 */
246 replayCurrentTrack: function() {
247 this.fire('replay');
248 },
249
250 /**
251 * Returns the current track.
252 * @param {AudioPlayer.TrackInfo} track TrackInfo of the current track.
253 */
254 getCurrentTrack: function() {
255 if (this.tracks.length === 0)
256 return null;
257
258 return this.tracks[this.currentTrackIndex];
259 },
260
261 /**
262 * Returns the next (or previous) track in the track list. If there is no
263 * next track, returns -1.
264 *
265 * @param {boolean} forward Specify direction: forward or previous mode.
266 * True: forward mode, false: previous mode.
267 * @param {boolean} cyclic Specify if cyclically or not: It true, the first
268 * track is succeeding to the last track, otherwise no track after the
269 * last.
270 * @return {number} The next track index.
271 */
272 getNextTrackIndex: function(forward, cyclic) {
273 if (this.tracks.length === 0)
274 return -1;
275
276 var defaultTrackIndex =
277 forward ? this.playOrder[0] : this.playOrder[this.tracks.length - 1];
278
279 var currentPlayOrder = this.playOrder.indexOf(this.currentTrackIndex);
280 console.assert(
281 (0 <= currentPlayOrder && currentPlayOrder < this.tracks.length),
282 'Insufficient TrackList.playOrder. The current track is not on the ' +
283 'track list.');
284
285 var newPlayOrder = currentPlayOrder + (forward ? +1 : -1);
286 if (newPlayOrder === -1 || newPlayOrder === this.tracks.length)
287 return cyclic ? defaultTrackIndex : -1;
288
289 var newTrackIndex = this.playOrder[newPlayOrder];
290 console.assert(
291 (0 <= newTrackIndex && newTrackIndex < this.tracks.length),
292 'Insufficient TrackList.playOrder. New Play Order: ' + newPlayOrder);
293
294 return newTrackIndex;
295 },
296 }); // Polymer('track-list') block
297 })(); // Anonymous closure
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698