1/* 2 * CirclePlayer for the jPlayer Plugin (jQuery) 3 * http://www.jplayer.org 4 * 5 * Copyright (c) 2009 - 2011 Happyworm Ltd 6 * Dual licensed under the MIT and GPL licenses. 7 * - http://www.opensource.org/licenses/mit-license.php 8 * - http://www.gnu.org/copyleft/gpl.html 9 * 10 * Version: 1.0.1 (jPlayer 2.0.9) 11 * Date: 30th May 2011 12 * 13 * Author: Mark J Panaghiston @thepag 14 * 15 * CirclePlayer prototype developed by: 16 * Mark Boas @maboa 17 * Silvia Benvenuti @aulentina 18 * Jussi Kalliokoski @quinirill 19 * 20 * Inspired by : 21 * Neway @imneway http://imneway.net/ http://forrst.com/posts/Untitled-CPt 22 * and 23 * Liam McKay @liammckay http://dribbble.com/shots/50882-Purple-Play-Pause 24 * 25 * Standing on the shoulders of : 26 * John Resig @jresig 27 * Mark Panaghiston @thepag 28 * Louis-Rémi Babé @Louis_Remi 29 */ 30 31var cir_width = 52; 32 33var CirclePlayer = function(jPlayerSelector, media, options) { 34 var self = this, 35 36 defaults = { 37 // solution: "flash, html", // For testing Flash with CSS3 38 supplied: "m4a, oga", 39 // Android 2.3 corrupts media element if preload:"none" is used. 40 // preload: "none", // No point preloading metadata since no times are displayed. It helps keep the buffer state correct too. 41 cssSelectorAncestor: "#cp_container_1", 42 cssSelector: { 43 play: ".cp-play", 44 pause: ".cp-pause" 45 } 46 }, 47 48 cssSelector = { 49 bufferHolder: ".cp-buffer-holder", 50 buffer1: ".cp-buffer-1", 51 buffer2: ".cp-buffer-2", 52 progressHolder: ".cp-progress-holder", 53 progress1: ".cp-progress-1", 54 progress2: ".cp-progress-2", 55 circleControl: ".cp-circle-control" 56 }; 57 58 this.cssClass = { 59 gt50: "cp-gt50", 60 fallback: "cp-fallback" 61 }; 62 63 this.spritePitch = cir_width; 64 this.spriteRatio = 0.5; // Number of steps / 100 65 66 this.player = $(jPlayerSelector); 67 this.media = $.extend({}, media); 68 this.options = $.extend(true, {}, defaults, options); // Deep copy 69 70 this.cssTransforms = Modernizr.csstransforms; 71 this.audio = {}; 72 this.dragging = false; // Indicates if the progressbar is being 'dragged'. 73 74 this.eventNamespace = ".CirclePlayer"; // So the events can easily be removed in destroy. 75 76 this.jq = {}; 77 $.each(cssSelector, function(entity, cssSel) { 78 self.jq[entity] = $(self.options.cssSelectorAncestor + " " + cssSel); 79 }); 80 81 this._initSolution(); 82 this._initPlayer(); 83}; 84 85CirclePlayer.prototype = { 86 _createHtml: function() { 87 }, 88 _initPlayer: function() { 89 var self = this; 90 this.player.jPlayer(this.options); 91 92 this.player.bind($.jPlayer.event.ready + this.eventNamespace, function(event) { 93 if(event.jPlayer.html.used && event.jPlayer.html.audio.available) { 94 self.audio = $(this).data("jPlayer").htmlElement.audio; 95 } 96 $(this).jPlayer("setMedia", self.media); 97 self._initCircleControl(); 98 }); 99 100 this.player.bind($.jPlayer.event.play + this.eventNamespace, function(event) { 101 $(this).jPlayer("pauseOthers"); 102 }); 103 104 // This event fired as play time increments 105 this.player.bind($.jPlayer.event.timeupdate + this.eventNamespace, function(event) { 106 if (!self.dragging) { 107 self._timeupdate(event.jPlayer.status.currentPercentAbsolute); 108 } 109 }); 110 111 // This event fired as buffered time increments 112 this.player.bind($.jPlayer.event.progress + this.eventNamespace, function(event) { 113 var percent = 0; 114 if((typeof self.audio.buffered === "object") && (self.audio.buffered.length > 0)) { 115 if(self.audio.duration > 0) { 116 var bufferTime = 0; 117 for(var i = 0; i < self.audio.buffered.length; i++) { 118 bufferTime += self.audio.buffered.end(i) - self.audio.buffered.start(i); 119 // console.log(i + " | start = " + self.audio.buffered.start(i) + " | end = " + self.audio.buffered.end(i) + " | bufferTime = " + bufferTime + " | duration = " + self.audio.duration); 120 } 121 percent = 100 * bufferTime / self.audio.duration; 122 } // else the Metadata has not been read yet. 123 // console.log("percent = " + percent); 124 } else { // Fallback if buffered not supported 125 // percent = event.jPlayer.status.seekPercent; 126 percent = 0; // Cleans up the inital conditions on all browsers, since seekPercent defaults to 100 when object is undefined. 127 } 128 self._progress(percent); // Problem here at initial condition. Due to the Opera clause above of buffered.length > 0 above... Removing it means Opera's white buffer ring never shows like with polyfill. 129 // Firefox 4 does not always give the final progress event when buffered = 100% 130 }); 131 132 this.player.bind($.jPlayer.event.ended + this.eventNamespace, function(event) { 133 self._resetSolution(); 134 }); 135 }, 136 _initSolution: function() { 137 if (this.cssTransforms) { 138 this.jq.progressHolder.show(); 139 this.jq.bufferHolder.show(); 140 } 141 else { 142 this.jq.progressHolder.addClass(this.cssClass.gt50).show(); 143 this.jq.progress1.addClass(this.cssClass.fallback); 144 this.jq.progress2.hide(); 145 this.jq.bufferHolder.hide(); 146 } 147 this._resetSolution(); 148 }, 149 _resetSolution: function() { 150 if (this.cssTransforms) { 151 this.jq.progressHolder.removeClass(this.cssClass.gt50); 152 this.jq.progress1.css({'transform': 'rotate(0deg)'}); 153 this.jq.progress2.css({'transform': 'rotate(0deg)'}).hide(); 154 } 155 else { 156 this.jq.progress1.css('background-position', '0 ' + this.spritePitch + 'px'); 157 } 158 }, 159 _initCircleControl: function() { 160 var self = this; 161 this.jq.circleControl.grab({ 162 onstart: function(){ 163 self.dragging = true; 164 }, onmove: function(event){ 165 var pc = self._getArcPercent(event.position.x, event.position.y); 166 self.player.jPlayer("playHead", pc).jPlayer("play"); 167 self._timeupdate(pc); 168 }, onfinish: function(event){ 169 self.dragging = false;
170 var pc = self._getArcPercent(event.position.x, event.position.y); 171 self.player.jPlayer("playHead", pc).jPlayer("play"); 172 } 173 }); 174 }, 175 _timeupdate: function(percent) { 176 var degs = percent * 3.6+"deg"; 177 178 var spriteOffset = (Math.floor((Math.round(percent))*this.spriteRatio)-1)*-this.spritePitch; 179 180 if (percent <= 50) { 181 if (this.cssTransforms) { 182 this.jq.progressHolder.removeClass(this.cssClass.gt50); 183 this.jq.progress1.css({'transform': 'rotate(' + degs + ')'}); 184 this.jq.progress2.hide(); 185 } else { // fall back 186 this.jq.progress1.css('background-position', '0 '+spriteOffset+'px'); 187 } 188 } else if (percent <= 100) { 189 if (this.cssTransforms) { 190 this.jq.progressHolder.addClass(this.cssClass.gt50); 191 this.jq.progress1.css({'transform': 'rotate(180deg)'}); 192 this.jq.progress2.css({'transform': 'rotate(' + degs + ')'}); 193 this.jq.progress2.show(); 194 } else { // fall back 195 this.jq.progress1.css('background-position', '0 '+spriteOffset+'px'); 196 } 197 } 198 }, 199 _progress: function(percent) { 200 var degs = percent * 3.6+"deg"; 201 202 if (this.cssTransforms) { 203 if (percent <= 50) { 204 this.jq.bufferHolder.removeClass(this.cssClass.gt50); 205 this.jq.buffer1.css({'transform': 'rotate(' + degs + ')'}); 206 this.jq.buffer2.hide(); 207 } else if (percent <= 100) { 208 this.jq.bufferHolder.addClass(this.cssClass.gt50); 209 this.jq.buffer1.css({'transform': 'rotate(180deg)'}); 210 this.jq.buffer2.show(); 211 this.jq.buffer2.css({'transform': 'rotate(' + degs + ')'}); 212 } 213 } 214 }, 215 _getArcPercent: function(pageX, pageY) { 216 var offset = this.jq.circleControl.offset(), 217 x = pageX - offset.left - this.jq.circleControl.width()/2, 218 y = pageY - offset.top - this.jq.circleControl.height()/2, 219 theta = Math.atan2(y,x); 220 221 if (theta > -1 * Math.PI && theta < -0.5 * Math.PI) { 222 theta = 2 * Math.PI + theta; 223 } 224 225 // theta is now value between -0.5PI and 1.5PI 226 // ready to be normalized and applied 227 228 return (theta + Math.PI / 2) / 2 * Math.PI * 10; 229 }, 230 setMedia: function(media) { 231 this.media = $.extend({}, media); 232 this.player.jPlayer("setMedia", this.media); 233 }, 234 play: function(time) { 235 this.player.jPlayer("play", time); 236 }, 237 pause: function(time) { 238 this.player.jPlayer("pause", time); 239 }, 240 destroy: function() { 241 this.player.unbind(this.eventNamespace); 242 this.player.jPlayer("destroy"); 243 } 244};
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.