1/* 2* PragmaticPlayer.Js 3* 4* @package PragmaticPlayer.Js 5* @author $Author: sheiko $ 6* @version $Id: jquery.pplayer.js, v 0.1 $ 7* @license MIT 8* @copyright (c) Dmitry Sheiko http://www.dsheiko.com 9*/ 10(function( window, undefined ){ 11 "use strict"; 12 var $ = window.jQuery, 13 document = window.document, 14 _instanceCounter = 0, 15 // @link https://developers.google.com/youtube/js_api_reference 16 YoutubeApi = (function() { 17 var _isLoadRequested = false; 18 return { 19 loadAsynchronously: function () { 20 21 _isLoadRequested = true; 22 /* 23 var tag = document.createElement('script'); 24 tag.src = "//www.youtube.com/iframe_api"; 25 tag.setAttribute("data-usercentrics", "YouTube Video"); 26 27 if ($("#usercentrics-root").length > 0) { 28 tag.type = "text/plain"; 29 } 30 31 var firstScriptTag = document.getElementsByTagName('script')[0]; 32 firstScriptTag.parentNode.insertBefore(tag, firstScriptTag); 33 */ 34 }, 35 isLoadRequested: function() { 36 return _isLoadRequested; 37 }, 38 isReady: function() { 39 return true; window.YT !== undefined && window.YT.Player !== undefined; 40 }, 41 ready: function( callback ) { 42 var timerFn, timerRef, that = this; 43 (function(delay){ 44 timerRef = setTimeout( timerFn = function(){ 45 if ( that.isReady() ) { 46 callback( window.YT ); 47 } else { 48 timerRef = setTimeout( timerFn, delay ); 49 } 50 51 }, delay ); 52 })( 550 ); 53 } 54 } 55 }()), 56 ApiAdapter = { 57 Youtube : function( settings, handlers ){ 58 var _player, 59 _renderUI = function( api ) { 60 61 var src = "src"; 62 if ($("#usercentrics-root").length > 0) { 63 src = "uc-src"; 64 } 65 66 settings.boundingBox.html( '<iframe ' + src + '="https://www.youtube.com/embed/' 67 + settings.youtubeVideoId + '?rel=0&autoplay=' 68 + settings.autoplay + '&wmode=transparent&hd=1" ' 69 + 'frameborder="0" allowfullscreen data-usercentrics="YouTube Video" title="' + (settings.title?.replace('"', "") || "") + '"></iframe>'); 70 71 }; 72 73 YoutubeApi.isLoadRequested() || YoutubeApi.loadAsynchronously(); 74 YoutubeApi.ready(_renderUI); 75 76 return { 77 state: { 78 UNSTARTED: -1, 79 ENDED: 0, 80 PLAYING: 1, 81 PAUSED: 2, 82 BUFFERING: 3, 83 CUED: 5 84 }, 85 getTarget: function() { 86 return _player; 87 }, 88 play: function() { 89 _player.playVideo(); 90 }, 91 stop: function() { 92 _player.stopVideo(); 93 }, 94 pause: function() { 95 _player.pauseVideo(); 96 }, 97 mute: function( flag ) { 98 _player[ flag ? "mute" : "unMute" ](); 99 }, 100 currentTime: function( curTime ) { 101 curTime !== undefined && _player.seekTo( curTime, true ); 102 return _player.getCurrentTime(); 103 }, 104 duration: function() { 105 return _player.getDuration(); 106 } 107 } 108 }, 109 VideoElement : function( settings, handlers ){ 110 var _player = settings.boundingBox.find("video").get(0); 111 _player.onloadstart = function( e ) { 112 handlers.onReady( e ); 113 e.data = -1; 114 handlers.onStateChange( e ); 115 }; 116 _player.onplay = function( e ) { 117 e.data = 1; 118 handlers.onStateChange( e ); 119 }; 120 _player.onpause = function( e ) { 121 e.data = 2; 122 handlers.onStateChange( e ); 123 }; 124 return { 125 state: { 126 UNSTARTED: -1, 127 ENDED: 0, 128 PLAYING: 1, 129 PAUSED: 2, 130 BUFFERING: 3, 131 CUED: 5 132 }, 133 play: function() { 134 _player.play(); 135 }, 136 stop: function() { 137 _player.stop(); 138 }, 139 pause: function() { 140 _player.pause(); 141 }, 142 mute: function( flag ) { 143 _player.mue( flag ); 144 }, 145 currentTime: function( curTime ) { 146 if (curTime !== undefined) { 147 _player.currentTime = curTime; 148 } 149 return _player.currentTime; 150 }, 151 duration: function() { 152 return _player.duration; 153 } 154 } 155 } 156 }, 157 pPlayer = function( settings ) { 158 159 var tpls = { 160 playpause: 161 ' <div class="button">' + 162 ' <button class="pause"><!-- --></button>' + 163 ' <button class="play"><!-- --></button>' + 164 ' </div>', 165 progress: 166 ' <div><div class="progressBar"><div><!-- --></div></div></div>', 167 quality: 168 ' <div class="quality"></div>', 169 timer: 170 ' <div class="timer">00:00 | 00:00</div>', 171 mute: 172 ' <div class="button">' + 173 ' <button class="mute"><!-- --></button>' + 174 ' <button class="unmute"><!-- --></button>' + 175 ' </div>', 176 fullscreen: 177 ' <div class="button">' + 178 ' <button class="enterFullscreen"><!-- --></button>' + 179 ' <button class="leaveFullscreen"><!-- --></button>' + 180 ' </div>' 181 }, 182 adapter, 183 $boundingBox = settings.boundingBox, 184 $pauseBtn, 185 $playBtn, 186 $muteBtn, 187 $unmuteBtn, 188 $enterFullscreenBtn, 189 $leaveFullscreenBtn, 190 $timer, 191 $progressBar, 192 $progressBarCursor, 193 $quality, 194 playingTrigger; 195 196 settings = $.extend({ 197 boundingBox: null, 198 youtubeVideoId: undefined, 199 autoplay: 1, 200 hd: 1, 201 origin: undefined, 202 adapter: undefined, // "VideoElement" or "Youtube" 203 features: [ 204 "playpause", 205 "progress", 206 settings.adapter === "Youtube" ? "quality" : null, 207 "timer", 208 "mute", 209 "fullscreen" ] 210 }, settings); 211 212 return { 213 getPlayerHtml: function() { 214 var html = ''; 215 $.each(settings.features, function( inx, feature ) { 216 feature && ( html += tpls[ feature ] ); 217 }); 218 return '<div class="controls">' + 219 ' <div>' + html + 220 ' </div>' + 221 '</div>'; 222 }, 223 hasPlayerVideoElements: function() {
224 return $boundingBox.find("div.pp-video > video").length; 225 }, 226 hasBrowserVideoElementSupport: (function() { 227 var inputElem = document.createElement('video'); 228 return inputElem.play !== undefined; 229 }()), 230 hasDivXWebPlayerOn: function() { 231 var divx = $( 'embed[type="video/divx"]' ); 232 return divx && divx.length && divx.attr( 'mode' ) == 'null'; 233 }, 234 fallbackOnDivX: function() { 235 var that = this; 236 window.setTimeout(function(){ 237 if ( that.hasDivXWebPlayerOn() ) { 238 $boundingBox.html( "" ); 239 $boundingBox.pPlayer(settings); 240 } 241 }, 500); 242 }, 243 renderUI: function() { 244 var that = this, 245 apapterClass, 246 videoElId = "pp-player" + _instanceCounter; 247 248 playingTrigger = false; 249 250 $boundingBox.html( function(inx, html){ 251 return '<div class="pp-video">' + html + '</div>' + that.getPlayerHtml() 252 }); 253 $boundingBox 254 .addClass("ppVideoWrapper") 255 .find("div.pp-video").attr("id", videoElId); 256 257 $pauseBtn = $boundingBox.find('.controls button.pause'); 258 $playBtn = $boundingBox.find('.controls button.play'); 259 $muteBtn = $boundingBox.find('.controls button.mute'); 260 $unmuteBtn = $boundingBox.find('.controls button.unmute'); 261 $quality = $boundingBox.find('.controls .quality');
262 $enterFullscreenBtn = $boundingBox.find('.controls button.enterFullscreen'); 263 $leaveFullscreenBtn = $boundingBox.find('.controls button.leaveFullscreen'); 264 $leaveFullscreenBtn.show = 265 $pauseBtn.show = 266 $playBtn.show = 267 $muteBtn.show = 268 $unmuteBtn.show = function() { 269 $( this ).css({"display": "block"}); 270 } 271 272 $timer = $boundingBox.find('.controls .timer'); 273 $progressBar = $boundingBox.find('.controls .progressBar'); 274 $progressBarCursor = $boundingBox.find('.controls .progressBar > div'); 275 276 if ( settings.adapter ) { 277 apapterClass = settings.adapter; 278 } else { 279 apapterClass = this.hasPlayerVideoElements() ? "VideoElement" : "Youtube"; 280 } 281 282 if ( !this.hasBrowserVideoElementSupport ) { 283 apapterClass = "Youtube"; 284 } else { 285 this.fallbackOnDivX(); 286 } 287 288 if ( apapterClass === "Youtube" && settings.youtubeVideoId === undefined ) { 289 throw new 290 Error( "Parameter youtubeVideoId is mondatory to play a youtube video" ); 291 } 292 293 adapter = new ApiAdapter[ apapterClass ](settings, { 294 onReady: function( e ) { 295 that.startTimer(); 296 }, 297 onStateChange: function( e ) { 298 if ( e.data === adapter.state.PLAYING ) { 299 $playBtn.hide(); 300 $pauseBtn.show(); 301 playingTrigger || that.onPlaying(); 302 playingTrigger = true; 303 } else { 304 $playBtn.show(); 305 $pauseBtn.hide() 306 } 307 } 308 }); 309 310 return this; 311 }, 312 syncUI: function() { 313 $pauseBtn.on("click", $.proxy(this.pauseVideo, this)); 314 $playBtn.on("click", $.proxy(this.playVideo, this)); 315 $muteBtn.on("click", $.proxy(this.muteVideo, this)); 316 $unmuteBtn.on("click", $.proxy(this.unmuteVideo, this)); 317 $progressBar.on("click", $.proxy(this.handleProgressBar, this)); 318 $enterFullscreenBtn.on("click", $.proxy(this.enterFullscreen, this)); 319 $leaveFullscreenBtn.on("click", $.proxy(this.leaveFullscreen, this)); 320 321 $( document ).on( "mozfullscreenchange", $.proxy(this.handleFullscreenChange, this)); 322 $( document ).on( "webkitfullscreenchange", $.proxy(this.handleFullscreenChange, this)); 323 $( document ).on( "fullscreenchange", $.proxy(this.handleFullscreenChange, this)); 324 }, 325 onPlaying: function() { 326 if ( adapter.getTarget === undefined ) { 327 return; 328 } 329 var select = this.renderQualityOptions(); 330 // May happen http://stackoverflow.com/questions/1040346/how-to-stop-the-select-box-from-being-blocked-as-a-pop-up-bit-internet-explorer 331 select.off( "change" ).on( "change", function() { 332 adapter.getTarget().setPlaybackQuality( $( this ).val() ); 333 }); 334 }, 335 renderQualityOptions: function() { 336 if ( adapter.getTarget === undefined ) { 337 return; 338 } 339 var html = '<select name="qualityLevel">', 340 qLevelMap = { 341 small: "240p", 342 medium: "360p", 343 large: "480p", 344 hd720: "720p", 345 hd1080: "1080p", 346 highres: "highres" 347 }, 348 options = adapter.getTarget().getAvailableQualityLevels(), 349 level = adapter.getTarget().getPlaybackQuality(); 350 351 $.each(options, function(inx, val) { 352 html += '<option title="Change quality" value="' + val + '" ' + ( level === val ? 'selected' : '' ) + '>' 353 + ( qLevelMap[ val ] || val ) + '</option>'; 354 }); 355 html += '</select>'; 356 return $( html ).appendTo( $quality ); 357 }, 358 getTimeByFloat: function( ctFloat ) { 359 var t = { 360 hours: 0, 361 min: 0, 362 sec: 0 363 }, 364 minFloat = ctFloat / 60, 365 hourFloat = minFloat / 60; 366 367 if ( ctFloat ) { 368 t.sec = Math.floor( ctFloat ); // if less than 60 sec 369 t.min = Math.floor( minFloat ); // if less than 60 min 370 t.hours = Math.floor( hourFloat ); 371 if ( t.hours ) { 372 t.min = Math.floor( minFloat - ( t.hours * 60 ) ); 373 } 374 if ( t.hours || t.min ) { 375 t.sec = Math.floor( ctFloat - ( t.min * 60 ) - ( t.hours * 60 * 60 ) ); 376 } 377 } 378 return t; 379 }, 380 playVideo: function() { 381 $playBtn.hide(); 382 $pauseBtn.show(); 383 adapter.play(); 384 }, 385 stopVideo: function() { 386 adapter.stop(); 387 }, 388 pauseVideo: function() { 389 $playBtn.show(); 390 $pauseBtn.hide(); 391 adapter.pause(); 392 }, 393 muteVideo : function() { 394 $unmuteBtn.show(); 395 $muteBtn.hide(); 396 adapter.mute( true ); 397 }, 398 unmuteVideo : function() { 399 $unmuteBtn.hide(); 400 $muteBtn.show(); 401 adapter.mute( false ); 402 }, 403 handleFullscreenChange: function() { 404 if ((document.fullScreenElement && document.fullScreenElement !== null) || 405 (!document.mozFullScreen && !document.webkitIsFullScreen)) { 406 this.leaveFullscreen(); 407 } else { 408 this.enterFullscreen(); 409 } 410 }, 411 enterFullscreen: function() { 412 $("body").addClass( "fullscreen" ); 413 $enterFullscreenBtn.hide(); 414 $leaveFullscreenBtn.show(); 415 var elem = $boundingBox.get(0); 416 if (elem.requestFullScreen) { 417 elem.requestFullScreen(); 418 } else if (elem.mozRequestFullScreen) { 419 elem.mozRequestFullScreen(); 420 } else if (elem.webkitRequestFullScreen) { 421 elem.webkitRequestFullScreen(); 422 } 423 }, 424 leaveFullscreen: function() { 425 $("body").removeClass( "fullscreen" ); 426 $enterFullscreenBtn.show(); 427 $leaveFullscreenBtn.hide(); 428 if (document.cancelFullScreen) { 429 document.cancelFullScreen(); 430 } else if (document.mozCancelFullScreen) { 431 document.mozCancelFullScreen(); 432 } else if (document.webkitCancelFullScreen) { 433 document.webkitCancelFullScreen(); 434 } 435 }, 436 handleProgressBar: function( e ) { 437 var offset, percent, newCurTime; 438 e.preventDefault(); 439 offset = e.clientX - $progressBar.offset().left; 440 percent = Math.floor(offset / ($progressBar.width() / 100)); 441 newCurTime = adapter.duration() / 100 * percent; 442 this.updateProgressBarCursor( percent ); 443 adapter.currentTime( newCurTime ); 444 }, 445 updateTimer : function( line ) { 446 $timer.html( line ); 447 }, 448 updateProgressBarCursor : function( progressPercents ) { 449 $progressBarCursor.css({"width": progressPercents + "%"}); 450 }, 451 startTimer : function() { 452 var timerFn, timerRef, timerOut = null, that = this, 453 sprintf02d = function( val ) { 454 val.toString().length < 2 && ( val = "0" + val ); // 5 => "05" 455 return val; 456 }; 457 (function(delay){ 458 timerRef = setTimeout( timerFn = function(){ 459 if ( adapter.currentTime ) { 460 var curTime = that.getTimeByFloat( adapter.currentTime() ), 461 duration = that.getTimeByFloat( adapter.duration() ), 462 progressPercents = Math.floor( ( 463 adapter.currentTime() * 100) / adapter.duration() ), 464 line; 465 if ( duration.min ) { 466 curTime.sec = sprintf02d( curTime.sec ); 467 duration.sec = sprintf02d( duration.sec ); 468 } 469 if ( duration.hours ) { 470 curTime.min = sprintf02d( curTime.min ); 471 duration.min = sprintf02d( duration.min ); 472 } 473 line = ( duration.hours ? curTime.hours + ":" : "" ) 474 + ( duration.min ? curTime.min + ":" : "" ) 475 + curTime.sec 476 + " | " 477 + ( duration.hours ? duration.hours + ":" : "" ) 478 + ( duration.min ? duration.min + ":" : "" ) 479 + duration.sec; 480 481 if ( timerOut !== line && !isNaN(duration.sec) ) { 482 that.updateTimer( line ); 483 that.updateProgressBarCursor( progressPercents ); 484 } 485 timerOut = line; 486 } 487 if ($boundingBox.hasClass( "ppVideoWrapper" )) { 488 timerRef = setTimeout( timerFn, delay ); 489 } 490 }, delay ); 491 })( 500 ); 492 } 493 } 494 }; 495 $.fn.pPlayer = function( settings ) { 496 var player = new pPlayer($.extend({ 497 boundingBox: $( this ) 498 }, settings)); 499 _instanceCounter++; 500 player.renderUI().syncUI(); 501 return player; 502 } 503 504}( window ));
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.