1/* 2 AUTHOR: Osvaldas Valutis, www.osvaldas.info 3*/ 4 5 6 7;(function( $, window, document, undefined ) 8{ 9 var isTouch = 'ontouchstart' in window, 10 eStart = isTouch ? 'touchstart' : 'mousedown', 11 eMove = isTouch ? 'touchmove' : 'mousemove', 12 eEnd = isTouch ? 'touchend' : 'mouseup', 13 eCancel = isTouch ? 'touchcancel' : 'mouseup', 14 secondsToTime = function( secs ) 15 { 16 var hours = Math.floor( secs / 3600 ), minutes = Math.floor( secs % 3600 / 60 ), seconds = Math.ceil( secs % 3600 % 60 ); 17 return ( hours == 0 ? '' : hours > 0 && hours.toString().length < 2 ? '0'+hours+':' : hours+':' ) + ( minutes.toString().length < 2 ? '0'+minutes : minutes ) + ':' + ( seconds.toString().length < 2 ? '0'+seconds : seconds ); 18 }, 19 canPlayType = function( file ) 20 { 21 var audioElement = document.createElement( 'audio' ); 22 return !!( audioElement.canPlayType && audioElement.canPlayType( 'audio/' + file.split( '.' ).pop().toLowerCase() + ';' ).replace( /no/, '' ) ); 23 }; 24 25 $.fn.audioPlayer = function( params ) 26 { 27 var params = $.extend( { classPrefix: 'audioplayer', strPlay: 'Play', strPause: 'Pause', strVolume: 'Volume' }, params ), 28 cssClass = {}, 29 cssClassSub = 30 { 31 playPause: 'playpause', 32 playing: 'playing', 33 time: 'time', 34 timeCurrent: 'time-current', 35 timeDuration: 'time-duration', 36 bar: 'bar', 37 barLoaded: 'bar-loaded', 38 barPlayed: 'bar-played', 39 volume: 'volume', 40 volumeButton: 'volume-button', 41 volumeAdjust: 'volume-adjust', 42 noVolume: 'novolume', 43 mute: 'mute', 44 mini: 'mini' 45 }; 46 47 for( var subName in cssClassSub ) 48 cssClass[ subName ] = params.classPrefix + '-' + cssClassSub[ subName ]; 49 50 this.each( function() 51 { 52 if( $( this ).prop( 'tagName' ).toLowerCase() != 'audio' ) 53 return false; 54 55 var $this = $( this ), 56 audioFile = $this.attr( 'src' ), 57 isAutoPlay = $this.get( 0 ).getAttribute( 'autoplay' ), isAutoPlay = isAutoPlay === '' || isAutoPlay === 'autoplay' ? true : false, 58 isLoop = $this.get( 0 ).getAttribute( 'loop' ), isLoop = isLoop === '' || isLoop === 'loop' ? true : false, 59 isSupport = false; 60 61 if( typeof audioFile === 'undefined' ) 62 { 63 $this.find( 'source' ).each( function() 64 { 65 audioFile = $( this ).attr( 'src' ); 66 if( typeof audioFile !== 'undefined' && canPlayType( audioFile ) ) 67 { 68 isSupport = true; 69 return false; 70 } 71 }); 72 } 73 else if( canPlayType( audioFile ) ) isSupport = true; 74 75 var thePlayer = $( '<div class="' + params.classPrefix + '">' + ( isSupport ? $( '<div>' ).append( $this.eq( 0 ).clone() ).html() : '<embed src="' + audioFile + '" width="0" height="0" volume="100" autostart="' + isAutoPlay.toString() +'" loop="' + isLoop.toString() + '" />' ) + '<div class="' + cssClass.playPause + '" title="' + params.strPlay + '"><a href="#">' + params.strPlay + '</a></div></div>' ), 76 theAudio = isSupport ? thePlayer.find( 'audio' ) : thePlayer.find( 'embed' ), theAudio = theAudio.get( 0 ); 77 78 if( isSupport ) 79 { 80 thePlayer.find( 'audio' ).css( { 'width': 0, 'height': 0, 'visibility': 'hidden' } ); 81 thePlayer.append( '<div class="' + cssClass.time + ' ' + cssClass.timeCurrent + '"></div><div class="' + cssClass.bar + '"><div class="' + cssClass.barLoaded + '"></div><div class="' + cssClass.barPlayed + '"></div></div><div class="' + cssClass.time + ' ' + cssClass.timeDuration + '"></div><div class="' + cssClass.volume + '"><div class="' + cssClass.volumeButton + '" title="' + params.strVolume + '"><a href="#">' + params.strVolume + '</a></div><div class="' + cssClass.volumeAdjust + '"><div><div></div></div></div></div>' ); 82 83 var theBar = thePlayer.find( '.' + cssClass.bar ), 84 barPlayed = thePlayer.find( '.' + cssClass.barPlayed ), 85 barLoaded = thePlayer.find( '.' + cssClass.barLoaded ), 86 timeCurrent = thePlayer.find( '.' + cssClass.timeCurrent ), 87 timeDuration = thePlayer.find( '.' + cssClass.timeDuration ), 88 volumeButton = thePlayer.find( '.' + cssClass.volumeButton ), 89 volumeAdjuster = thePlayer.find( '.' + cssClass.volumeAdjust + ' > div' ), 90 volumeDefault = 0, 91 adjustCurrentTime = function( e ) 92 { 93 theRealEvent = isTouch ? e.originalEvent.touches[ 0 ] : e; 94 theAudio.currentTime = Math.round( ( theAudio.duration * ( theRealEvent.pageX - theBar.offset().left ) ) / theBar.width() ); 95 }, 96 adjustVolume = function( e ) 97 { 98 theRealEvent = isTouch ? e.originalEvent.touches[ 0 ] : e; 99 theAudio.volume = Math.abs( ( theRealEvent.pageY - ( volumeAdjuster.offset().top + volumeAdjuster.height() ) ) / volumeAdjuster.height() ); 100 }, 101 updateLoadBar = setInterval( function() 102 { 103 if( theAudio.buffered.length > 0){ 104 barLoaded.width( ( theAudio.buffered.end( 0 ) / theAudio.duration ) * 100 + '%' ); 105 if( theAudio.buffered.end( 0 ) >= theAudio.duration ) 106 clearInterval( updateLoadBar ); 107 } 108 }, 100 ); 109 110 var volumeTestDefault = theAudio.volume, volumeTestValue = theAudio.volume = 0.111; 111 if( Math.round( theAudio.volume * 1000 ) / 1000 == volumeTestValue ) theAudio.volume = volumeTestDefault; 112 else thePlayer.addClass( cssClass.noVolume ); 113 114 timeDuration.html( '…' ); 115 timeCurrent.text( secondsToTime( 0 ) ); 116 117 theAudio.addEventListener( 'loadeddata', function() 118 { 119 timeDuration.text( secondsToTime( theAudio.duration ) ); 120 volumeAdjuster.find( 'div' ).height( theAudio.volume * 100 + '%' ); 121 volumeDefault = theAudio.volume; 122 }); 123 124 theAudio.addEventListener( 'timeupdate', function() 125 { 126 timeCurrent.text( secondsToTime( theAudio.currentTime ) ); 127 barPlayed.width( ( theAudio.currentTime / theAudio.duration ) * 100 + '%' ); 128 }); 129 130 theAudio.addEventListener( 'volumechange', function() 131 { 132 volumeAdjuster.find( 'div' ).height( theAudio.volume * 100 + '%' ); 133 if( theAudio.volume > 0 && thePlayer.hasClass( cssClass.mute ) ) thePlayer.removeClass( cssClass.mute ); 134 if( theAudio.volume <= 0 && !thePlayer.hasClass( cssClass.mute ) ) thePlayer.addClass( cssClass.mute ); 135 }); 136 137 theAudio.addEventListener( 'ended', function() 138 { 139 thePlayer.removeClass( cssClass.playing ); 140 }); 141 142 theBar.on( eStart, function( e ) 143 { 144 adjustCurrentTime( e ); 145 theBar.on( eMove, function( e ) { adjustCurrentTime( e ); } ); 146 }) 147 .on( eCancel, function() 148 { 149 theBar.unbind( eMove ); 150 }); 151 152 volumeButton.on( 'click', function() 153 { 154 if( thePlayer.hasClass( cssClass.mute ) ) 155 { 156 thePlayer.removeClass( cssClass.mute ); 157 theAudio.volume = volumeDefault; 158 } 159 else 160 { 161 thePlayer.addClass( cssClass.mute ); 162 volumeDefault = theAudio.volume; 163 theAudio.volume = 0; 164 } 165 return false; 166 }); 167 168 volumeAdjuster.on( eStart, function( e ) 169 { 170 adjustVolume( e ); 171 volumeAdjuster.on( eMove, function( e ) { adjustVolume( e ); } ); 172 }) 173 .on( eCancel, function() 174 { 175 volumeAdjuster.unbind( eMove ); 176 }); 177 } 178 else thePlayer.addClass( cssClass.mini ); 179 180 if( isAutoPlay ) thePlayer.addClass( cssClass.playing ); 181 182 thePlayer.find( '.' + cssClass.playPause ).on( 'click', function() 183 { 184 if( thePlayer.hasClass( cssClass.playing ) ) 185 { 186 $( this ).attr( 'title', params.strPlay ).find( 'a' ).html( params.strPlay ); 187 thePlayer.removeClass( cssClass.playing ); 188 isSupport ? theAudio.pause() : theAudio.Stop(); 189 } 190 else 191 { 192 $( this ).attr( 'title', params.strPause ).find( 'a' ).html( params.strPause ); 193 thePlayer.addClass( cssClass.playing ); 194 isSupport ? theAudio.play() : theAudio.Play(); 195 } 196 return false; 197 }); 198 199 $this.replaceWith( thePlayer ); 200 }); 201 return this; 202 }; 203})( jQuery, window, document );
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.