Chromium Code Reviews| Index: chrome/browser/resources/file_manager/audio_player/elements/audio_player.js |
| diff --git a/chrome/browser/resources/file_manager/audio_player/elements/audio_player.js b/chrome/browser/resources/file_manager/audio_player/elements/audio_player.js |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..1adf2a155f73f3e83de3c09707f918e040b39774 |
| --- /dev/null |
| +++ b/chrome/browser/resources/file_manager/audio_player/elements/audio_player.js |
| @@ -0,0 +1,293 @@ |
| +// Cpyright (c) 2013 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +'use strict'; |
| + |
| +Polymer('audio-player', { |
| + /** |
| + * Child Elements |
| + */ |
| + audioController: null, |
| + audioElement: null, |
| + trackList: null, |
| + |
| + /** |
| + * Initialize an element. This method is called automatically when the |
| + * element is ready. |
| + */ |
| + ready: function() { |
| + this.audioController = this.$.audioController; |
| + this.audioElement = this.$.audio; |
| + this.trackList = this.$.trackList; |
| + |
| + this.audioElement.volume = this.audioController.volume / 100; |
| + this.audioElement.addEventListener('ended', this.onAudioEnded.bind(this)); |
| + this.audioElement.addEventListener('error', this.onAudioError.bind(this)); |
| + |
| + var onAudioStatusUpdatedBound = this.onAudioStatusUpdate_.bind(this); |
| + this.audioElement.addEventListener('timeupdate', onAudioStatusUpdatedBound); |
| + this.audioElement.addEventListener('ended', onAudioStatusUpdatedBound); |
| + this.audioElement.addEventListener('play', onAudioStatusUpdatedBound); |
| + this.audioElement.addEventListener('pause', onAudioStatusUpdatedBound); |
| + this.audioElement.addEventListener('suspend', onAudioStatusUpdatedBound); |
| + this.audioElement.addEventListener('abort', onAudioStatusUpdatedBound); |
| + this.audioElement.addEventListener('error', onAudioStatusUpdatedBound); |
| + this.audioElement.addEventListener('emptied', onAudioStatusUpdatedBound); |
| + this.audioElement.addEventListener('stalled', onAudioStatusUpdatedBound); |
| + }, |
| + |
| + /** |
| + * Register handlers for changing of external variables |
| + */ |
| + observe: { |
| + 'trackList.currentTrackIndex': 'onCurrentTrackIndexChanged', |
| + 'audioController.playlistExpanded': 'onPlayerExpandedChanged', |
| + 'audioController.playing': 'onControllerPlayingChanged', |
| + 'audioController.volume': 'onControllerVolumeChanged', |
| + 'audioController.time': 'onControllerTimeChanged', |
| + 'audioController.shuffle': 'onControllerShuffleChanged', |
| + 'audioController.repeat': 'onControllerRepeatChanged', |
| + }, |
| + |
| + /** |
| + * Invoked when trackList.currentTrackIndex is changed. |
| + * @param {number} oldValue old value. |
| + * @param {number} newValue new value. |
| + */ |
| + onCurrentTrackIndexChanged: function(oldValue, newValue) { |
| + if (oldValue != newValue) { |
| + var currentTrack = this.trackList.getCurrentTrack(); |
| + if (currentTrack && currentTrack.url != this.audioElement.src) { |
| + this.audioElement.src = currentTrack.url; |
| + this.audioElement.play(); |
| + } |
| + } |
| + }, |
| + |
| + /** |
| + * Invoked when audioController.playlistExpanded is changed. |
| + * @param {boolean} oldValue old value. |
| + * @param {boolean} newValue new value. |
| + */ |
| + onPlayerExpandedChanged: function(oldValue, newValue) { |
| + if (oldValue != newValue) { |
| + this.trackList.expanded = newValue; |
| + if (AudioPlayer.instance) |
| + AudioPlayer.instance.syncExpanded(); |
| + } |
| + }, |
| + |
| + /** |
| + * Invoked when audioController.playing is changed. |
| + * @param {boolean} oldValue old value. |
| + * @param {boolean} newValue new value. |
| + */ |
| + onControllerPlayingChanged: function(oldValue, newValue) { |
| + if (newValue) { |
| + if (!this.audioElement.src) { |
| + var currentTrack = this.trackList.getCurrentTrack(); |
| + if (currentTrack && currentTrack.url != this.audioElement.src) |
| + this.audioElement.src = currentTrack.url; |
| + } |
| + |
| + if (this.audioElement.src) { |
| + this.audioElement.play(); |
| + return; |
| + } |
| + } |
| + |
| + this.audioController.playing = false; |
| + this.audioElement.pause(); |
| + }, |
| + |
| + /** |
| + * Invoked when audioController.volume is changed. |
| + * @param {number} oldValue old value. |
| + * @param {number} newValue new value. |
| + */ |
| + onControllerVolumeChanged: function(oldValue, newValue) { |
| + this.audioElement.volume = newValue / 100; |
| + }, |
| + |
| + /** |
| + * Invoked when audioController.time is changed. |
| + * @param {number} oldValue old value. |
|
mtomasz
2014/01/23 08:05:09
nit: Please add a unit (ms?)
yoshiki
2014/01/24 15:34:19
Done.
|
| + * @param {number} newValue new value. |
| + */ |
| + onControllerTimeChanged: function(oldValue, newValue) { |
| + // Ignore periodical updates and small amount change. |
| + if (Math.abs(oldValue - newValue) <= 500) |
| + return; |
| + |
| + if (this.audioElement.readyState !== 0) |
| + this.audioElement.currentTime = this.audioController.time / 1000; |
| + }, |
| + |
| + /** |
| + * Invoked when audioController.shuffle is changed. |
| + * @param {boolean} oldValue old value. |
| + * @param {boolean} newValue new value. |
| + */ |
| + onControllerShuffleChanged: function(oldValue, newValue) { |
| + // TODO(yoshiki): Implement shuffle mode. |
| + }, |
| + |
| + /** |
| + * Invoked when audioController.repeat is changed. |
| + * @param {boolean} oldValue old value. |
| + * @param {boolean} newValue new value. |
| + */ |
| + onControllerRepeatChanged: function(oldValue, newValue) { |
| + this.trackList.repeat = newValue; |
| + }, |
| + |
| + /** |
| + * Invoked when the next button in the controller is clicked. |
| + * This handler is registered in the 'on-click' attribute of the element. |
| + */ |
| + onControllerNextClicked: function() { |
| + this.advance_(true, true); |
|
mtomasz
2014/01/23 08:05:09
Can we use an enum instead? It is hard to understa
yoshiki
2014/01/24 15:34:19
Done.
|
| + }, |
| + |
| + /** |
| + * Invoked when the prev button in the controller is clicked. |
| + * This handler is registered in the 'on-click' attribute of the element. |
| + */ |
| + onControllerPreviousClicked: function() { |
| + this.advance_(true, true); |
| + }, |
| + |
| + /** |
| + * Invoked when the playback in the audio element is ended. |
| + * This handler is registered in this.ready(). |
| + */ |
| + onAudioEnded: function() { |
| + this.advance_(true, this.audioController.repeat); |
| + }, |
| + |
| + /** |
| + * Invoked when the playback in the audio element gets error. |
| + * This handler is registered in this.ready(). |
| + */ |
| + onAudioError: function() { |
| + this.scheduleAutoAdvance_(true, this.audioController.repeat); |
| + }, |
| + |
| + /** |
| + * Invoked when the time of playback in the audio element is updated. |
| + * This handler is registered in this.ready(). |
|
mtomasz
2014/01/23 08:05:09
@private missing
yoshiki
2014/01/24 15:34:19
Done.
|
| + */ |
| + onAudioStatusUpdate_: function() { |
| + this.audioController.time = this.audioElement.currentTime * 1000; |
| + this.audioController.duration = this.audioElement.duration * 1000; |
| + this.audioController.playing = !this.audioElement.paused; |
| + }, |
| + |
| + /** |
| + * Go to the previous or the next track. |
| + * @param {boolean} forward True if next, false if previous. |
|
mtomasz
2014/01/23 08:05:09
One @param missing.
yoshiki
2014/01/24 15:34:19
Done.
|
| + * @private |
| + */ |
| + advance_: function(forward, repeat) { |
| + this.cancelAutoAdvance_(); |
| + |
| + var nextTrackIndex = this.trackList.getNextTrackIndex(forward); |
| + var nextTrack = this.trackList.tracks[nextTrackIndex]; |
| + var isNextTrackAvailable = this.trackList.isNextTrackAvailable(forward); |
| + |
| + this.trackList.currentTrackIndex = nextTrackIndex; |
| + |
| + if (isNextTrackAvailable || repeat && nextTrack) { |
| + this.audioElement.src = nextTrack.url; |
| + this.audioElement.play(); |
| + } else { |
| + this.audioElement.pause(); |
| + } |
| + }, |
| + |
| + /** |
| + * Timeout ID of auto advance. Used internally in scheduleAutoAdvance_() and |
| + * cancelAutoAdvance_(). |
|
mtomasz
2014/01/23 08:05:09
No indent for jsdoc descriptions.
yoshiki
2014/01/24 15:34:19
Done.
mtomasz
2014/01/27 01:09:24
The indent still looks off.
|
| + * @type {number} |
| + * @private |
| + */ |
| + autoAdvanceTimer_: null, |
| + |
| + /** |
| + * Schedule automatic advance to the next track after a timeout. |
|
mtomasz
2014/01/23 08:05:09
ditto: jsdoc missing
yoshiki
2014/01/24 15:34:19
Done.
|
| + * @private |
| + */ |
| + scheduleAutoAdvance_: function(forward, repeat) { |
| + this.cancelAutoAdvance_(); |
| + this.autoAdvanceTimer_ = setTimeout( |
| + function() { |
| + this.autoAdvanceTimer_ = null; |
| + // We are advancing only if the next track is not known to be invalid. |
| + // This prevents an endless auto-advancing in the case when all tracks |
| + // are invalid (we will only visit each track once). |
| + this.advance_(forward, repeat, true /* only if valid */); |
| + }.bind(this), |
| + 3000); |
|
mtomasz
2014/01/23 08:05:09
Why do we need a timeout? I think users don't expe
yoshiki
2014/01/24 15:34:19
This gap happens when error is happened and the pl
|
| + }, |
| + |
| + /** |
| + * Cancel the scheduled auto advance. |
| + * @private |
| + */ |
| + cancelAutoAdvance_: function() { |
| + if (this.autoAdvanceTimer_) { |
| + clearTimeout(this.autoAdvanceTimer_); |
| + this.autoAdvanceTimer_ = null; |
| + } |
| + }, |
| + |
| + set currentTrackIndex(value) { |
| + this.trackList.currentTrackIndex = value; |
| + }, |
| + get currentTrackIndex() { |
| + return this.trackList.currentTrackIndex; |
| + }, |
| + |
| + /** |
| + * Setter of 'tracks' property. |
| + * |
| + * This ends current operation including playback, and restarts playback if |
|
mtomasz
2014/01/23 08:05:09
jsdoc missing.
yoshiki
2014/01/24 15:34:19
Done.
|
| + * necessary. |
| + */ |
| + set tracks(tracks) { |
| + if (this.trackList.tracks === tracks) |
| + return; |
| + |
| + this.cancelAutoAdvance_(); |
| + |
| + this.trackList.tracks = tracks; |
| + var currentTrack = this.trackList.getCurrentTrack(); |
| + if (currentTrack && currentTrack.url != this.audioElement.src) { |
| + this.audioElement.src = currentTrack.url; |
| + this.audioElement.play(); |
| + } |
| + }, |
| + |
| + /** |
| + * Getter of 'tracks' property. |
|
mtomasz
2014/01/23 08:05:09
ditto: jsdoc missing
yoshiki
2014/01/24 15:34:19
Done.
|
| + * This returns 'tracks' in the track list element. |
| + */ |
| + get tracks() { |
| + return this.trackList ? this.trackList.tracks : null; |
| + }, |
| + |
| + /** |
| + * Returns whether the track list is expanded or not. |
| + */ |
| + isExpanded: function() { |
| + return this.audioController.playlistExpanded; |
| + }, |
| + |
| + /** |
| + * Expands or collapse the track list. |
| + */ |
| + expand: function(expand) { |
| + this.audioController.playlistExpanded = !!expand; |
| + } |
| +}); |