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

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

Issue 1176483002: AudioPlayer.app: Migrate to Polymer 1.0. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Address review comments. Created 5 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
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 /** 5 /**
6 * @constructor 6 * @constructor
7 * @extends {PolymerElement} 7 * @extends {PolymerElement}
8 */ 8 */
9 var AudioPlayerElement = function() {}; 9 var AudioPlayerElement = function() {};
10 10
11 AudioPlayerElement.prototype = { 11 AudioPlayerElement.prototype = {
12 is: 'audio-player',
13
12 // Child Elements 14 // Child Elements
13 audioController: null,
14 audioElement: null, 15 audioElement: null,
15 trackList: null, 16 trackList: null,
16 17
17 // Published values 18 properties: {
18 playing: true, 19 /**
19 currenttrackurl: '', 20 * Flag whether the audio is playing or paused. True if playing, or false
20 playcount: 0, 21 * paused.
22 */
23 playing: {
24 type: Boolean,
25 observer: 'playingChanged',
26 reflectToAttribute: true
27 },
21 28
22 // Attributes of the element (lower characters only). 29 /**
23 // These values must be used only to data binding and shouldn't be assigned 30 * Current elapsed time in the current music in millisecond.
24 // any value nowhere except in the handler. 31 */
25 publish: { 32 time: {
26 playing: { 33 type: Number,
27 value: true, 34 observer: 'timeChanged'
28 reflect: true
29 }, 35 },
36
37 /**
38 * Whether the shuffle button is ON.
39 */
40 shuffle: {
41 type: Boolean,
42 observer: 'shuffleChanged'
43 },
44
45 /**
46 * Whether the repeat button is ON.
47 */
48 repeat: {
49 type: Boolean,
50 observer: 'repeatChanged'
51 },
52
53 /**
54 * The audio volume. 0 is silent, and 100 is maximum loud.
55 */
56 volume: {
57 type: Number,
58 observer: 'volumeChanged'
59 },
60
61 /**
62 * Whether the expanded button is ON.
63 */
64 expanded: {
65 type: Boolean,
66 observer: 'expandedChanged'
67 },
68
69 /**
70 * Track index of the current track.
71 */
72 currentTrackIndex: {
73 type: Number,
74 observer: 'currentTrackIndexChanged'
75 },
76
77 /**
78 * Model object of the Audio Player.
79 * @type {AudioPlayerModel}
80 */
81 model: {
82 type: Object,
83 value: null,
84 observer: 'modelChanged'
85 },
86
87 /**
88 * URL of the current track. (exposed publicly for tests)
89 */
30 currenttrackurl: { 90 currenttrackurl: {
91 type: String,
31 value: '', 92 value: '',
32 reflect: true 93 reflectToAttribute: true
33 }, 94 },
95
96 /**
97 * The number of played tracks. (exposed publicly for tests)
98 */
34 playcount: { 99 playcount: {
100 type: Number,
35 value: 0, 101 value: 0,
36 reflect: true 102 reflectToAttribute: true
37 } 103 }
38 }, 104 },
39 105
40 /** 106 /**
41 * Model object of the Audio Player. 107 * Handles change event for shuffle mode.
42 * @type {AudioPlayerModel} 108 * @param {boolean} shuffle
43 */ 109 */
44 model: null, 110 shuffleChanged: function(shuffle) {
111 if (this.model)
112 this.model.shuffle = shuffle;
113 },
114
115 /**
116 * Handles change event for repeat mode.
117 * @param {boolean} repeat
118 */
119 repeatChanged: function(repeat) {
120 if (this.model)
121 this.model.repeat = repeat;
122 },
123
124 /**
125 * Handles change event for audio volume.
126 * @param {boolean} volume
127 */
128 volumeChanged: function(volume) {
129 if (this.model)
130 this.model.volume = volume;
131 },
132
133 /**
134 * Handles change event for expanded state of track list.
135 */
136 expandedChanged: function(expanded) {
137 if (this.model)
138 this.model.expanded = expanded;
139 },
45 140
46 /** 141 /**
47 * Initializes an element. This method is called automatically when the 142 * Initializes an element. This method is called automatically when the
48 * element is ready. 143 * element is ready.
49 */ 144 */
50 ready: function() { 145 ready: function() {
51 this.audioController = this.$.audioController;
52 this.audioElement = this.$.audio; 146 this.audioElement = this.$.audio;
53 this.trackList = this.$.trackList; 147 this.trackList = this.$.trackList;
54 148
55 this.addEventListener('keydown', this.onKeyDown_.bind(this)); 149 this.addEventListener('keydown', this.onKeyDown_.bind(this));
56 150
57 this.audioElement.volume = 0; // Temporary initial volume. 151 this.audioElement.volume = 0; // Temporary initial volume.
58 this.audioElement.addEventListener('ended', this.onAudioEnded.bind(this)); 152 this.audioElement.addEventListener('ended', this.onAudioEnded.bind(this));
59 this.audioElement.addEventListener('error', this.onAudioError.bind(this)); 153 this.audioElement.addEventListener('error', this.onAudioError.bind(this));
60 154
61 var onAudioStatusUpdatedBound = this.onAudioStatusUpdate_.bind(this); 155 var onAudioStatusUpdatedBound = this.onAudioStatusUpdate_.bind(this);
62 this.audioElement.addEventListener('timeupdate', onAudioStatusUpdatedBound); 156 this.audioElement.addEventListener('timeupdate', onAudioStatusUpdatedBound);
63 this.audioElement.addEventListener('ended', onAudioStatusUpdatedBound); 157 this.audioElement.addEventListener('ended', onAudioStatusUpdatedBound);
64 this.audioElement.addEventListener('play', onAudioStatusUpdatedBound); 158 this.audioElement.addEventListener('play', onAudioStatusUpdatedBound);
65 this.audioElement.addEventListener('pause', onAudioStatusUpdatedBound); 159 this.audioElement.addEventListener('pause', onAudioStatusUpdatedBound);
66 this.audioElement.addEventListener('suspend', onAudioStatusUpdatedBound); 160 this.audioElement.addEventListener('suspend', onAudioStatusUpdatedBound);
67 this.audioElement.addEventListener('abort', onAudioStatusUpdatedBound); 161 this.audioElement.addEventListener('abort', onAudioStatusUpdatedBound);
68 this.audioElement.addEventListener('error', onAudioStatusUpdatedBound); 162 this.audioElement.addEventListener('error', onAudioStatusUpdatedBound);
69 this.audioElement.addEventListener('emptied', onAudioStatusUpdatedBound); 163 this.audioElement.addEventListener('emptied', onAudioStatusUpdatedBound);
70 this.audioElement.addEventListener('stalled', onAudioStatusUpdatedBound); 164 this.audioElement.addEventListener('stalled', onAudioStatusUpdatedBound);
71 }, 165 },
72 166
73 /** 167 /**
74 * Registers handlers for changing of external variables
75 */
76 observe: {
77 'trackList.currentTrackIndex': 'onCurrentTrackIndexChanged',
78 'audioController.playing': 'onControllerPlayingChanged',
79 'audioController.time': 'onControllerTimeChanged',
80 'model.volume': 'onVolumeChanged',
81 },
82
83 /**
84 * Invoked when trackList.currentTrackIndex is changed. 168 * Invoked when trackList.currentTrackIndex is changed.
169 * @param {number} newValue new value.
85 * @param {number} oldValue old value. 170 * @param {number} oldValue old value.
86 * @param {number} newValue new value.
87 */ 171 */
88 onCurrentTrackIndexChanged: function(oldValue, newValue) { 172 currentTrackIndexChanged: function(newValue, oldValue) {
173 if (!this.trackList)
yawano 2015/06/10 06:46:18 Can we remove this condition if we access it via t
fukino 2015/06/10 07:00:22 Yes, I updated the CL to use this.$ consistently,
174 return;
175
89 var currentTrackUrl = ''; 176 var currentTrackUrl = '';
90 177
91 if (oldValue != newValue) { 178 if (oldValue != newValue) {
92 var currentTrack = this.trackList.getCurrentTrack(); 179 var currentTrack = this.trackList.getCurrentTrack();
93 if (currentTrack && currentTrack.url != this.audioElement.src) { 180 if (currentTrack && currentTrack.url != this.audioElement.src) {
94 this.audioElement.src = currentTrack.url; 181 this.audioElement.src = currentTrack.url;
95 currentTrackUrl = this.audioElement.src; 182 currentTrackUrl = this.audioElement.src;
96 if (this.audioController.playing) 183 if (this.playing)
97 this.audioElement.play(); 184 this.audioElement.play();
98 } 185 }
99 } 186 }
100 187
101 // The attributes may be being watched, so we change it at the last. 188 // The attributes may be being watched, so we change it at the last.
102 this.currenttrackurl = currentTrackUrl; 189 this.currenttrackurl = currentTrackUrl;
103 }, 190 },
104 191
105 /** 192 /**
106 * Invoked when audioController.playing is changed. 193 * Invoked when playing is changed.
194 * @param {boolean} newValue new value.
107 * @param {boolean} oldValue old value. 195 * @param {boolean} oldValue old value.
108 * @param {boolean} newValue new value.
109 */ 196 */
110 onControllerPlayingChanged: function(oldValue, newValue) { 197 playingChanged: function(newValue, oldValue) {
111 this.playing = newValue;
112
113 if (newValue) { 198 if (newValue) {
114 if (!this.audioElement.src) { 199 if (!this.audioElement.src) {
115 var currentTrack = this.trackList.getCurrentTrack(); 200 var currentTrack = this.trackList.getCurrentTrack();
116 if (currentTrack && currentTrack.url != this.audioElement.src) { 201 if (currentTrack && currentTrack.url != this.audioElement.src) {
117 this.audioElement.src = currentTrack.url; 202 this.audioElement.src = currentTrack.url;
118 } 203 }
119 } 204 }
120 205
121 if (this.audioElement.src) { 206 if (this.audioElement.src) {
122 this.currenttrackurl = this.audioElement.src; 207 this.currenttrackurl = this.audioElement.src;
123 this.audioElement.play(); 208 this.audioElement.play();
124 return; 209 return;
125 } 210 }
126 } 211 }
127 212
128 // When the new status is "stopped". 213 // When the new status is "stopped".
129 this.cancelAutoAdvance_(); 214 this.cancelAutoAdvance_();
130 this.audioElement.pause(); 215 if (this.audioElement)
216 this.audioElement.pause();
131 this.currenttrackurl = ''; 217 this.currenttrackurl = '';
132 this.lastAudioUpdateTime_ = null; 218 this.lastAudioUpdateTime_ = null;
133 }, 219 },
134 220
135 /** 221 /**
136 * Invoked when audioController.volume is changed. 222 * Invoked when the model changed.
137 * @param {number} oldValue old value. 223 * @param {AudioPlayerModel} newModel New model.
138 * @param {number} newValue new value. 224 * @param {AudioPlayerModel} oldModel Old model.
139 */ 225 */
140 onVolumeChanged: function(oldValue, newValue) { 226 modelChanged: function(newModel, oldModel) {
141 this.audioElement.volume = newValue / 100; 227 // Setting up the UI
228 if (newModel !== oldModel && newModel) {
229 this.shuffle = newModel.shuffle;
230 this.repeat = newModel.repeat;
231 this.volume = newModel.volume;
232 this.expanded = newModel.expanded;
233 }
142 }, 234 },
143 235
144 /** 236 /**
145 * Invoked when the model changed. 237 * Invoked when time is changed.
146 * @param {AudioPlayerModel} oldValue Old Value. 238 * @param {number} newValue new time (in ms).
147 * @param {AudioPlayerModel} newValue New Value. 239 * @param {number} oldValue old time (in ms).
148 */ 240 */
149 modelChanged: function(oldValue, newValue) { 241 timeChanged: function(newValue, oldValue) {
150 this.trackList.model = newValue;
151 this.audioController.model = newValue;
152
153 // Invoke the handler manually.
154 this.onVolumeChanged(0, newValue.volume);
155 },
156
157 /**
158 * Invoked when audioController.time is changed.
159 * @param {number} oldValue old time (in ms).
160 * @param {number} newValue new time (in ms).
161 */
162 onControllerTimeChanged: function(oldValue, newValue) {
163 // Ignores updates from the audio element. 242 // Ignores updates from the audio element.
164 if (this.lastAudioUpdateTime_ === newValue) 243 if (this.lastAudioUpdateTime_ === newValue)
165 return; 244 return;
166 245
167 if (this.audioElement.readyState !== 0) 246 if (this.audioElement && this.audioElement.readyState !== 0)
168 this.audioElement.currentTime = this.audioController.time / 1000; 247 this.audioElement.currentTime = this.time / 1000;
169 }, 248 },
170 249
171 /** 250 /**
172 * Invoked when the next button in the controller is clicked. 251 * Invoked when the next button in the controller is clicked.
173 * This handler is registered in the 'on-click' attribute of the element. 252 * This handler is registered in the 'on-click' attribute of the element.
174 */ 253 */
175 onControllerNextClicked: function() { 254 onControllerNextClicked: function() {
176 this.advance_(true /* forward */, true /* repeat */); 255 this.advance_(true /* forward */, true /* repeat */);
177 }, 256 },
178 257
179 /** 258 /**
180 * Invoked when the previous button in the controller is clicked. 259 * Invoked when the previous button in the controller is clicked.
181 * This handler is registered in the 'on-click' attribute of the element. 260 * This handler is registered in the 'on-click' attribute of the element.
182 */ 261 */
183 onControllerPreviousClicked: function() { 262 onControllerPreviousClicked: function() {
184 this.advance_(false /* forward */, true /* repeat */); 263 this.advance_(false /* forward */, true /* repeat */);
185 }, 264 },
186 265
187 /** 266 /**
188 * Invoked when the playback in the audio element is ended. 267 * Invoked when the playback in the audio element is ended.
189 * This handler is registered in this.ready(). 268 * This handler is registered in this.ready().
190 */ 269 */
191 onAudioEnded: function() { 270 onAudioEnded: function() {
192 this.playcount++; 271 this.playcount++;
193 this.advance_(true /* forward */, this.model.repeat); 272 this.advance_(true /* forward */, this.repeat);
194 }, 273 },
195 274
196 /** 275 /**
197 * Invoked when the playback in the audio element gets error. 276 * Invoked when the playback in the audio element gets error.
198 * This handler is registered in this.ready(). 277 * This handler is registered in this.ready().
199 */ 278 */
200 onAudioError: function() { 279 onAudioError: function() {
201 this.scheduleAutoAdvance_(true /* forward */, this.model.repeat); 280 this.scheduleAutoAdvance_(true /* forward */, this.repeat);
202 }, 281 },
203 282
204 /** 283 /**
205 * Invoked when the time of playback in the audio element is updated. 284 * Invoked when the time of playback in the audio element is updated.
206 * This handler is registered in this.ready(). 285 * This handler is registered in this.ready().
207 * @private 286 * @private
208 */ 287 */
209 onAudioStatusUpdate_: function() { 288 onAudioStatusUpdate_: function() {
210 this.audioController.time = 289 this.time =
211 (this.lastAudioUpdateTime_ = this.audioElement.currentTime * 1000); 290 (this.lastAudioUpdateTime_ = this.audioElement.currentTime * 1000);
212 this.audioController.duration = this.audioElement.duration * 1000; 291 this.duration = this.audioElement.duration * 1000;
213 this.audioController.playing = !this.audioElement.paused; 292 this.playing = !this.audioElement.paused;
214 }, 293 },
215 294
216 /** 295 /**
217 * Invoked when receiving a request to replay the current music from the track 296 * Invoked when receiving a request to replay the current music from the track
218 * list element. 297 * list element.
219 */ 298 */
220 onReplayCurrentTrack: function() { 299 onReplayCurrentTrack: function() {
221 // Changes the current time back to the beginning, regardless of the current 300 // Changes the current time back to the beginning, regardless of the current
222 // status (playing or paused). 301 // status (playing or paused).
223 this.audioElement.currentTime = 0; 302 this.audioElement.currentTime = 0;
224 this.audioController.time = 0; 303 this.time = 0;
225 }, 304 },
226 305
227 /** 306 /**
228 * Goes to the previous or the next track. 307 * Goes to the previous or the next track.
229 * @param {boolean} forward True if next, false if previous. 308 * @param {boolean} forward True if next, false if previous.
230 * @param {boolean} repeat True if repeat-mode is enabled. False otherwise. 309 * @param {boolean} repeat True if repeat-mode is enabled. False otherwise.
231 * @private 310 * @private
232 */ 311 */
233 advance_: function(forward, repeat) { 312 advance_: function(forward, repeat) {
234 this.cancelAutoAdvance_(); 313 this.cancelAutoAdvance_();
235 314
236 var nextTrackIndex = this.trackList.getNextTrackIndex(forward, true); 315 var nextTrackIndex = this.trackList.getNextTrackIndex(forward, true);
237 var isNextTrackAvailable = 316 var isNextTrackAvailable =
238 (this.trackList.getNextTrackIndex(forward, repeat) !== -1); 317 (this.trackList.getNextTrackIndex(forward, repeat) !== -1);
239 318
240 this.audioController.playing = isNextTrackAvailable; 319 this.playing = isNextTrackAvailable;
241 320
242 // If there is only a single file in the list, 'currentTrackInde' is not 321 // If there is only a single file in the list, 'currentTrackInde' is not
243 // changed and the handler is not invoked. Instead, plays here. 322 // changed and the handler is not invoked. Instead, plays here.
244 // TODO(yoshiki): clean up the code around here. 323 // TODO(yoshiki): clean up the code around here.
245 if (isNextTrackAvailable && 324 if (isNextTrackAvailable &&
246 this.trackList.currentTrackIndex == nextTrackIndex) { 325 this.trackList.currentTrackIndex == nextTrackIndex) {
247 this.audioElement.play(); 326 this.audioElement.play();
248 } 327 }
249 328
250 this.trackList.currentTrackIndex = nextTrackIndex; 329 this.trackList.currentTrackIndex = nextTrackIndex;
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
296 * @private 375 * @private
297 */ 376 */
298 cancelAutoAdvance_: function() { 377 cancelAutoAdvance_: function() {
299 if (this.autoAdvanceTimer_) { 378 if (this.autoAdvanceTimer_) {
300 clearTimeout(this.autoAdvanceTimer_); 379 clearTimeout(this.autoAdvanceTimer_);
301 this.autoAdvanceTimer_ = null; 380 this.autoAdvanceTimer_ = null;
302 } 381 }
303 }, 382 },
304 383
305 /** 384 /**
306 * The index of the current track.
307 * If the list has no tracks, the value must be -1.
308 *
309 * @type {number}
310 */
311 get currentTrackIndex() {
312 return this.trackList.currentTrackIndex;
313 },
314 set currentTrackIndex(value) {
315 this.trackList.currentTrackIndex = value;
316 },
317
318 /**
319 * The list of the tracks in the playlist. 385 * The list of the tracks in the playlist.
320 * 386 *
321 * When it changed, current operation including playback is stopped and 387 * When it changed, current operation including playback is stopped and
322 * restarts playback with new tracks if necessary. 388 * restarts playback with new tracks if necessary.
323 * 389 *
324 * @type {Array<AudioPlayer.TrackInfo>} 390 * @type {Array<AudioPlayer.TrackInfo>}
325 */ 391 */
326 get tracks() { 392 get tracks() {
327 return this.trackList ? this.trackList.tracks : null; 393 return this.trackList ? this.trackList.tracks : null;
328 }, 394 },
(...skipping 18 matching lines...) Expand all
347 this.audioElement.src = ''; // Hack to prevent crashing. 413 this.audioElement.src = ''; // Hack to prevent crashing.
348 }, 414 },
349 415
350 /** 416 /**
351 * Invoked when the 'keydown' event is fired. 417 * Invoked when the 'keydown' event is fired.
352 * @param {Event} event The event object. 418 * @param {Event} event The event object.
353 */ 419 */
354 onKeyDown_: function(event) { 420 onKeyDown_: function(event) {
355 switch (event.keyIdentifier) { 421 switch (event.keyIdentifier) {
356 case 'Up': 422 case 'Up':
357 if (this.audioController.volumeSliderShown && this.model.volume < 100) 423 if (this.$.audioController.volumeSliderShown && this.model.volume < 100)
358 this.model.volume += 1; 424 this.model.volume += 1;
359 break; 425 break;
360 case 'Down': 426 case 'Down':
361 if (this.audioController.volumeSliderShown && this.model.volume > 0) 427 if (this.$.audioController.volumeSliderShown && this.model.volume > 0)
362 this.model.volume -= 1; 428 this.model.volume -= 1;
363 break; 429 break;
364 case 'PageUp': 430 case 'PageUp':
365 if (this.audioController.volumeSliderShown && this.model.volume < 91) 431 if (this.$.audioController.volumeSliderShown && this.model.volume < 91)
366 this.model.volume += 10; 432 this.model.volume += 10;
367 break; 433 break;
368 case 'PageDown': 434 case 'PageDown':
369 if (this.audioController.volumeSliderShown && this.model.volume > 9) 435 if (this.$.audioController.volumeSliderShown && this.model.volume > 9)
370 this.model.volume -= 10; 436 this.model.volume -= 10;
371 break; 437 break;
372 case 'MediaNextTrack': 438 case 'MediaNextTrack':
373 this.onControllerNextClicked(); 439 this.onControllerNextClicked();
374 break; 440 break;
375 case 'MediaPlayPause': 441 case 'MediaPlayPause':
376 var playing = this.audioController.playing; 442 this.playing = !this.playing;
377 this.onControllerPlayingChanged(playing, !playing);
378 break; 443 break;
379 case 'MediaPreviousTrack': 444 case 'MediaPreviousTrack':
380 this.onControllerPreviousClicked(); 445 this.onControllerPreviousClicked();
381 break; 446 break;
382 case 'MediaStop': 447 case 'MediaStop':
383 // TODO: Define "Stop" behavior. 448 // TODO: Define "Stop" behavior.
384 break; 449 break;
385 } 450 }
386 }, 451 },
452
453 /**
454 * Computes volume value for audio element. (should be in [0.0, 1.0])
455 * @param {number} volume Volume which is set in the UI. ([0, 100])
456 * @return {number}
457 */
458 computeAudioVolume_: function(volume) {
459 return volume / 100;
460 }
387 }; 461 };
388 462
389 Polymer('audio-player', AudioPlayerElement.prototype); 463 Polymer(AudioPlayerElement.prototype);
OLDNEW
« no previous file with comments | « ui/file_manager/audio_player/elements/audio_player.html ('k') | ui/file_manager/audio_player/elements/control_panel.html » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698