// JavaScript Document /** Yahoo Media Player - TrackSeek extension Displays a visual position indicator and allows the user to control the seek position @author: Eric Fehrenbacher @company: Yahoo! @version 0.1.2 */ var TrackSeek = function() { // reference to YMP this.player = YAHOO.MediaPlayer; // position of the left edge of the slider relative to the page this.seekControlX = 0; // reference to the currently playing track this.track = null; // the elapsed time of the currently playing track this.elapsed = 0; // the duration of the currently playing track this.duration = 0; // tells us if the track is playing or not this.paused = true; // tells us if we are dragging the slider or not this.dragging = false; // tracks the percentage of movement from the left edge of the control this.position = 0; // setup of delegates, subscribers, and UI this.init(); }; TrackSeek.create = function(args) { YAHOO.mediaplayer.TrackSeek = new TrackSeek(args[0]); return YAHOO.mediaplayer.TrackSeek; }; TrackSeek.attachElement = 'ymp-meta-album-title'; TrackSeek.prototype = { /** Fires during the contruction of this object @method init */ init: function() { // this.setupUI(); // some ui specs this.ui = { // define the total width width: function() { return parseInt(YAHOO.ympyui.util.Dom.getStyle('ymp-seek', 'width')); }, // define the left edge left: function() { return Math.round(parseInt(YAHOO.ympyui.util.Dom.getStyle('ymp-seek-thumb', 'width')) / 2); }, // define the right edge right: function() { return this.width() - this.left(); } }; // initialize default seek position... this.onPositionChange(1); // handle mousedown on the position control YAHOO.ympyui.util.Event.on('ymp-seek', 'mousedown', this.seekStartDrag, this, true); // handle clicks on the position control YAHOO.ympyui.util.Event.on('ymp-seek', 'click', this.stopEvent); // track hash of active track when play is clicked this.player.onTrackStart.subscribe(this.onPlay, this, true); // update position based on elapsed time of active track this.player.onProgress.subscribe(this.onProgress, this, true); // this.player.onTrackPause.subscribe(this.onPause, this, true); // YAHOO.ympyui.util.Event.addListener(['ymp-next','ymp-prev'], 'click', function() { this.onPositionChange(1); }, this, true); }, /** We just setup the GUI here. @method setupUI */ setupUI: function() { // grab the volume control var displaced = document.getElementById(TrackSeek.attachElement); YAHOO.ympyui.util.Dom.setStyles(displaced, {display: 'none'}); // create slider var seekContainer = document.createElement('div'); seekContainer.id = 'ymp-seek'; YAHOO.ympyui.util.Dom.setStyles(seekContainer, { position: 'absolute', width: '190px', height: '15px', zIndex: '2' }); displaced.parentNode.insertBefore(seekContainer, displaced); /* // we need to be notified when the timer changes size so we can readjust // or better yet, why do we need to readjust the timer should be doing that var seekRegion = YAHOO.ympyui.util.Dom.getRegion(seekContainer); var seekWidth = seekRegion.right - seekRegion.left; YAHOO.ympyui.util.Dom.setStyle(seekContainer, 'width', (seekWidth - 10) + 'px'); */ var seekCover = document.createElement('div'); seekCover.id = 'ymp-seek-cover'; YAHOO.ympyui.util.Dom.setStyles(seekCover, { display: 'block', position: 'absolute', overflow: 'hidden', top: '5px', left: '0px', width: '100%', height: '4px', backgroundColor: '#D6D6D6' }); seekContainer.appendChild(seekCover); var seekCoverElapsed = document.createElement('div'); seekCoverElapsed.id = 'ymp-seek-cover-elapsed'; YAHOO.ympyui.util.Dom.setStyles(seekCoverElapsed, { display: 'block', position: 'absolute', visibility: 'hidden', overflow: 'hidden', top: '0px', left: '0px', width: '100%', height: '4px', backgroundColor: '#929392' }); seekCover.appendChild(seekCoverElapsed); YAHOO.ympyui.util.Event.addListener(seekContainer, 'mouseover', function() { this.style.backgroundColor = '#CEFD0D'; }, seekCoverElapsed, true); YAHOO.ympyui.util.Event.addListener(seekContainer, 'mouseout', function() { this.style.backgroundColor = '#929392'; }, seekCoverElapsed, true); var seekThumb = document.createElement('div'); seekThumb.id = 'ymp-seek-thumb'; YAHOO.ympyui.util.Event.addListener(seekThumb, 'mouseover', function() { this.style.borderColor = '#CEFD0D'; }, seekThumb, true); YAHOO.ympyui.util.Event.addListener(seekThumb, 'mouseout', function() { this.style.borderColor = '#DDDDDD #B2B2B2 #B2B2B2 #DDDDDD'; }, seekThumb, true); YAHOO.ympyui.util.Dom.setStyles(seekThumb, { display: 'block', position: 'absolute', overflow: 'hidden', top: '3px', left: '0px', width: '4px', height: '7px', cursor: 'pointer', backgroundColor: '#E9E8E8', borderWidth: '1px', borderStyle: 'solid', borderColor: '#DDDDDD #B2B2B2 #B2B2B2 #DDDDDD' }); seekContainer.appendChild(seekThumb); }, /** Provides a shortcut for stopping an event @method stopEvent @param evt */ stopEvent: function(evt) { YAHOO.ympyui.util.Event.stopEvent(evt); }, /** Event handler for when the user starts to drag the position slider @method seekStartDrag @param eventObj The HTML event object. */ seekStartDrag: function(evt) { if (this.paused) { return; } this.stopEvent(evt); this.dragging = true; // get the current position of the left edge of the slider relative to the page this.seekControlX = YAHOO.ympyui.util.Dom.getX('ymp-seek'); // notify everyone about position change this.notifySeekChange(evt); YAHOO.ympyui.util.Event.on(document, 'mousemove', this.notifySeekChange, this, true); YAHOO.ympyui.util.Event.on(document, 'mouseup', this.seekMouseUp, this, true); }, /** Event handler when the user releases the mouse after dragging the position slider. Remove the appropriate event listeners. @method seekMouseUp @param eventObj The HTML event object */ seekMouseUp: function(evt) { this.dragging = false; this.stopEvent(evt); this.elapsed = this.duration - (this.position * this.duration); YAHOO.ympyui.util.Event.removeListener(document, 'mousemove', this.notifySeekChange); YAHOO.ympyui.util.Event.removeListener(document, 'mouseup', this.seekMouseUp); if (this.paused) { this.player.pause(); return; // reduce the volume before we play so that no one here's the brief noise var volume = this.player.getVolume(); this.player.setVolume(0); this.player.play(this.track, this.elapsed); /* it would be nice to be able to move the position while paused, but... for some reason this hack won't work here, haven't figured out why yet */ /* this.playCheck = YAHOO.ympyui.lang.later(100, this, function(volume) { if (this.player.getPlayerState() == 2) { this.playCheck.cancel(); //this.updateSeekPosition(); this.onProgress({elapsed: this.elapsed, duration: this.duration}) console.log("asddddddddd"); this.player.pause(); //this.player.setVolume(volume); } }, [volume], true); */ } else { this.player.play(this.track, this.elapsed); } }, /** Get the right requested position based on where the user has dragged the position slider and then fire the position change request event for that position @method notifySeekChange @param evt */ notifySeekChange: function(evt) { this.stopEvent(evt); var newMouseX = YAHOO.ympyui.util.Event.getPageX(evt); var xDiff = (newMouseX - this.seekControlX); xDiff -= 0; var thumbLeft; // calculate position percentage (0 - 1) and fire the event to notify whoever is listening if ((xDiff >= this.ui.left()) && (xDiff < this.ui.right())) { // mouse is within the constraint thumbLeft = xDiff - this.ui.left(); } else if (xDiff >= this.ui.right()) { // mouse is way below the position, so cap the thumb at the maximum x it is allowed to go thumbLeft = this.ui.right() - this.ui.left(); } else if (xDiff < this.ui.left()) { // mouse is way above the position, so cap the x at 0 thumbLeft = 0; } // percentage of movement from the left edge of the control this.position = 1 - (thumbLeft / (this.ui.right() - this.ui.left())); this.onPositionChange(this.position); }, /** Event handler for onPlay. Record the track as a mediaObject for reference. @method onPlay @param track The currently playing track */ onPlay: function(track) { this.paused = false; this.track = track.mediaObject; }, /** This function updates the seek position based on the elapsed time of the currently playing track @method onProgress @param options */ onProgress: function(options) { this.elapsed = options.elapsed; this.duration = options.duration || (YAHOO.mediaplayer.TrackResume && YAHOO.mediaplayer.TrackResume.duration) || 0; if (!this.dragging && (this.duration != 0)) { var thumbLeft; // convert thumb position into seek position var xDiff = Math.ceil((Math.ceil(this.elapsed) * this.ui.right() - this.ui.left()) / Math.ceil(this.duration)); xDiff -= 0; // calculate position percentage (0 - 1) and fire the event to notify whoever is listening if ((xDiff >= this.ui.left()) && (xDiff < this.ui.right())) { // seek is within the constraint thumbLeft = xDiff - this.ui.left(); } else if (xDiff >= this.ui.right()) { // seek is way below the position, so cap the thumb at the maximum x it is allowed to go thumbLeft = this.ui.right() - this.ui.left(); } else if (xDiff < this.ui.left()) { // seek is way above the position, so cap the x at 0 thumbLeft = 0; } // percentage of seek position from the left edge of the controle var position = 1 - (thumbLeft / (this.ui.right() - this.ui.left())); this.onPositionChange(position); } }, /** Event handler for onPlay. Record the track as a mediaObject for reference. @method onPause @param track The currently playing track */ onPause: function(track) { this.paused = true; }, /** Event handler for onPositionChange. If the seek position is changed through API update the view appropriately @method onPositionChange @param seek The new position [0-1] */ onPositionChange: function(position) { // convert seek position into thumb position var thumbLeft = (1 - position) * (this.ui.right() - this.ui.left()); // adjust seek thumb position YAHOO.ympyui.util.Dom.setStyle('ymp-seek-thumb', 'left', thumbLeft + 'px'); // adjust elapsed position YAHOO.ympyui.util.Dom.setStyle('ymp-seek-cover-elapsed', 'visibility', 'visible'); YAHOO.ympyui.util.Dom.setStyle('ymp-seek-cover-elapsed', 'left', -((this.ui.right() - this.ui.left()) - thumbLeft) + 'px'); } }; /** This creates a new TrackSeek object and attaches to the MediaPlayer */ (typeof YAHOO != 'undefined') && YAHOO.ympyui.util.Event.onAvailable(TrackSeek.attachElement, TrackSeek.create, TrackSeek);