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

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: 2011->2012 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 document.oncontextmenu = function(e) { e.preventDefault(); };
55
56 var player = new AudioPlayer(document.querySelector('.audio-player'));
57 function getPlaylist() {
58 chrome.mediaPlayerPrivate.getPlaylist(player.load.bind(player));
59 }
60 getPlaylist();
61 chrome.mediaPlayerPrivate.onPlaylistChanged.addListener(getPlaylist);
62 };
63
64 AudioPlayer.prototype.load = function(playlist) {
65 this.playlistGeneration_++;
66
67 this.audioControls_.pause();
68
69 this.currentTrack_ = -1;
70
71 this.urls_ = playlist.items;
72
73 if (this.urls_.length == 1)
74 this.container_.classList.add('single-track');
75 else
76 this.container_.classList.remove('single-track');
77
78 this.syncHeight_();
79
80 this.trackList_.textContent = '';
81 this.trackStack_.textContent = '';
82
83 this.trackListItems_ = [];
84 this.trackStackItems_ = [];
85
86 for (var i = 0; i != this.urls_.length; i++) {
87 var url = this.urls_[i];
88 var onClick = this.select_.bind(this, i);
89 this.trackListItems_.push(
90 new AudioPlayer.TrackInfo(this.trackList_, url, onClick));
91 this.trackStackItems_.push(
92 new AudioPlayer.TrackInfo(this.trackStack_, url, onClick));
93 }
94
95 this.select_(playlist.position);
96
97 // This class will be removed if at least one track has art.
98 this.container_.classList.add('noart');
99
100 // Load the selected track metadata first, then load the rest.
101 this.loadMetadata_(playlist.position);
102 for (i = 0; i != this.urls_.length; i++) {
103 if (i != playlist.position)
104 this.loadMetadata_(i);
105 }
106 };
107
108 AudioPlayer.prototype.loadMetadata_ = function(track) {
109 this.metadataProvider_.fetch(
110 this.urls_[track],
111 function(generation, metadata) {
112 // Do nothing if another load happened since the metadata request.
113 if (this.playlistGeneration_ != generation)
114 return;
115
116 if (metadata.thumbnailURL) {
117 this.container_.classList.remove('noart');
118 }
119 this.trackListItems_[track].setMetadata(metadata);
120 this.trackStackItems_[track].setMetadata(metadata);
121 }.bind(this, this.playlistGeneration_));
122 };
123
124 AudioPlayer.prototype.select_ = function(newTrack) {
125 if (this.currentTrack_ == newTrack) return;
126
127 this.changeSelectionInList_(this.currentTrack_, newTrack);
128 this.changeSelectionInStack_(this.currentTrack_, newTrack);
129
130 this.currentTrack_ = newTrack;
131 this.scrollToCurrent_(false);
132
133 var media = this.audioControls_.getMedia();
134 media.src = this.urls_[this.currentTrack_];
135 media.load();
136 this.audioControls_.play();
137 };
138
139 AudioPlayer.prototype.changeSelectionInList_ = function(oldTrack, newTrack) {
140 this.trackListItems_[newTrack].getBox().classList.add('selected');
141
142 if (oldTrack >= 0) {
143 this.trackListItems_[oldTrack].getBox().classList.remove('selected');
144 }
145 };
146
147 AudioPlayer.prototype.changeSelectionInStack_ = function(oldTrack, newTrack) {
148 var newBox = this.trackStackItems_[newTrack].getBox();
149 newBox.classList.add('selected'); // Put on top immediately.
150 newBox.classList.add('visible'); // Start fading in.
151
152 if (oldTrack >= 0) {
153 var oldBox = this.trackStackItems_[oldTrack].getBox();
154 oldBox.classList.remove('selected'); // Put under immediately.
155 setTimeout(function () {
156 if (!oldBox.classList.contains('selected')) {
157 // This will start fading out which is not really necessary because
158 // oldBox is already completely obscured by newBox.
159 oldBox.classList.remove('visible');
160 }
161 }, 300);
162 }
163 };
164
165 /**
166 * Scrolls the current track into the viewport.
167 *
168 * @param {boolean} keepAtBottom If true, make the selected track the last
169 * of the visible (if possible). If false, perform minimal scrolling.
170 */
171 AudioPlayer.prototype.scrollToCurrent_ = function(keepAtBottom) {
172 var box = this.trackListItems_[this.currentTrack_].getBox();
173 this.trackList_.scrollTop = Math.max(
174 keepAtBottom ? 0 : Math.min(box.offsetTop, this.trackList_.scrollTop),
175 box.offsetTop + box.offsetHeight - this.trackList_.clientHeight);
176 };
177
178 AudioPlayer.prototype.isCompact_ = function() {
179 return this.container_.classList.contains('collapsed') ||
180 this.container_.classList.contains('single-track');
181 };
182
183 AudioPlayer.prototype.advance_ = function(forward) {
184 var newTrack = this.currentTrack_ + (forward ? 1 : -1);
185 if (newTrack < 0) newTrack = this.urls_.length - 1;
186 if (newTrack == this.urls_.length) newTrack = 0;
187 this.select_(newTrack);
188 };
189
190 AudioPlayer.prototype.onExpandCollapse_ = function() {
191 this.container_.classList.toggle('collapsed');
192 this.syncHeight_();
193 if (!this.isCompact_())
194 this.scrollToCurrent_(true);
195 };
196
197 /* Keep the below constants in sync with the CSS. */
198 AudioPlayer.HEADER_HEIGHT = 30;
199 AudioPlayer.TRACK_HEIGHT = 58;
200 AudioPlayer.CONTROLS_HEIGHT = 35;
201
202 AudioPlayer.prototype.syncHeight_ = function() {
203 var expandedListHeight =
204 Math.min(this.urls_.length, 3) * AudioPlayer.TRACK_HEIGHT;
205 this.trackList_.style.height = expandedListHeight + 'px';
206
207 chrome.mediaPlayerPrivate.setWindowHeight(
208 (this.isCompact_() ?
209 AudioPlayer.TRACK_HEIGHT :
210 AudioPlayer.HEADER_HEIGHT + expandedListHeight) +
211 AudioPlayer.CONTROLS_HEIGHT);
212 };
213
214
215 /**
216 * Create a TrackInfo object encapsulating the information about one track.
217 *
218 * @param {HTMLElement} container
219 * @param {string} url
220 * @param {function} onClick
221 * @constructor
222 */
223 AudioPlayer.TrackInfo = function(container, url, onClick) {
224 this.url_ = url;
225
226 var doc = container.ownerDocument;
227
228 this.box_ = doc.createElement('div');
229 this.box_.className = 'track';
230 this.box_.addEventListener('click', onClick);
231 container.appendChild(this.box_);
232
233 this.art_ = doc.createElement('div');
234 this.art_.className = 'art blank';
235 this.box_.appendChild(this.art_);
236
237 this.img_ = doc.createElement('img');
238 this.art_.appendChild(this.img_);
239
240 this.data_ = doc.createElement('div');
241 this.data_.className = 'data';
242 this.box_.appendChild(this.data_);
243
244 this.title_ = doc.createElement('div');
245 this.title_.className = 'data-title';
246 this.data_.appendChild(this.title_);
247
248 this.artist_ = doc.createElement('div');
249 this.artist_.className = 'data-artist';
250 this.data_.appendChild(this.artist_);
251 };
252
253 AudioPlayer.TrackInfo.prototype.getBox = function() { return this.box_ };
254
255 AudioPlayer.TrackInfo.prototype.getDefaultTitle = function() {
256 var title = this.url_.split('/').pop();
257 var dotIndex = title.lastIndexOf('.');
258 if (dotIndex >= 0) title = title.substr(0, dotIndex);
259 return title;
260 };
261
262 AudioPlayer.TrackInfo.prototype.getDefaultArtist = function() {
263 return 'Unknown Artist'; // TODO(kaznacheev): i18n
264 };
265
266 AudioPlayer.TrackInfo.prototype.setMetadata = function(metadata) {
267 if (metadata.thumbnailURL) {
268 this.art_.classList.remove('blank');
269 this.img_.src = metadata.thumbnailURL;
270 }
271 this.title_.textContent = metadata.title || this.getDefaultTitle();
272 this.artist_.textContent = metadata.artist || this.getDefaultArtist();
273 };
OLDNEW
« no previous file with comments | « chrome/browser/resources/file_manager/gallery.html ('k') | chrome/browser/resources/file_manager/js/byte_reader.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698