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

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

Issue 9583009: [File Manager] Cleanup: Moving js/css/html files to dedicated directories (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 9 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) 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 document.addEventListener('DOMContentLoaded', function() {
6 // Test harness sets the search string to prevent the automatic load.
7 // It calls AudioPlayer.load() explicitly after initializing
8 // the |chrome| variable with an appropriate mock object.
9 if (!document.location.search) {
10 AudioPlayer.load();
11 }
12 });
13
14 /**
15 * @param {HTMLElement} container
16 * @constructor
17 */
18 function AudioPlayer(container) {
19 this.container_ = container;
20 this.metadataProvider_ = new MetadataProvider();
21 this.currentTrack_ = -1;
22 this.playlistGeneration_ = 0;
23
24 this.container_.classList.add('collapsed');
25
26 function createChild(opt_className, opt_tag) {
27 var child = container.ownerDocument.createElement(opt_tag || 'div');
28 if (opt_className)
29 child.className = opt_className;
30 container.appendChild(child);
31 return child;
32 }
33
34 // We create two separate containers (for expanded and compact view) and keep
35 // two sets of TrackInfo instances. We could fiddle with a single set instead
36 // but it would make keeping the list scroll position very tricky.
37 this.trackList_ = createChild('track-list');
38 this.trackStack_ = createChild('track-stack');
39
40 createChild('title-button close').addEventListener(
41 'click', function() { chrome.mediaPlayerPrivate.closeWindow() });
42
43 createChild('title-button collapse').addEventListener(
44 'click', this.onExpandCollapse_.bind(this));
45
46 this.audioControls_ = new AudioControls(
47 createChild(), this.advance_.bind(this));
48
49 this.audioControls_.attachMedia(createChild('', 'audio'));
50 }
51
52 AudioPlayer.load = function() {
53 document.ondragstart = function(e) { e.preventDefault() };
54
55 var player = new AudioPlayer(document.querySelector('.audio-player'));
56 function getPlaylist() {
57 chrome.mediaPlayerPrivate.getPlaylist(player.load.bind(player));
58 }
59 getPlaylist();
60 chrome.mediaPlayerPrivate.onPlaylistChanged.addListener(getPlaylist);
61 };
62
63 AudioPlayer.prototype.load = function(playlist) {
64 this.playlistGeneration_++;
65
66 this.audioControls_.pause();
67
68 this.currentTrack_ = -1;
69
70 this.urls_ = playlist.items;
71
72 if (this.urls_.length == 1)
73 this.container_.classList.add('single-track');
74 else
75 this.container_.classList.remove('single-track');
76
77 this.syncHeight_();
78
79 this.trackList_.textContent = '';
80 this.trackStack_.textContent = '';
81
82 this.trackListItems_ = [];
83 this.trackStackItems_ = [];
84
85 for (var i = 0; i != this.urls_.length; i++) {
86 var url = this.urls_[i];
87 var onClick = this.select_.bind(this, i);
88 this.trackListItems_.push(
89 new AudioPlayer.TrackInfo(this.trackList_, url, onClick));
90 this.trackStackItems_.push(
91 new AudioPlayer.TrackInfo(this.trackStack_, url, onClick));
92 }
93
94 this.select_(playlist.position);
95
96 // This class will be removed if at least one track has art.
97 this.container_.classList.add('noart');
98
99 // Load the selected track metadata first, then load the rest.
100 this.loadMetadata_(playlist.position);
101 for (i = 0; i != this.urls_.length; i++) {
102 if (i != playlist.position)
103 this.loadMetadata_(i);
104 }
105 };
106
107 AudioPlayer.prototype.loadMetadata_ = function(track) {
108 this.metadataProvider_.fetch(
109 this.urls_[track],
110 function(generation, metadata) {
111 // Do nothing if another load happened since the metadata request.
112 if (this.playlistGeneration_ != generation)
113 return;
114
115 if (metadata.thumbnailURL) {
116 this.container_.classList.remove('noart');
117 }
118 this.trackListItems_[track].setMetadata(metadata);
119 this.trackStackItems_[track].setMetadata(metadata);
120 }.bind(this, this.playlistGeneration_));
121 };
122
123 AudioPlayer.prototype.select_ = function(newTrack) {
124 if (this.currentTrack_ == newTrack) return;
125
126 this.changeSelectionInList_(this.currentTrack_, newTrack);
127 this.changeSelectionInStack_(this.currentTrack_, newTrack);
128
129 this.currentTrack_ = newTrack;
130 this.scrollToCurrent_(false);
131
132 var media = this.audioControls_.getMedia();
133 media.src = this.urls_[this.currentTrack_];
134 media.load();
135 this.audioControls_.play();
136 };
137
138 AudioPlayer.prototype.changeSelectionInList_ = function(oldTrack, newTrack) {
139 this.trackListItems_[newTrack].getBox().classList.add('selected');
140
141 if (oldTrack >= 0) {
142 this.trackListItems_[oldTrack].getBox().classList.remove('selected');
143 }
144 };
145
146 AudioPlayer.prototype.changeSelectionInStack_ = function(oldTrack, newTrack) {
147 var newBox = this.trackStackItems_[newTrack].getBox();
148 newBox.classList.add('selected'); // Put on top immediately.
149 newBox.classList.add('visible'); // Start fading in.
150
151 if (oldTrack >= 0) {
152 var oldBox = this.trackStackItems_[oldTrack].getBox();
153 oldBox.classList.remove('selected'); // Put under immediately.
154 setTimeout(function () {
155 if (!oldBox.classList.contains('selected')) {
156 // This will start fading out which is not really necessary because
157 // oldBox is already completely obscured by newBox.
158 oldBox.classList.remove('visible');
159 }
160 }, 300);
161 }
162 };
163
164 /**
165 * Scrolls the current track into the viewport.
166 *
167 * @param {boolean} keepAtBottom If true, make the selected track the last
168 * of the visible (if possible). If false, perform minimal scrolling.
169 */
170 AudioPlayer.prototype.scrollToCurrent_ = function(keepAtBottom) {
171 var box = this.trackListItems_[this.currentTrack_].getBox();
172 this.trackList_.scrollTop = Math.max(
173 keepAtBottom ? 0 : Math.min(box.offsetTop, this.trackList_.scrollTop),
174 box.offsetTop + box.offsetHeight - this.trackList_.clientHeight);
175 };
176
177 AudioPlayer.prototype.isCompact_ = function() {
178 return this.container_.classList.contains('collapsed') ||
179 this.container_.classList.contains('single-track');
180 };
181
182 AudioPlayer.prototype.advance_ = function(forward) {
183 var newTrack = this.currentTrack_ + (forward ? 1 : -1);
184 if (newTrack < 0) newTrack = this.urls_.length - 1;
185 if (newTrack == this.urls_.length) newTrack = 0;
186 this.select_(newTrack);
187 };
188
189 AudioPlayer.prototype.onExpandCollapse_ = function() {
190 this.container_.classList.toggle('collapsed');
191 this.syncHeight_();
192 if (!this.isCompact_())
193 this.scrollToCurrent_(true);
194 };
195
196 /* Keep the below constants in sync with the CSS. */
197 AudioPlayer.HEADER_HEIGHT = 30;
198 AudioPlayer.TRACK_HEIGHT = 58;
199 AudioPlayer.CONTROLS_HEIGHT = 35;
200
201 AudioPlayer.prototype.syncHeight_ = function() {
202 var expandedListHeight =
203 Math.min(this.urls_.length, 3) * AudioPlayer.TRACK_HEIGHT;
204 this.trackList_.style.height = expandedListHeight + 'px';
205
206 chrome.mediaPlayerPrivate.setWindowHeight(
207 (this.isCompact_() ?
208 AudioPlayer.TRACK_HEIGHT :
209 AudioPlayer.HEADER_HEIGHT + expandedListHeight) +
210 AudioPlayer.CONTROLS_HEIGHT);
211 };
212
213
214 /**
215 * Create a TrackInfo object encapsulating the information about one track.
216 *
217 * @param {HTMLElement} container
218 * @param {string} url
219 * @param {function} onClick
220 * @constructor
221 */
222 AudioPlayer.TrackInfo = function(container, url, onClick) {
223 this.url_ = url;
224
225 var doc = container.ownerDocument;
226
227 this.box_ = doc.createElement('div');
228 this.box_.className = 'track';
229 this.box_.addEventListener('click', onClick);
230 container.appendChild(this.box_);
231
232 this.art_ = doc.createElement('div');
233 this.art_.className = 'art blank';
234 this.box_.appendChild(this.art_);
235
236 this.img_ = doc.createElement('img');
237 this.art_.appendChild(this.img_);
238
239 this.data_ = doc.createElement('div');
240 this.data_.className = 'data';
241 this.box_.appendChild(this.data_);
242
243 this.title_ = doc.createElement('div');
244 this.title_.className = 'data-title';
245 this.data_.appendChild(this.title_);
246
247 this.artist_ = doc.createElement('div');
248 this.artist_.className = 'data-artist';
249 this.data_.appendChild(this.artist_);
250 };
251
252 AudioPlayer.TrackInfo.prototype.getBox = function() { return this.box_ };
253
254 AudioPlayer.TrackInfo.prototype.getDefaultTitle = function() {
255 var title = this.url_.split('/').pop();
256 var dotIndex = title.lastIndexOf('.');
257 if (dotIndex >= 0) title = title.substr(0, dotIndex);
258 return title;
259 };
260
261 AudioPlayer.TrackInfo.prototype.getDefaultArtist = function() {
262 return 'Unknown Artist'; // TODO(kaznacheev): i18n
263 };
264
265 AudioPlayer.TrackInfo.prototype.setMetadata = function(metadata) {
266 if (metadata.thumbnailURL) {
267 this.art_.classList.remove('blank');
268 this.img_.src = metadata.thumbnailURL;
269 }
270 this.title_.textContent = metadata.title || this.getDefaultTitle();
271 this.artist_.textContent = metadata.artist || this.getDefaultArtist();
272 };
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698