1(()=>{const e=document.querySelectorAll(".coblocks-animate");if("IntersectionObserver"in window){const t=new IntersectionObserver((e=>{e.forEach((e=>{e.isIntersecting&&(e.target.classList.add(e.target.dataset.coblocksAnimation),t.unobserve(e.target))}))}),{threshold:[.15]});e.forEach((e=>{t.observe(e)}))}else e.forEach((e=>{e.classList.remove("coblocks-animate"),delete e.dataset.coblocksAnimation}))})();; 2/*! 3* FitVids 1.1 4* 5* Copyright 2013, Chris Coyier - http://css-tricks.com + Dave Rupert - http://daverupert.com 6* Credit to Thierry Koblentz - http://www.alistapart.com/articles/creating-intrinsic-ratios-for-video/ 7* Released under the WTFPL license - http://sam.zoy.org/wtfpl/ 8* 9*/ 10(function( $ ){ 11 12 "use strict"; 13 14 $.fn.fitVids = function( options ) { 15 var settings = { 16 customSelector: null 17 }; 18 19 if(!document.getElementById('fit-vids-style')) { 20 // appendStyles: https://github.com/toddmotto/fluidvids/blob/master/dist/fluidvids.js 21 var head = document.head || document.getElementsByTagName('head')[0]; 22 var css = '.fluid-width-video-wrapper{width:100%;position:relative;padding:0;}.fluid-width-video-wrapper iframe,.fluid-width-video-wrapper object,.fluid-width-video-wrapper embed {position:absolute;top:0;left:0;width:100%;height:100%;}'; 23 var div = document.createElement('div'); 24 div.innerHTML = '<p>x</p><style id="fit-vids-style">' + css + '</style>'; 25 head.appendChild(div.childNodes[1]); 26 } 27 28 if ( options ) { 29 $.extend( settings, options ); 30 } 31 32 return this.each(function(){ 33 var selectors = [ 34 "iframe[src*='player.vimeo.com']", 35 "iframe[src*='youtube.com']", 36 "iframe[src*='youtube-nocookie.com']", 37 "iframe[src*='kickstarter.com'][src*='video.html']", 38 "object", 39 "embed" 40 ]; 41 42 if (settings.customSelector) { 43 selectors.push(settings.customSelector); 44 } 45 46 var $allVideos = $(this).find(selectors.join(',')); 47 $allVideos = $allVideos.not("object object"); // SwfObj conflict patch 48 49 $allVideos.each(function(){ 50 var $this = $(this); 51 if (this.tagName.toLowerCase() === 'embed' && $this.parent('object').length || $this.parent('.fluid-width-video-wrapper').length) { return; } 52 var height = ( this.tagName.toLowerCase() === 'object' || ($this.attr('height') && !isNaN(parseInt($this.attr('height'), 10))) ) ? parseInt($this.attr('height'), 10) : $this.height(), 53 width = !isNaN(parseInt($this.attr('width'), 10)) ? parseInt($this.attr('width'), 10) : $this.width(), 54 aspectRatio = height / width; 55 if(!$this.attr('id')){ 56 var videoID = 'fitvid' + Math.floor(Math.random()*999999); 57 $this.attr('id', videoID); 58 } 59 $this.wrap('<div class="fluid-width-video-wrapper"></div>').parent('.fluid-width-video-wrapper').css('padding-top', (aspectRatio * 100)+"%"); 60 $this.removeAttr('height').removeAttr('width'); 61 }); 62 }); 63 }; 64// Works with either jQuery or Zepto 65})( window.jQuery || window.Zepto ); 66/* 67 * jQuery FlexSlider v2.2.0 68 * Copyright 2012 WooThemes 69 * Contributing Author: Tyler Smith 70 */ 71; 72(function ($) { 73 74 //FlexSlider: Object Instance 75 $.flexslider = function(el, options) { 76 var slider = $(el); 77 78 // making variables public 79 slider.vars = $.extend({}, $.flexslider.defaults, options); 80 81 var namespace = slider.vars.namespace, 82 msGesture = window.navigator && window.navigator.msPointerEnabled && window.MSGesture, 83 touch = (( "ontouchstart" in window ) || msGesture || window.DocumentTouch && document instanceof DocumentTouch) && slider.vars.touch, 84 // depricating this idea, as devices are being released with both of these events 85 //eventType = (touch) ? "touchend" : "click", 86 eventType = "click touchend MSPointerUp", 87 watchedEvent = "", 88 watchedEventClearTimer, 89 vertical = slider.vars.direction === "vertical", 90 reverse = slider.vars.reverse, 91 carousel = (slider.vars.itemWidth > 0), 92 fade = slider.vars.animation === "fade", 93 asNav = slider.vars.asNavFor !== "", 94 methods = {}, 95 focused = true; 96 97 // Store a reference to the slider object 98 $.data(el, "flexslider", slider); 99 100 // Private slider methods 101 methods = { 102 init: function() { 103 slider.animating = false;
104 // Get current slide and make sure it is a number 105 slider.currentSlide = parseInt( ( slider.vars.startAt ? slider.vars.startAt : 0) ); 106 if ( isNaN( slider.currentSlide ) ) slider.currentSlide = 0; 107 slider.animatingTo = slider.currentSlide; 108 slider.atEnd = (slider.currentSlide === 0 || slider.currentSlide === slider.last); 109 slider.containerSelector = slider.vars.selector.substr(0,slider.vars.selector.search(' ')); 110 slider.slides = $(slider.vars.selector, slider); 111 slider.container = $(slider.containerSelector, slider); 112 slider.count = slider.slides.length; 113 // SYNC: 114 slider.syncExists = $(slider.vars.sync).length > 0; 115 // SLIDE: 116 if (slider.vars.animation === "slide") slider.vars.animation = "swing"; 117 slider.prop = (vertical) ? "top" : "marginLeft"; 118 slider.args = {}; 119 // SLIDESHOW: 120 slider.manualPause = false; 121 slider.stopped = false; 122 //PAUSE WHEN INVISIBLE 123 slider.started = false; 124 slider.startTimeout = null; 125 // TOUCH/USECSS: 126 slider.transitions = !slider.vars.video && !fade && slider.vars.useCSS && (function() { 127 var obj = document.createElement('div'), 128 props = ['perspectiveProperty', 'WebkitPerspective', 'MozPerspective', 'OPerspective', 'msPerspective']; 129 for (var i in props) { 130 if ( obj.style[ props[i] ] !== undefined ) { 131 slider.pfx = props[i].replace('Perspective','').toLowerCase(); 132 slider.prop = "-" + slider.pfx + "-transform"; 133 return true; 134 } 135 } 136 return false; 137 }()); 138 // CONTROLSCONTAINER: 139 if (slider.vars.controlsContainer !== "") slider.controlsContainer = $(slider.vars.controlsContainer).length > 0 && $(slider.vars.controlsContainer); 140 // MANUAL: 141 if (slider.vars.manualControls !== "") slider.manualControls = $(slider.vars.manualControls).length > 0 && $(slider.vars.manualControls); 142 143 // RANDOMIZE: 144 if (slider.vars.randomize) { 145 slider.slides.sort(function() { return (Math.round(Math.random())-0.5); }); 146 slider.container.empty().append(slider.slides); 147 } 148 149 slider.doMath(); 150 151 // INIT 152 slider.setup("init"); 153 154 // CONTROLNAV: 155 if (slider.vars.controlNav) methods.controlNav.setup(); 156 157 // DIRECTIONNAV: 158 if (slider.vars.directionNav) methods.directionNav.setup(); 159 160 // KEYBOARD: 161 if (slider.vars.keyboard && ($(slider.containerSelector).length === 1 || slider.vars.multipleKeyboard)) { 162 $(document).bind('keyup', function(event) { 163 var keycode = event.keyCode; 164 if (!slider.animating && (keycode === 39 || keycode === 37)) { 165 var target = (keycode === 39) ? slider.getTarget('next') : 166 (keycode === 37) ? slider.getTarget('prev') : false; 167 slider.flexAnimate(target, slider.vars.pauseOnAction); 168 } 169 }); 170 } 171 // MOUSEWHEEL: 172 if (slider.vars.mousewheel) { 173 slider.bind('mousewheel', function(event, delta, deltaX, deltaY) { 174 event.preventDefault(); 175 var target = (delta < 0) ? slider.getTarget('next') : slider.getTarget('prev'); 176 slider.flexAnimate(target, slider.vars.pauseOnAction); 177 }); 178 } 179 180 // PAUSEPLAY 181 if (slider.vars.pausePlay) methods.pausePlay.setup(); 182 183 //PAUSE WHEN INVISIBLE 184 if (slider.vars.slideshow && slider.vars.pauseInvisible) methods.pauseInvisible.init(); 185 186 // SLIDSESHOW 187 if (slider.vars.slideshow) { 188 if (slider.vars.pauseOnHover) { 189 slider.hover(function() { 190 if (!slider.manualPlay && !slider.manualPause) slider.pause(); 191 }, function() { 192 if (!slider.manualPause && !slider.manualPlay && !slider.stopped) slider.play(); 193 }); 194 } 195 // initialize animation 196 //If we're visible, or we don't use PageVisibility API
vendor: 16,379 bytes, lines 197-565
197 if(!slider.vars.pauseInvisible || !methods.pauseInvisible.isHidden()) { 198 (slider.vars.initDelay > 0) ? slider.startTimeout = setTimeout(slider.play, slider.vars.initDelay) : slider.play(); 199 } 200 } 201 202 // ASNAV: 203 if (asNav) methods.asNav.setup(); 204 205 // TOUCH 206 if (touch && slider.vars.touch) methods.touch(); 207 208 // FADE&&SMOOTHHEIGHT || SLIDE: 209 if (!fade || (fade && slider.vars.smoothHeight)) $(window).bind("resize orientationchange focus", methods.resize); 210 211 slider.find("img").attr("draggable", "false"); 212 213 // API: start() Callback 214 setTimeout(function(){ 215 slider.vars.start(slider); 216 }, 200); 217 }, 218 asNav: { 219 setup: function() { 220 slider.asNav = true; 221 slider.animatingTo = Math.floor(slider.currentSlide/slider.move); 222 slider.currentItem = slider.currentSlide; 223 slider.slides.removeClass(namespace + "active-slide").eq(slider.currentItem).addClass(namespace + "active-slide"); 224 if(!msGesture){ 225 slider.slides.click(function(e){ 226 e.preventDefault(); 227 var $slide = $(this), 228 target = $slide.index(); 229 var posFromLeft = $slide.offset().left - $(slider).scrollLeft(); // Find position of slide relative to left of slider container 230 if( posFromLeft <= 0 && $slide.hasClass( namespace + 'active-slide' ) ) { 231 slider.flexAnimate(slider.getTarget("prev"), true); 232 } else if (!$(slider.vars.asNavFor).data('flexslider').animating && !$slide.hasClass(namespace + "active-slide")) { 233 slider.direction = (slider.currentItem < target) ? "next" : "prev"; 234 slider.flexAnimate(target, slider.vars.pauseOnAction, false, true, true); 235 } 236 }); 237 }else{ 238 el._slider = slider; 239 slider.slides.each(function (){ 240 var that = this; 241 that._gesture = new MSGesture(); 242 that._gesture.target = that; 243 that.addEventListener("MSPointerDown", function (e){ 244 e.preventDefault(); 245 if(e.currentTarget._gesture) 246 e.currentTarget._gesture.addPointer(e.pointerId); 247 }, false); 248 that.addEventListener("MSGestureTap", function (e){ 249 e.preventDefault(); 250 var $slide = $(this), 251 target = $slide.index(); 252 if (!$(slider.vars.asNavFor).data('flexslider').animating && !$slide.hasClass('active')) { 253 slider.direction = (slider.currentItem < target) ? "next" : "prev"; 254 slider.flexAnimate(target, slider.vars.pauseOnAction, false, true, true); 255 } 256 }); 257 }); 258 } 259 } 260 }, 261 controlNav: { 262 setup: function() { 263 if (!slider.manualControls) { 264 methods.controlNav.setupPaging(); 265 } else { // MANUALCONTROLS: 266 methods.controlNav.setupManual(); 267 } 268 }, 269 setupPaging: function() { 270 var type = (slider.vars.controlNav === "thumbnails") ? 'control-thumbs' : 'control-paging', 271 j = 1, 272 item, 273 slide; 274 275 slider.controlNavScaffold = $('<ol class="'+ namespace + 'control-nav ' + namespace + type + '"></ol>'); 276 277 if (slider.pagingCount > 1) { 278 for (var i = 0; i < slider.pagingCount; i++) { 279 slide = slider.slides.eq(i); 280 item = (slider.vars.controlNav === "thumbnails") ? '<img src="' + slide.attr( 'data-thumb' ) + '"/>' : '<a>' + j + '</a>'; 281 if ( 'thumbnails' === slider.vars.controlNav && true === slider.vars.thumbCaptions ) { 282 var captn = slide.attr( 'data-thumbcaption' ); 283 if ( '' != captn && undefined != captn ) item += '<span class="' + namespace + 'caption">' + captn + '</span>'; 284 } 285 slider.controlNavScaffold.append('<li>' + item + '</li>'); 286 j++; 287 } 288 } 289 290 // CONTROLSCONTAINER: 291 (slider.controlsContainer) ? $(slider.controlsContainer).append(slider.controlNavScaffold) : slider.append(slider.controlNavScaffold); 292 methods.controlNav.set(); 293 294 methods.controlNav.active(); 295 296 slider.controlNavScaffold.delegate('a, img', eventType, function(event) { 297 event.preventDefault(); 298 299 if (watchedEvent === "" || watchedEvent === event.type) { 300 var $this = $(this), 301 target = slider.controlNav.index($this); 302 303 if (!$this.hasClass(namespace + 'active')) { 304 slider.direction = (target > slider.currentSlide) ? "next" : "prev"; 305 slider.flexAnimate(target, slider.vars.pauseOnAction); 306 } 307 } 308 309 // setup flags to prevent event duplication 310 if (watchedEvent === "") { 311 watchedEvent = event.type; 312 } 313 methods.setToClearWatchedEvent(); 314 315 }); 316 }, 317 setupManual: function() { 318 slider.controlNav = slider.manualControls; 319 methods.controlNav.active(); 320 321 slider.controlNav.bind(eventType, function(event) { 322 event.preventDefault(); 323 324 if (watchedEvent === "" || watchedEvent === event.type) { 325 var $this = $(this), 326 target = slider.controlNav.index($this); 327 328 if (!$this.hasClass(namespace + 'active')) { 329 (target > slider.currentSlide) ? slider.direction = "next" : slider.direction = "prev"; 330 slider.flexAnimate(target, slider.vars.pauseOnAction); 331 } 332 } 333 334 // setup flags to prevent event duplication 335 if (watchedEvent === "") { 336 watchedEvent = event.type; 337 } 338 methods.setToClearWatchedEvent(); 339 }); 340 }, 341 set: function() { 342 var selector = (slider.vars.controlNav === "thumbnails") ? 'img' : 'a'; 343 slider.controlNav = $('.' + namespace + 'control-nav li ' + selector, (slider.controlsContainer) ? slider.controlsContainer : slider); 344 }, 345 active: function() { 346 slider.controlNav.removeClass(namespace + "active").eq(slider.animatingTo).addClass(namespace + "active"); 347 }, 348 update: function(action, pos) { 349 if (slider.pagingCount > 1 && action === "add") { 350 slider.controlNavScaffold.append($('<li><a>' + slider.count + '</a></li>')); 351 } else if (slider.pagingCount === 1) { 352 slider.controlNavScaffold.find('li').remove(); 353 } else { 354 slider.controlNav.eq(pos).closest('li').remove(); 355 } 356 methods.controlNav.set(); 357 (slider.pagingCount > 1 && slider.pagingCount !== slider.controlNav.length) ? slider.update(pos, action) : methods.controlNav.active(); 358 } 359 }, 360 directionNav: { 361 setup: function() { 362 var directionNavScaffold = $('<ul class="' + namespace + 'direction-nav"><li><a class="' + namespace + 'prev" href="#">' + slider.vars.prevText + '</a></li><li><a class="' + namespace + 'next" href="#">' + slider.vars.nextText + '</a></li></ul>'); 363 364 // CONTROLSCONTAINER: 365 if (slider.controlsContainer) { 366 $(slider.controlsContainer).append(directionNavScaffold); 367 slider.directionNav = $('.' + namespace + 'direction-nav li a', slider.controlsContainer); 368 } else { 369 slider.append(directionNavScaffold); 370 slider.directionNav = $('.' + namespace + 'direction-nav li a', slider); 371 } 372 373 methods.directionNav.update(); 374 375 slider.directionNav.bind(eventType, function(event) { 376 event.preventDefault(); 377 var target; 378 379 if (watchedEvent === "" || watchedEvent === event.type) { 380 target = ($(this).hasClass(namespace + 'next')) ? slider.getTarget('next') : slider.getTarget('prev'); 381 slider.flexAnimate(target, slider.vars.pauseOnAction); 382 } 383 384 // setup flags to prevent event duplication 385 if (watchedEvent === "") { 386 watchedEvent = event.type; 387 } 388 methods.setToClearWatchedEvent(); 389 }); 390 }, 391 update: function() { 392 var disabledClass = namespace + 'disabled'; 393 if (slider.pagingCount === 1) { 394 slider.directionNav.addClass(disabledClass).attr('tabindex', '-1'); 395 } else if (!slider.vars.animationLoop) { 396 if (slider.animatingTo === 0) { 397 slider.directionNav.removeClass(disabledClass).filter('.' + namespace + "prev").addClass(disabledClass).attr('tabindex', '-1'); 398 } else if (slider.animatingTo === slider.last) { 399 slider.directionNav.removeClass(disabledClass).filter('.' + namespace + "next").addClass(disabledClass).attr('tabindex', '-1'); 400 } else { 401 slider.directionNav.removeClass(disabledClass).removeAttr('tabindex'); 402 } 403 } else { 404 slider.directionNav.removeClass(disabledClass).removeAttr('tabindex'); 405 } 406 } 407 }, 408 pausePlay: { 409 setup: function() { 410 var pausePlayScaffold = $('<div class="' + namespace + 'pauseplay"><a></a></div>'); 411 412 // CONTROLSCONTAINER: 413 if (slider.controlsContainer) { 414 slider.controlsContainer.append(pausePlayScaffold); 415 slider.pausePlay = $('.' + namespace + 'pauseplay a', slider.controlsContainer); 416 } else { 417 slider.append(pausePlayScaffold); 418 slider.pausePlay = $('.' + namespace + 'pauseplay a', slider); 419 } 420 421 methods.pausePlay.update((slider.vars.slideshow) ? namespace + 'pause' : namespace + 'play'); 422 423 slider.pausePlay.bind(eventType, function(event) { 424 event.preventDefault(); 425 426 if (watchedEvent === "" || watchedEvent === event.type) { 427 if ($(this).hasClass(namespace + 'pause')) { 428 slider.manualPause = true; 429 slider.manualPlay = false; 430 slider.pause(); 431 } else { 432 slider.manualPause = false; 433 slider.manualPlay = true; 434 slider.play(); 435 } 436 } 437 438 // setup flags to prevent event duplication 439 if (watchedEvent === "") { 440 watchedEvent = event.type; 441 } 442 methods.setToClearWatchedEvent(); 443 }); 444 }, 445 update: function(state) { 446 (state === "play") ? slider.pausePlay.removeClass(namespace + 'pause').addClass(namespace + 'play').html(slider.vars.playText) : slider.pausePlay.removeClass(namespace + 'play').addClass(namespace + 'pause').html(slider.vars.pauseText); 447 } 448 }, 449 touch: function() { 450 var startX, 451 startY, 452 offset, 453 cwidth, 454 dx, 455 startT, 456 scrolling = false, 457 localX = 0, 458 localY = 0, 459 accDx = 0; 460 461 if(!msGesture){ 462 el.addEventListener('touchstart', onTouchStart, false); 463 464 function onTouchStart(e) { 465 if (slider.animating) { 466 e.preventDefault(); 467 } else if ( ( window.navigator.msPointerEnabled ) || e.touches.length === 1 ) { 468 slider.pause(); 469 // CAROUSEL: 470 cwidth = (vertical) ? slider.h : slider. w; 471 startT = Number(new Date()); 472 // CAROUSEL: 473 474 // Local vars for X and Y points. 475 localX = e.touches[0].pageX; 476 localY = e.touches[0].pageY; 477 478 offset = (carousel && reverse && slider.animatingTo === slider.last) ? 0 : 479 (carousel && reverse) ? slider.limit - (((slider.itemW + slider.vars.itemMargin) * slider.move) * slider.animatingTo) : 480 (carousel && slider.currentSlide === slider.last) ? slider.limit : 481 (carousel) ? ((slider.itemW + slider.vars.itemMargin) * slider.move) * slider.currentSlide : 482 (reverse) ? (slider.last - slider.currentSlide + slider.cloneOffset) * cwidth : (slider.currentSlide + slider.cloneOffset) * cwidth; 483 startX = (vertical) ? localY : localX; 484 startY = (vertical) ? localX : localY; 485 486 el.addEventListener('touchmove', onTouchMove, false); 487 el.addEventListener('touchend', onTouchEnd, false); 488 } 489 } 490 491 function onTouchMove(e) { 492 // Local vars for X and Y points. 493 494 localX = e.touches[0].pageX; 495 localY = e.touches[0].pageY; 496 497 dx = (vertical) ? startX - localY : startX - localX; 498 scrolling = (vertical) ? (Math.abs(dx) < Math.abs(localX - startY)) : (Math.abs(dx) < Math.abs(localY - startY)); 499 500 var fxms = 500; 501 502 if ( ! scrolling || Number( new Date() ) - startT > fxms ) { 503 e.preventDefault(); 504 if (!fade && slider.transitions) { 505 if (!slider.vars.animationLoop) { 506 dx = dx/((slider.currentSlide === 0 && dx < 0 || slider.currentSlide === slider.last && dx > 0) ? (Math.abs(dx)/cwidth+2) : 1); 507 } 508 slider.setProps(offset + dx, "setTouch"); 509 } 510 } 511 } 512 513 function onTouchEnd(e) { 514 // finish the touch by undoing the touch session 515 el.removeEventListener('touchmove', onTouchMove, false); 516 517 if (slider.animatingTo === slider.currentSlide && !scrolling && !(dx === null)) { 518 var updateDx = (reverse) ? -dx : dx, 519 target = (updateDx > 0) ? slider.getTarget('next') : slider.getTarget('prev'); 520 521 if (slider.canAdvance(target) && (Number(new Date()) - startT < 550 && Math.abs(updateDx) > 50 || Math.abs(updateDx) > cwidth/2)) { 522 slider.flexAnimate(target, slider.vars.pauseOnAction); 523 } else { 524 if (!fade) slider.flexAnimate(slider.currentSlide, slider.vars.pauseOnAction, true); 525 } 526 } 527 el.removeEventListener('touchend', onTouchEnd, false); 528 529 startX = null; 530 startY = null; 531 dx = null; 532 offset = null; 533 } 534 }else{ 535 el.style.msTouchAction = "none"; 536 el._gesture = new MSGesture(); 537 el._gesture.target = el; 538 el.addEventListener("MSPointerDown", onMSPointerDown, false); 539 el._slider = slider; 540 el.addEventListener("MSGestureChange", onMSGestureChange, false); 541 el.addEventListener("MSGestureEnd", onMSGestureEnd, false); 542 543 function onMSPointerDown(e){ 544 e.stopPropagation(); 545 if (slider.animating) { 546 e.preventDefault(); 547 }else{ 548 slider.pause(); 549 el._gesture.addPointer(e.pointerId); 550 accDx = 0; 551 cwidth = (vertical) ? slider.h : slider. w; 552 startT = Number(new Date()); 553 // CAROUSEL: 554 555 offset = (carousel && reverse && slider.animatingTo === slider.last) ? 0 : 556 (carousel && reverse) ? slider.limit - (((slider.itemW + slider.vars.itemMargin) * slider.move) * slider.animatingTo) : 557 (carousel && slider.currentSlide === slider.last) ? slider.limit : 558 (carousel) ? ((slider.itemW + slider.vars.itemMargin) * slider.move) * slider.currentSlide : 559 (reverse) ? (slider.last - slider.currentSlide + slider.cloneOffset) * cwidth : (slider.currentSlide + slider.cloneOffset) * cwidth; 560 } 561 } 562 563 function onMSGestureChange(e) { 564 e.stopPropagation(); 565 var slider = e.target._slider;
566 if(!slider){ 567 return; 568 } 569 var transX = -e.translationX, 570 transY = -e.translationY; 571 572 //Accumulate translations. 573 accDx = accDx + ((vertical) ? transY : transX); 574 dx = accDx; 575 scrolling = (vertical) ? (Math.abs(accDx) < Math.abs(-transX)) : (Math.abs(accDx) < Math.abs(-transY)); 576 577 if(e.detail === e.MSGESTURE_FLAG_INERTIA){ 578 setImmediate(function (){ 579 el._gesture.stop(); 580 }); 581 582 return; 583 } 584 585 if (!scrolling || Number(new Date()) - startT > 500) { 586 e.preventDefault(); 587 if (!fade && slider.transitions) { 588 if (!slider.vars.animationLoop) { 589 dx = accDx / ((slider.currentSlide === 0 && accDx < 0 || slider.currentSlide === slider.last && accDx > 0) ? (Math.abs(accDx) / cwidth + 2) : 1); 590 } 591 slider.setProps(offset + dx, "setTouch"); 592 } 593 } 594 } 595 596 function onMSGestureEnd(e) { 597 e.stopPropagation(); 598 var slider = e.target._slider; 599 if(!slider){ 600 return; 601 } 602 if (slider.animatingTo === slider.currentSlide && !scrolling && !(dx === null)) { 603 var updateDx = (reverse) ? -dx : dx, 604 target = (updateDx > 0) ? slider.getTarget('next') : slider.getTarget('prev'); 605 606 if (slider.canAdvance(target) && (Number(new Date()) - startT < 550 && Math.abs(updateDx) > 50 || Math.abs(updateDx) > cwidth/2)) { 607 slider.flexAnimate(target, slider.vars.pauseOnAction); 608 } else { 609 if (!fade) slider.flexAnimate(slider.currentSlide, slider.vars.pauseOnAction, true); 610 } 611 } 612 613 startX = null; 614 startY = null; 615 dx = null; 616 offset = null; 617 accDx = 0; 618 } 619 } 620 }, 621 resize: function() { 622 if (!slider.animating && slider.is(':visible')) { 623 if (!carousel) slider.doMath(); 624 625 if (fade) { 626 // SMOOTH HEIGHT: 627 methods.smoothHeight(); 628 } else if (carousel) { //CAROUSEL: 629 slider.slides.width(slider.computedW); 630 slider.update(slider.pagingCount); 631 slider.setProps(); 632 } 633 else if (vertical) { //VERTICAL: 634 slider.viewport.height(slider.h); 635 slider.setProps(slider.h, "setTotal"); 636 } else { 637 // SMOOTH HEIGHT: 638 if (slider.vars.smoothHeight) methods.smoothHeight(); 639 slider.newSlides.width(slider.computedW); 640 slider.setProps(slider.computedW, "setTotal"); 641 } 642 } 643 }, 644 smoothHeight: function(dur) { 645 if (!vertical || fade) { 646 var $obj = (fade) ? slider : slider.viewport; 647 (dur) ? $obj.animate({"height": slider.slides.eq(slider.animatingTo).height()}, dur) : $obj.height(slider.slides.eq(slider.animatingTo).height()); 648 } 649 }, 650 sync: function(action) { 651 var $obj = $(slider.vars.sync).data("flexslider"), 652 target = slider.animatingTo; 653 654 switch (action) { 655 case "animate": $obj.flexAnimate(target, slider.vars.pauseOnAction, false, true); break; 656 case "play": if (!$obj.playing && !$obj.asNav) { $obj.play(); } break; 657 case "pause": $obj.pause(); break; 658 } 659 }, 660 pauseInvisible: { 661 visProp: null, 662 init: function() { 663 var prefixes = ['webkit','moz','ms','o']; 664 665 if ('hidden' in document) return 'hidden'; 666 for (var i = 0; i < prefixes.length; i++) { 667 if ((prefixes[i] + 'Hidden') in document) 668 methods.pauseInvisible.visProp = prefixes[i] + 'Hidden'; 669 } 670 if (methods.pauseInvisible.visProp) { 671 var evtname = methods.pauseInvisible.visProp.replace(/[H|h]idden/,'') + 'visibilitychange'; 672 document.addEventListener(evtname, function() { 673 if (methods.pauseInvisible.isHidden()) { 674 if(slider.startTimeout) clearTimeout(slider.startTimeout); //If clock is ticking, stop timer and prevent from starting while invisible 675 else slider.pause(); //Or just pause 676 } 677 else { 678 if(slider.started) slider.play(); //Initiated before, just play 679 else (slider.vars.initDelay > 0) ? setTimeout(slider.play, slider.vars.initDelay) : slider.play(); //Didn't init before: simply init or wait for it 680 } 681 }); 682 } 683 }, 684 isHidden: function() { 685 return document[methods.pauseInvisible.visProp] || false; 686 } 687 }, 688 setToClearWatchedEvent: function() { 689 clearTimeout(watchedEventClearTimer); 690 watchedEventClearTimer = setTimeout(function() { 691 watchedEvent = ""; 692 }, 3000); 693 } 694 } 695 696 // public methods 697 slider.flexAnimate = function(target, pause, override, withSync, fromNav) { 698 if (!slider.vars.animationLoop && target !== slider.currentSlide) { 699 slider.direction = (target > slider.currentSlide) ? "next" : "prev"; 700 } 701 702 if (asNav && slider.pagingCount === 1) slider.direction = (slider.currentItem < target) ? "next" : "prev"; 703
vendor: 5,333 bytes, lines 704-816
704 if (!slider.animating && (slider.canAdvance(target, fromNav) || override) && slider.is(":visible")) { 705 if (asNav && withSync) { 706 var master = $(slider.vars.asNavFor).data('flexslider'); 707 slider.atEnd = target === 0 || target === slider.count - 1; 708 master.flexAnimate(target, true, false, true, fromNav); 709 slider.direction = (slider.currentItem < target) ? "next" : "prev"; 710 master.direction = slider.direction; 711 712 if (Math.ceil((target + 1)/slider.visible) - 1 !== slider.currentSlide && target !== 0) { 713 slider.currentItem = target; 714 slider.slides.removeClass(namespace + "active-slide").eq(target).addClass(namespace + "active-slide"); 715 target = Math.floor(target/slider.visible); 716 } else { 717 slider.currentItem = target; 718 slider.slides.removeClass(namespace + "active-slide").eq(target).addClass(namespace + "active-slide"); 719 return false; 720 } 721 } 722 723 slider.animating = true; 724 slider.animatingTo = target; 725 726 // SLIDESHOW: 727 if (pause) slider.pause(); 728 729 // API: before() animation Callback 730 slider.vars.before(slider); 731 732 // SYNC: 733 if (slider.syncExists && !fromNav) methods.sync("animate"); 734 735 // CONTROLNAV 736 if (slider.vars.controlNav) methods.controlNav.active(); 737 738 // !CAROUSEL: 739 // CANDIDATE: slide active class (for add/remove slide) 740 if (!carousel) slider.slides.removeClass(namespace + 'active-slide').eq(target).addClass(namespace + 'active-slide'); 741 742 // INFINITE LOOP: 743 // CANDIDATE: atEnd 744 slider.atEnd = target === 0 || target === slider.last; 745 746 // DIRECTIONNAV: 747 if (slider.vars.directionNav) methods.directionNav.update(); 748 749 if (target === slider.last) { 750 // API: end() of cycle Callback 751 slider.vars.end(slider); 752 // SLIDESHOW && !INFINITE LOOP: 753 if (!slider.vars.animationLoop) slider.pause(); 754 } 755 756 // SLIDE: 757 if (!fade) { 758 var dimension = (vertical) ? slider.slides.filter(':first').height() : slider.computedW, 759 margin, slideString, calcNext; 760 761 // INFINITE LOOP / REVERSE: 762 if (carousel) { 763 //margin = (slider.vars.itemWidth > slider.w) ? slider.vars.itemMargin * 2 : slider.vars.itemMargin; 764 margin = slider.vars.itemMargin; 765 calcNext = ((slider.itemW + margin) * slider.move) * slider.animatingTo; 766 slideString = (calcNext > slider.limit && slider.visible !== 1) ? slider.limit : calcNext; 767 } else if (slider.currentSlide === 0 && target === slider.count - 1 && slider.vars.animationLoop && slider.direction !== "next") { 768 slideString = (reverse) ? (slider.count + slider.cloneOffset) * dimension : 0; 769 } else if (slider.currentSlide === slider.last && target === 0 && slider.vars.animationLoop && slider.direction !== "prev") { 770 slideString = (reverse) ? 0 : (slider.count + 1) * dimension; 771 } else { 772 slideString = (reverse) ? ((slider.count - 1) - target + slider.cloneOffset) * dimension : (target + slider.cloneOffset) * dimension; 773 } 774 slider.setProps(slideString, "", slider.vars.animationSpeed); 775 if (slider.transitions) { 776 if (!slider.vars.animationLoop || !slider.atEnd) { 777 slider.animating = false; 778 slider.currentSlide = slider.animatingTo; 779 } 780 slider.container.unbind("webkitTransitionEnd transitionend"); 781 slider.container.bind("webkitTransitionEnd transitionend", function() { 782 slider.wrapup(dimension); 783 }); 784 } else { 785 slider.container.animate(slider.args, slider.vars.animationSpeed, slider.vars.easing, function(){ 786 slider.wrapup(dimension); 787 }); 788 } 789 } else { // FADE: 790 if (!touch) { 791 //slider.slides.eq(slider.currentSlide).fadeOut(slider.vars.animationSpeed, slider.vars.easing); 792 //slider.slides.eq(target).fadeIn(slider.vars.animationSpeed, slider.vars.easing, slider.wrapup); 793 794 slider.slides.eq(slider.currentSlide).css({"zIndex": 1}).animate({"opacity": 0}, slider.vars.animationSpeed, slider.vars.easing); 795 slider.slides.eq(target).css({"zIndex": 2}).animate({"opacity": 1}, slider.vars.animationSpeed, slider.vars.easing, slider.wrapup); 796 797 } else { 798 slider.slides.eq(slider.currentSlide).css({ "opacity": 0, "zIndex": 1 }); 799 slider.slides.eq(target).css({ "opacity": 1, "zIndex": 2 }); 800 slider.wrapup(dimension); 801 } 802 } 803 // SMOOTH HEIGHT: 804 if (slider.vars.smoothHeight) methods.smoothHeight(slider.vars.animationSpeed); 805 } 806 } 807 slider.wrapup = function(dimension) { 808 // SLIDE: 809 if (!fade && !carousel) { 810 if (slider.currentSlide === 0 && slider.animatingTo === slider.last && slider.vars.animationLoop) { 811 slider.setProps(dimension, "jumpEnd"); 812 } else if (slider.currentSlide === slider.last && slider.animatingTo === 0 && slider.vars.animationLoop) { 813 slider.setProps(dimension, "jumpStart"); 814 } 815 } 816 slider.animating = false;
817 slider.currentSlide = slider.animatingTo; 818 // API: after() animation Callback 819 slider.vars.after(slider); 820 } 821 822 // SLIDESHOW: 823 slider.animateSlides = function() { 824 if (!slider.animating && focused ) slider.flexAnimate(slider.getTarget("next")); 825 } 826 // SLIDESHOW: 827 slider.pause = function() { 828 clearInterval(slider.animatedSlides); 829 slider.animatedSlides = null; 830 slider.playing = false; 831 // PAUSEPLAY: 832 if (slider.vars.pausePlay) methods.pausePlay.update("play"); 833 // SYNC: 834 if (slider.syncExists) methods.sync("pause"); 835 } 836 // SLIDESHOW: 837 slider.play = function() { 838 if (slider.playing) clearInterval(slider.animatedSlides); 839 slider.animatedSlides = slider.animatedSlides || setInterval(slider.animateSlides, slider.vars.slideshowSpeed); 840 slider.started = slider.playing = true; 841 // PAUSEPLAY: 842 if (slider.vars.pausePlay) methods.pausePlay.update("pause"); 843 // SYNC: 844 if (slider.syncExists) methods.sync("play"); 845 } 846 // STOP: 847 slider.stop = function () { 848 slider.pause(); 849 slider.stopped = true; 850 } 851 slider.canAdvance = function(target, fromNav) { 852 // ASNAV: 853 var last = (asNav) ? slider.pagingCount - 1 : slider.last; 854 return (fromNav) ? true : 855 (asNav && slider.currentItem === slider.count - 1 && target === 0 && slider.direction === "prev") ? true : 856 (asNav && slider.currentItem === 0 && target === slider.pagingCount - 1 && slider.direction !== "next") ? false : 857 (target === slider.currentSlide && !asNav) ? false : 858 (slider.vars.animationLoop) ? true : 859 (slider.atEnd && slider.currentSlide === 0 && target === last && slider.direction !== "next") ? false : 860 (slider.atEnd && slider.currentSlide === last && target === 0 && slider.direction === "next") ? false : 861 true; 862 } 863 slider.getTarget = function(dir) { 864 slider.direction = dir; 865 if (dir === "next") { 866 return (slider.currentSlide === slider.last) ? 0 : slider.currentSlide + 1; 867 } else { 868 return (slider.currentSlide === 0) ? slider.last : slider.currentSlide - 1; 869 } 870 } 871 872 // SLIDE: 873 slider.setProps = function(pos, special, dur) { 874 var target = (function() { 875 var posCheck = (pos) ? pos : ((slider.itemW + slider.vars.itemMargin) * slider.move) * slider.animatingTo, 876 posCalc = (function() { 877 if (carousel) { 878 return (special === "setTouch") ? pos : 879 (reverse && slider.animatingTo === slider.last) ? 0 : 880 (reverse) ? slider.limit - (((slider.itemW + slider.vars.itemMargin) * slider.move) * slider.animatingTo) : 881 (slider.animatingTo === slider.last) ? slider.limit : posCheck; 882 } else { 883 switch (special) { 884 case "setTotal": return (reverse) ? ((slider.count - 1) - slider.currentSlide + slider.cloneOffset) * pos : (slider.currentSlide + slider.cloneOffset) * pos; 885 case "setTouch": return (reverse) ? pos : pos; 886 case "jumpEnd": return (reverse) ? pos : slider.count * pos; 887 case "jumpStart": return (reverse) ? slider.count * pos : pos; 888 default: return pos; 889 } 890 } 891 }()); 892 893 return (posCalc * -1) + "px"; 894 }()); 895 896 if (slider.transitions) { 897 target = (vertical) ? "translate3d(0," + target + ",0)" : "translate3d(" + target + ",0,0)"; 898 dur = (dur !== undefined) ? (dur/1000) + "s" : "0s"; 899 slider.container.css("-" + slider.pfx + "-transition-duration", dur); 900 } 901 902 slider.args[slider.prop] = target; 903 if (slider.transitions || dur === undefined) slider.container.css(slider.args); 904 } 905 906 slider.setup = function(type) { 907 // SLIDE: 908 if (!fade) { 909 var sliderOffset, arr; 910 911 if (type === "init") { 912 slider.viewport = $('<div class="' + namespace + 'viewport"></div>').css({"overflow": "hidden", "position": "relative"}).appendTo(slider).append(slider.container); 913 // INFINITE LOOP: 914 slider.cloneCount = 0; 915 slider.cloneOffset = 0; 916 // REVERSE: 917 if (reverse) { 918 arr = $.makeArray(slider.slides).reverse(); 919 slider.slides = $(arr); 920 slider.container.empty().append(slider.slides); 921 } 922 } 923 // INFINITE LOOP && !CAROUSEL: 924 if (slider.vars.animationLoop && !carousel) { 925 slider.cloneCount = 2; 926 slider.cloneOffset = 1; 927 // clear out old clones 928 if (type !== "init") slider.container.find('.clone').remove(); 929 slider.container.append(slider.slides.first().clone().addClass('clone').attr('aria-hidden', 'true')).prepend(sli
vendor: 10,363 bytes, lines 929-1133
929der.slides.last().clone().addClass('clone').attr('aria-hidden', 'true')); 930 } 931 slider.newSlides = $(slider.vars.selector, slider); 932 933 sliderOffset = (reverse) ? slider.count - 1 - slider.currentSlide + slider.cloneOffset : slider.currentSlide + slider.cloneOffset; 934 // VERTICAL: 935 if (vertical && !carousel) { 936 slider.container.height((slider.count + slider.cloneCount) * 200 + "%").css("position", "absolute").width("100%"); 937 setTimeout(function(){ 938 slider.newSlides.css({"display": "block"}); 939 slider.doMath(); 940 slider.viewport.height(slider.h); 941 slider.setProps(sliderOffset * slider.h, "init"); 942 }, (type === "init") ? 100 : 0); 943 } else { 944 slider.container.width((slider.count + slider.cloneCount) * 200 + "%"); 945 slider.setProps(sliderOffset * slider.computedW, "init"); 946 setTimeout(function(){ 947 slider.doMath(); 948 slider.newSlides.css({"width": slider.computedW, "float": "left", "display": "block"}); 949 // SMOOTH HEIGHT: 950 if (slider.vars.smoothHeight) methods.smoothHeight(); 951 }, (type === "init") ? 100 : 0); 952 } 953 } else { // FADE: 954 slider.slides.css({"width": "100%", "float": "left", "marginRight": "-100%", "position": "relative"}); 955 if (type === "init") { 956 if (!touch) { 957 //slider.slides.eq(slider.currentSlide).fadeIn(slider.vars.animationSpeed, slider.vars.easing); 958 slider.slides.css({ "opacity": 0, "display": "block", "zIndex": 1 }).eq(slider.currentSlide).css({"zIndex": 2}).animate({"opacity": 1},slider.vars.animationSpeed,slider.vars.easing); 959 } else { 960 slider.slides.css({ "opacity": 0, "display": "block", "webkitTransition": "opacity " + slider.vars.animationSpeed / 1000 + "s ease", "zIndex": 1 }).eq(slider.currentSlide).css({ "opacity": 1, "zIndex": 2}); 961 } 962 } 963 // SMOOTH HEIGHT: 964 if (slider.vars.smoothHeight) methods.smoothHeight(); 965 } 966 // !CAROUSEL: 967 // CANDIDATE: active slide 968 if (!carousel) slider.slides.removeClass(namespace + "active-slide").eq(slider.currentSlide).addClass(namespace + "active-slide"); 969 } 970 971 972 slider.doMath = function() { 973 var slide = slider.slides.first(), 974 slideMargin = slider.vars.itemMargin, 975 minItems = slider.vars.minItems, 976 maxItems = slider.vars.maxItems; 977 978 slider.w = (slider.viewport===undefined) ? slider.width() : slider.viewport.width(); 979 slider.h = slide.height(); 980 slider.boxPadding = slide.outerWidth() - slide.width(); 981 982 // CAROUSEL: 983 if (carousel) { 984 slider.itemT = slider.vars.itemWidth + slideMargin; 985 slider.minW = (minItems) ? minItems * slider.itemT : slider.w; 986 slider.maxW = (maxItems) ? (maxItems * slider.itemT) - slideMargin : slider.w; 987 slider.itemW = (slider.minW > slider.w) ? (slider.w - (slideMargin * (minItems - 1)))/minItems : 988 (slider.maxW < slider.w) ? (slider.w - (slideMargin * (maxItems - 1)))/maxItems : 989 (slider.vars.itemWidth > slider.w) ? slider.w : slider.vars.itemWidth; 990 991 slider.visible = Math.floor(slider.w/(slider.itemW)); 992 slider.move = (slider.vars.move > 0 && slider.vars.move < slider.visible ) ? slider.vars.move : slider.visible; 993 slider.pagingCount = Math.ceil(((slider.count - slider.visible)/slider.move) + 1); 994 slider.last = slider.pagingCount - 1; 995 slider.limit = (slider.pagingCount === 1) ? 0 : 996 (slider.vars.itemWidth > slider.w) ? (slider.itemW * (slider.count - 1)) + (slideMargin * (slider.count - 1)) : ((slider.itemW + slideMargin) * slider.count) - slider.w - slideMargin; 997 } else { 998 slider.itemW = slider.w; 999 slider.pagingCount = slider.count; 1000 slider.last = slider.count - 1; 1001 } 1002 slider.computedW = slider.itemW - slider.boxPadding; 1003 } 1004 1005 1006 slider.update = function(pos, action) { 1007 slider.doMath(); 1008 1009 // update currentSlide and slider.animatingTo if necessary 1010 if (!carousel) { 1011 if (pos < slider.currentSlide) { 1012 slider.currentSlide += 1; 1013 } else if (pos <= slider.currentSlide && pos !== 0) { 1014 slider.currentSlide -= 1; 1015 } 1016 slider.animatingTo = slider.currentSlide; 1017 } 1018 1019 // update controlNav 1020 if (slider.vars.controlNav && !slider.manualControls) { 1021 if ((action === "add" && !carousel) || slider.pagingCount > slider.controlNav.length) { 1022 methods.controlNav.update("add"); 1023 } else if ((action === "remove" && !carousel) || slider.pagingCount < slider.controlNav.length) { 1024 if (carousel && slider.currentSlide > slider.last) { 1025 slider.currentSlide -= 1; 1026 slider.animatingTo -= 1; 1027 } 1028 methods.controlNav.update("remove", slider.last); 1029 } 1030 } 1031 // update directionNav 1032 if (slider.vars.directionNav) methods.directionNav.update(); 1033 1034 } 1035 1036 slider.addSlide = function(obj, pos) { 1037 var $obj = $(obj); 1038 1039 slider.count += 1; 1040 slider.last = slider.count - 1; 1041 1042 // append new slide 1043 if (vertical && reverse) { 1044 (pos !== undefined) ? slider.slides.eq(slider.count - pos).after($obj) : slider.container.prepend($obj); 1045 } else { 1046 (pos !== undefined) ? slider.slides.eq(pos).before($obj) : slider.container.append($obj); 1047 } 1048 1049 // update currentSlide, animatingTo, controlNav, and directionNav 1050 slider.update(pos, "add"); 1051 1052 // update slider.slides 1053 slider.slides = $(slider.vars.selector + ':not(.clone)', slider); 1054 // re-setup the slider to accomdate new slide 1055 slider.setup(); 1056 1057 //FlexSlider: added() Callback 1058 slider.vars.added(slider); 1059 } 1060 slider.removeSlide = function(obj) { 1061 var pos = (isNaN(obj)) ? slider.slides.index($(obj)) : obj; 1062 1063 // update count 1064 slider.count -= 1; 1065 slider.last = slider.count - 1; 1066 1067 // remove slide 1068 if (isNaN(obj)) { 1069 $(obj, slider.slides).remove(); 1070 } else { 1071 (vertical && reverse) ? slider.slides.eq(slider.last).remove() : slider.slides.eq(obj).remove(); 1072 } 1073 1074 // update currentSlide, animatingTo, controlNav, and directionNav 1075 slider.doMath(); 1076 slider.update(pos, "remove"); 1077 1078 // update slider.slides 1079 slider.slides = $(slider.vars.selector + ':not(.clone)', slider); 1080 // re-setup the slider to accomdate new slide 1081 slider.setup(); 1082 1083 // FlexSlider: removed() Callback 1084 slider.vars.removed(slider); 1085 } 1086 1087 //FlexSlider: Initialize 1088 methods.init(); 1089 } 1090 1091 // Ensure the slider isn't focussed if the window loses focus. 1092 $( window ).blur( function ( e ) { 1093 focused = false; 1094 }).focus( function ( e ) { 1095 focused = true; 1096 }); 1097 1098 //FlexSlider: Default Settings 1099 $.flexslider.defaults = { 1100 namespace: "flex-", //{NEW} String: Prefix string attached to the class of every element generated by the plugin 1101 selector: ".slides > li", //{NEW} Selector: Must match a simple pattern. '{container} > {slide}' -- Ignore pattern at your own peril 1102 animation: "fade", //String: Select your animation type, "fade" or "slide" 1103 easing: "swing", //{NEW} String: Determines the easing method used in jQuery transitions. jQuery easing plugin is supported! 1104 direction: "horizontal", //String: Select the sliding direction, "horizontal" or "vertical" 1105 reverse: false, //{NEW} Boolean: Reverse the animation direction 1106 animationLoop: true, //Boolean: Should the animation loop? If false, directionNav will received "disable" classes at either end 1107 smoothHeight: false, //{NEW} Boolean: Allow height of the slider to animate smoothly in horizontal mode 1108 startAt: 0, //Integer: The slide that the slider should start on. Array notation (0 = first slide) 1109 slideshow: true, //Boolean: Animate slider automatically 1110 slideshowSpeed: 7000, //Integer: Set the speed of the slideshow cycling, in milliseconds 1111 animationSpeed: 600, //Integer: Set the speed of animations, in milliseconds 1112 initDelay: 0, //{NEW} Integer: Set an initialization delay, in milliseconds 1113 randomize: false, //Boolean: Randomize slide order 1114 thumbCaptions: false, //Boolean: Whether or not to put captions on thumbnails when using the "thumbnails" controlNav. 1115 1116 // Usability features 1117 pauseOnAction: true, //Boolean: Pause the slideshow when interacting with control elements, highly recommended. 1118 pauseOnHover: false, //Boolean: Pause the slideshow when hovering over slider, then resume when no longer hovering 1119 pauseInvisible: true, //{NEW} Boolean: Pause the slideshow when tab is invisible, resume when visible. Provides better UX, lower CPU usage. 1120 useCSS: true, //{NEW} Boolean: Slider will use CSS3 transitions if available 1121 touch: true, //{NEW} Boolean: Allow touch swipe navigation of the slider on touch-enabled devices 1122 video: false, //{NEW} Boolean: If using video in the slider, will prevent CSS3 3D Transforms to avoid graphical glitches 1123 1124 // Primary Controls 1125 controlNav: true, //Boolean: Create navigation for paging control of each clide? Note: Leave true for manualControls usage 1126 directionNav: true, //Boolean: Create navigation for previous/next navigation? (true/false) 1127 prevText: "Previous", //String: Set the text for the "previous" directionNav item 1128 nextText: "Next", //String: Set the text for the "next" directionNav item 1129 1130 // Secondary Navigation 1131 keyboard: true, //Boolean: Allow slider navigating via keyboard left/right keys 1132 multipleKeyboard: false, //{NEW} Boolean: Allow keyboard navigation to affect multiple sliders. Default behavior cuts out keyboard navigation with more than one slider present. 1133 mousewheel: false, //{UPDATED} Boolean: Requires jquery.mousewheel.js (https://github.com/brandonaaron/jquery-mousewheel) - Allows slider navigating via mousewheel
1134 pausePlay: false, //Boolean: Create pause/play dynamic element 1135 pauseText: "Pause", //String: Set the text for the "pause" pausePlay item 1136 playText: "Play", //String: Set the text for the "play" pausePlay item 1137 1138 // Special properties 1139 controlsContainer: "", //{UPDATED} jQuery Object/Selector: Declare which container the navigation elements should be appended too. Default container is the FlexSlider element. Example use would be $(".flexslider-container"). Property is ignored if given element is not found. 1140 manualControls: "", //{UPDATED} jQuery Object/Selector: Declare custom control navigation. Examples would be $(".flex-control-nav li") or "#tabs-nav li img", etc. The number of elements in your controlNav should match the number of slides/tabs. 1141 sync: "", //{NEW} Selector: Mirror the actions performed on this slider with another slider. Use with care. 1142 asNavFor: "", //{NEW} Selector: Internal property exposed for turning the slider into a thumbnail navigation for another slider 1143 1144 // Carousel Options 1145 itemWidth: 0, //{NEW} Integer: Box-model width of individual carousel items, including horizontal borders and padding. 1146 itemMargin: 0, //{NEW} Integer: Margin between carousel items. 1147 minItems: 1, //{NEW} Integer: Minimum number of carousel items that should be visible. Items will resize fluidly when below this. 1148 maxItems: 0, //{NEW} Integer: Maxmimum number of carousel items that should be visible. Items will resize fluidly when above this limit. 1149 move: 0, //{NEW} Integer: Number of carousel items that should move on animation. If 0, slider will move all visible items. 1150 allowOneSlide: true, //{NEW} Boolean: Whether or not to allow a slider comprised of a single slide 1151 1152 // Callback API 1153 start: function(){}, //Callback: function(slider) - Fires when the slider loads the first slide 1154 before: function(){}, //Callback: function(slider) - Fires asynchronously with each slider animation 1155 after: function(){}, //Callback: function(slider) - Fires after each slider animation completes 1156 end: function(){}, //Callback: function(slider) - Fires when the slider reaches the last slide (asynchronous) 1157 added: function(){}, //{NEW} Callback: function(slider) - Fires after a slide is added 1158 removed: function(){} //{NEW} Callback: function(slider) - Fires after a slide is removed 1159 } 1160 1161 1162 //FlexSlider: Plugin Function 1163 $.fn.flexslider = function(options) { 1164 if (options === undefined) options = {}; 1165 1166 if (typeof options === "object") { 1167 return this.each(function() { 1168 var $this = $(this), 1169 selector = (options.selector) ? options.selector : ".slides > li", 1170 $slides = $this.find(selector); 1171 1172 if ( ( $slides.length === 1 && options.allowOneSlide === true ) || $slides.length === 0 ) { 1173 $slides.fadeIn(400); 1174 if (options.start) options.start($this); 1175 } else if ($this.data('flexslider') === undefined) { 1176 new $.flexslider(this, options); 1177 } 1178 }); 1179 } else { 1180 // Helper strings to quickly perform functions on the slider 1181 var $slider = $(this).data('flexslider'); 1182 switch (options) { 1183 case "play": $slider.play(); break; 1184 case "pause": $slider.pause(); break; 1185 case "stop": $slider.stop(); break; 1186 case "next": $slider.flexAnimate($slider.getTarget("next"), true); break; 1187 case "prev": 1188 case "previous": $slider.flexAnimate($slider.getTarget("prev"), true); break; 1189 default: if (typeof options === "number") $slider.flexAnimate(options, true); 1190 } 1191 } 1192 } 1193})(jQuery); 1194 1195/* 1196 * jPlayer Plugin for jQuery JavaScript Library 1197 * http://www.jplayer.org 1198 * 1199 * Copyright (c) 2009 - 2014 Happyworm Ltd 1200 * Licensed under the MIT license. 1201 * http://opensource.org/licenses/MIT 1202 * 1203 * Author: Mark J Panaghiston 1204 * Version: 2.6.1 1205 * Date: 3rd April 2014 1206 */ 1207 1208/* Code verified using http://www.jshint.com/ */ 1209/*jshint asi:false, bitwise:false, boss:false, browser:true, curly:true, debug:false, eqeqeq:true, eqnull:false, evil:false, forin:false, immed:false, jquery:true, laxbreak:false, newcap:true, noarg:true, noempty:true, nonew:true, onevar:false, passfail:false, plusplus:false, regexp:false, undef:true, sub:false, strict:false, white:false, smarttabs:true */ 1210/*global define:false, ActiveXObject:false, alert:false */ 1211 1212/* Support for Zepto 1.0 compiled with optional data module. 1213 * For AMD support, you will need to manually switch the 2 lines in the code below. 1214 * Search terms: "jQuery Switch" and "Zepto Switch" 1215 */ 1216 1217(function (root, factory) { 1218 if (typeof define === 'function' && define.amd) { 1219 // AMD. Register as an anonymous module. 1220 define(['jquery'], factory); // jQuery Switch 1221 // define(['zepto'], factory); // Zepto Switch 1222 } else { 1223 // Browser globals 1224 if(root.jQuery) { // Use jQuery if available 1225 factory(root.jQuery); 1226 } else { // Otherwise, use Zepto 1227 factory(root.Zepto); 1228 } 1229 } 1230}(this, function ($, undefined) { 1231 1232 // Adapted from jquery.ui.widget.js (1.8.7): $.widget.bridge - Tweaked $.data(this,XYZ) to $(this).data(XYZ) for Zepto 1233 $.fn.jPlayer = function( options ) { 1234 var name = "jPlayer"; 1235 var isMethodCall = typeof options === "string", 1236 args = Array.prototype.slice.call( arguments, 1 ), 1237 returnValue = this; 1238 1239 // allow multiple hashes to be passed on init 1240 options = !isMethodCall && args.length ? 1241 $.extend.apply( null, [ true, options ].concat(args) ) : 1242 options; 1243 1244 // prevent calls to internal methods 1245 if ( isMethodCall && options.charAt( 0 ) === "_" ) { 1246 return returnValue; 1247 } 1248 1249 if ( isMethodCall ) { 1250 this.each(function() { 1251 var instance = $(this).data( name ), 1252 methodValue = instance && $.isFunction( instance[options] ) ? 1253 instance[ options ].apply( instance, args ) : 1254 instance; 1255 if ( methodValue !== instance && methodValue !== undefined ) { 1256 returnValue = methodValue; 1257 return false;
vendor: 18,260 bytes, lines 1258-1796
1258 } 1259 }); 1260 } else { 1261 this.each(function() { 1262 var instance = $(this).data( name ); 1263 if ( instance ) { 1264 // instance.option( options || {} )._init(); // Orig jquery.ui.widget.js code: Not recommend for jPlayer. ie., Applying new options to an existing instance (via the jPlayer constructor) and performing the _init(). The _init() is what concerns me. It would leave a lot of event handlers acting on jPlayer instance and the interface. 1265 instance.option( options || {} ); // The new constructor only changes the options. Changing options only has basic support atm. 1266 } else { 1267 $(this).data( name, new $.jPlayer( options, this ) ); 1268 } 1269 }); 1270 } 1271 1272 return returnValue; 1273 }; 1274 1275 $.jPlayer = function( options, element ) { 1276 // allow instantiation without initializing for simple inheritance 1277 if ( arguments.length ) { 1278 this.element = $(element); 1279 this.options = $.extend(true, {}, 1280 this.options, 1281 options 1282 ); 1283 var self = this; 1284 this.element.bind( "remove.jPlayer", function() { 1285 self.destroy(); 1286 }); 1287 this._init(); 1288 } 1289 }; 1290 // End of: (Adapted from jquery.ui.widget.js (1.8.7)) 1291 1292 // Zepto is missing one of the animation methods. 1293 if(typeof $.fn.stop !== 'function') { 1294 $.fn.stop = function() {}; 1295 } 1296 1297 // Emulated HTML5 methods and properties 1298 $.jPlayer.emulateMethods = "load play pause"; 1299 $.jPlayer.emulateStatus = "src readyState networkState currentTime duration paused ended playbackRate"; 1300 $.jPlayer.emulateOptions = "muted volume"; 1301 1302 // Reserved event names generated by jPlayer that are not part of the HTML5 Media element spec 1303 $.jPlayer.reservedEvent = "ready flashreset resize repeat error warning"; 1304 1305 // Events generated by jPlayer 1306 $.jPlayer.event = {}; 1307 $.each( 1308 [ 1309 'ready', 1310 'setmedia', // Fires when the media is set 1311 'flashreset', // Similar to the ready event if the Flash solution is set to display:none and then shown again or if it's reloaded for another reason by the browser. For example, using CSS position:fixed on Firefox for the full screen feature. 1312 'resize', // Occurs when the size changes through a full/restore screen operation or if the size/sizeFull options are changed. 1313 'repeat', // Occurs when the repeat status changes. Usually through clicks on the repeat button of the interface. 1314 'click', // Occurs when the user clicks on one of the following: poster image, html video, flash video. 1315 'error', // Event error code in event.jPlayer.error.type. See $.jPlayer.error 1316 'warning', // Event warning code in event.jPlayer.warning.type. See $.jPlayer.warning 1317 1318 // Other events match HTML5 spec. 1319 'loadstart', 1320 'progress', 1321 'suspend', 1322 'abort', 1323 'emptied', 1324 'stalled', 1325 'play', 1326 'pause', 1327 'loadedmetadata', 1328 'loadeddata', 1329 'waiting', 1330 'playing', 1331 'canplay', 1332 'canplaythrough', 1333 'seeking', 1334 'seeked', 1335 'timeupdate', 1336 'ended', 1337 'ratechange', 1338 'durationchange', 1339 'volumechange' 1340 ], 1341 function() { 1342 $.jPlayer.event[ this ] = 'jPlayer_' + this; 1343 } 1344 ); 1345 1346 $.jPlayer.htmlEvent = [ // These HTML events are bubbled through to the jPlayer event, without any internal action. 1347 "loadstart", 1348 // "progress", // jPlayer uses internally before bubbling. 1349 // "suspend", // jPlayer uses internally before bubbling. 1350 "abort", 1351 // "error", // jPlayer uses internally before bubbling. 1352 "emptied", 1353 "stalled", 1354 // "play", // jPlayer uses internally before bubbling. 1355 // "pause", // jPlayer uses internally before bubbling. 1356 "loadedmetadata", 1357 "loadeddata", 1358 // "waiting", // jPlayer uses internally before bubbling. 1359 // "playing", // jPlayer uses internally before bubbling. 1360 "canplay", 1361 "canplaythrough" 1362 // "seeking", // jPlayer uses internally before bubbling. 1363 // "seeked", // jPlayer uses internally before bubbling. 1364 // "timeupdate", // jPlayer uses internally before bubbling. 1365 // "ended", // jPlayer uses internally before bubbling. 1366 // "ratechange" // jPlayer uses internally before bubbling. 1367 // "durationchange" // jPlayer uses internally before bubbling. 1368 // "volumechange" // jPlayer uses internally before bubbling. 1369 ]; 1370 1371 $.jPlayer.pause = function() { 1372 $.each($.jPlayer.prototype.instances, function(i, element) { 1373 if(element.data("jPlayer").status.srcSet) { // Check that media is set otherwise would cause error event. 1374 element.jPlayer("pause"); 1375 } 1376 }); 1377 }; 1378 1379 // Default for jPlayer option.timeFormat 1380 $.jPlayer.timeFormat = { 1381 showHour: false, 1382 showMin: true, 1383 showSec: true, 1384 padHour: false, 1385 padMin: true, 1386 padSec: true, 1387 sepHour: ":", 1388 sepMin: ":", 1389 sepSec: "" 1390 }; 1391 var ConvertTime = function() { 1392 this.init(); 1393 }; 1394 ConvertTime.prototype = { 1395 init: function() { 1396 this.options = { 1397 timeFormat: $.jPlayer.timeFormat 1398 }; 1399 }, 1400 time: function(s) { // function used on jPlayer.prototype._convertTime to enable per instance options. 1401 s = (s && typeof s === 'number') ? s : 0; 1402 1403 var myTime = new Date(s * 1000), 1404 hour = myTime.getUTCHours(), 1405 min = this.options.timeFormat.showHour ? myTime.getUTCMinutes() : myTime.getUTCMinutes() + hour * 60, 1406 sec = this.options.timeFormat.showMin ? myTime.getUTCSeconds() : myTime.getUTCSeconds() + min * 60, 1407 strHour = (this.options.timeFormat.padHour && hour < 10) ? "0" + hour : hour, 1408 strMin = (this.options.timeFormat.padMin && min < 10) ? "0" + min : min, 1409 strSec = (this.options.timeFormat.padSec && sec < 10) ? "0" + sec : sec, 1410 strTime = ""; 1411 1412 strTime += this.options.timeFormat.showHour ? strHour + this.options.timeFormat.sepHour : ""; 1413 strTime += this.options.timeFormat.showMin ? strMin + this.options.timeFormat.sepMin : ""; 1414 strTime += this.options.timeFormat.showSec ? strSec + this.options.timeFormat.sepSec : ""; 1415 1416 return strTime; 1417 } 1418 }; 1419 var myConvertTime = new ConvertTime(); 1420 $.jPlayer.convertTime = function(s) { 1421 return myConvertTime.time(s); 1422 }; 1423 1424 // Adapting jQuery 1.4.4 code for jQuery.browser. Required since jQuery 1.3.2 does not detect Chrome as webkit. 1425 $.jPlayer.uaBrowser = function( userAgent ) { 1426 var ua = userAgent.toLowerCase(); 1427 1428 // Useragent RegExp 1429 var rwebkit = /(webkit)[ \/]([\w.]+)/; 1430 var ropera = /(opera)(?:.*version)?[ \/]([\w.]+)/; 1431 var rmsie = /(msie) ([\w.]+)/; 1432 var rmozilla = /(mozilla)(?:.*? rv:([\w.]+))?/; 1433 1434 var match = rwebkit.exec( ua ) || 1435 ropera.exec( ua ) || 1436 rmsie.exec( ua ) || 1437 ua.indexOf("compatible") < 0 && rmozilla.exec( ua ) || 1438 []; 1439 1440 return { browser: match[1] || "", version: match[2] || "0" }; 1441 }; 1442 1443 // Platform sniffer for detecting mobile devices 1444 $.jPlayer.uaPlatform = function( userAgent ) { 1445 var ua = userAgent.toLowerCase(); 1446 1447 // Useragent RegExp 1448 var rplatform = /(ipad|iphone|ipod|android|blackberry|playbook|windows ce|webos)/; 1449 var rtablet = /(ipad|playbook)/; 1450 var randroid = /(android)/; 1451 var rmobile = /(mobile)/; 1452 1453 var platform = rplatform.exec( ua ) || []; 1454 var tablet = rtablet.exec( ua ) || 1455 !rmobile.exec( ua ) && randroid.exec( ua ) || 1456 []; 1457 1458 if(platform[1]) { 1459 platform[1] = platform[1].replace(/\s/g, "_"); // Change whitespace to underscore. Enables dot notation. 1460 } 1461 1462 return { platform: platform[1] || "", tablet: tablet[1] || "" }; 1463 }; 1464 1465 $.jPlayer.browser = { 1466 }; 1467 $.jPlayer.platform = { 1468 }; 1469 1470 var browserMatch = $.jPlayer.uaBrowser(navigator.userAgent); 1471 if ( browserMatch.browser ) { 1472 $.jPlayer.browser[ browserMatch.browser ] = true; 1473 $.jPlayer.browser.version = browserMatch.version; 1474 } 1475 var platformMatch = $.jPlayer.uaPlatform(navigator.userAgent); 1476 if ( platformMatch.platform ) { 1477 $.jPlayer.platform[ platformMatch.platform ] = true; 1478 $.jPlayer.platform.mobile = !platformMatch.tablet; 1479 $.jPlayer.platform.tablet = !!platformMatch.tablet; 1480 } 1481 1482 // Internet Explorer (IE) Browser Document Mode Sniffer. Based on code at: 1483 // http://msdn.microsoft.com/en-us/library/cc288325%28v=vs.85%29.aspx#GetMode 1484 $.jPlayer.getDocMode = function() { 1485 var docMode; 1486 if ($.jPlayer.browser.msie) { 1487 if (document.documentMode) { // IE8 or later 1488 docMode = document.documentMode; 1489 } else { // IE 5-7 1490 docMode = 5; // Assume quirks mode unless proven otherwise 1491 if (document.compatMode) { 1492 if (document.compatMode === "CSS1Compat") { 1493 docMode = 7; // standards mode 1494 } 1495 } 1496 } 1497 } 1498 return docMode; 1499 }; 1500 $.jPlayer.browser.documentMode = $.jPlayer.getDocMode(); 1501 1502 $.jPlayer.nativeFeatures = { 1503 init: function() { 1504 1505 /* Fullscreen function naming influenced by W3C naming. 1506 * No support for: Mozilla Proposal: https://wiki.mozilla.org/Gecko:FullScreenAPI 1507 */ 1508 1509 var d = document, 1510 v = d.createElement('video'), 1511 spec = { 1512 // http://www.w3.org/TR/fullscreen/ 1513 w3c: [ 1514 'fullscreenEnabled', 1515 'fullscreenElement', 1516 'requestFullscreen', 1517 'exitFullscreen', 1518 'fullscreenchange', 1519 'fullscreenerror' 1520 ], 1521 // https://developer.mozilla.org/en-US/docs/DOM/Using_fullscreen_mode 1522 moz: [ 1523 'mozFullScreenEnabled', 1524 'mozFullScreenElement', 1525 'mozRequestFullScreen', 1526 'mozCancelFullScreen', 1527 'mozfullscreenchange', 1528 'mozfullscreenerror' 1529 ], 1530 // http://developer.apple.com/library/safari/#documentation/WebKit/Reference/ElementClassRef/Element/Element.html 1531 // http://developer.apple.com/library/safari/#documentation/UserExperience/Reference/DocumentAdditionsReference/DocumentAdditions/DocumentAdditions.html 1532 webkit: [ 1533 '', 1534 'webkitCurrentFullScreenElement', 1535 'webkitRequestFullScreen', 1536 'webkitCancelFullScreen', 1537 'webkitfullscreenchange', 1538 '' 1539 ], 1540 // http://developer.apple.com/library/safari/#documentation/AudioVideo/Reference/HTMLVideoElementClassReference/HTMLVideoElement/HTMLVideoElement.html 1541 // https://developer.apple.com/library/safari/samplecode/HTML5VideoEventFlow/Listings/events_js.html#//apple_ref/doc/uid/DTS40010085-events_js-DontLinkElementID_5 1542 // Events: 'webkitbeginfullscreen' and 'webkitendfullscreen' 1543 webkitVideo: [ 1544 'webkitSupportsFullscreen', 1545 'webkitDisplayingFullscreen', 1546 'webkitEnterFullscreen', 1547 'webkitExitFullscreen', 1548 '', 1549 '' 1550 ] 1551 }, 1552 specOrder = [ 1553 'w3c', 1554 'moz', 1555 'webkit', 1556 'webkitVideo' 1557 ], 1558 fs, i, il; 1559 1560 this.fullscreen = fs = { 1561 support: { 1562 w3c: !!d[spec.w3c[0]], 1563 moz: !!d[spec.moz[0]], 1564 webkit: typeof d[spec.webkit[3]] === 'function', 1565 webkitVideo: typeof v[spec.webkitVideo[2]] === 'function' 1566 }, 1567 used: {} 1568 }; 1569 1570 // Store the name of the spec being used and as a handy boolean. 1571 for(i = 0, il = specOrder.length; i < il; i++) { 1572 var n = specOrder[i]; 1573 if(fs.support[n]) { 1574 fs.spec = n; 1575 fs.used[n] = true; 1576 break; 1577 } 1578 } 1579 1580 if(fs.spec) { 1581 var s = spec[fs.spec]; 1582 fs.api = { 1583 fullscreenEnabled: true, 1584 fullscreenElement: function(elem) { 1585 elem = elem ? elem : d; // Video element required for webkitVideo 1586 return elem[s[1]]; 1587 }, 1588 requestFullscreen: function(elem) { 1589 return elem[s[2]](); 1590 }, 1591 exitFullscreen: function(elem) { 1592 elem = elem ? elem : d; // Video element required for webkitVideo 1593 return elem[s[3]](); 1594 } 1595 }; 1596 fs.event = { 1597 fullscreenchange: s[4], 1598 fullscreenerror: s[5] 1599 }; 1600 } else { 1601 fs.api = { 1602 fullscreenEnabled: false, 1603 fullscreenElement: function() { 1604 return null; 1605 }, 1606 requestFullscreen: function() {}, 1607 exitFullscreen: function() {} 1608 }; 1609 fs.event = {}; 1610 } 1611 } 1612 }; 1613 $.jPlayer.nativeFeatures.init(); 1614 1615 // The keyboard control system. 1616 1617 // The current jPlayer instance in focus. 1618 $.jPlayer.focus = null; 1619 1620 // The list of element node names to ignore with key controls. 1621 $.jPlayer.keyIgnoreElementNames = "INPUT TEXTAREA"; 1622 1623 // The function that deals with key presses. 1624 var keyBindings = function(event) { 1625 1626 var f = $.jPlayer.focus, 1627 ignoreKey; 1628 1629 // A jPlayer instance must be in focus. ie., keyEnabled and the last one played. 1630 if(f) { 1631 // What generated the key press? 1632 $.each( $.jPlayer.keyIgnoreElementNames.split(/\s+/g), function(i, name) { 1633 // The strings should already be uppercase. 1634 if(event.target.nodeName.toUpperCase() === name.toUpperCase()) { 1635 ignoreKey = true; 1636 return false; // exit each. 1637 } 1638 }); 1639 if(!ignoreKey) { 1640 // See if the key pressed matches any of the bindings. 1641 $.each(f.options.keyBindings, function(action, binding) { 1642 // The binding could be a null when the default has been disabled. ie., 1st clause in if() 1643 if(binding && event.which === binding.key && $.isFunction(binding.fn)) { 1644 event.preventDefault(); // Key being used by jPlayer, so prevent default operation. 1645 binding.fn(f); 1646 return false; // exit each. 1647 } 1648 }); 1649 } 1650 } 1651 }; 1652 1653 $.jPlayer.keys = function(en) { 1654 var event = "keydown.jPlayer"; 1655 // Remove any binding, just in case enabled more than once. 1656 $(document.documentElement).unbind(event); 1657 if(en) { 1658 $(document.documentElement).bind(event, keyBindings); 1659 } 1660 }; 1661 1662 // Enable the global key control handler ready for any jPlayer instance with the keyEnabled option enabled. 1663 $.jPlayer.keys(true); 1664 1665 $.jPlayer.prototype = { 1666 count: 0, // Static Variable: Change it via prototype. 1667 version: { // Static Object 1668 script: "2.6.1", 1669 needFlash: "2.6.0", 1670 flash: "unknown" 1671 }, 1672 options: { // Instanced in $.jPlayer() constructor 1673 swfPath: "js", // Path to Jplayer.swf. Can be relative, absolute or server root relative. 1674 solution: "html, flash", // Valid solutions: html, flash. Order defines priority. 1st is highest, 1675 supplied: "mp3", // Defines which formats jPlayer will try and support and the priority by the order. 1st is highest, 1676 preload: 'metadata', // HTML5 Spec values: none, metadata, auto. 1677 volume: 0.8, // The volume. Number 0 to 1. 1678 muted: false, 1679 remainingDuration: false, // When true, the remaining time is shown in the duration GUI element. 1680 toggleDuration: false, // When true, clicks on the duration toggle between the duration and remaining display. 1681 captureDuration: true, // When true, clicks on the duration are captured and no longer propagate up the DOM. 1682 playbackRate: 1, 1683 defaultPlaybackRate: 1, 1684 minPlaybackRate: 0.5, 1685 maxPlaybackRate: 4, 1686 wmode: "opaque", // Valid wmode: window, transparent, opaque, direct, gpu. 1687 backgroundColor: "#000000", // To define the jPlayer div and Flash background color. 1688 cssSelectorAncestor: "#jp_container_1", 1689 cssSelector: { // * denotes properties that should only be required when video media type required. _cssSelector() would require changes to enable splitting these into Audio and Video defaults. 1690 videoPlay: ".jp-video-play", // * 1691 play: ".jp-play", 1692 pause: ".jp-pause", 1693 stop: ".jp-stop", 1694 seekBar: ".jp-seek-bar", 1695 playBar: ".jp-play-bar", 1696 mute: ".jp-mute", 1697 unmute: ".jp-unmute", 1698 volumeBar: ".jp-volume-bar", 1699 volumeBarValue: ".jp-volume-bar-value", 1700 volumeMax: ".jp-volume-max", 1701 playbackRateBar: ".jp-playback-rate-bar", 1702 playbackRateBarValue: ".jp-playback-rate-bar-value", 1703 currentTime: ".jp-current-time", 1704 duration: ".jp-duration", 1705 title: ".jp-title", 1706 fullScreen: ".jp-full-screen", // * 1707 restoreScreen: ".jp-restore-screen", // * 1708 repeat: ".jp-repeat", 1709 repeatOff: ".jp-repeat-off", 1710 gui: ".jp-gui", // The interface used with autohide feature. 1711 noSolution: ".jp-no-solution" // For error feedback when jPlayer cannot find a solution. 1712 }, 1713 smoothPlayBar: false, // Smooths the play bar transitions, which affects clicks and short media with big changes per second. 1714 fullScreen: false, // Native Full Screen 1715 fullWindow: false, 1716 autohide: { 1717 restored: false, // Controls the interface autohide feature. 1718 full: true, // Controls the interface autohide feature. 1719 fadeIn: 200, // Milliseconds. The period of the fadeIn anim. 1720 fadeOut: 600, // Milliseconds. The period of the fadeOut anim. 1721 hold: 1000 // Milliseconds. The period of the pause before autohide beings. 1722 }, 1723 loop: false, 1724 repeat: function(event) { // The default jPlayer repeat event handler 1725 if(event.jPlayer.options.loop) { 1726 $(this).unbind(".jPlayerRepeat").bind($.jPlayer.event.ended + ".jPlayer.jPlayerRepeat", function() { 1727 $(this).jPlayer("play"); 1728 }); 1729 } else { 1730 $(this).unbind(".jPlayerRepeat"); 1731 } 1732 }, 1733 nativeVideoControls: { 1734 // Works well on standard browsers. 1735 // Phone and tablet browsers can have problems with the controls disappearing. 1736 }, 1737 noFullWindow: { 1738 msie: /msie [0-6]\./, 1739 ipad: /ipad.*?os [0-4]\./, 1740 iphone: /iphone/, 1741 ipod: /ipod/, 1742 android_pad: /android [0-3]\.(?!.*?mobile)/, 1743 android_phone: /android.*?mobile/, 1744 blackberry: /blackberry/, 1745 windows_ce: /windows ce/, 1746 iemobile: /iemobile/, 1747 webos: /webos/ 1748 }, 1749 noVolume: { 1750 ipad: /ipad/, 1751 iphone: /iphone/, 1752 ipod: /ipod/, 1753 android_pad: /android(?!.*?mobile)/, 1754 android_phone: /android.*?mobile/, 1755 blackberry: /blackberry/, 1756 windows_ce: /windows ce/, 1757 iemobile: /iemobile/, 1758 webos: /webos/, 1759 playbook: /playbook/ 1760 }, 1761 timeFormat: { 1762 // Specific time format for this instance. The supported options are defined in $.jPlayer.timeFormat 1763 // For the undefined options we use the default from $.jPlayer.timeFormat 1764 }, 1765 keyEnabled: false, // Enables keyboard controls. 1766 audioFullScreen: false, // Enables keyboard controls to enter full screen with audio media. 1767 keyBindings: { // The key control object, defining the key codes and the functions to execute. 1768 // The parameter, f = $.jPlayer.focus, will be checked truethy before attempting to call any of these functions. 1769 // Properties may be added to this object, in key/fn pairs, to enable other key controls. EG, for the playlist add-on. 1770 play: { 1771 key: 32, // space 1772 fn: function(f) { 1773 if(f.status.paused) { 1774 f.play(); 1775 } else { 1776 f.pause(); 1777 } 1778 } 1779 }, 1780 fullScreen: { 1781 key: 13, // enter 1782 fn: function(f) { 1783 if(f.status.video || f.options.audioFullScreen) { 1784 f._setOption("fullScreen", !f.options.fullScreen); 1785 } 1786 } 1787 }, 1788 muted: { 1789 key: 8, // backspace 1790 fn: function(f) { 1791 f._muted(!f.options.muted); 1792 } 1793 }, 1794 volumeUp: { 1795 key: 38, // UP 1796 fn: function(f) {
1797 f.volume(f.options.volume + 0.1); 1798 } 1799 }, 1800 volumeDown: { 1801 key: 40, // DOWN 1802 fn: function(f) { 1803 f.volume(f.options.volume - 0.1); 1804 } 1805 } 1806 }, 1807 verticalVolume: false, // Calculate volume from the bottom of the volume bar. Default is from the left. Also volume affects either width or height. 1808 verticalPlaybackRate: false, 1809 globalVolume: false, // Set to make volume and muted changes affect all jPlayer instances with this option enabled 1810 idPrefix: "jp", // Prefix for the ids of html elements created by jPlayer. For flash, this must not include characters: . - + * / \ 1811 noConflict: "jQuery", 1812 emulateHtml: false, // Emulates the HTML5 Media element on the jPlayer element. 1813 consoleAlerts: true, // Alerts are sent to the console.log() instead of alert(). 1814 errorAlerts: false, 1815 warningAlerts: false 1816 }, 1817 optionsAudio: { 1818 size: { 1819 width: "0px", 1820 height: "0px", 1821 cssClass: "" 1822 }, 1823 sizeFull: { 1824 width: "0px", 1825 height: "0px", 1826 cssClass: "" 1827 } 1828 }, 1829 optionsVideo: { 1830 size: { 1831 width: "480px", 1832 height: "270px", 1833 cssClass: "jp-video-270p" 1834 }, 1835 sizeFull: { 1836 width: "100%", 1837 height: "100%", 1838 cssClass: "jp-video-full" 1839 } 1840 }, 1841 instances: {}, // Static Object 1842 status: { // Instanced in _init() 1843 src: "", 1844 media: {}, 1845 paused: true, 1846 format: {}, 1847 formatType: "", 1848 waitForPlay: true, // Same as waitForLoad except in case where preloading. 1849 waitForLoad: true, 1850 srcSet: false, 1851 video: false, // True if playing a video 1852 seekPercent: 0, 1853 currentPercentRelative: 0, 1854 currentPercentAbsolute: 0, 1855 currentTime: 0, 1856 duration: 0, 1857 remaining: 0, 1858 videoWidth: 0, // Intrinsic width of the video in pixels. 1859 videoHeight: 0, // Intrinsic height of the video in pixels. 1860 readyState: 0, 1861 networkState: 0, 1862 playbackRate: 1, // Warning - Now both an option and a status property 1863 ended: 0 1864 1865/* Persistant status properties created dynamically at _init(): 1866 width 1867 height 1868 cssClass 1869 nativeVideoControls 1870 noFullWindow 1871 noVolume 1872 playbackRateEnabled // Warning - Technically, we can have both Flash and HTML, so this might not be correct if the Flash is active. That is a niche case. 1873*/ 1874 }, 1875 1876 internal: { // Instanced in _init() 1877 ready: false 1878 // instance: undefined 1879 // domNode: undefined 1880 // htmlDlyCmdId: undefined 1881 // autohideId: undefined 1882 // cmdsIgnored 1883 }, 1884 solution: { // Static Object: Defines the solutions built in jPlayer. 1885 html: true, 1886 flash: true 1887 }, 1888 // 'MPEG-4 support' : canPlayType('video/mp4; codecs="mp4v.20.8"') 1889 format: { // Static Object 1890 mp3: { 1891 codec: 'audio/mpeg; codecs="mp3"', 1892 flashCanPlay: true, 1893 media: 'audio' 1894 }, 1895 m4a: { // AAC / MP4 1896 codec: 'audio/mp4; codecs="mp4a.40.2"', 1897 flashCanPlay: true, 1898 media: 'audio' 1899 }, 1900 m3u8a: { // AAC / MP4 / Apple HLS 1901 codec: 'application/vnd.apple.mpegurl; codecs="mp4a.40.2"', 1902 flashCanPlay: false, 1903 media: 'audio' 1904 }, 1905 m3ua: { // M3U 1906 codec: 'audio/mpegurl', 1907 flashCanPlay: false, 1908 media: 'audio' 1909 }, 1910 oga: { // OGG 1911 codec: 'audio/ogg; codecs="vorbis, opus"', 1912 flashCanPlay: false, 1913 media: 'audio' 1914 }, 1915 flac: { // FLAC 1916 codec: 'audio/x-flac', 1917 flashCanPlay: false, 1918 media: 'audio' 1919 }, 1920 wav: { // PCM 1921 codec: 'audio/wav; codecs="1"', 1922 flashCanPlay: false, 1923 media: 'audio' 1924 }, 1925 webma: { // WEBM 1926 codec: 'audio/webm; codecs="vorbis"', 1927 flashCanPlay: false, 1928 media: 'audio' 1929 }, 1930 fla: { // FLV / F4A 1931 codec: 'audio/x-flv', 1932 flashCanPlay: true, 1933 media: 'audio' 1934 }, 1935 rtmpa: { // RTMP AUDIO 1936 codec: 'audio/rtmp; codecs="rtmp"', 1937 flashCanPlay: true, 1938 media: 'audio' 1939 }, 1940 m4v: { // H.264 / MP4 1941 codec: 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"', 1942 flashCanPlay: true, 1943 media: 'video' 1944 }, 1945 m3u8v: { // H.264 / AAC / MP4 / Apple HLS 1946 codec: 'application/vnd.apple.mpegurl; codecs="avc1.42E01E, mp4a.40.2"', 1947 flashCanPlay: false, 1948 media: 'video' 1949 }, 1950 m3uv: { // M3U 1951 codec: 'audio/mpegurl', 1952 flashCanPlay: false, 1953 media: 'video' 1954 }, 1955 ogv: { // OGG 1956 codec: 'video/ogg; codecs="theora, vorbis"',
vendor: 63,235 bytes, lines 1957-3733
1957 flashCanPlay: false, 1958 media: 'video' 1959 }, 1960 webmv: { // WEBM 1961 codec: 'video/webm; codecs="vorbis, vp8"', 1962 flashCanPlay: false, 1963 media: 'video' 1964 }, 1965 flv: { // FLV / F4V 1966 codec: 'video/x-flv', 1967 flashCanPlay: true, 1968 media: 'video' 1969 }, 1970 rtmpv: { // RTMP VIDEO 1971 codec: 'video/rtmp; codecs="rtmp"', 1972 flashCanPlay: true, 1973 media: 'video' 1974 } 1975 }, 1976 _init: function() { 1977 var self = this; 1978 1979 this.element.empty(); 1980 1981 this.status = $.extend({}, this.status); // Copy static to unique instance. 1982 this.internal = $.extend({}, this.internal); // Copy static to unique instance. 1983 1984 // Initialize the time format 1985 this.options.timeFormat = $.extend({}, $.jPlayer.timeFormat, this.options.timeFormat); 1986 1987 // On iOS, assume commands will be ignored before user initiates them. 1988 this.internal.cmdsIgnored = $.jPlayer.platform.ipad || $.jPlayer.platform.iphone || $.jPlayer.platform.ipod; 1989 1990 this.internal.domNode = this.element.get(0); 1991 1992 // Add key bindings focus to 1st jPlayer instanced with key control enabled. 1993 if(this.options.keyEnabled && !$.jPlayer.focus) { 1994 $.jPlayer.focus = this; 1995 } 1996 1997 // A fix for Android where older (2.3) and even some 4.x devices fail to work when changing the *audio* SRC and then playing immediately. 1998 this.androidFix = { 1999 setMedia: false, // True when media set 2000 play: false, // True when a progress event will instruct the media to play 2001 pause: false, // True when a progress event will instruct the media to pause at a time. 2002 time: NaN // The play(time) parameter 2003 }; 2004 if($.jPlayer.platform.android) { 2005 this.options.preload = this.options.preload !== 'auto' ? 'metadata' : 'auto'; // Default to metadata, but allow auto. 2006 } 2007 2008 this.formats = []; // Array based on supplied string option. Order defines priority. 2009 this.solutions = []; // Array based on solution string option. Order defines priority. 2010 this.require = {}; // Which media types are required: video, audio. 2011 2012 this.htmlElement = {}; // DOM elements created by jPlayer 2013 this.html = {}; // In _init()'s this.desired code and setmedia(): Accessed via this[solution], where solution from this.solutions array. 2014 this.html.audio = {}; 2015 this.html.video = {}; 2016 this.flash = {}; // In _init()'s this.desired code and setmedia(): Accessed via this[solution], where solution from this.solutions array. 2017 2018 this.css = {}; 2019 this.css.cs = {}; // Holds the css selector strings 2020 this.css.jq = {}; // Holds jQuery selectors. ie., $(css.cs.method) 2021 2022 this.ancestorJq = []; // Holds jQuery selector of cssSelectorAncestor. Init would use $() instead of [], but it is only 1.4+ 2023 2024 this.options.volume = this._limitValue(this.options.volume, 0, 1); // Limit volume value's bounds. 2025 2026 // Create the formats array, with prority based on the order of the supplied formats string 2027 $.each(this.options.supplied.toLowerCase().split(","), function(index1, value1) { 2028 var format = value1.replace(/^\s+|\s+$/g, ""); //trim 2029 if(self.format[format]) { // Check format is valid. 2030 var dupFound = false; 2031 $.each(self.formats, function(index2, value2) { // Check for duplicates 2032 if(format === value2) { 2033 dupFound = true; 2034 return false; 2035 } 2036 }); 2037 if(!dupFound) { 2038 self.formats.push(format); 2039 } 2040 } 2041 }); 2042 2043 // Create the solutions array, with prority based on the order of the solution string 2044 $.each(this.options.solution.toLowerCase().split(","), function(index1, value1) { 2045 var solution = value1.replace(/^\s+|\s+$/g, ""); //trim 2046 if(self.solution[solution]) { // Check solution is valid. 2047 var dupFound = false; 2048 $.each(self.solutions, function(index2, value2) { // Check for duplicates 2049 if(solution === value2) { 2050 dupFound = true; 2051 return false; 2052 } 2053 }); 2054 if(!dupFound) { 2055 self.solutions.push(solution); 2056 } 2057 } 2058 }); 2059 2060 this.internal.instance = "jp_" + this.count; 2061 this.instances[this.internal.instance] = this.element; 2062 2063 // Check the jPlayer div has an id and create one if required. Important for Flash to know the unique id for comms. 2064 if(!this.element.attr("id")) { 2065 this.element.attr("id", this.options.idPrefix + "_jplayer_" + this.count); 2066 } 2067 2068 this.internal.self = $.extend({}, { 2069 id: this.element.attr("id"), 2070 jq: this.element 2071 }); 2072 this.internal.audio = $.extend({}, { 2073 id: this.options.idPrefix + "_audio_" + this.count, 2074 jq: undefined 2075 }); 2076 this.internal.video = $.extend({}, { 2077 id: this.options.idPrefix + "_video_" + this.count, 2078 jq: undefined 2079 }); 2080 this.internal.flash = $.extend({}, { 2081 id: this.options.idPrefix + "_flash_" + this.count, 2082 jq: undefined, 2083 swf: this.options.swfPath + (this.options.swfPath.toLowerCase().slice(-4) !== ".swf" ? (this.options.swfPath && this.options.swfPath.slice(-1) !== "/" ? "/" : "") + "Jplayer.swf" : "") 2084 }); 2085 this.internal.poster = $.extend({}, { 2086 id: this.options.idPrefix + "_poster_" + this.count, 2087 jq: undefined 2088 }); 2089 2090 // Register listeners defined in the constructor 2091 $.each($.jPlayer.event, function(eventName,eventType) { 2092 if(self.options[eventName] !== undefined) { 2093 self.element.bind(eventType + ".jPlayer", self.options[eventName]); // With .jPlayer namespace. 2094 self.options[eventName] = undefined; // Destroy the handler pointer copy on the options. Reason, events can be added/removed in other ways so this could be obsolete and misleading. 2095 } 2096 }); 2097 2098 // Determine if we require solutions for audio, video or both media types. 2099 this.require.audio = false; 2100 this.require.video = false; 2101 $.each(this.formats, function(priority, format) { 2102 self.require[self.format[format].media] = true; 2103 }); 2104 2105 // Now required types are known, finish the options default settings. 2106 if(this.require.video) { 2107 this.options = $.extend(true, {}, 2108 this.optionsVideo, 2109 this.options 2110 ); 2111 } else { 2112 this.options = $.extend(true, {}, 2113 this.optionsAudio, 2114 this.options 2115 ); 2116 } 2117 this._setSize(); // update status and jPlayer element size 2118 2119 // Determine the status for Blocklisted options. 2120 this.status.nativeVideoControls = this._uaBlocklist(this.options.nativeVideoControls); 2121 this.status.noFullWindow = this._uaBlocklist(this.options.noFullWindow); 2122 this.status.noVolume = this._uaBlocklist(this.options.noVolume); 2123 2124 // Create event handlers if native fullscreen is supported 2125 if($.jPlayer.nativeFeatures.fullscreen.api.fullscreenEnabled) { 2126 this._fullscreenAddEventListeners(); 2127 } 2128 2129 // The native controls are only for video and are disabled when audio is also used. 2130 this._restrictNativeVideoControls(); 2131 2132 // Create the poster image. 2133 this.htmlElement.poster = document.createElement('img'); 2134 this.htmlElement.poster.id = this.internal.poster.id; 2135 this.htmlElement.poster.onload = function() { // Note that this did not work on Firefox 3.6: poster.addEventListener("onload", function() {}, false); Did not investigate x-browser. 2136 if(!self.status.video || self.status.waitForPlay) { 2137 self.internal.poster.jq.show(); 2138 } 2139 }; 2140 this.element.append(this.htmlElement.poster); 2141 this.internal.poster.jq = $("#" + this.internal.poster.id); 2142 this.internal.poster.jq.css({'width': this.status.width, 'height': this.status.height}); 2143 this.internal.poster.jq.hide(); 2144 this.internal.poster.jq.bind("click.jPlayer", function() { 2145 self._trigger($.jPlayer.event.click); 2146 }); 2147 2148 // Generate the required media elements 2149 this.html.audio.available = false; 2150 if(this.require.audio) { // If a supplied format is audio 2151 this.htmlElement.audio = document.createElement('audio'); 2152 this.htmlElement.audio.id = this.internal.audio.id; 2153 this.html.audio.available = !!this.htmlElement.audio.canPlayType && this._testCanPlayType(this.htmlElement.audio); // Test is for IE9 on Win Server 2008. 2154 } 2155 this.html.video.available = false; 2156 if(this.require.video) { // If a supplied format is video 2157 this.htmlElement.video = document.createElement('video'); 2158 this.htmlElement.video.id = this.internal.video.id; 2159 this.html.video.available = !!this.htmlElement.video.canPlayType && this._testCanPlayType(this.htmlElement.video); // Test is for IE9 on Win Server 2008. 2160 } 2161 2162 this.flash.available = this._checkForFlash(10.1); 2163 2164 this.html.canPlay = {}; 2165 this.flash.canPlay = {}; 2166 $.each(this.formats, function(priority, format) { 2167 self.html.canPlay[format] = self.html[self.format[format].media].available && "" !== self.htmlElement[self.format[format].media].canPlayType(self.format[format].codec); 2168 self.flash.canPlay[format] = self.format[format].flashCanPlay && self.flash.available; 2169 }); 2170 this.html.desired = false; 2171 this.flash.desired = false; 2172 $.each(this.solutions, function(solutionPriority, solution) { 2173 if(solutionPriority === 0) { 2174 self[solution].desired = true; 2175 } else { 2176 var audioCanPlay = false; 2177 var videoCanPlay = false; 2178 $.each(self.formats, function(formatPriority, format) { 2179 if(self[self.solutions[0]].canPlay[format]) { // The other solution can play 2180 if(self.format[format].media === 'video') { 2181 videoCanPlay = true; 2182 } else { 2183 audioCanPlay = true; 2184 } 2185 } 2186 }); 2187 self[solution].desired = (self.require.audio && !audioCanPlay) || (self.require.video && !videoCanPlay); 2188 } 2189 }); 2190 // This is what jPlayer will support, based on solution and supplied. 2191 this.html.support = {}; 2192 this.flash.support = {}; 2193 $.each(this.formats, function(priority, format) { 2194 self.html.support[format] = self.html.canPlay[format] && self.html.desired; 2195 self.flash.support[format] = self.flash.canPlay[format] && self.flash.desired; 2196 }); 2197 // If jPlayer is supporting any format in a solution, then the solution is used. 2198 this.html.used = false; 2199 this.flash.used = false; 2200 $.each(this.solutions, function(solutionPriority, solution) { 2201 $.each(self.formats, function(formatPriority, format) { 2202 if(self[solution].support[format]) { 2203 self[solution].used = true; 2204 return false; 2205 } 2206 }); 2207 }); 2208 2209 // Init solution active state and the event gates to false. 2210 this._resetActive(); 2211 this._resetGate(); 2212 2213 // Set up the css selectors for the control and feedback entities. 2214 this._cssSelectorAncestor(this.options.cssSelectorAncestor); 2215 2216 // If neither html nor flash are being used by this browser, then media playback is not possible. Trigger an error event. 2217 if(!(this.html.used || this.flash.used)) { 2218 this._error( { 2219 type: $.jPlayer.error.NO_SOLUTION, 2220 context: "{solution:'" + this.options.solution + "', supplied:'" + this.options.supplied + "'}", 2221 message: $.jPlayer.errorMsg.NO_SOLUTION, 2222 hint: $.jPlayer.errorHint.NO_SOLUTION 2223 }); 2224 if(this.css.jq.noSolution.length) { 2225 this.css.jq.noSolution.show(); 2226 } 2227 } else { 2228 if(this.css.jq.noSolution.length) { 2229 this.css.jq.noSolution.hide(); 2230 } 2231 } 2232 2233 // Add the flash solution if it is being used. 2234 if(this.flash.used) { 2235 var htmlObj, 2236 flashVars = 'jQuery=' + encodeURI(this.options.noConflict) + '&id=' + encodeURI(this.internal.self.id) + '&vol=' + this.options.volume + '&muted=' + this.options.muted; 2237 2238 // Code influenced by SWFObject 2.2: http://code.google.com/p/swfobject/ 2239 // Non IE browsers have an initial Flash size of 1 by 1 otherwise the wmode affected the Flash ready event. 2240 2241 if($.jPlayer.browser.msie && (Number($.jPlayer.browser.version) < 9 || $.jPlayer.browser.documentMode < 9)) { 2242 var objStr = '<object id="' + this.internal.flash.id + '" classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="0" height="0" tabindex="-1"></object>'; 2243 2244 var paramStr = [ 2245 '<param name="movie" value="' + this.internal.flash.swf + '" />', 2246 '<param name="FlashVars" value="' + flashVars + '" />', 2247 '<param name="allowScriptAccess" value="always" />', 2248 '<param name="bgcolor" value="' + this.options.backgroundColor + '" />', 2249 '<param name="wmode" value="' + this.options.wmode + '" />' 2250 ]; 2251 2252 htmlObj = document.createElement(objStr); 2253 for(var i=0; i < paramStr.length; i++) { 2254 htmlObj.appendChild(document.createElement(paramStr[i])); 2255 } 2256 } else { 2257 var createParam = function(el, n, v) { 2258 var p = document.createElement("param"); 2259 p.setAttribute("name", n); 2260 p.setAttribute("value", v); 2261 el.appendChild(p); 2262 }; 2263 2264 htmlObj = document.createElement("object"); 2265 htmlObj.setAttribute("id", this.internal.flash.id); 2266 htmlObj.setAttribute("name", this.internal.flash.id); 2267 htmlObj.setAttribute("data", this.internal.flash.swf); 2268 htmlObj.setAttribute("type", "application/x-shockwave-flash"); 2269 htmlObj.setAttribute("width", "1"); // Non-zero 2270 htmlObj.setAttribute("height", "1"); // Non-zero 2271 htmlObj.setAttribute("tabindex", "-1"); 2272 createParam(htmlObj, "flashvars", flashVars); 2273 createParam(htmlObj, "allowscriptaccess", "always"); 2274 createParam(htmlObj, "bgcolor", this.options.backgroundColor); 2275 createParam(htmlObj, "wmode", this.options.wmode); 2276 } 2277 2278 this.element.append(htmlObj); 2279 this.internal.flash.jq = $(htmlObj); 2280 } 2281 2282 // Setup playbackRate ability before using _addHtmlEventListeners() 2283 if(this.html.used && !this.flash.used) { // If only HTML 2284 // Using the audio element capabilities for playbackRate. ie., Assuming video element is the same. 2285 this.status.playbackRateEnabled = this._testPlaybackRate('audio'); 2286 } else { 2287 this.status.playbackRateEnabled = false; 2288 } 2289 2290 this._updatePlaybackRate(); 2291 2292 // Add the HTML solution if being used. 2293 if(this.html.used) { 2294 2295 // The HTML Audio handlers 2296 if(this.html.audio.available) { 2297 this._addHtmlEventListeners(this.htmlElement.audio, this.html.audio); 2298 this.element.append(this.htmlElement.audio); 2299 this.internal.audio.jq = $("#" + this.internal.audio.id); 2300 } 2301 2302 // The HTML Video handlers 2303 if(this.html.video.available) { 2304 this._addHtmlEventListeners(this.htmlElement.video, this.html.video); 2305 this.element.append(this.htmlElement.video); 2306 this.internal.video.jq = $("#" + this.internal.video.id); 2307 if(this.status.nativeVideoControls) { 2308 this.internal.video.jq.css({'width': this.status.width, 'height': this.status.height}); 2309 } else { 2310 this.internal.video.jq.css({'width':'0px', 'height':'0px'}); // Using size 0x0 since a .hide() causes issues in iOS 2311 } 2312 this.internal.video.jq.bind("click.jPlayer", function() { 2313 self._trigger($.jPlayer.event.click); 2314 }); 2315 } 2316 } 2317 2318 // Create the bridge that emulates the HTML Media element on the jPlayer DIV 2319 if( this.options.emulateHtml ) { 2320 this._emulateHtmlBridge(); 2321 } 2322 2323 if(this.html.used && !this.flash.used) { // If only HTML, then emulate flash ready() call after 100ms. 2324 setTimeout( function() { 2325 self.internal.ready = true; 2326 self.version.flash = "n/a"; 2327 self._trigger($.jPlayer.event.repeat); // Trigger the repeat event so its handler can initialize itself with the loop option. 2328 self._trigger($.jPlayer.event.ready); 2329 }, 100); 2330 } 2331 2332 // Initialize the interface components with the options. 2333 this._updateNativeVideoControls(); 2334 // The other controls are now setup in _cssSelectorAncestor() 2335 if(this.css.jq.videoPlay.length) { 2336 this.css.jq.videoPlay.hide(); 2337 } 2338 2339 $.jPlayer.prototype.count++; // Change static variable via prototype. 2340 }, 2341 destroy: function() { 2342 // MJP: The background change remains. Would need to store the original to restore it correctly. 2343 // MJP: The jPlayer element's size change remains. 2344 2345 // Clear the media to reset the GUI and stop any downloads. Streams on some browsers had persited. (Chrome) 2346 this.clearMedia(); 2347 // Remove the size/sizeFull cssClass from the cssSelectorAncestor 2348 this._removeUiClass(); 2349 // Remove the times from the GUI 2350 if(this.css.jq.currentTime.length) { 2351 this.css.jq.currentTime.text(""); 2352 } 2353 if(this.css.jq.duration.length) { 2354 this.css.jq.duration.text(""); 2355 } 2356 // Remove any bindings from the interface controls. 2357 $.each(this.css.jq, function(fn, jq) { 2358 // Check selector is valid before trying to execute method. 2359 if(jq.length) { 2360 jq.unbind(".jPlayer"); 2361 } 2362 }); 2363 // Remove the click handlers for $.jPlayer.event.click 2364 this.internal.poster.jq.unbind(".jPlayer"); 2365 if(this.internal.video.jq) { 2366 this.internal.video.jq.unbind(".jPlayer"); 2367 } 2368 // Remove the fullscreen event handlers 2369 this._fullscreenRemoveEventListeners(); 2370 // Remove key bindings 2371 if(this === $.jPlayer.focus) { 2372 $.jPlayer.focus = null; 2373 } 2374 // Destroy the HTML bridge. 2375 if(this.options.emulateHtml) { 2376 this._destroyHtmlBridge(); 2377 } 2378 this.element.removeData("jPlayer"); // Remove jPlayer data 2379 this.element.unbind(".jPlayer"); // Remove all event handlers created by the jPlayer constructor 2380 this.element.empty(); // Remove the inserted child elements 2381 2382 delete this.instances[this.internal.instance]; // Clear the instance on the static instance object 2383 }, 2384 enable: function() { // Plan to implement 2385 // options.disabled = false 2386 }, 2387 disable: function () { // Plan to implement 2388 // options.disabled = true 2389 }, 2390 _testCanPlayType: function(elem) { 2391 // IE9 on Win Server 2008 did not implement canPlayType(), but it has the property. 2392 try { 2393 elem.canPlayType(this.format.mp3.codec); // The type is irrelevant. 2394 return true; 2395 } catch(err) { 2396 return false; 2397 } 2398 }, 2399 _testPlaybackRate: function(type) { 2400 // type: String 'audio' or 'video' 2401 var el, rate = 0.5; 2402 type = typeof type === 'string' ? type : 'audio'; 2403 el = document.createElement(type); 2404 // Wrapping in a try/catch, just in case older HTML5 browsers throw and error. 2405 try { 2406 if('playbackRate' in el) { 2407 el.playbackRate = rate; 2408 return el.playbackRate === rate; 2409 } else { 2410 return false; 2411 } 2412 } catch(err) { 2413 return false; 2414 } 2415 }, 2416 _uaBlocklist: function(list) { 2417 // list : object with properties that are all regular expressions. Property names are irrelevant. 2418 // Returns true if the user agent is matched in list. 2419 var ua = navigator.userAgent.toLowerCase(), 2420 block = false; 2421 2422 $.each(list, function(p, re) { 2423 if(re && re.test(ua)) { 2424 block = true; 2425 return false; // exit $.each. 2426 } 2427 }); 2428 return block; 2429 }, 2430 _restrictNativeVideoControls: function() { 2431 // Fallback to noFullWindow when nativeVideoControls is true and audio media is being used. Affects when both media types are used. 2432 if(this.require.audio) { 2433 if(this.status.nativeVideoControls) { 2434 this.status.nativeVideoControls = false; 2435 this.status.noFullWindow = true; 2436 } 2437 } 2438 }, 2439 _updateNativeVideoControls: function() { 2440 if(this.html.video.available && this.html.used) { 2441 // Turn the HTML Video controls on/off 2442 this.htmlElement.video.controls = this.status.nativeVideoControls; 2443 // Show/hide the jPlayer GUI. 2444 this._updateAutohide(); 2445 // For when option changed. The poster image is not updated, as it is dealt with in setMedia(). Acceptable degradation since seriously doubt these options will change on the fly. Can again review later. 2446 if(this.status.nativeVideoControls && this.require.video) { 2447 this.internal.poster.jq.hide(); 2448 this.internal.video.jq.css({'width': this.status.width, 'height': this.status.height}); 2449 } else if(this.status.waitForPlay && this.status.video) { 2450 this.internal.poster.jq.show(); 2451 this.internal.video.jq.css({'width': '0px', 'height': '0px'}); 2452 } 2453 } 2454 }, 2455 _addHtmlEventListeners: function(mediaElement, entity) { 2456 var self = this; 2457 mediaElement.preload = this.options.preload; 2458 mediaElement.muted = this.options.muted; 2459 mediaElement.volume = this.options.volume; 2460 2461 if(this.status.playbackRateEnabled) { 2462 mediaElement.defaultPlaybackRate = this.options.defaultPlaybackRate; 2463 mediaElement.playbackRate = this.options.playbackRate; 2464 } 2465 2466 // Create the event listeners 2467 // Only want the active entity to affect jPlayer and bubble events. 2468 // Using entity.gate so that object is referenced and gate property always current 2469 2470 mediaElement.addEventListener("progress", function() { 2471 if(entity.gate) { 2472 if(self.internal.cmdsIgnored && this.readyState > 0) { // Detect iOS executed the command 2473 self.internal.cmdsIgnored = false; 2474 } 2475 self.androidFix.setMedia = false; // Disable the fix after the first progress event. 2476 if(self.androidFix.play) { // Play Android audio - performing the fix. 2477 self.androidFix.play = false; 2478 self.play(self.androidFix.time); 2479 } 2480 if(self.androidFix.pause) { // Pause Android audio at time - performing the fix. 2481 self.androidFix.pause = false; 2482 self.pause(self.androidFix.time); 2483 } 2484 self._getHtmlStatus(mediaElement); 2485 self._updateInterface(); 2486 self._trigger($.jPlayer.event.progress); 2487 } 2488 }, false); 2489 mediaElement.addEventListener("timeupdate", function() { 2490 if(entity.gate) { 2491 self._getHtmlStatus(mediaElement); 2492 self._updateInterface(); 2493 self._trigger($.jPlayer.event.timeupdate); 2494 } 2495 }, false); 2496 mediaElement.addEventListener("durationchange", function() { 2497 if(entity.gate) { 2498 self._getHtmlStatus(mediaElement); 2499 self._updateInterface(); 2500 self._trigger($.jPlayer.event.durationchange); 2501 } 2502 }, false); 2503 mediaElement.addEventListener("play", function() { 2504 if(entity.gate) { 2505 self._updateButtons(true); 2506 self._html_checkWaitForPlay(); // So the native controls update this variable and puts the hidden interface in the correct state. Affects toggling native controls. 2507 self._trigger($.jPlayer.event.play); 2508 } 2509 }, false); 2510 mediaElement.addEventListener("playing", function() { 2511 if(entity.gate) { 2512 self._updateButtons(true); 2513 self._seeked(); 2514 self._trigger($.jPlayer.event.playing); 2515 } 2516 }, false); 2517 mediaElement.addEventListener("pause", function() { 2518 if(entity.gate) { 2519 self._updateButtons(false); 2520 self._trigger($.jPlayer.event.pause); 2521 } 2522 }, false); 2523 mediaElement.addEventListener("waiting", function() { 2524 if(entity.gate) { 2525 self._seeking(); 2526 self._trigger($.jPlayer.event.waiting); 2527 } 2528 }, false); 2529 mediaElement.addEventListener("seeking", function() { 2530 if(entity.gate) { 2531 self._seeking(); 2532 self._trigger($.jPlayer.event.seeking); 2533 } 2534 }, false); 2535 mediaElement.addEventListener("seeked", function() { 2536 if(entity.gate) { 2537 self._seeked(); 2538 self._trigger($.jPlayer.event.seeked); 2539 } 2540 }, false); 2541 mediaElement.addEventListener("volumechange", function() { 2542 if(entity.gate) { 2543 // Read the values back from the element as the Blackberry PlayBook shares the volume with the physical buttons master volume control. 2544 // However, when tested 6th July 2011, those buttons do not generate an event. The physical play/pause button does though. 2545 self.options.volume = mediaElement.volume; 2546 self.options.muted = mediaElement.muted; 2547 self._updateMute(); 2548 self._updateVolume(); 2549 self._trigger($.jPlayer.event.volumechange); 2550 } 2551 }, false); 2552 mediaElement.addEventListener("ratechange", function() { 2553 if(entity.gate) { 2554 self.options.defaultPlaybackRate = mediaElement.defaultPlaybackRate; 2555 self.options.playbackRate = mediaElement.playbackRate; 2556 self._updatePlaybackRate(); 2557 self._trigger($.jPlayer.event.ratechange); 2558 } 2559 }, false); 2560 mediaElement.addEventListener("suspend", function() { // Seems to be the only way of capturing that the iOS4 browser did not actually play the media from the page code. ie., It needs a user gesture. 2561 if(entity.gate) { 2562 self._seeked(); 2563 self._trigger($.jPlayer.event.suspend); 2564 } 2565 }, false); 2566 mediaElement.addEventListener("ended", function() { 2567 if(entity.gate) { 2568 // Order of the next few commands are important. Change the time and then pause. 2569 // Solves a bug in Firefox, where issuing pause 1st causes the media to play from the start. ie., The pause is ignored. 2570 if(!$.jPlayer.browser.webkit) { // Chrome crashes if you do this in conjunction with a setMedia command in an ended event handler. ie., The playlist demo. 2571 self.htmlElement.media.currentTime = 0; // Safari does not care about this command. ie., It works with or without this line. (Both Safari and Chrome are Webkit.) 2572 } 2573 self.htmlElement.media.pause(); // Pause otherwise a click on the progress bar will play from that point, when it shouldn't, since it stopped playback. 2574 self._updateButtons(false); 2575 self._getHtmlStatus(mediaElement, true); // With override true. Otherwise Chrome leaves progress at full. 2576 self._updateInterface(); 2577 self._trigger($.jPlayer.event.ended); 2578 } 2579 }, false); 2580 mediaElement.addEventListener("error", function() { 2581 if(entity.gate) { 2582 self._updateButtons(false); 2583 self._seeked(); 2584 if(self.status.srcSet) { // Deals with case of clearMedia() causing an error event. 2585 clearTimeout(self.internal.htmlDlyCmdId); // Clears any delayed commands used in the HTML solution. 2586 self.status.waitForLoad = true; // Allows the load operation to try again. 2587 self.status.waitForPlay = true; // Reset since a play was captured. 2588 if(self.status.video && !self.status.nativeVideoControls) { 2589 self.internal.video.jq.css({'width':'0px', 'height':'0px'}); 2590 } 2591 if(self._validString(self.status.media.poster) && !self.status.nativeVideoControls) { 2592 self.internal.poster.jq.show(); 2593 } 2594 if(self.css.jq.videoPlay.length) { 2595 self.css.jq.videoPlay.show(); 2596 } 2597 self._error( { 2598 type: $.jPlayer.error.URL, 2599 context: self.status.src, // this.src shows absolute urls. Want context to show the url given. 2600 message: $.jPlayer.errorMsg.URL, 2601 hint: $.jPlayer.errorHint.URL 2602 }); 2603 } 2604 } 2605 }, false); 2606 // Create all the other event listeners that bubble up to a jPlayer event from html, without being used by jPlayer. 2607 $.each($.jPlayer.htmlEvent, function(i, eventType) { 2608 mediaElement.addEventListener(this, function() { 2609 if(entity.gate) { 2610 self._trigger($.jPlayer.event[eventType]); 2611 } 2612 }, false); 2613 }); 2614 }, 2615 _getHtmlStatus: function(media, override) { 2616 var ct = 0, cpa = 0, sp = 0, cpr = 0; 2617 2618 // Fixes the duration bug in iOS, where the durationchange event occurs when media.duration is not always correct. 2619 // Fixes the initial duration bug in BB OS7, where the media.duration is infinity and displays as NaN:NaN due to Date() using inifity. 2620 if(isFinite(media.duration)) { 2621 this.status.duration = media.duration; 2622 } 2623 2624 ct = media.currentTime; 2625 cpa = (this.status.duration > 0) ? 100 * ct / this.status.duration : 0; 2626 if((typeof media.seekable === "object") && (media.seekable.length > 0)) { 2627 sp = (this.status.duration > 0) ? 100 * media.seekable.end(media.seekable.length-1) / this.status.duration : 100; 2628 cpr = (this.status.duration > 0) ? 100 * media.currentTime / media.seekable.end(media.seekable.length-1) : 0; // Duration conditional for iOS duration bug. ie., seekable.end is a NaN in that case. 2629 } else { 2630 sp = 100; 2631 cpr = cpa; 2632 } 2633 2634 if(override) { 2635 ct = 0; 2636 cpr = 0; 2637 cpa = 0; 2638 } 2639 2640 this.status.seekPercent = sp; 2641 this.status.currentPercentRelative = cpr; 2642 this.status.currentPercentAbsolute = cpa; 2643 this.status.currentTime = ct; 2644 2645 this.status.remaining = this.status.duration - this.status.currentTime; 2646 2647 this.status.videoWidth = media.videoWidth; 2648 this.status.videoHeight = media.videoHeight; 2649 2650 this.status.readyState = media.readyState; 2651 this.status.networkState = media.networkState; 2652 this.status.playbackRate = media.playbackRate; 2653 this.status.ended = media.ended; 2654 }, 2655 _resetStatus: function() { 2656 this.status = $.extend({}, this.status, $.jPlayer.prototype.status); // Maintains the status properties that persist through a reset. 2657 }, 2658 _trigger: function(eventType, error, warning) { // eventType always valid as called using $.jPlayer.event.eventType 2659 var event = $.Event(eventType); 2660 event.jPlayer = {}; 2661 event.jPlayer.version = $.extend({}, this.version); 2662 event.jPlayer.options = $.extend(true, {}, this.options); // Deep copy 2663 event.jPlayer.status = $.extend(true, {}, this.status); // Deep copy 2664 event.jPlayer.html = $.extend(true, {}, this.html); // Deep copy 2665 event.jPlayer.flash = $.extend(true, {}, this.flash); // Deep copy 2666 if(error) { 2667 event.jPlayer.error = $.extend({}, error); 2668 } 2669 if(warning) { 2670 event.jPlayer.warning = $.extend({}, warning); 2671 } 2672 this.element.trigger(event); 2673 }, 2674 jPlayerFlashEvent: function(eventType, status) { // Called from Flash 2675 if(eventType === $.jPlayer.event.ready) { 2676 if(!this.internal.ready) { 2677 this.internal.ready = true; 2678 this.internal.flash.jq.css({'width':'0px', 'height':'0px'}); // Once Flash generates the ready event, minimise to zero as it is not affected by wmode anymore. 2679 2680 this.version.flash = status.version; 2681 if(this.version.needFlash !== this.version.flash) { 2682 this._error( { 2683 type: $.jPlayer.error.VERSION, 2684 context: this.version.flash, 2685 message: $.jPlayer.errorMsg.VERSION + this.version.flash, 2686 hint: $.jPlayer.errorHint.VERSION 2687 }); 2688 } 2689 this._trigger($.jPlayer.event.repeat); // Trigger the repeat event so its handler can initialize itself with the loop option. 2690 this._trigger(eventType); 2691 } else { 2692 // This condition occurs if the Flash is hidden and then shown again. 2693 // Firefox also reloads the Flash if the CSS position changes. position:fixed is used for full screen. 2694 2695 // Only do this if the Flash is the solution being used at the moment. Affects Media players where both solution may be being used. 2696 if(this.flash.gate) { 2697 2698 // Send the current status to the Flash now that it is ready (available) again. 2699 if(this.status.srcSet) { 2700 2701 // Need to read original status before issuing the setMedia command. 2702 var currentTime = this.status.currentTime, 2703 paused = this.status.paused; 2704 2705 this.setMedia(this.status.media); 2706 this.volumeWorker(this.options.volume); 2707 if(currentTime > 0) { 2708 if(paused) { 2709 this.pause(currentTime); 2710 } else { 2711 this.play(currentTime); 2712 } 2713 } 2714 } 2715 this._trigger($.jPlayer.event.flashreset); 2716 } 2717 } 2718 } 2719 if(this.flash.gate) { 2720 switch(eventType) { 2721 case $.jPlayer.event.progress: 2722 this._getFlashStatus(status); 2723 this._updateInterface(); 2724 this._trigger(eventType); 2725 break; 2726 case $.jPlayer.event.timeupdate: 2727 this._getFlashStatus(status); 2728 this._updateInterface(); 2729 this._trigger(eventType); 2730 break; 2731 case $.jPlayer.event.play: 2732 this._seeked(); 2733 this._updateButtons(true); 2734 this._trigger(eventType); 2735 break; 2736 case $.jPlayer.event.pause: 2737 this._updateButtons(false); 2738 this._trigger(eventType); 2739 break; 2740 case $.jPlayer.event.ended: 2741 this._updateButtons(false); 2742 this._trigger(eventType); 2743 break; 2744 case $.jPlayer.event.click: 2745 this._trigger(eventType); // This could be dealt with by the default 2746 break; 2747 case $.jPlayer.event.error: 2748 this.status.waitForLoad = true; // Allows the load operation to try again. 2749 this.status.waitForPlay = true; // Reset since a play was captured. 2750 if(this.status.video) { 2751 this.internal.flash.jq.css({'width':'0px', 'height':'0px'}); 2752 } 2753 if(this._validString(this.status.media.poster)) { 2754 this.internal.poster.jq.show(); 2755 } 2756 if(this.css.jq.videoPlay.length && this.status.video) { 2757 this.css.jq.videoPlay.show(); 2758 } 2759 if(this.status.video) { // Set up for another try. Execute before error event. 2760 this._flash_setVideo(this.status.media); 2761 } else { 2762 this._flash_setAudio(this.status.media); 2763 } 2764 this._updateButtons(false); 2765 this._error( { 2766 type: $.jPlayer.error.URL, 2767 context:status.src, 2768 message: $.jPlayer.errorMsg.URL, 2769 hint: $.jPlayer.errorHint.URL 2770 }); 2771 break; 2772 case $.jPlayer.event.seeking: 2773 this._seeking(); 2774 this._trigger(eventType); 2775 break; 2776 case $.jPlayer.event.seeked: 2777 this._seeked(); 2778 this._trigger(eventType); 2779 break; 2780 case $.jPlayer.event.ready: 2781 // The ready event is handled outside the switch statement. 2782 // Captured here otherwise 2 ready events would be generated if the ready event handler used setMedia. 2783 break; 2784 default: 2785 this._trigger(eventType); 2786 } 2787 } 2788 return false; 2789 }, 2790 _getFlashStatus: function(status) { 2791 this.status.seekPercent = status.seekPercent; 2792 this.status.currentPercentRelative = status.currentPercentRelative; 2793 this.status.currentPercentAbsolute = status.currentPercentAbsolute; 2794 this.status.currentTime = status.currentTime; 2795 this.status.duration = status.duration; 2796 this.status.remaining = status.duration - status.currentTime; 2797 2798 this.status.videoWidth = status.videoWidth; 2799 this.status.videoHeight = status.videoHeight; 2800 2801 // The Flash does not generate this information in this release 2802 this.status.readyState = 4; // status.readyState; 2803 this.status.networkState = 0; // status.networkState; 2804 this.status.playbackRate = 1; // status.playbackRate; 2805 this.status.ended = false; // status.ended; 2806 }, 2807 _updateButtons: function(playing) { 2808 if(playing === undefined) { 2809 playing = !this.status.paused; 2810 } else { 2811 this.status.paused = !playing; 2812 } 2813 if(this.css.jq.play.length && this.css.jq.pause.length) { 2814 if(playing) { 2815 this.css.jq.play.hide(); 2816 this.css.jq.pause.show(); 2817 } else { 2818 this.css.jq.play.show(); 2819 this.css.jq.pause.hide(); 2820 } 2821 } 2822 if(this.css.jq.restoreScreen.length && this.css.jq.fullScreen.length) { 2823 if(this.status.noFullWindow) { 2824 this.css.jq.fullScreen.hide(); 2825 this.css.jq.restoreScreen.hide(); 2826 } else if(this.options.fullWindow) { 2827 this.css.jq.fullScreen.hide(); 2828 this.css.jq.restoreScreen.show(); 2829 } else { 2830 this.css.jq.fullScreen.show(); 2831 this.css.jq.restoreScreen.hide(); 2832 } 2833 } 2834 if(this.css.jq.repeat.length && this.css.jq.repeatOff.length) { 2835 if(this.options.loop) { 2836 this.css.jq.repeat.hide(); 2837 this.css.jq.repeatOff.show(); 2838 } else { 2839 this.css.jq.repeat.show(); 2840 this.css.jq.repeatOff.hide(); 2841 } 2842 } 2843 }, 2844 _updateInterface: function() { 2845 if(this.css.jq.seekBar.length) { 2846 this.css.jq.seekBar.width(this.status.seekPercent+"%"); 2847 } 2848 if(this.css.jq.playBar.length) { 2849 if(this.options.smoothPlayBar) { 2850 this.css.jq.playBar.stop().animate({ 2851 width: this.status.currentPercentAbsolute+"%" 2852 }, 250, "linear"); 2853 } else { 2854 this.css.jq.playBar.width(this.status.currentPercentRelative+"%"); 2855 } 2856 } 2857 var currentTimeText = ''; 2858 if(this.css.jq.currentTime.length) { 2859 currentTimeText = this._convertTime(this.status.currentTime); 2860 if(currentTimeText !== this.css.jq.currentTime.text()) { 2861 this.css.jq.currentTime.text(this._convertTime(this.status.currentTime)); 2862 } 2863 } 2864 var durationText = '', 2865 duration = this.status.duration, 2866 remaining = this.status.remaining; 2867 if(this.css.jq.duration.length) { 2868 if(typeof this.status.media.duration === 'string') { 2869 durationText = this.status.media.duration; 2870 } else { 2871 if(typeof this.status.media.duration === 'number') { 2872 duration = this.status.media.duration; 2873 remaining = duration - this.status.currentTime; 2874 } 2875 if(this.options.remainingDuration) { 2876 durationText = (remaining > 0 ? '-' : '') + this._convertTime(remaining); 2877 } else { 2878 durationText = this._convertTime(duration); 2879 } 2880 } 2881 if(durationText !== this.css.jq.duration.text()) { 2882 this.css.jq.duration.text(durationText); 2883 } 2884 } 2885 }, 2886 _convertTime: ConvertTime.prototype.time, 2887 _seeking: function() { 2888 if(this.css.jq.seekBar.length) { 2889 this.css.jq.seekBar.addClass("jp-seeking-bg"); 2890 } 2891 }, 2892 _seeked: function() { 2893 if(this.css.jq.seekBar.length) { 2894 this.css.jq.seekBar.removeClass("jp-seeking-bg"); 2895 } 2896 }, 2897 _resetGate: function() { 2898 this.html.audio.gate = false; 2899 this.html.video.gate = false; 2900 this.flash.gate = false; 2901 }, 2902 _resetActive: function() { 2903 this.html.active = false; 2904 this.flash.active = false; 2905 }, 2906 _escapeHtml: function(s) { 2907 return s.split('&').join('&').split('<').join('<').split('>').join('>').split('"').join('"'); 2908 }, 2909 _qualifyURL: function(url) { 2910 var el = document.createElement('div'); 2911 el.innerHTML= '<a href="' + this._escapeHtml(url) + '">x</a>'; 2912 return el.firstChild.href; 2913 }, 2914 _absoluteMediaUrls: function(media) { 2915 var self = this; 2916 $.each(media, function(type, url) { 2917 if(url && self.format[type]) { 2918 media[type] = self._qualifyURL(url); 2919 } 2920 }); 2921 return media; 2922 }, 2923 setMedia: function(media) { 2924 2925 /* media[format] = String: URL of format. Must contain all of the supplied option's video or audio formats. 2926 * media.poster = String: Video poster URL. 2927 * media.track = Array: Of objects defining the track element: kind, src, srclang, label, def. 2928 * media.stream = Boolean: * NOT IMPLEMENTED * Designating actual media streams. ie., "false/undefined" for files. Plan to refresh the flash every so often. 2929 */ 2930 2931 var self = this, 2932 supported = false, 2933 posterChanged = this.status.media.poster !== media.poster; // Compare before reset. Important for OSX Safari as this.htmlElement.poster.src is absolute, even if original poster URL was relative. 2934 2935 this._resetMedia(); 2936 this._resetGate(); 2937 this._resetActive(); 2938 2939 // Clear the Android Fix. 2940 this.androidFix.setMedia = false; 2941 this.androidFix.play = false; 2942 this.androidFix.pause = false; 2943 2944 // Convert all media URLs to absolute URLs. 2945 media = this._absoluteMediaUrls(media); 2946 2947 $.each(this.formats, function(formatPriority, format) { 2948 var isVideo = self.format[format].media === 'video'; 2949 $.each(self.solutions, function(solutionPriority, solution) { 2950 if(self[solution].support[format] && self._validString(media[format])) { // Format supported in solution and url given for format. 2951 var isHtml = solution === 'html'; 2952 2953 if(isVideo) { 2954 if(isHtml) { 2955 self.html.video.gate = true; 2956 self._html_setVideo(media); 2957 self.html.active = true; 2958 } else { 2959 self.flash.gate = true; 2960 self._flash_setVideo(media); 2961 self.flash.active = true; 2962 } 2963 if(self.css.jq.videoPlay.length) { 2964 self.css.jq.videoPlay.show(); 2965 } 2966 self.status.video = true; 2967 } else { 2968 if(isHtml) { 2969 self.html.audio.gate = true; 2970 self._html_setAudio(media); 2971 self.html.active = true; 2972 2973 // Setup the Android Fix - Only for HTML audio. 2974 if($.jPlayer.platform.android) { 2975 self.androidFix.setMedia = true; 2976 } 2977 } else { 2978 self.flash.gate = true; 2979 self._flash_setAudio(media); 2980 self.flash.active = true; 2981 } 2982 if(self.css.jq.videoPlay.length) { 2983 self.css.jq.videoPlay.hide(); 2984 } 2985 self.status.video = false; 2986 } 2987 2988 supported = true; 2989 return false; // Exit $.each 2990 } 2991 }); 2992 if(supported) { 2993 return false; // Exit $.each 2994 } 2995 }); 2996 2997 if(supported) { 2998 if(!(this.status.nativeVideoControls && this.html.video.gate)) { 2999 // Set poster IMG if native video controls are not being used 3000 // Note: With IE the IMG onload event occurs immediately when cached. 3001 // Note: Poster hidden by default in _resetMedia() 3002 if(this._validString(media.poster)) { 3003 if(posterChanged) { // Since some browsers do not generate img onload event. 3004 this.htmlElement.poster.src = media.poster; 3005 } else { 3006 this.internal.poster.jq.show(); 3007 } 3008 } 3009 } 3010 if(this.css.jq.title.length) { 3011 if(typeof media.title === 'string') { 3012 this.css.jq.title.html(media.title); 3013 if(this.htmlElement.audio) { 3014 this.htmlElement.audio.setAttribute('title', media.title); 3015 } 3016 if(this.htmlElement.video) { 3017 this.htmlElement.video.setAttribute('title', media.title); 3018 } 3019 } 3020 } 3021 this.status.srcSet = true; 3022 this.status.media = $.extend({}, media); 3023 this._updateButtons(false); 3024 this._updateInterface(); 3025 this._trigger($.jPlayer.event.setmedia); 3026 } else { // jPlayer cannot support any formats provided in this browser 3027 // Send an error event 3028 this._error( { 3029 type: $.jPlayer.error.NO_SUPPORT, 3030 context: "{supplied:'" + this.options.supplied + "'}", 3031 message: $.jPlayer.errorMsg.NO_SUPPORT, 3032 hint: $.jPlayer.errorHint.NO_SUPPORT 3033 }); 3034 } 3035 }, 3036 _resetMedia: function() { 3037 this._resetStatus(); 3038 this._updateButtons(false); 3039 this._updateInterface(); 3040 this._seeked(); 3041 this.internal.poster.jq.hide(); 3042 3043 clearTimeout(this.internal.htmlDlyCmdId); 3044 3045 if(this.html.active) { 3046 this._html_resetMedia(); 3047 } else if(this.flash.active) { 3048 this._flash_resetMedia(); 3049 } 3050 }, 3051 clearMedia: function() { 3052 this._resetMedia(); 3053 3054 if(this.html.active) { 3055 this._html_clearMedia(); 3056 } else if(this.flash.active) { 3057 this._flash_clearMedia(); 3058 } 3059 3060 this._resetGate(); 3061 this._resetActive(); 3062 }, 3063 load: function() { 3064 if(this.status.srcSet) { 3065 if(this.html.active) { 3066 this._html_load(); 3067 } else if(this.flash.active) { 3068 this._flash_load(); 3069 } 3070 } else { 3071 this._urlNotSetError("load"); 3072 } 3073 }, 3074 focus: function() { 3075 if(this.options.keyEnabled) { 3076 $.jPlayer.focus = this; 3077 } 3078 }, 3079 play: function(time) { 3080 time = (typeof time === "number") ? time : NaN; // Remove jQuery event from click handler 3081 if(this.status.srcSet) { 3082 this.focus(); 3083 if(this.html.active) { 3084 this._html_play(time); 3085 } else if(this.flash.active) { 3086 this._flash_play(time); 3087 } 3088 } else { 3089 this._urlNotSetError("play"); 3090 } 3091 }, 3092 videoPlay: function() { // Handles clicks on the play button over the video poster 3093 this.play(); 3094 }, 3095 pause: function(time) { 3096 time = (typeof time === "number") ? time : NaN; // Remove jQuery event from click handler 3097 if(this.status.srcSet) { 3098 if(this.html.active) { 3099 this._html_pause(time); 3100 } else if(this.flash.active) { 3101 this._flash_pause(time); 3102 } 3103 } else { 3104 this._urlNotSetError("pause"); 3105 } 3106 }, 3107 tellOthers: function(command, conditions) { 3108 var self = this, 3109 hasConditions = typeof conditions === 'function', 3110 args = Array.prototype.slice.call(arguments); // Convert arguments to an Array. 3111 3112 if(typeof command !== 'string') { // Ignore, since no command. 3113 return; // Return undefined to maintain chaining. 3114 } 3115 if(hasConditions) { 3116 args.splice(1, 1); // Remove the conditions from the arguments 3117 } 3118 3119 $.each(this.instances, function() { 3120 // Remember that "this" is the instance's "element" in the $.each() loop. 3121 if(self.element !== this) { // Do not tell my instance. 3122 if(!hasConditions || conditions.call(this.data("jPlayer"), self)) { 3123 this.jPlayer.apply(this, args); 3124 } 3125 } 3126 }); 3127 }, 3128 pauseOthers: function(time) { 3129 this.tellOthers("pause", function() { 3130 // In the conditions function, the "this" context is the other instance's jPlayer object. 3131 return this.status.srcSet; 3132 }, time); 3133 }, 3134 stop: function() { 3135 if(this.status.srcSet) { 3136 if(this.html.active) { 3137 this._html_pause(0); 3138 } else if(this.flash.active) { 3139 this._flash_pause(0); 3140 } 3141 } else { 3142 this._urlNotSetError("stop"); 3143 } 3144 }, 3145 playHead: function(p) { 3146 p = this._limitValue(p, 0, 100); 3147 if(this.status.srcSet) { 3148 if(this.html.active) { 3149 this._html_playHead(p); 3150 } else if(this.flash.active) { 3151 this._flash_playHead(p); 3152 } 3153 } else { 3154 this._urlNotSetError("playHead"); 3155 } 3156 }, 3157 _muted: function(muted) { 3158 this.mutedWorker(muted); 3159 if(this.options.globalVolume) { 3160 this.tellOthers("mutedWorker", function() { 3161 // Check the other instance has global volume enabled. 3162 return this.options.globalVolume; 3163 }, muted); 3164 } 3165 }, 3166 mutedWorker: function(muted) { 3167 this.options.muted = muted; 3168 if(this.html.used) { 3169 this._html_setProperty('muted', muted); 3170 } 3171 if(this.flash.used) { 3172 this._flash_mute(muted); 3173 } 3174 3175 // The HTML solution generates this event from the media element itself. 3176 if(!this.html.video.gate && !this.html.audio.gate) { 3177 this._updateMute(muted); 3178 this._updateVolume(this.options.volume); 3179 this._trigger($.jPlayer.event.volumechange); 3180 } 3181 }, 3182 mute: function(mute) { // mute is either: undefined (true), an event object (true) or a boolean (muted). 3183 mute = mute === undefined ? true : !!mute; 3184 this._muted(mute); 3185 }, 3186 unmute: function(unmute) { // unmute is either: undefined (true), an event object (true) or a boolean (!muted). 3187 unmute = unmute === undefined ? true : !!unmute; 3188 this._muted(!unmute); 3189 }, 3190 _updateMute: function(mute) { 3191 if(mute === undefined) { 3192 mute = this.options.muted; 3193 } 3194 if(this.css.jq.mute.length && this.css.jq.unmute.length) { 3195 if(this.status.noVolume) { 3196 this.css.jq.mute.hide(); 3197 this.css.jq.unmute.hide(); 3198 } else if(mute) { 3199 this.css.jq.mute.hide(); 3200 this.css.jq.unmute.show(); 3201 } else { 3202 this.css.jq.mute.show(); 3203 this.css.jq.unmute.hide(); 3204 } 3205 } 3206 }, 3207 volume: function(v) { 3208 this.volumeWorker(v); 3209 if(this.options.globalVolume) { 3210 this.tellOthers("volumeWorker", function() { 3211 // Check the other instance has global volume enabled. 3212 return this.options.globalVolume; 3213 }, v); 3214 } 3215 }, 3216 volumeWorker: function(v) { 3217 v = this._limitValue(v, 0, 1); 3218 this.options.volume = v; 3219 3220 if(this.html.used) { 3221 this._html_setProperty('volume', v); 3222 } 3223 if(this.flash.used) { 3224 this._flash_volume(v); 3225 } 3226 3227 // The HTML solution generates this event from the media element itself. 3228 if(!this.html.video.gate && !this.html.audio.gate) { 3229 this._updateVolume(v); 3230 this._trigger($.jPlayer.event.volumechange); 3231 } 3232 }, 3233 volumeBar: function(e) { // Handles clicks on the volumeBar 3234 if(this.css.jq.volumeBar.length) { 3235 // Using $(e.currentTarget) to enable multiple volume bars 3236 var $bar = $(e.currentTarget), 3237 offset = $bar.offset(), 3238 x = e.pageX - offset.left, 3239 w = $bar.width(), 3240 y = $bar.height() - e.pageY + offset.top, 3241 h = $bar.height(); 3242 if(this.options.verticalVolume) { 3243 this.volume(y/h); 3244 } else { 3245 this.volume(x/w); 3246 } 3247 } 3248 if(this.options.muted) { 3249 this._muted(false); 3250 } 3251 }, 3252 _updateVolume: function(v) { 3253 if(v === undefined) { 3254 v = this.options.volume; 3255 } 3256 v = this.options.muted ? 0 : v; 3257 3258 if(this.status.noVolume) { 3259 if(this.css.jq.volumeBar.length) { 3260 this.css.jq.volumeBar.hide(); 3261 } 3262 if(this.css.jq.volumeBarValue.length) { 3263 this.css.jq.volumeBarValue.hide(); 3264 } 3265 if(this.css.jq.volumeMax.length) { 3266 this.css.jq.volumeMax.hide(); 3267 } 3268 } else { 3269 if(this.css.jq.volumeBar.length) { 3270 this.css.jq.volumeBar.show(); 3271 } 3272 if(this.css.jq.volumeBarValue.length) { 3273 this.css.jq.volumeBarValue.show(); 3274 this.css.jq.volumeBarValue[this.options.verticalVolume ? "height" : "width"]((v*100)+"%"); 3275 } 3276 if(this.css.jq.volumeMax.length) { 3277 this.css.jq.volumeMax.show(); 3278 } 3279 } 3280 }, 3281 volumeMax: function() { // Handles clicks on the volume max 3282 this.volume(1); 3283 if(this.options.muted) { 3284 this._muted(false); 3285 } 3286 }, 3287 _cssSelectorAncestor: function(ancestor) { 3288 var self = this; 3289 this.options.cssSelectorAncestor = ancestor; 3290 this._removeUiClass(); 3291 this.ancestorJq = ancestor ? $(ancestor) : []; // Would use $() instead of [], but it is only 1.4+ 3292 if(ancestor && this.ancestorJq.length !== 1) { // So empty strings do not generate the warning. 3293 this._warning( { 3294 type: $.jPlayer.warning.CSS_SELECTOR_COUNT, 3295 context: ancestor, 3296 message: $.jPlayer.warningMsg.CSS_SELECTOR_COUNT + this.ancestorJq.length + " found for cssSelectorAncestor.", 3297 hint: $.jPlayer.warningHint.CSS_SELECTOR_COUNT 3298 }); 3299 } 3300 this._addUiClass(); 3301 $.each(this.options.cssSelector, function(fn, cssSel) { 3302 self._cssSelector(fn, cssSel); 3303 }); 3304 3305 // Set the GUI to the current state. 3306 this._updateInterface(); 3307 this._updateButtons(); 3308 this._updateAutohide(); 3309 this._updateVolume(); 3310 this._updateMute(); 3311 }, 3312 _cssSelector: function(fn, cssSel) { 3313 var self = this; 3314 if(typeof cssSel === 'string') { 3315 if($.jPlayer.prototype.options.cssSelector[fn]) { 3316 if(this.css.jq[fn] && this.css.jq[fn].length) { 3317 this.css.jq[fn].unbind(".jPlayer"); 3318 } 3319 this.options.cssSelector[fn] = cssSel; 3320 this.css.cs[fn] = this.options.cssSelectorAncestor + " " + cssSel; 3321 3322 if(cssSel) { // Checks for empty string 3323 this.css.jq[fn] = $(this.css.cs[fn]); 3324 } else { 3325 this.css.jq[fn] = []; // To comply with the css.jq[fn].length check before its use. As of jQuery 1.4 could have used $() for an empty set. 3326 } 3327 3328 if(this.css.jq[fn].length && this[fn]) { 3329 var handler = function(e) { 3330 e.preventDefault(); 3331 self[fn](e); 3332 $(this).blur(); 3333 }; 3334 this.css.jq[fn].bind("click.jPlayer", handler); // Using jPlayer namespace 3335 } 3336 3337 if(cssSel && this.css.jq[fn].length !== 1) { // So empty strings do not generate the warning. ie., they just remove the old one. 3338 this._warning( { 3339 type: $.jPlayer.warning.CSS_SELECTOR_COUNT, 3340 context: this.css.cs[fn], 3341 message: $.jPlayer.warningMsg.CSS_SELECTOR_COUNT + this.css.jq[fn].length + " found for " + fn + " method.", 3342 hint: $.jPlayer.warningHint.CSS_SELECTOR_COUNT 3343 }); 3344 } 3345 } else { 3346 this._warning( { 3347 type: $.jPlayer.warning.CSS_SELECTOR_METHOD, 3348 context: fn, 3349 message: $.jPlayer.warningMsg.CSS_SELECTOR_METHOD, 3350 hint: $.jPlayer.warningHint.CSS_SELECTOR_METHOD 3351 }); 3352 } 3353 } else { 3354 this._warning( { 3355 type: $.jPlayer.warning.CSS_SELECTOR_STRING, 3356 context: cssSel, 3357 message: $.jPlayer.warningMsg.CSS_SELECTOR_STRING, 3358 hint: $.jPlayer.warningHint.CSS_SELECTOR_STRING 3359 }); 3360 } 3361 }, 3362 duration: function(e) { 3363 if(this.options.toggleDuration) { 3364 if(this.options.captureDuration) { 3365 e.stopPropagation(); 3366 } 3367 this._setOption("remainingDuration", !this.options.remainingDuration); 3368 } 3369 }, 3370 seekBar: function(e) { // Handles clicks on the seekBar 3371 if(this.css.jq.seekBar.length) { 3372 // Using $(e.currentTarget) to enable multiple seek bars 3373 var $bar = $(e.currentTarget), 3374 offset = $bar.offset(), 3375 x = e.pageX - offset.left, 3376 w = $bar.width(), 3377 p = 100 * x / w; 3378 this.playHead(p); 3379 } 3380 }, 3381 playbackRate: function(pbr) { 3382 this._setOption("playbackRate", pbr); 3383 }, 3384 playbackRateBar: function(e) { // Handles clicks on the playbackRateBar 3385 if(this.css.jq.playbackRateBar.length) { 3386 // Using $(e.currentTarget) to enable multiple playbackRate bars 3387 var $bar = $(e.currentTarget), 3388 offset = $bar.offset(), 3389 x = e.pageX - offset.left, 3390 w = $bar.width(), 3391 y = $bar.height() - e.pageY + offset.top, 3392 h = $bar.height(), 3393 ratio, pbr; 3394 if(this.options.verticalPlaybackRate) { 3395 ratio = y/h; 3396 } else { 3397 ratio = x/w; 3398 } 3399 pbr = ratio * (this.options.maxPlaybackRate - this.options.minPlaybackRate) + this.options.minPlaybackRate; 3400 this.playbackRate(pbr); 3401 } 3402 }, 3403 _updatePlaybackRate: function() { 3404 var pbr = this.options.playbackRate, 3405 ratio = (pbr - this.options.minPlaybackRate) / (this.options.maxPlaybackRate - this.options.minPlaybackRate); 3406 if(this.status.playbackRateEnabled) { 3407 if(this.css.jq.playbackRateBar.length) { 3408 this.css.jq.playbackRateBar.show(); 3409 } 3410 if(this.css.jq.playbackRateBarValue.length) { 3411 this.css.jq.playbackRateBarValue.show(); 3412 this.css.jq.playbackRateBarValue[this.options.verticalPlaybackRate ? "height" : "width"]((ratio*100)+"%"); 3413 } 3414 } else { 3415 if(this.css.jq.playbackRateBar.length) { 3416 this.css.jq.playbackRateBar.hide(); 3417 } 3418 if(this.css.jq.playbackRateBarValue.length) { 3419 this.css.jq.playbackRateBarValue.hide(); 3420 } 3421 } 3422 }, 3423 repeat: function() { // Handle clicks on the repeat button 3424 this._loop(true); 3425 }, 3426 repeatOff: function() { // Handle clicks on the repeatOff button 3427 this._loop(false); 3428 }, 3429 _loop: function(loop) { 3430 if(this.options.loop !== loop) { 3431 this.options.loop = loop; 3432 this._updateButtons(); 3433 this._trigger($.jPlayer.event.repeat); 3434 } 3435 }, 3436 3437 // Options code adapted from ui.widget.js (1.8.7). Made changes so the key can use dot notation. To match previous getData solution in jPlayer 1. 3438 option: function(key, value) { 3439 var options = key; 3440 3441 // Enables use: options(). Returns a copy of options object 3442 if ( arguments.length === 0 ) { 3443 return $.extend( true, {}, this.options ); 3444 } 3445 3446 if(typeof key === "string") { 3447 var keys = key.split("."); 3448 3449 // Enables use: options("someOption") Returns a copy of the option. Supports dot notation. 3450 if(value === undefined) { 3451 3452 var opt = $.extend(true, {}, this.options); 3453 for(var i = 0; i < keys.length; i++) { 3454 if(opt[keys[i]] !== undefined) { 3455 opt = opt[keys[i]]; 3456 } else { 3457 this._warning( { 3458 type: $.jPlayer.warning.OPTION_KEY, 3459 context: key, 3460 message: $.jPlayer.warningMsg.OPTION_KEY, 3461 hint: $.jPlayer.warningHint.OPTION_KEY 3462 }); 3463 return undefined; 3464 } 3465 } 3466 return opt; 3467 } 3468 3469 // Enables use: options("someOptionObject", someObject}). Creates: {someOptionObject:someObject} 3470 // Enables use: options("someOption", someValue). Creates: {someOption:someValue} 3471 // Enables use: options("someOptionObject.someOption", someValue). Creates: {someOptionObject:{someOption:someValue}} 3472 3473 options = {}; 3474 var opts = options; 3475 3476 for(var j = 0; j < keys.length; j++) { 3477 if(j < keys.length - 1) { 3478 opts[keys[j]] = {}; 3479 opts = opts[keys[j]]; 3480 } else { 3481 opts[keys[j]] = value; 3482 } 3483 } 3484 } 3485 3486 // Otherwise enables use: options(optionObject). Uses original object (the key) 3487 3488 this._setOptions(options); 3489 3490 return this; 3491 }, 3492 _setOptions: function(options) { 3493 var self = this; 3494 $.each(options, function(key, value) { // This supports the 2 level depth that the options of jPlayer has. Would review if we ever need more depth. 3495 self._setOption(key, value); 3496 }); 3497 3498 return this; 3499 }, 3500 _setOption: function(key, value) { 3501 var self = this; 3502 3503 // The ability to set options is limited at this time. 3504 3505 switch(key) { 3506 case "volume" : 3507 this.volume(value); 3508 break; 3509 case "muted" : 3510 this._muted(value); 3511 break; 3512 case "globalVolume" : 3513 this.options[key] = value; 3514 break; 3515 case "cssSelectorAncestor" : 3516 this._cssSelectorAncestor(value); // Set and refresh all associations for the new ancestor. 3517 break; 3518 case "cssSelector" : 3519 $.each(value, function(fn, cssSel) { 3520 self._cssSelector(fn, cssSel); // NB: The option is set inside this function, after further validity checks. 3521 }); 3522 break; 3523 case "playbackRate" : 3524 this.options[key] = value = this._limitValue(value, this.options.minPlaybackRate, this.options.maxPlaybackRate); 3525 if(this.html.used) { 3526 this._html_setProperty('playbackRate', value); 3527 } 3528 this._updatePlaybackRate(); 3529 break; 3530 case "defaultPlaybackRate" : 3531 this.options[key] = value = this._limitValue(value, this.options.minPlaybackRate, this.options.maxPlaybackRate); 3532 if(this.html.used) { 3533 this._html_setProperty('defaultPlaybackRate', value); 3534 } 3535 this._updatePlaybackRate(); 3536 break; 3537 case "minPlaybackRate" : 3538 this.options[key] = value = this._limitValue(value, 0.1, this.options.maxPlaybackRate - 0.1); 3539 this._updatePlaybackRate(); 3540 break; 3541 case "maxPlaybackRate" : 3542 this.options[key] = value = this._limitValue(value, this.options.minPlaybackRate + 0.1, 16); 3543 this._updatePlaybackRate(); 3544 break; 3545 case "fullScreen" : 3546 if(this.options[key] !== value) { // if changed 3547 var wkv = $.jPlayer.nativeFeatures.fullscreen.used.webkitVideo; 3548 if(!wkv || wkv && !this.status.waitForPlay) { 3549 if(!wkv) { // No sensible way to unset option on these devices. 3550 this.options[key] = value; 3551 } 3552 if(value) { 3553 this._requestFullscreen(); 3554 } else { 3555 this._exitFullscreen(); 3556 } 3557 if(!wkv) { 3558 this._setOption("fullWindow", value); 3559 } 3560 } 3561 } 3562 break; 3563 case "fullWindow" : 3564 if(this.options[key] !== value) { // if changed 3565 this._removeUiClass(); 3566 this.options[key] = value; 3567 this._refreshSize(); 3568 } 3569 break; 3570 case "size" : 3571 if(!this.options.fullWindow && this.options[key].cssClass !== value.cssClass) { 3572 this._removeUiClass(); 3573 } 3574 this.options[key] = $.extend({}, this.options[key], value); // store a merged copy of it, incase not all properties changed. 3575 this._refreshSize(); 3576 break; 3577 case "sizeFull" : 3578 if(this.options.fullWindow && this.options[key].cssClass !== value.cssClass) { 3579 this._removeUiClass(); 3580 } 3581 this.options[key] = $.extend({}, this.options[key], value); // store a merged copy of it, incase not all properties changed. 3582 this._refreshSize(); 3583 break; 3584 case "autohide" : 3585 this.options[key] = $.extend({}, this.options[key], value); // store a merged copy of it, incase not all properties changed. 3586 this._updateAutohide(); 3587 break; 3588 case "loop" : 3589 this._loop(value); 3590 break; 3591 case "remainingDuration" : 3592 this.options[key] = value; 3593 this._updateInterface(); 3594 break; 3595 case "toggleDuration" : 3596 this.options[key] = value; 3597 break; 3598 case "nativeVideoControls" : 3599 this.options[key] = $.extend({}, this.options[key], value); // store a merged copy of it, incase not all properties changed. 3600 this.status.nativeVideoControls = this._uaBlocklist(this.options.nativeVideoControls); 3601 this._restrictNativeVideoControls(); 3602 this._updateNativeVideoControls(); 3603 break; 3604 case "noFullWindow" : 3605 this.options[key] = $.extend({}, this.options[key], value); // store a merged copy of it, incase not all properties changed. 3606 this.status.nativeVideoControls = this._uaBlocklist(this.options.nativeVideoControls); // Need to check again as noFullWindow can depend on this flag and the restrict() can override it. 3607 this.status.noFullWindow = this._uaBlocklist(this.options.noFullWindow); 3608 this._restrictNativeVideoControls(); 3609 this._updateButtons(); 3610 break; 3611 case "noVolume" : 3612 this.options[key] = $.extend({}, this.options[key], value); // store a merged copy of it, incase not all properties changed. 3613 this.status.noVolume = this._uaBlocklist(this.options.noVolume); 3614 this._updateVolume(); 3615 this._updateMute(); 3616 break; 3617 case "emulateHtml" : 3618 if(this.options[key] !== value) { // To avoid multiple event handlers being created, if true already. 3619 this.options[key] = value; 3620 if(value) { 3621 this._emulateHtmlBridge(); 3622 } else { 3623 this._destroyHtmlBridge(); 3624 } 3625 } 3626 break; 3627 case "timeFormat" : 3628 this.options[key] = $.extend({}, this.options[key], value); // store a merged copy of it, incase not all properties changed. 3629 break; 3630 case "keyEnabled" : 3631 this.options[key] = value; 3632 if(!value && this === $.jPlayer.focus) { 3633 $.jPlayer.focus = null; 3634 } 3635 break; 3636 case "keyBindings" : 3637 this.options[key] = $.extend(true, {}, this.options[key], value); // store a merged DEEP copy of it, incase not all properties changed. 3638 break; 3639 case "audioFullScreen" : 3640 this.options[key] = value; 3641 break; 3642 } 3643 3644 return this; 3645 }, 3646 // End of: (Options code adapted from ui.widget.js) 3647 3648 _refreshSize: function() { 3649 this._setSize(); // update status and jPlayer element size 3650 this._addUiClass(); // update the ui class 3651 this._updateSize(); // update internal sizes 3652 this._updateButtons(); 3653 this._updateAutohide(); 3654 this._trigger($.jPlayer.event.resize); 3655 }, 3656 _setSize: function() { 3657 // Determine the current size from the options 3658 if(this.options.fullWindow) { 3659 this.status.width = this.options.sizeFull.width; 3660 this.status.height = this.options.sizeFull.height; 3661 this.status.cssClass = this.options.sizeFull.cssClass; 3662 } else { 3663 this.status.width = this.options.size.width; 3664 this.status.height = this.options.size.height; 3665 this.status.cssClass = this.options.size.cssClass; 3666 } 3667 3668 // Set the size of the jPlayer area. 3669 this.element.css({'width': this.status.width, 'height': this.status.height}); 3670 }, 3671 _addUiClass: function() { 3672 if(this.ancestorJq.length) { 3673 this.ancestorJq.addClass(this.status.cssClass); 3674 } 3675 }, 3676 _removeUiClass: function() { 3677 if(this.ancestorJq.length) { 3678 this.ancestorJq.removeClass(this.status.cssClass); 3679 } 3680 }, 3681 _updateSize: function() { 3682 // The poster uses show/hide so can simply resize it. 3683 this.internal.poster.jq.css({'width': this.status.width, 'height': this.status.height}); 3684 3685 // Video html or flash resized if necessary at this time, or if native video controls being used. 3686 if(!this.status.waitForPlay && this.html.active && this.status.video || this.html.video.available && this.html.used && this.status.nativeVideoControls) { 3687 this.internal.video.jq.css({'width': this.status.width, 'height': this.status.height}); 3688 } 3689 else if(!this.status.waitForPlay && this.flash.active && this.status.video) { 3690 this.internal.flash.jq.css({'width': this.status.width, 'height': this.status.height}); 3691 } 3692 }, 3693 _updateAutohide: function() { 3694 var self = this, 3695 event = "mousemove.jPlayer", 3696 namespace = ".jPlayerAutohide", 3697 eventType = event + namespace, 3698 handler = function() { 3699 self.css.jq.gui.fadeIn(self.options.autohide.fadeIn, function() { 3700 clearTimeout(self.internal.autohideId); 3701 self.internal.autohideId = setTimeout( function() { 3702 self.css.jq.gui.fadeOut(self.options.autohide.fadeOut); 3703 }, self.options.autohide.hold); 3704 }); 3705 }; 3706 3707 if(this.css.jq.gui.length) { 3708 3709 // End animations first so that its callback is executed now. 3710 // Otherwise an in progress fadeIn animation still has the callback to fadeOut again. 3711 this.css.jq.gui.stop(true, true); 3712 3713 // Removes the fadeOut operation from the fadeIn callback. 3714 clearTimeout(this.internal.autohideId); 3715 3716 this.element.unbind(namespace); 3717 this.css.jq.gui.unbind(namespace); 3718 3719 if(!this.status.nativeVideoControls) { 3720 if(this.options.fullWindow && this.options.autohide.full || !this.options.fullWindow && this.options.autohide.restored) { 3721 this.element.bind(eventType, handler); 3722 this.css.jq.gui.bind(eventType, handler); 3723 this.css.jq.gui.hide(); 3724 } else { 3725 this.css.jq.gui.show(); 3726 } 3727 } else { 3728 this.css.jq.gui.hide(); 3729 } 3730 } 3731 }, 3732 fullScreen: function() { 3733 this._setOption("fullScreen", true);
vendor: 8,794 bytes, lines 3733-3995
3733 3734 }, 3735 restoreScreen: function() { 3736 this._setOption("fullScreen", false); 3737 }, 3738 _fullscreenAddEventListeners: function() { 3739 var self = this, 3740 fs = $.jPlayer.nativeFeatures.fullscreen; 3741 3742 if(fs.api.fullscreenEnabled) { 3743 if(fs.event.fullscreenchange) { 3744 // Create the event handler function and store it for removal. 3745 if(typeof this.internal.fullscreenchangeHandler !== 'function') { 3746 this.internal.fullscreenchangeHandler = function() { 3747 self._fullscreenchange(); 3748 }; 3749 } 3750 document.addEventListener(fs.event.fullscreenchange, this.internal.fullscreenchangeHandler, false); 3751 } 3752 // No point creating handler for fullscreenerror. 3753 // Either logic avoids fullscreen occurring (w3c/moz), or their is no event on the browser (webkit). 3754 } 3755 }, 3756 _fullscreenRemoveEventListeners: function() { 3757 var fs = $.jPlayer.nativeFeatures.fullscreen; 3758 if(this.internal.fullscreenchangeHandler) { 3759 document.removeEventListener(fs.event.fullscreenchange, this.internal.fullscreenchangeHandler, false); 3760 } 3761 }, 3762 _fullscreenchange: function() { 3763 // If nothing is fullscreen, then we cannot be in fullscreen mode. 3764 if(this.options.fullScreen && !$.jPlayer.nativeFeatures.fullscreen.api.fullscreenElement()) { 3765 this._setOption("fullScreen", false); 3766 } 3767 }, 3768 _requestFullscreen: function() { 3769 // Either the container or the jPlayer div 3770 var e = this.ancestorJq.length ? this.ancestorJq[0] : this.element[0], 3771 fs = $.jPlayer.nativeFeatures.fullscreen; 3772 3773 // This method needs the video element. For iOS and Android. 3774 if(fs.used.webkitVideo) { 3775 e = this.htmlElement.video; 3776 } 3777 3778 if(fs.api.fullscreenEnabled) { 3779 fs.api.requestFullscreen(e); 3780 } 3781 }, 3782 _exitFullscreen: function() { 3783 3784 var fs = $.jPlayer.nativeFeatures.fullscreen, 3785 e; 3786 3787 // This method needs the video element. For iOS and Android. 3788 if(fs.used.webkitVideo) { 3789 e = this.htmlElement.video; 3790 } 3791 3792 if(fs.api.fullscreenEnabled) { 3793 fs.api.exitFullscreen(e); 3794 } 3795 }, 3796 _html_initMedia: function(media) { 3797 // Remove any existing track elements 3798 var $media = $(this.htmlElement.media).empty(); 3799 3800 // Create any track elements given with the media, as an Array of track Objects. 3801 $.each(media.track || [], function(i,v) { 3802 var track = document.createElement('track'); 3803 track.setAttribute("kind", v.kind ? v.kind : ""); 3804 track.setAttribute("src", v.src ? v.src : ""); 3805 track.setAttribute("srclang", v.srclang ? v.srclang : ""); 3806 track.setAttribute("label", v.label ? v.label : ""); 3807 if(v.def) { 3808 track.setAttribute("default", v.def); 3809 } 3810 $media.append(track); 3811 }); 3812 3813 this.htmlElement.media.src = this.status.src; 3814 3815 if(this.options.preload !== 'none') { 3816 this._html_load(); // See function for comments 3817 } 3818 this._trigger($.jPlayer.event.timeupdate); // The flash generates this event for its solution. 3819 }, 3820 _html_setFormat: function(media) { 3821 var self = this; 3822 // Always finds a format due to checks in setMedia() 3823 $.each(this.formats, function(priority, format) { 3824 if(self.html.support[format] && media[format]) { 3825 self.status.src = media[format]; 3826 self.status.format[format] = true; 3827 self.status.formatType = format; 3828 return false; 3829 } 3830 }); 3831 }, 3832 _html_setAudio: function(media) { 3833 this._html_setFormat(media); 3834 this.htmlElement.media = this.htmlElement.audio; 3835 this._html_initMedia(media); 3836 }, 3837 _html_setVideo: function(media) { 3838 this._html_setFormat(media); 3839 if(this.status.nativeVideoControls) { 3840 this.htmlElement.video.poster = this._validString(media.poster) ? media.poster : ""; 3841 } 3842 this.htmlElement.media = this.htmlElement.video; 3843 this._html_initMedia(media); 3844 }, 3845 _html_resetMedia: function() { 3846 if(this.htmlElement.media) { 3847 if(this.htmlElement.media.id === this.internal.video.id && !this.status.nativeVideoControls) { 3848 this.internal.video.jq.css({'width':'0px', 'height':'0px'}); 3849 } 3850 this.htmlElement.media.pause(); 3851 } 3852 }, 3853 _html_clearMedia: function() { 3854 if(this.htmlElement.media) { 3855 this.htmlElement.media.src = "about:blank"; 3856 // The following load() is only required for Firefox 3.6 (PowerMacs). 3857 // Recent HTMl5 browsers only require the src change. Due to changes in W3C spec and load() effect. 3858 this.htmlElement.media.load(); // Stops an old, "in progress" download from continuing the download. Triggers the loadstart, error and emptied events, due to the empty src. Also an abort event if a download was in progress. 3859 } 3860 }, 3861 _html_load: function() { 3862 // This function remains to allow the early HTML5 browsers to work, such as Firefox 3.6 3863 // A change in the W3C spec for the media.load() command means that this is no longer necessary. 3864 // This command should be removed and actually causes minor undesirable effects on some browsers. Such as loading the whole file and not only the metadata. 3865 if(this.status.waitForLoad) { 3866 this.status.waitForLoad = false; 3867 this.htmlElement.media.load(); 3868 } 3869 clearTimeout(this.internal.htmlDlyCmdId); 3870 }, 3871 _html_play: function(time) { 3872 var self = this, 3873 media = this.htmlElement.media; 3874 3875 this.androidFix.pause = false; // Cancel the pause fix. 3876 3877 this._html_load(); // Loads if required and clears any delayed commands. 3878 3879 // Setup the Android Fix. 3880 if(this.androidFix.setMedia) { 3881 this.androidFix.play = true; 3882 this.androidFix.time = time; 3883 3884 } else if(!isNaN(time)) { 3885 3886 // Attempt to play it, since iOS has been ignoring commands 3887 if(this.internal.cmdsIgnored) { 3888 media.play(); 3889 } 3890 3891 try { 3892 // !media.seekable is for old HTML5 browsers, like Firefox 3.6. 3893 // Checking seekable.length is important for iOS6 to work with setMedia().play(time) 3894 if(!media.seekable || typeof media.seekable === "object" && media.seekable.length > 0) { 3895 media.currentTime = time; 3896 media.play(); 3897 } else { 3898 throw 1; 3899 } 3900 } catch(err) { 3901 this.internal.htmlDlyCmdId = setTimeout(function() { 3902 self.play(time); 3903 }, 250); 3904 return; // Cancel execution and wait for the delayed command. 3905 } 3906 } else { 3907 media.play(); 3908 } 3909 this._html_checkWaitForPlay(); 3910 }, 3911 _html_pause: function(time) { 3912 var self = this, 3913 media = this.htmlElement.media; 3914 3915 this.androidFix.play = false; // Cancel the play fix. 3916 3917 if(time > 0) { // We do not want the stop() command, which does pause(0), causing a load operation. 3918 this._html_load(); // Loads if required and clears any delayed commands. 3919 } else { 3920 clearTimeout(this.internal.htmlDlyCmdId); 3921 } 3922 3923 // Order of these commands is important for Safari (Win) and IE9. Pause then change currentTime. 3924 media.pause(); 3925 3926 // Setup the Android Fix. 3927 if(this.androidFix.setMedia) { 3928 this.androidFix.pause = true; 3929 this.androidFix.time = time; 3930 3931 } else if(!isNaN(time)) { 3932 try { 3933 if(!media.seekable || typeof media.seekable === "object" && media.seekable.length > 0) { 3934 media.currentTime = time; 3935 } else { 3936 throw 1; 3937 } 3938 } catch(err) { 3939 this.internal.htmlDlyCmdId = setTimeout(function() { 3940 self.pause(time); 3941 }, 250); 3942 return; // Cancel execution and wait for the delayed command. 3943 } 3944 } 3945 if(time > 0) { // Avoids a setMedia() followed by stop() or pause(0) hiding the video play button. 3946 this._html_checkWaitForPlay(); 3947 } 3948 }, 3949 _html_playHead: function(percent) { 3950 var self = this, 3951 media = this.htmlElement.media; 3952 3953 this._html_load(); // Loads if required and clears any delayed commands. 3954 3955 // This playHead() method needs a refactor to apply the android fix. 3956 3957 try { 3958 if(typeof media.seekable === "object" && media.seekable.length > 0) { 3959 media.currentTime = percent * media.seekable.end(media.seekable.length-1) / 100; 3960 } else if(media.duration > 0 && !isNaN(media.duration)) { 3961 media.currentTime = percent * media.duration / 100; 3962 } else { 3963 throw "e"; 3964 } 3965 } catch(err) { 3966 this.internal.htmlDlyCmdId = setTimeout(function() { 3967 self.playHead(percent); 3968 }, 250); 3969 return; // Cancel execution and wait for the delayed command. 3970 } 3971 if(!this.status.waitForLoad) { 3972 this._html_checkWaitForPlay(); 3973 } 3974 }, 3975 _html_checkWaitForPlay: function() { 3976 if(this.status.waitForPlay) { 3977 this.status.waitForPlay = false; 3978 if(this.css.jq.videoPlay.length) { 3979 this.css.jq.videoPlay.hide(); 3980 } 3981 if(this.status.video) { 3982 this.internal.poster.jq.hide(); 3983 this.internal.video.jq.css({'width': this.status.width, 'height': this.status.height}); 3984 } 3985 } 3986 }, 3987 _html_setProperty: function(property, value) { 3988 if(this.html.audio.available) { 3989 this.htmlElement.audio[property] = value; 3990 } 3991 if(this.html.video.available) { 3992 this.htmlElement.video[property] = value; 3993 } 3994 }, 3995 _
vendor: 12,159 bytes, lines 3995-4341
3995flash_setAudio: function(media) { 3996 var self = this; 3997 try { 3998 // Always finds a format due to checks in setMedia() 3999 $.each(this.formats, function(priority, format) { 4000 if(self.flash.support[format] && media[format]) { 4001 switch (format) { 4002 case "m4a" : 4003 case "fla" : 4004 self._getMovie().fl_setAudio_m4a(media[format]); 4005 break; 4006 case "mp3" : 4007 self._getMovie().fl_setAudio_mp3(media[format]); 4008 break; 4009 case "rtmpa": 4010 self._getMovie().fl_setAudio_rtmp(media[format]); 4011 break; 4012 } 4013 self.status.src = media[format]; 4014 self.status.format[format] = true; 4015 self.status.formatType = format; 4016 return false; 4017 } 4018 }); 4019 4020 if(this.options.preload === 'auto') { 4021 this._flash_load(); 4022 this.status.waitForLoad = false; 4023 } 4024 } catch(err) { this._flashError(err); } 4025 }, 4026 _flash_setVideo: function(media) { 4027 var self = this; 4028 try { 4029 // Always finds a format due to checks in setMedia() 4030 $.each(this.formats, function(priority, format) { 4031 if(self.flash.support[format] && media[format]) { 4032 switch (format) { 4033 case "m4v" : 4034 case "flv" : 4035 self._getMovie().fl_setVideo_m4v(media[format]); 4036 break; 4037 case "rtmpv": 4038 self._getMovie().fl_setVideo_rtmp(media[format]); 4039 break; 4040 } 4041 self.status.src = media[format]; 4042 self.status.format[format] = true; 4043 self.status.formatType = format; 4044 return false; 4045 } 4046 }); 4047 4048 if(this.options.preload === 'auto') { 4049 this._flash_load(); 4050 this.status.waitForLoad = false; 4051 } 4052 } catch(err) { this._flashError(err); } 4053 }, 4054 _flash_resetMedia: function() { 4055 this.internal.flash.jq.css({'width':'0px', 'height':'0px'}); // Must do via CSS as setting attr() to zero causes a jQuery error in IE. 4056 this._flash_pause(NaN); 4057 }, 4058 _flash_clearMedia: function() { 4059 try { 4060 this._getMovie().fl_clearMedia(); 4061 } catch(err) { this._flashError(err); } 4062 }, 4063 _flash_load: function() { 4064 try { 4065 this._getMovie().fl_load(); 4066 } catch(err) { this._flashError(err); } 4067 this.status.waitForLoad = false; 4068 }, 4069 _flash_play: function(time) { 4070 try { 4071 this._getMovie().fl_play(time); 4072 } catch(err) { this._flashError(err); } 4073 this.status.waitForLoad = false; 4074 this._flash_checkWaitForPlay(); 4075 }, 4076 _flash_pause: function(time) { 4077 try { 4078 this._getMovie().fl_pause(time); 4079 } catch(err) { this._flashError(err); } 4080 if(time > 0) { // Avoids a setMedia() followed by stop() or pause(0) hiding the video play button. 4081 this.status.waitForLoad = false; 4082 this._flash_checkWaitForPlay(); 4083 } 4084 }, 4085 _flash_playHead: function(p) { 4086 try { 4087 this._getMovie().fl_play_head(p); 4088 } catch(err) { this._flashError(err); } 4089 if(!this.status.waitForLoad) { 4090 this._flash_checkWaitForPlay(); 4091 } 4092 }, 4093 _flash_checkWaitForPlay: function() { 4094 if(this.status.waitForPlay) { 4095 this.status.waitForPlay = false; 4096 if(this.css.jq.videoPlay.length) { 4097 this.css.jq.videoPlay.hide(); 4098 } 4099 if(this.status.video) { 4100 this.internal.poster.jq.hide(); 4101 this.internal.flash.jq.css({'width': this.status.width, 'height': this.status.height}); 4102 } 4103 } 4104 }, 4105 _flash_volume: function(v) { 4106 try { 4107 this._getMovie().fl_volume(v); 4108 } catch(err) { this._flashError(err); } 4109 }, 4110 _flash_mute: function(m) { 4111 try { 4112 this._getMovie().fl_mute(m); 4113 } catch(err) { this._flashError(err); } 4114 }, 4115 _getMovie: function() { 4116 return document[this.internal.flash.id]; 4117 }, 4118 _getFlashPluginVersion: function() { 4119 4120 // _getFlashPluginVersion() code influenced by: 4121 // - FlashReplace 1.01: http://code.google.com/p/flashreplace/ 4122 // - SWFObject 2.2: http://code.google.com/p/swfobject/ 4123 4124 var version = 0, 4125 flash; 4126 if(window.ActiveXObject) { 4127 try { 4128 flash = new ActiveXObject("ShockwaveFlash.ShockwaveFlash"); 4129 if (flash) { // flash will return null when ActiveX is disabled 4130 var v = flash.GetVariable("$version"); 4131 if(v) { 4132 v = v.split(" ")[1].split(","); 4133 version = parseInt(v[0], 10) + "." + parseInt(v[1], 10); 4134 } 4135 } 4136 } catch(e) {} 4137 } 4138 else if(navigator.plugins && navigator.mimeTypes.length > 0) { 4139 flash = navigator.plugins["Shockwave Flash"]; 4140 if(flash) { 4141 version = navigator.plugins["Shockwave Flash"].description.replace(/.*\s(\d+\.\d+).*/, "$1"); 4142 } 4143 } 4144 return version * 1; // Converts to a number 4145 }, 4146 _checkForFlash: function (version) { 4147 var flashOk = false; 4148 if(this._getFlashPluginVersion() >= version) { 4149 flashOk = true; 4150 } 4151 return flashOk; 4152 }, 4153 _validString: function(url) { 4154 return (url && typeof url === "string"); // Empty strings return false 4155 }, 4156 _limitValue: function(value, min, max) { 4157 return (value < min) ? min : ((value > max) ? max : value); 4158 }, 4159 _urlNotSetError: function(context) { 4160 this._error( { 4161 type: $.jPlayer.error.URL_NOT_SET, 4162 context: context, 4163 message: $.jPlayer.errorMsg.URL_NOT_SET, 4164 hint: $.jPlayer.errorHint.URL_NOT_SET 4165 }); 4166 }, 4167 _flashError: function(error) { 4168 var errorType; 4169 if(!this.internal.ready) { 4170 errorType = "FLASH"; 4171 } else { 4172 errorType = "FLASH_DISABLED"; 4173 } 4174 this._error( { 4175 type: $.jPlayer.error[errorType], 4176 context: this.internal.flash.swf, 4177 message: $.jPlayer.errorMsg[errorType] + error.message, 4178 hint: $.jPlayer.errorHint[errorType] 4179 }); 4180 // Allow the audio player to recover if display:none and then shown again, or with position:fixed on Firefox. 4181 // This really only affects audio in a media player, as an audio player could easily move the jPlayer element away from such issues. 4182 this.internal.flash.jq.css({'width':'1px', 'height':'1px'}); 4183 }, 4184 _error: function(error) { 4185 this._trigger($.jPlayer.event.error, error); 4186 if(this.options.errorAlerts) { 4187 this._alert("Error!" + (error.message ? "\n" + error.message : "") + (error.hint ? "\n" + error.hint : "") + "\nContext: " + error.context); 4188 } 4189 }, 4190 _warning: function(warning) { 4191 this._trigger($.jPlayer.event.warning, undefined, warning); 4192 if(this.options.warningAlerts) { 4193 this._alert("Warning!" + (warning.message ? "\n" + warning.message : "") + (warning.hint ? "\n" + warning.hint : "") + "\nContext: " + warning.context); 4194 } 4195 }, 4196 _alert: function(message) { 4197 var msg = "jPlayer " + this.version.script + " : id='" + this.internal.self.id +"' : " + message; 4198 if(!this.options.consoleAlerts) { 4199 alert(msg); 4200 } else if(window.console && window.console.log) { 4201 window.console.log(msg); 4202 } 4203 }, 4204 _emulateHtmlBridge: function() { 4205 var self = this; 4206 4207 // Emulate methods on jPlayer's DOM element. 4208 $.each( $.jPlayer.emulateMethods.split(/\s+/g), function(i, name) { 4209 self.internal.domNode[name] = function(arg) { 4210 self[name](arg); 4211 }; 4212 4213 }); 4214 4215 // Bubble jPlayer events to its DOM element. 4216 $.each($.jPlayer.event, function(eventName,eventType) { 4217 var nativeEvent = true; 4218 $.each( $.jPlayer.reservedEvent.split(/\s+/g), function(i, name) { 4219 if(name === eventName) { 4220 nativeEvent = false; 4221 return false; 4222 } 4223 }); 4224 if(nativeEvent) { 4225 self.element.bind(eventType + ".jPlayer.jPlayerHtml", function() { // With .jPlayer & .jPlayerHtml namespaces. 4226 self._emulateHtmlUpdate(); 4227 var domEvent = document.createEvent("Event"); 4228 domEvent.initEvent(eventName, false, true); 4229 self.internal.domNode.dispatchEvent(domEvent); 4230 }); 4231 } 4232 // The error event would require a special case 4233 }); 4234 4235 // IE9 has a readyState property on all elements. The document should have it, but all (except media) elements inherit it in IE9. This conflicts with Popcorn, which polls the readyState. 4236 }, 4237 _emulateHtmlUpdate: function() { 4238 var self = this; 4239 4240 $.each( $.jPlayer.emulateStatus.split(/\s+/g), function(i, name) { 4241 self.internal.domNode[name] = self.status[name]; 4242 }); 4243 $.each( $.jPlayer.emulateOptions.split(/\s+/g), function(i, name) { 4244 self.internal.domNode[name] = self.options[name]; 4245 }); 4246 }, 4247 _destroyHtmlBridge: function() { 4248 var self = this; 4249 4250 // Bridge event handlers are also removed by destroy() through .jPlayer namespace. 4251 this.element.unbind(".jPlayerHtml"); // Remove all event handlers created by the jPlayer bridge. So you can change the emulateHtml option. 4252 4253 // Remove the methods and properties 4254 var emulated = $.jPlayer.emulateMethods + " " + $.jPlayer.emulateStatus + " " + $.jPlayer.emulateOptions; 4255 $.each( emulated.split(/\s+/g), function(i, name) { 4256 delete self.internal.domNode[name]; 4257 }); 4258 } 4259 }; 4260 4261 $.jPlayer.error = { 4262 FLASH: "e_flash", 4263 FLASH_DISABLED: "e_flash_disabled", 4264 NO_SOLUTION: "e_no_solution", 4265 NO_SUPPORT: "e_no_support", 4266 URL: "e_url", 4267 URL_NOT_SET: "e_url_not_set", 4268 VERSION: "e_version" 4269 }; 4270 4271 $.jPlayer.errorMsg = { 4272 FLASH: "jPlayer's Flash fallback is not configured correctly, or a command was issued before the jPlayer Ready event. Details: ", // Used in: _flashError() 4273 FLASH_DISABLED: "jPlayer's Flash fallback has been disabled by the browser due to the CSS rules you have used. Details: ", // Used in: _flashError() 4274 NO_SOLUTION: "No solution can be found by jPlayer in this browser. Neither HTML nor Flash can be used.", // Used in: _init() 4275 NO_SUPPORT: "It is not possible to play any media format provided in setMedia() on this browser using your current options.", // Used in: setMedia() 4276 URL: "Media URL could not be loaded.", // Used in: jPlayerFlashEvent() and _addHtmlEventListeners() 4277 URL_NOT_SET: "Attempt to issue media playback commands, while no media url is set.", // Used in: load(), play(), pause(), stop() and playHead() 4278 VERSION: "jPlayer " + $.jPlayer.prototype.version.script + " needs Jplayer.swf version " + $.jPlayer.prototype.version.needFlash + " but found " // Used in: jPlayerReady() 4279 }; 4280 4281 $.jPlayer.errorHint = { 4282 FLASH: "Check your swfPath option and that Jplayer.swf is there.", 4283 FLASH_DISABLED: "Check that you have not display:none; the jPlayer entity or any ancestor.", 4284 NO_SOLUTION: "Review the jPlayer options: support and supplied.", 4285 NO_SUPPORT: "Video or audio formats defined in the supplied option are missing.", 4286 URL: "Check media URL is valid.", 4287 URL_NOT_SET: "Use setMedia() to set the media URL.", 4288 VERSION: "Update jPlayer files." 4289 }; 4290 4291 $.jPlayer.warning = { 4292 CSS_SELECTOR_COUNT: "e_css_selector_count", 4293 CSS_SELECTOR_METHOD: "e_css_selector_method", 4294 CSS_SELECTOR_STRING: "e_css_selector_string", 4295 OPTION_KEY: "e_option_key" 4296 }; 4297 4298 $.jPlayer.warningMsg = { 4299 CSS_SELECTOR_COUNT: "The number of css selectors found did not equal one: ", 4300 CSS_SELECTOR_METHOD: "The methodName given in jPlayer('cssSelector') is not a valid jPlayer method.", 4301 CSS_SELECTOR_STRING: "The methodCssSelector given in jPlayer('cssSelector') is not a String or is empty.", 4302 OPTION_KEY: "The option requested in jPlayer('option') is undefined." 4303 }; 4304 4305 $.jPlayer.warningHint = { 4306 CSS_SELECTOR_COUNT: "Check your css selector and the ancestor.", 4307 CSS_SELECTOR_METHOD: "Check your method name.", 4308 CSS_SELECTOR_STRING: "Check your css selector is a string.", 4309 OPTION_KEY: "Check your option name." 4310 }; 4311})); 4312 4313/* 4314 * Playlist Object for the jPlayer Plugin 4315 * http://www.jplayer.org 4316 * 4317 * Copyright (c) 2009 - 2013 Happyworm Ltd 4318 * Licensed under the MIT license. 4319 * http://www.opensource.org/licenses/MIT 4320 * 4321 * Author: Mark J Panaghiston 4322 * Version: 2.3.0 4323 * Date: 20th April 2013 4324 * 4325 * Requires: 4326 * - jQuery 1.7.0+ 4327 * - jPlayer 2.3.0+ 4328 */ 4329 4330/* Code verified using http://www.jshint.com/ */ 4331/*jshint asi:false, bitwise:false, boss:false, browser:true, curly:true, debug:false, eqeqeq:true, eqnull:false, evil:false, forin:false, immed:false, jquery:true, laxbreak:false, newcap:true, noarg:true, noempty:true, nonew:true, onevar:false, passfail:false, plusplus:false, regexp:false, undef:true, sub:false, strict:false, white:false, smarttabs:true */ 4332/*global jPlayerPlaylist:true */ 4333 4334(function($, undefined) { 4335 4336 jPlayerPlaylist = function(cssSelector, playlist, options) { 4337 var self = this; 4338 4339 this.current = 0; 4340 this.loop = false; // Flag used with the jPlayer repeat event 4341 this.shuffled = false;
vendor: 8,036 bytes, lines 4342-4581
4342 this.removing = false; // Flag is true during remove animation, disabling the remove() method until complete. 4343 4344 this.cssSelector = $.extend({}, this._cssSelector, cssSelector); // Object: Containing the css selectors for jPlayer and its cssSelectorAncestor 4345 this.options = $.extend(true, { 4346 keyBindings: { 4347 next: { 4348 key: 39, // RIGHT 4349 fn: function() { 4350 self.next(); 4351 } 4352 }, 4353 previous: { 4354 key: 37, // LEFT 4355 fn: function() { 4356 self.previous(); 4357 } 4358 } 4359 } 4360 }, this._options, options); // Object: The jPlayer constructor options for this playlist and the playlist options 4361 4362 this.playlist = []; // Array of Objects: The current playlist displayed (Un-shuffled or Shuffled) 4363 this.original = []; // Array of Objects: The original playlist 4364 4365 this._initPlaylist(playlist); // Copies playlist to this.original. Then mirrors this.original to this.playlist. Creating two arrays, where the element pointers match. (Enables pointer comparison.) 4366 4367 // Setup the css selectors for the extra interface items used by the playlist. 4368 this.cssSelector.title = this.cssSelector.cssSelectorAncestor + " .jp-title"; // Note that the text is written to the decendant li node. 4369 this.cssSelector.playlist = this.cssSelector.cssSelectorAncestor + " .jp-playlist"; 4370 this.cssSelector.next = this.cssSelector.cssSelectorAncestor + " .jp-next"; 4371 this.cssSelector.previous = this.cssSelector.cssSelectorAncestor + " .jp-previous"; 4372 this.cssSelector.shuffle = this.cssSelector.cssSelectorAncestor + " .jp-shuffle"; 4373 this.cssSelector.shuffleOff = this.cssSelector.cssSelectorAncestor + " .jp-shuffle-off"; 4374 4375 // Override the cssSelectorAncestor given in options 4376 this.options.cssSelectorAncestor = this.cssSelector.cssSelectorAncestor; 4377 4378 // Override the default repeat event handler 4379 this.options.repeat = function(event) { 4380 self.loop = event.jPlayer.options.loop; 4381 }; 4382 4383 // Create a ready event handler to initialize the playlist 4384 $(this.cssSelector.jPlayer).bind($.jPlayer.event.ready, function() { 4385 self._init(); 4386 }); 4387 4388 // Create an ended event handler to move to the next item 4389 $(this.cssSelector.jPlayer).bind($.jPlayer.event.ended, function() { 4390 self.next(); 4391 }); 4392 4393 // Create a play event handler to pause other instances 4394 $(this.cssSelector.jPlayer).bind($.jPlayer.event.play, function() { 4395 $(this).jPlayer("pauseOthers"); 4396 }); 4397 4398 // Create a resize event handler to show the title in full screen mode. 4399 $(this.cssSelector.jPlayer).bind($.jPlayer.event.resize, function(event) { 4400 if(event.jPlayer.options.fullScreen) { 4401 $(self.cssSelector.title).show(); 4402 } else { 4403 $(self.cssSelector.title).hide(); 4404 } 4405 }); 4406 4407 // Create click handlers for the extra buttons that do playlist functions. 4408 $(this.cssSelector.previous).click(function() { 4409 self.previous(); 4410 $(this).blur(); 4411 return false; 4412 }); 4413 4414 $(this.cssSelector.next).click(function() { 4415 self.next(); 4416 $(this).blur(); 4417 return false; 4418 }); 4419 4420 $(this.cssSelector.shuffle).click(function() { 4421 self.shuffle(true); 4422 return false; 4423 }); 4424 $(this.cssSelector.shuffleOff).click(function() { 4425 self.shuffle(false); 4426 return false; 4427 }).hide(); 4428 4429 // Put the title in its initial display state 4430 if(!this.options.fullScreen) { 4431 $(this.cssSelector.title).hide(); 4432 } 4433 4434 // Remove the empty <li> from the page HTML. Allows page to be valid HTML, while not interfereing with display animations 4435 $(this.cssSelector.playlist + " ul").empty(); 4436 4437 // Create .on() handlers for the playlist items along with the free media and remove controls. 4438 this._createItemHandlers(); 4439 4440 // Instance jPlayer 4441 $(this.cssSelector.jPlayer).jPlayer(this.options); 4442 }; 4443 4444 jPlayerPlaylist.prototype = { 4445 _cssSelector: { // static object, instanced in constructor 4446 jPlayer: "#jquery_jplayer_1", 4447 cssSelectorAncestor: "#jp_container_1" 4448 }, 4449 _options: { // static object, instanced in constructor 4450 playlistOptions: { 4451 autoPlay: false, 4452 loopOnPrevious: false, 4453 shuffleOnLoop: true, 4454 enableRemoveControls: false, 4455 displayTime: 'slow', 4456 addTime: 'fast', 4457 removeTime: 'fast', 4458 shuffleTime: 'slow', 4459 itemClass: "jp-playlist-item", 4460 freeGroupClass: "jp-free-media", 4461 freeItemClass: "jp-playlist-item-free", 4462 removeItemClass: "jp-playlist-item-remove" 4463 } 4464 }, 4465 option: function(option, value) { // For changing playlist options only 4466 if(value === undefined) { 4467 return this.options.playlistOptions[option]; 4468 } 4469 4470 this.options.playlistOptions[option] = value; 4471 4472 switch(option) { 4473 case "enableRemoveControls": 4474 this._updateControls(); 4475 break; 4476 case "itemClass": 4477 case "freeGroupClass": 4478 case "freeItemClass": 4479 case "removeItemClass": 4480 this._refresh(true); // Instant 4481 this._createItemHandlers(); 4482 break; 4483 } 4484 return this; 4485 }, 4486 _init: function() { 4487 var self = this; 4488 this._refresh(function() { 4489 if(self.options.playlistOptions.autoPlay) { 4490 self.play(self.current); 4491 } else { 4492 self.select(self.current); 4493 } 4494 }); 4495 }, 4496 _initPlaylist: function(playlist) { 4497 this.current = 0; 4498 this.shuffled = false; 4499 this.removing = false; 4500 this.original = $.extend(true, [], playlist); // Copy the Array of Objects 4501 this._originalPlaylist(); 4502 }, 4503 _originalPlaylist: function() { 4504 var self = this; 4505 this.playlist = []; 4506 // Make both arrays point to the same object elements. Gives us 2 different arrays, each pointing to the same actual object. ie., Not copies of the object. 4507 $.each(this.original, function(i) { 4508 self.playlist[i] = self.original[i]; 4509 }); 4510 }, 4511 _refresh: function(instant) { 4512 /* instant: Can be undefined, true or a function. 4513 * undefined -> use animation timings 4514 * true -> no animation 4515 * function -> use animation timings and excute function at half way point. 4516 */ 4517 var self = this; 4518 4519 if(instant && !$.isFunction(instant)) { 4520 $(this.cssSelector.playlist + " ul").empty(); 4521 $.each(this.playlist, function(i) { 4522 $(self.cssSelector.playlist + " ul").append(self._createListItem(self.playlist[i])); 4523 }); 4524 this._updateControls(); 4525 } else { 4526 var displayTime = $(this.cssSelector.playlist + " ul").children().length ? this.options.playlistOptions.displayTime : 0; 4527 4528 $(this.cssSelector.playlist + " ul").slideUp(displayTime, function() { 4529 var $this = $(this); 4530 $(this).empty(); 4531 4532 $.each(self.playlist, function(i) { 4533 $this.append(self._createListItem(self.playlist[i])); 4534 }); 4535 self._updateControls(); 4536 if($.isFunction(instant)) { 4537 instant(); 4538 } 4539 if(self.playlist.length) { 4540 $(this).slideDown(self.options.playlistOptions.displayTime); 4541 } else { 4542 $(this).show(); 4543 } 4544 }); 4545 } 4546 }, 4547 _createListItem: function(media) { 4548 var self = this; 4549 4550 // Wrap the <li> contents in a <div> 4551 var listItem = "<li><div>"; 4552 4553 // Create remove control 4554 listItem += "<a href='javascript:;' class='" + this.options.playlistOptions.removeItemClass + "'>×</a>"; 4555 4556 // Create links to free media 4557 if(media.free) { 4558 var first = true; 4559 listItem += "<span class='" + this.options.playlistOptions.freeGroupClass + "'>("; 4560 $.each(media, function(property,value) { 4561 if($.jPlayer.prototype.format[property]) { // Check property is a media format. 4562 if(first) { 4563 first = false; 4564 } else { 4565 listItem += " | "; 4566 } 4567 listItem += "<a class='" + self.options.playlistOptions.freeItemClass + "' href='" + value + "' tabindex='1'>" + property + "</a>"; 4568 } 4569 }); 4570 listItem += ")</span>"; 4571 } 4572 4573 // The title is given next in the HTML otherwise the float:right on the free media corrupts in IE6/7 4574 listItem += "<a href='javascript:;' class='" + this.options.playlistOptions.itemClass + "' tabindex='1'>" + media.title + (media.artist ? " <span class='jp-artist'>by " + media.artist + "</span>" : "") + "</a>"; 4575 listItem += "</div></li>"; 4576 4577 return listItem; 4578 }, 4579 _createItemHandlers: function() { 4580 var self = this; 4581 // Create live handlers for the playlist items
4582 $(this.cssSelector.playlist).off("click", "a." + this.options.playlistOptions.itemClass).on("click", "a." + this.options.playlistOptions.itemClass, function() { 4583 var index = $(this).parent().parent().index(); 4584 if(self.current !== index) { 4585 self.play(index); 4586 } else { 4587 $(self.cssSelector.jPlayer).jPlayer("play"); 4588 } 4589 $(this).blur(); 4590 return false; 4591 }); 4592 4593 // Create live handlers that disable free media links to force access via right click 4594 $(this.cssSelector.playlist).off("click", "a." + this.options.playlistOptions.freeItemClass).on("click", "a." + this.options.playlistOptions.freeItemClass, function() { 4595 $(this).parent().parent().find("." + self.options.playlistOptions.itemClass).click(); 4596 $(this).blur(); 4597 return false; 4598 }); 4599 4600 // Create live handlers for the remove controls 4601 $(this.cssSelector.playlist).off("click", "a." + this.options.playlistOptions.removeItemClass).on("click", "a." + this.options.playlistOptions.removeItemClass, function() { 4602 var index = $(this).parent().parent().index(); 4603 self.remove(index); 4604 $(this).blur(); 4605 return false; 4606 }); 4607 }, 4608 _updateControls: function() { 4609 if(this.options.playlistOptions.enableRemoveControls) { 4610 $(this.cssSelector.playlist + " ." + this.options.playlistOptions.removeItemClass).show(); 4611 } else { 4612 $(this.cssSelector.playlist + " ." + this.options.playlistOptions.removeItemClass).hide(); 4613 } 4614 if(this.shuffled) { 4615 $(this.cssSelector.shuffleOff).show(); 4616 $(this.cssSelector.shuffle).hide(); 4617 } else { 4618 $(this.cssSelector.shuffleOff).hide(); 4619 $(this.cssSelector.shuffle).show(); 4620 } 4621 }, 4622 _highlight: function(index) { 4623 if(this.playlist.length && index !== undefined) { 4624 $(this.cssSelector.playlist + " .jp-playlist-current").removeClass("jp-playlist-current"); 4625 $(this.cssSelector.playlist + " li:nth-child(" + (index + 1) + ")").addClass("jp-playlist-current").find(".jp-playlist-item").addClass("jp-playlist-current"); 4626 $(this.cssSelector.title + " li").html(this.playlist[index].title + (this.playlist[index].artist ? " <span class='jp-artist'>by " + this.playlist[index].artist + "</span>" : "")); 4627 } 4628 }, 4629 setPlaylist: function(playlist) { 4630 this._initPlaylist(playlist); 4631 this._init(); 4632 }, 4633 add: function(media, playNow) { 4634 $(this.cssSelector.playlist + " ul").append(this._createListItem(media)).find("li:last-child").hide().slideDown(this.options.playlistOptions.addTime); 4635 this._updateControls(); 4636 this.original.push(media); 4637 this.playlist.push(media); // Both array elements share the same object pointer. Comforms with _initPlaylist(p) system. 4638 4639 if(playNow) { 4640 this.play(this.playlist.length - 1); 4641 } else { 4642 if(this.original.length === 1) { 4643 this.select(0); 4644 } 4645 } 4646 }, 4647 remove: function(index) { 4648 var self = this; 4649 4650 if(index === undefined) { 4651 this._initPlaylist([]); 4652 this._refresh(function() { 4653 $(self.cssSelector.jPlayer).jPlayer("clearMedia"); 4654 }); 4655 return true; 4656 } else { 4657 4658 if(this.removing) { 4659 return false; 4660 } else { 4661 index = (index < 0) ? self.original.length + index : index; // Negative index relates to end of array. 4662 if(0 <= index && index < this.playlist.length) { 4663 this.removing = true; 4664 4665 $(this.cssSelector.playlist + " li:nth-child(" + (index + 1) + ")").slide
4665Up(this.options.playlistOptions.removeTime, function() { 4666 $(this).remove(); 4667 4668 if(self.shuffled) { 4669 var item = self.playlist[index]; 4670 $.each(self.original, function(i) { 4671 if(self.original[i] === item) { 4672 self.original.splice(i, 1); 4673 return false; // Exit $.each 4674 } 4675 }); 4676 self.playlist.splice(index, 1); 4677 } else { 4678 self.original.splice(index, 1); 4679 self.playlist.splice(index, 1); 4680 } 4681 4682 if(self.original.length) { 4683 if(index === self.current) { 4684 self.current = (index < self.original.length) ? self.current : self.original.length - 1; // To cope when last element being selected when it was removed 4685 self.select(self.current); 4686 } else if(index < self.current) { 4687 self.current--; 4688 } 4689 } else { 4690 $(self.cssSelector.jPlayer).jPlayer("clearMedia"); 4691 self.current = 0; 4692 self.shuffled = false; 4693 self._updateControls(); 4694 } 4695 4696 self.removing = false; 4697 }); 4698 } 4699 return true; 4700 } 4701 } 4702 }, 4703 select: function(index) { 4704 index = (index < 0) ? this.original.length + index : index; // Negative index relates to end of array. 4705 if(0 <= index && index < this.playlist.length) { 4706 this.current = index; 4707 this._highlight(index); 4708 $(this.cssSelector.jPlayer).jPlayer("setMedia", this.playlist[this.current]); 4709 } else { 4710 this.current = 0; 4711 } 4712 }, 4713 play: function(index) { 4714 index = (index < 0) ? this.original.length + index : index; // Negative index relates to end of array. 4715 if(0 <= index && index < this.playlist.length) { 4716 if(this.playlist.length) { 4717 this.select(index); 4718 $(this.cssSelector.jPlayer).jPlayer("play"); 4719 } 4720 } else if(index === undefined) { 4721 $(this.cssSelector.jPlayer).jPlayer("play"); 4722 } 4723 }, 4724 pause: function() { 4725 $(this.cssSelector.jPlayer).jPlayer("pause"); 4726 }, 4727 next: function() { 4728 var index = (this.current + 1 < this.playlist.length) ? this.current + 1 : 0; 4729 4730 if(this.loop) { 4731 // See if we need to shuffle before looping to start, and only shuffle if more than 1 item. 4732 if(index === 0 && this.shuffled && this.options.playlistOptions.shuffleOnLoop && this.playlist.length > 1) { 4733 this.shuffle(true, true); // playNow 4734 } else { 4735 this.play(index); 4736 } 4737 } else { 4738 // The index will be zero if it just looped round 4739 if(index > 0) { 4740 this.play(index); 4741 } 4742 } 4743 }, 4744 previous: function() { 4745 var index = (this.current - 1 >= 0) ? this.current - 1 : this.playlist.length - 1; 4746 4747 if(this.loop && this.options.playlistOptions.loopOnPrevious || index < this.playlist.length - 1) { 4748 this.play(index); 4749 } 4750 }, 4751 shuffle: function(shuffled, playNow) { 4752 var self = this; 4753 4754 if(shuffled === undefined) { 4755 shuffled = !this.shuffled; 4756 } 4757 4758 if(shuffled || shuffled !== this.shuffled) { 4759 4760 $(this.cssSelector.playlist + " ul").slideUp(this.options.playlistOptions.shuffleTime, function() { 4761 self.shuffled = shuffled; 4762 if(shuffled) { 4763 self.playlist.sort(function() { 4764 return 0.5 - Math.random(); 4765 }); 4766 } else { 4767 self._originalPlaylist(); 4768 } 4769 self._refresh(true); // Instant 4770 4771 if(playNow || !$(self.cssSelector.jPlayer).data("jPlayer").status.paused) { 4772 self.play(0); 4773 } else { 4774 self.select(0); 4775 } 4776 4777 $(this).slideDown(self.options.playlistOptions.shuffleTime); 4778 }); 4779 } 4780 } 4781 }; 4782})(jQuery); 4783; 4784/*global _soundcheckSettings:true, jPlayerPlaylist:false */ 4785 4786window.soundcheck = window.soundcheck || {}; 4787 4788(function( window, $, undefined ) { 4789 'use strict'; 4790 4791 var $body = $( 'body' ), 4792 soundcheck = window.soundcheck; 4793 4794 $.extend( soundcheck, { 4795 config: {}, 4796 4797 init: function() { 4798 $body.addClass( 'ontouchstart' in window || 'onmsgesturechange' in window ? 'touch' : 'no-touch' ); 4799 4800 // Scrolls down to content area on pages that are not the home/blog page. 4801 if ( ! $body.hasClass( 'home' ) && ! $body.hasClass( 'blog' ) ) { 4802 var headerHeight = $( '#header' ).height(), 4803 navigationHeight = $( '#primary-nav' ).height(); 4804 4805 $( 'html, body' ).animate({ 4806 scrollTop: headerHeight - navigationHeight 4807 }, 500 ); 4808 } 4809 }, 4810 4811 getParameterByName: function( name ) { 4812 name = name.replace( /[\[]/, '\\\[' ).replace( /[\]]/, '\\\]' ); 4813 4814 var regexS = '[\\?&]' + name + '=([^&#]*)', 4815 regex = new RegExp( regexS ), 4816 results = regex.exec( window.location.search ); 4817 4818 if ( results == null ) { 4819 return ''; 4820 } else { 4821 return decodeURIComponent( results[1].replace( /\+/g, ' ' ) ); 4822 } 4823 }, 4824 4825 /** 4826 * Set up featured image carousel. 4827 */ 4828 setupAudioPlayer: function() { 4829 // Misc (localized in includes/hooks.php) 4830 var audio = $.parseJSON( _soundcheckSettings.audioPlayer.tracks.replace( /"/g, '"' ) ); 4831 4832 // Check if playlist has a value 4833 if( audio.playlist ) { 4834 $( '[id^="jp_container_"]' ).each( function() { 4835 // Player vars 4836 var newID = this.id.replace( /jp_container_/, '' ), 4837 randID = newID.substr(0,4), 4838 theID = newID.substr(5), 4839 theTracks = audio.playlist[theID], 4840 thePlayer = $( '#jp_container_' + randID + '_' + theID ), 4841 Tracklist = 'playlist' + randID + '_' + theID; 4842 4843 // Player display vars 4844 var jpPlaylist = $( '.jp-type-playlist', thePlayer ), 4845 jpPlaylistView = $( '.jp-playlist-view', thePlayer ), 4846 jpPlaylistNav = $( '.jp-playlist', thePlayer ), 4847 jpContent = $( '.jp-content', thePlayer ), 4848 jpContentView = $( '.jp-content-view', thePlayer ), 4849 jpTrack = $( '.jp-current-track span', thePlayer ), 4850 jpArtist = $( '.jp-current-artist span', thePlayer ), 4851 jpAlbum = $( '.jp-current-album span', thePlayer ), 4852 jpArtwork = $( '.jp-current-artwork img.artwork', thePlayer ), 4853 jpCurrentTime = $( '.jp-current-time-wrap', thePlayer ), 4854 jpNowPlaying = $( '.jp-now-playing', thePlayer ), 4855 jpNotifictions = $( '.jp-notification', thePlayer ); 4856 4857 // Used for playlist_view() to only effect the content area and not the players in the sidebar. 4858 var jpPlaylistNavContent = $( '.single #content .jp-playlist' ); 4859 4860 // Update current track information 4861 function update_current_track_info() { 4862 var currentItem = Tracklist.playlist[Tracklist.current], 4863 currentTrack = ( currentItem.title ) ? currentItem.title : '', 4864 currentArtist = ( currentItem.artist ) ? currentItem.artist : '', 4865 currentAlbum = ( currentItem.album ) ? currentItem.album : '', 4866 currentPoster = ( currentItem.poster ) ? currentItem.poster : ''; 4867 4868 jpTrack.html( currentTrack ); 4869 jpArtist.html( currentArtist ); 4870 jpAlbum.html( currentAlbum ); 4871 jpArtwork.attr( 'src', currentPoster ); 4872 } 4873 4874 function is_widget() { 4875 if ( thePlayer.parent().parent().hasClass( 'widget' ) ) { 4876 return 1; 4877 } else { 4878 return 0; 4879 } 4880 } 4881 4882 // Show and Hide playlist 4883 function show_hide_playlist(shouldShow) { 4884 if ( 1 === is_widget() ) { 4885 if( shouldShow ) { 4886 thePlayer.removeClass( 'hide-playlist' ); 4887 jpPlaylistNav.fadeIn( 'fast' ); 4888 } else { 4889 jpPlaylistNav.fadeOut( 'fast', function() { 4890 thePlayer.addClass( 'hide-playlist' ); 4891 }); 4892 } 4893 } else { 4894 if( shouldShow ) { 4895 thePlayer.removeClass( 'hide-playlist'); 4896 jpPlaylistNav.slideDown( 'fast' ); 4897 } else { 4898 jpPlaylistNav.slideUp( 'fast', function() { 4899 thePlayer.addClass( 'hide-playlist' ); 4900 }); 4901 } 4902 } 4903 } 4904 4905 // Show and Hide player content 4906 function show_hide_content( shouldShow ) { 4907 if ( shouldShow ) { 4908 thePlayer.removeClass( 'hide-content'); 4909 jpContent.slideDown( 'fast' ); 4910 } else { 4911 jpContent.slideUp( 'fast', function() { 4912 thePlayer.addClass( 'hide-content'); 4913 }); 4914 } 4915 } 4916 4917 // Show playlist if option is checked in Theme Options 4918 function playlist_view() { 4919 if ( _soundcheckSettings.audioPlayer.options.showPlaylist ) { 4920 jpPlaylistNavContent.hide(); 4921 } else { 4922 jpPlaylistNavContent.show(); 4923 } 4924 } 4925 4926 // Hide notification messages - Loading & Updated Info 4927 function on_ready() { 4928 jpNotifictions.hide(); 4929 jpNowPlaying.fadeTo( 200, 1 ); 4930 playlist_view(); 4931 update_current_track_info(); 4932 jpPlaylist.removeClass( 'preloading' ).addClass( 'loaded' ); 4933 4934 if( jpPlaylistNav.is( ':visible' ) ) { 4935 jpPlaylistView.addClass( 'open' ); 4936 } else { 4937 jpPlaylistView.removeClass( 'open' ); 4938 } 4939 } 4940 4941 // Performed each time a track is played. 4942 function on_play() { 4943 update_current_track_info(); 4944 jpCurrentTime.fadeTo( 'fast', 1 ); 4945 thePlayer.addClass( 'playing' ); 4946 } 4947 4948 // Performed each time a track is paused. 4949 function on_pause() { 4950 jpCurrentTime.fadeTo( 'fast', 0 ); 4951 thePlayer.removeClass( 'playing' ); 4952 } 4953 4954 // Add track number 4955 function add_track_number() { 4956 var jpTrackNumber = $('.jp-track-number', thePlayer ); 4957 4958 jpTrackNumber.remove(); 4959 4960 $('.tracks li', thePlayer ).each( function() { 4961 var trackNumber = $( this ).index() + 1; 4962 4963 $( this ).find( 'a.jp-playlist-item').wrapInner( '<span class="jp-track-title" />' ); 4964 $( this ).find( 'a.jp-playlist-item').prepend( '<span class="jp-track-number">' + trackNumber + '.</span>'); 4965 }); 4966 } 4967 4968 // Update buttons 4969 $( '.jp-next, .jp-previous, .jp-playlist-item' ).click( function() { 4970 update_current_track_info(); 4971 }); 4972 4973 // Show and Hide playlist 4974 jpPlaylistView.click(function(e){ 4975 e.preventDefault(); 4976 4977 if( jpPlaylistNav.is( ':visible' ) ) { 4978 show_hide_playlist(); 4979 jpPlaylistView.removeClass( 'open' ); 4980 } else { 4981 show_hide_playlist(true); 4982 jpPlaylistView.addClass( 'open' ); 4983 } 4984 }); 4985 4986 // Show and Hide playlist 4987 jpContentView.click( function(e){ 4988 e.preventDefault(); 4989 4990 if ( jpContent.is( ':visible' ) ) { 4991 show_hide_content(); 4992 jpContentView.removeClass( 'open' ); 4993 } else { 4994 show_hide_content( true ); 4995 jpContentView.addClass( 'open' ); 4996 } 4997 }); 4998 4999 5000 Tracklist = new jPlayerPlaylist({ 5001 jPlayer: '#jquery_jplayer_' + randID + '_' + theID, 5002 cssSelectorAncestor: '#jp_container_' + randID + '_' + theID 5003 }, 5004 theTracks, // track list 5005 { 5006 playlistOptions: { 5007 enableRemoveControls: false, 5008 autoPlay: ( 1 === is_widget() ) ? 0 : _soundcheckSettings.audioPlayer.options.autoplay 5009 }, 5010 supplied: 'mp3', 5011 wmode: 'window', 5012 solution: 'html', 5013 ready: function() { 5014 on_ready(); 5015 add_track_number(); 5016 }, 5017 play: function() { 5018 on_play(); 5019 }, 5020 pause: function() { 5021 on_pause(); 5022 }, 5023 ended: function() { 5024 update_current_track_info(); 5025 } 5026 }); 5027 }); 5028 } 5029 }, 5030 5031 /** 5032 * Set up featured image carousel. 5033 */ 5034 setupEvents: function() { 5035 var filterLink = $( '.events-filter-list .filter-list-items-container a' ), 5036 filterTitleWidth = $( '.events-list-items .event:first .event-date' ).width(), 5037 event_id = soundcheck.getParameterByName( 'event_id' ); 5038 5039 filterLink.click( function() { 5040 $( 'li.event' ).removeClass( 'inactive' ); 5041 5042 filterLink.not( this ).removeClass( 'active' ); 5043 $( this ).addClass('active'); 5044 5045 var activeCat = $( this ).attr( 'href' ).replace( '#', '' ).toLowerCase(); 5046 5047 $( '#content li.event' ).not( 'li.' + activeCat ).addClass( 'inactive' ).children().stop( true, true ).animate({ opacity: '.3' }, 350 ); 5048 $( '#content li.' + activeCat ).children().stop( true, true ).animate({ opacity: '1' }, 350 ); 5049 5050 return false;
5051 }); 5052 5053 // Make filter title width the same as the first date 5054 $( '.events-list-container .filter-title' ).css( 'width', filterTitleWidth ); 5055 5056 // Event Description Display 5057 $( '.page-template-template-events-php .event' ).each( function() { 5058 var event = this; 5059 5060 $( '.event-title', event ).click( function() { 5061 $( event ).toggleClass( 'active' ); 5062 $( '.event-description', event ).slideToggle( 'fast' ); 5063 }); 5064 }); 5065 5066 // Widget Settings 5067 if ( event_id ) { 5068 var id = '#content #post-' + event_id; 5069 5070 $( id ).addClass( 'active' ); 5071 $( '.event-description', id ).slideDown( 'fast' ); 5072 } 5073 }, 5074 5075 /** 5076 * Set up hero slider 5077 * 5078 * - Displays featured content in an conent slider. 5079 * - Adds click events to active, next, and prevous slides. Next and 5080 * previous slides will trigger the sliders directional nav events, 5081 * advancing the slider in either direction. 5082 */ 5083 setupHeroSlider: function() { 5084 var $hero = $( '.hero-container' ), 5085 hero = _soundcheckSettings.heroSlider; 5086 5087 $hero.flexslider({ 5088 namespace : hero.namespace, 5089 animation : hero.animation, 5090 direction : hero.direction, 5091 slideshowSpeed : parseInt( hero.slideshowSpeed, 10 ), 5092 animationSpeed : parseInt( hero.animationSpeed, 10 ), 5093 prevText : hero.prevText, 5094 nextText : hero.nextText 5095 }); 5096 }, 5097 5098 /** 5099 * Set up featured image carousel. 5100 */ 5101 setupImageCarousel: function() { 5102 var $carousel = $( '#image-carousel-container' ); 5103 5104 $carousel.flexslider({ 5105 namespace: 'image-carousel-', 5106 selector: '.image-carousel-items > li', 5107 animation: 'slide', 5108 animationLoop: false, 5109 itemWidth: 134, 5110 itemMargin: 20, 5111 slideshow: false 5112 }); 5113 }, 5114 5115 /** 5116 * Set up videos. 5117 * 5118 * - Makes videos responsive. 5119 * - Moves videos embedded in page content to an '.entry-video' 5120 * container. Used primarily with the WPCOM single video templates. 5121 */ 5122 setupVideos: function() { 5123 $( '.hentry' ).fitVids({ 5124 customSelector: 'iframe[src^="http://dailymotion.com"], embed[src^="http://v.wordpress.com"]' 5125 }); 5126 5127 $( '.site-content .format-video' ).each( function() { 5128 var $this = $( this ), 5129 video = $this.find( '.wp-embed' ).first(); 5130 5131 if ( video.length ) { 5132 // Remove video paragraph wrapper. 5133 if ( video.parent().is( 'p' ) ) { 5134 video.unwrap(); 5135 } 5136 5137 $( '.entry-video', $this ).append( video ).addClass( 'has-video' ); 5138 } 5139 }); 5140 } 5141 }); 5142 5143 // Document ready. 5144 jQuery( function() { 5145 soundcheck.init(); 5146 soundcheck.setupAudioPlayer(); 5147 soundcheck.setupEvents(); 5148 soundcheck.setupHeroSlider(); 5149 soundcheck.setupImageCarousel(); 5150 soundcheck.setupVideos(); 5151 }); 5152 5153})( this, jQuery ); 5154; 5155!function(){"use strict";var e,t={noop:function(){},texturize:function(e){return(e=(e=(e=(e+="").replace(/'/g,"’").replace(/'/g,"’")).replace(/"/g,"”").replace(/"/g,"”").replace(/"/g,"”").replace(/[\u201D]/g,"”")).replace(/([\w]+)=&#[\d]+;(.+?)&#[\d]+;/g,'$1="$2"')).trim()},applyReplacements:function(e,t){if(e)return t?e.replace(/{(\d+)}/g,function(e,r){return void 0!==t[r]?t[r]:e}):e},getBackgroundImage:function(e){var t=document.createElement("canvas"),r=t.getContext&&t.getContext("2d");if(e){r.filter="blur(20px) ",r.drawImage(e,0,0);var o=t.toDataURL("image/png");return t=null,o}}},r=function(){function e(e,t){return Element.prototype.matches?e.matches(t):Element.prototype.msMatchesSelector?e.msMatchesSelector(t):void 0}function r(e,t,r,o){if(!e)return o();e.jpCarouselCancelFade&&e.jpCarouselCancelFade(),e.classList.remove("jp-carousel-fade"),e.style.removeProperty("display"),e.style.opacity=t,e.style.pointerEvents="none",e.offsetWidth,e.classList.add("jp-carousel-fade"),e.style.opacity=r;var a=1e3*parseFloat(getComputedStyle(e).transitionDuration)||0,i=setTimeout(function(){e.jpCarouselCancelFade=null,e.style.removeProperty("pointer-events"),o()},a+50);e.jpCarouselCancelFade=function(){clearTimeout(i),e.jpCarouselCancelFade=null}}return{closest:function(t,r){if(t.closest)return t.closest(r);var o=t;do{if(e(o,r))return o;o=o.parentElement||o.parentNode}while(null!==o&&1===o.nodeType);return null},matches:e,hide:function(e){e&&(e.style.display="none")},show:function(e){e&&(e.style.display="block")},fadeIn:function(e,o){r(e,0,1,o=o||t.noop)},fadeOut:function(e,o){o=o||t.noop,r(e,1,0,function(){e&&(e.style.display="none"),o()})},scrollToElement:function(e,t,r){if(!e||!t)return r?r():void 0;var o=t.querySelector(".jp-carousel-info-extra");o&&(o.style.minHeight=window.innerHeight-64+"px");var a=!0,i=Date.now(),n=t.scrollTop,l=Math.max(0,e.offsetTop-Math.max(0,window.innerHeight-function(e){var t=e.querySelector(".jp-carousel-info-footer"),r=e.querySelector(".jp-carousel-info-extra"),o=e.querySelector(".jp-carousel-info-content-wrapper");if(t&&r&&o){var a=window.getComputedStyle(r),i=parseInt(a.paddingTop,10)+parseInt(a.paddingBottom,10);return i=isNaN(i)?0:i,o.offsetHeight+t.offsetHeight+i}return 0}(t)))-t.scrollTop;function s(){a=!1}
5155l=Math.min(l,t.scrollHeight-window.innerHeight),t.addEventListener("wheel",s),function e(){var c,u=Date.now(),d=(c=(u-i)/300)<.5?2*c*c:1-Math.pow(-2*c+2,2)/2,p=(d=d>1?1:d)*l;if(t.scrollTop=n+p,u<=i+300&&a)return requestAnimationFrame(e);r&&r(),o&&(o.style.minHeight=""),a=!1,t.removeEventListener("wheel",s)}()},getJSONAttribute:function(e,t){if(e&&e.hasAttribute(t))try{return JSON.parse(e.getAttribute(t))}catch{return}},convertToPlainText:function(e){var t=document.createElement("div");return t.textContent=e,t.innerHTML},stripHTML:function(e){var t=document.createElement("div");return t.innerHTML=e.replace(/<[^>]*>?/gm,""),t.textContent},emitEvent:function(e,t,r){var o;try{o=new CustomEvent(t,{bubbles:!0,cancelable:!0,detail:r||null})}catch{(o=document.createEvent("CustomEvent")).initCustomEvent(t,!0,!0,r||null)}e.dispatchEvent(o)},isTouch:function(){return"ontouchstart"in window||window.DocumentTouch&&document instanceof DocumentTouch}}}();function o(){var o,a,i,n,l="",s=!1,c="div.gallery, div.tiled-gallery, ul.wp-block-gallery, ul.blocks-gallery-grid, figure.wp-block-gallery.has-nested-images, div.wp-block-jetpack-tiled-gallery, a.single-image-gallery",u=".gallery-item, .tiled-gallery-item, .blocks-gallery-item, .tiled-gallery__item",d=u+", .wp-block-image",p={},m="undefined"!=typeof wpcom&&wpcom.carousel&&wpcom.carousel.stat?wpcom.carousel.stat:t.noop,g="undefined"!=typeof wpcom&&wpcom.carousel&&wpcom.carousel.pageview?wpcom.carousel.pageview:t.noop;function h(t){if(!s)switch(t.which){case 38:t.preventDefault(),p.overlay.scrollTop-=100;break;case 40:t.preventDefault(),p.overlay.scrollTop+=100;break;case 39:t.preventDefault(),e.slideNext();break;case 37:case 8:t.preventDefault(),e.slidePrev();break;case 27:t.preventDefault(),x()}}function f(){s=!0}function v(){s=!1}function y(e){e.role="button",e.tabIndex=0,e.ariaLabel=jetpackCarouselStrings.image_label}function w(){p.overlay||(p.overlay=document.querySelector(".jp-carousel-overlay"),p.container=p.overlay.querySelector(".jp-carousel-wrap"),p.gallery=p.container.querySelector(".jp-carousel"),p.info=p.overlay.querySelector(".jp-carousel-info"),p.caption=p.info.querySelector(".jp-carousel-caption"),p.commentField=p.overlay.querySelector("#jp-carousel-comment-form-comment-field"),p.emailField=p.overlay.querySelector("#jp-carousel-comment-form-email-field"),p.authorField=p.overlay.querySelector("#jp-carousel-comment-form-author-field"),p.urlField=p.overlay.querySelector("#jp-carousel-comment-form-url-field"),window.innerWidth<=760&&Math.round(window.innerWidth/760*110)<40&&r.isTouch(),[p.commentField,p.emailField,p.authorField,p.urlField].forEach(function(e){e&&(e.addEventListener("focus",f),e.addEventListener("blur",v))}),p.overlay.addEventListener("click",function(e){var t,o,a=e.target,i=!!r.closest(a,".jp-carousel-close-hint"),n=!!window.matchMedia("(max-device-width: 760px)").matches;a===p.overlay?n||x():i?x():a.classList.contains("jp-carousel-image-download")?m("download_original_click"):a.classList.contains("jp-carousel-comment-login")?(t=p.currentSlide,o=t?t.attrs.attachmentId:"0",window.location.href=jetpackCarouselStrings.login_url+"%23jp-carousel-"+o):r.closest(a,"#jp-carousel-comment-form-container")?function(e){var t=e.target,o=r.getJSONAttribute(p.container,"data-carousel-extra")||{},a=p.currentSlide.attrs.attachmentId,i=document.querySelector("#jp-carousel-comment-form-submit-and-info-wrapper"),n=document.querySelector("#jp-carousel-comment-form-spinner"),l=document.querySelector("#jp-carousel-comment-form-button-submit"),s=document.querySelector("#jp-carousel-comment-form");if(p.commentField&&p.commentField.getAttribute("id")===t.getAttribute("id"))f(),r.show(i);else if(r.matches(t,'input[type="submit"]')){e.preventDefault(),e.stopPropagation(),r.show(n),s.classList.add("jp-carousel-is-disabled");var c={action:"post_attachment_comment",nonce:jetpackCarouselStrings.nonce,blog_id:o.blog_id,id:a,comment:p.commentField.value};if(!c.comment.length)return void j(jetpackCarouselStrings.no_comment_text,!1);if(1!==Number(jetpackCarouselStrings.is_logged_in)&&(c.email=p.emailField.value,c.author=p.authorField.value,c.url=p.urlField.value,1===Number(jetpackCarouselStrings.require_name_email))){if(!c.email.length||!c.email.match("@"))return void j(jetpackCarouselStrings.no_comment_email,!1);if(!c.author.length)return void j(jetpackCarouselStrings.no_comment_author,!1)}var u=new XMLHttpRequest;u.open("POST",jetpackCarouselStrings.ajaxurl,!0),u.setRequestHeader("X-Requested-With","XMLHttpRequest"),u.setRequestHeader("Content-Type","application/x-www-form-urlencoded; charset=UTF-8"),u.onreadystatechange=function(){if(this.readyState===XMLHttpRequest.DONE&&this.status>=200&&this.status<300){var e;try{e=JSON.parse(this.response)}catch{return void j(jetpackCarouselStrings.comment_post_error,!1)}"approved"===e.comment_status?j(jetpackCarouselStrings.comment_approved,!0):"unapproved"===e.comment_status?j(jetpackCarouselStrings.comment_unapproved,!0):j(jetpackCarouselStrings.comment_post_error,!1),H(),q(a),l.value=jetpackCarouselStrings.post_comment,r.hide(n),s.classList.remove("jp-carousel-is-disabled")}else j(jetpackCarouselStrings.comment_post_error,!1)};var d=[];for(var m in c)if(m){var g=encodeURIComponent(m)+"="+encodeURIComponent(c[m]);d.push(g.replace(/%20/g,"+"))}var h=d.join("&");u.send(h)}}(e):(r.closest(a,".jp-carousel-photo-icons-container")||a.classList.contains("jp-carousel-photo-title"))&&function(e){e.preventDefault();var t=e.target,o=p.info.querySelector(".jp-carousel-info-extra"),a=p.info.querySelector(".jp-carousel-image-meta"),i=p.info.querySelector(".jp-carousel-comments-wrapper"),n=p.info.querySelector(".jp-carousel-icon-info"),l=p.info.querySelector(".jp-carousel-icon-comments");function s(){l&&l.classList.remove("jp-carousel-selected"),n.classList.toggle("jp-carousel-selected"),i&&i.classList.remove("jp-carousel-show"),a&&(a.classList.toggle("jp-carousel-show"),a.classList.contains("jp-carousel-show")?o.classList.add("jp-carousel-show"):o.classList.remove("jp-carousel-show"))}function c(){n&&n.classList.remove("jp-carousel-selected"),l.classList.toggle("jp-carousel-selected"),a&&a.classList.remove("jp-carousel-show"),i&&(i.classList.toggle("jp-carousel-show"),i.classList.contains("jp-carousel-show")?o.classList.add("jp-carousel-show"):o.classList.remove("jp-carousel-show"))}(r.closest(t,".jp-carousel-icon-info")||t.classList.contains("jp-carousel-photo-title"))&&(a&&a.classList.contains("jp-carousel-show")?r.scrollToElement(p.overlay,p.overlay,s):(s(),r.scrollToElement(p.info,p.overlay))),r.closest(t,".jp-carousel-icon-comments")&&(i&&i.classList.contains("jp-carousel-show")?r.scrollToElement(p.overlay,p.overlay,c):(c(),r.scrollToElement(p.info,p.overlay)))}(e)}),window.addEventListener("keydown",h),p.overlay.addEventListener("jp_carousel.afterOpen",function(){v(),p.slides.length<=1||(p.slides.length<=5?r.show(p.info.querySelector(".jp-swiper-pagination")):r.show(p.info.querySelector(".jp-carousel-pagination")))}),p.overlay.addEventListener("jp_carousel.beforeClose",function(){f(),document.documentElement.style.removeProperty("height"),e&&e.enable(),r.hide(p.info.querySelector(".jp-swiper-pagination")),r.hide(p.info.querySelector(".jp-carousel-pagination"))}),p.overlay.addEventListener("jp_carousel.afterClose",function(){window.history.pushState?history.pushState("",document.title,window.location.pathname+window.location.search):window.location.href="",l="",p.isOpen=!1}),p.overlay.addEventListener("touchstart",function(e){e.touches.length>1&&e.preventDefault()}))}function j(e,t){var o=p.overlay.querySelector("#jp-carousel-comment-post-results"),a="jp-carousel-comment-post-"+(t?"success":"error");o.innerHTML='<span class="'+a+'">'+e+"</span>",r.hide(p.overlay.querySelector("#jp-carousel-comment-form-spinner")),p.overlay.querySelector("#jp-carousel-comment-form").classList.remove("jp-carousel-is-disabled"),r.show(o)}function b(){var e=document.querySelectorAll("a img[data-attachment-id]");Array.prototype.forEach.call(e,function(e){var t=e.parentElement,o=t.parentElement;if(!o.classList.contains("gallery-icon")&&!r.closest(o,u)&&t.hasAttribute("href")){var a=!1;t.getAttribute("href").split("?")[0]===e.getAttribute("data-orig-file").split("?")[0]&&1===Number(jetpackCarouselStrings.single_image_gallery_media_file)&&(a=!0),t.getAttribute("href")===e.getAttribute("data-permalink")&&(a=!0),a&&(y(e),t.classList.add("single-image-gallery"),t.setAttribute("data-carousel-extra",JSON.stringify({blog_id:Number(jetpackCarouselStrings.blog_id)})))}})}function S(t,r){p.isOpen?(L(r),e.slideTo(r+1)):M(t,{startIndex:r})}function L(e){(!e||e<0||e>p.slides.length)&&(e=0),p.currentSlide=p.slides[e];var o,a,i=p.currentSlide,n=i.attrs.attachmentId;A(p.slides[e]),function(e){var t=[],r=p.slides.length;if(r>1){var o=e>0?e-1:r-1;t.push(o);var a=e<r-1?e+1:0;t.push(a)}t.forEach(function(e){var t=p.slides[e];t&&(A(t),1!==Number(jetpackCarouselStrings.display_background_image)||t.backgroundImage||_(t))})}(e),1!==Number(jetpackCarouselStrings.display_background_image)||p.slides[e].backgroundImage||_(p.slides[e]),r.hide(p.caption),function(e){var t,o,a,i,n,l,s;if(i=p.overlay.querySelector(".jp-carousel-photo-caption"),n=p.overlay.querySelector(".jp-carousel-caption"),l=p.overlay.querySelector(".jp-carousel-photo-title"),s=p.overlay.querySelector(".jp-carousel-photo-description"),r.hide(i),r.hide(n),r.hide(l),r.hide(s),t=E(e.caption)||"",o=E(e.title)||"",a=E(e.desc)||"",(t||o||a)&&(t&&(i.innerHTML=t,n.innerHTML=t,r.show(i),r.show(n)),r.stripHTML(t)===r.stripHTML(o)&&(o=""),r.stripHTML(t)===r.stripHTML(a)&&(a=""),r.stripHTML(o)===r.stripHTML(a)&&(a=""),a&&(s.innerHTML=a,r.show(s),o||t||(i.textContent=r.stripHTML(a),r.show(i))),o)){var c=r.stripHTML(o);l.textContent=c,t||(i.textContent=c,n.textContent=c,r.show(i)),r.show(l)}}
5155({caption:i.attrs.caption,title:i.attrs.title,desc:i.attrs.desc}),function(e){if(!e||1!==Number(jetpackCarouselStrings.display_exif))return!1;var t=p.info.querySelector(".jp-carousel-image-meta");if(!t)return!1;var r="";for(var o in e){var a=e[o],i=jetpackCarouselStrings.meta_data||[];if(0!==parseFloat(a)&&a.length&&-1!==i.indexOf(o)){switch(o){case"focal_length":a+="mm";break;case"shutter_speed":a=C(a);break;case"aperture":a="f/"+a}r+="<li><h5>"+jetpackCarouselStrings[o]+"</h5>"+a+"</li>"}}var n=t.querySelector("ul.jp-carousel-image-exif");if(""!==r){if(!n){(n=document.createElement("ul")).className="jp-carousel-image-exif";var l=t.querySelector(".jp-carousel-title-and-caption");l&&l.nextSibling?t.insertBefore(n,l.nextSibling):t.insertBefore(n,t.firstChild)}n.innerHTML=r,n.style.removeProperty("display")}else n&&n.parentNode.removeChild(n)}(p.slides[e].attrs.imageMeta),function(e){if(!e)return!1;var r,o=[e.attrs.origWidth,e.attrs.origHeight],a=document.createElement("a");a.href=e.attrs.src.replace(/\?.+$/,""),r=null!==a.hostname.match(/^i[\d]{1}\.wp\.com$/i)?a.href:e.attrs.origFile.replace(/\?.+$/,"");var i=p.info.querySelector(".jp-carousel-download-text"),n=p.info.querySelector(".jp-carousel-image-download");i.innerHTML=t.applyReplacements(jetpackCarouselStrings.download_original,o),n.setAttribute("href",r),n.style.removeProperty("display")}(i),1===Number(jetpackCarouselStrings.display_comments)&&(o=p.slides[e].attrs.commentsOpened,a=p.info.querySelector("#jp-carousel-comment-form-container"),1===parseInt(o,10)?r.fadeIn(a):r.fadeOut(a),q(n),r.hide(p.info.querySelector("#jp-carousel-comment-post-results")));var s=p.info.querySelector(".jp-carousel-pagination");if(s&&p.slides.length>5){var c=e+1;s.innerHTML="<span>"+c+" / "+p.slides.length+"</span>"}jetpackCarouselStrings.stats&&p.isOpen&&((new Image).src=document.location.protocol+"//pixel.wp.com/g.gif?"+jetpackCarouselStrings.stats+"&post="+encodeURIComponent(n)+"&rand="+Math.random()),p.isOpen&&g(n),l="#jp-carousel-"+n,window.location.hash=l}function x(){document.body.style.overflow=a,document.documentElement.style.overflow=i,H(),f(),r.emitEvent(p.overlay,"jp_carousel.beforeClose"),window.scrollTo(window.scrollX||window.pageXOffset||0,n||0),p.isOpen=!1,e.destroy(),p.slides=[],p.currentSlide=void 0,p.gallery.innerHTML="",r.fadeOut(p.overlay,function(){r.emitEvent(p.overlay,"jp_carousel.afterClose")})}function k(e){if("object"!=typeof e&&(e={}),void 0===e.origFile)return"";if(void 0===e.origWidth||void 0===e.maxWidth)return e.origFile;if(!e.largeFile)return e.origFile;var t=document.createElement("a");t.href=e.largeFile;var r=/^i[0-2]\.wp\.com$/i.test(t.hostname),o=function(e,t,r){var o,a=r?e.replace(/.*=([\d]+%2C[\d]+).*$/,"$1"):e.replace(/.*-([\d]+x[\d]+)\..+$/,"$1");return"9999"===(o=a!==e?r?a.split("%2C"):a.split("x"):[t,0])[0]&&(o[0]="0"),"9999"===o[1]&&(o[1]="0"),o}(e.largeFile,e.origWidth,r),a=parseInt(o[0],10),i=parseInt(o[1],10);if(e.origMaxWidth=e.maxWidth,e.origMaxHeight=e.maxHeight,void 0!==window.devicePixelRatio&&window.devicePixelRatio>1&&(e.maxWidth=e.maxWidth*window.devicePixelRatio,e.maxHeight=e.maxHeight*window.devicePixelRatio),a>=e.maxWidth||i>=e.maxHeight)return e.largeFile;if(r){if(-1===e.largeFile.lastIndexOf("?"))return e.largeFile;var n=function(e){var t;try{t=new URL(e)}catch(t){return e}var r=["quality","ssl","filter","brightness","contrast","colorize","smooth"],o=Array.from(t.searchParams.entries());return t.search="",o.forEach(([e,o])=>{r.includes(e)&&t.searchParams.append(e,o)}),t}(e.largeFile);return(e.origWidth>e.maxWidth||e.origHeight>e.maxHeight)&&(e.origMaxWidth=2*e.maxWidth,e.origMaxHeight=2*e.maxHeight,n.searchParams.set("fit",e.origMaxWidth+","+e.origMaxHeight)),n.toString()}return e.origFile}function C(e){return e>=1?Math.round(10*e)/10+"s":"1/"+Math.round(1/e)+"s"}function E(e){return!e.match(" ")&&e.match("_")?"":e}function q(e,t){var a=void 0===t,i=p.info.querySelector(".jp-carousel-icon-comments .jp-carousel-has-comments-indicator");if(i.classList.remove("jp-carousel-show"),clearInterval(o),e){(!t||t<1)&&(t=0);var n=p.info.querySelector(".jp-carousel-comments"),l=p.info.querySelector("#jp-carousel-comments-loading");r.show(l),a&&(r.hide(n),n.innerHTML="");var s=new XMLHttpRequest,c=jetpackCarouselStrings.ajaxurl+"?action=get_attachment_comments&nonce="+jetpackCarouselStrings.nonce+"&id="+e+"&offset="+t;s.open("GET",c),s.setRequestHeader("X-Requested-With","XMLHttpRequest");var u=function(){r.fadeIn(n),r.fadeOut(l)};s.onload=function(){if(p.currentSlide&&p.currentSlide.attrs.attachmentId===e){var c,d=s.status>=200&&s.status<300;try{c=JSON.parse(s.responseText)}catch{}if(!d||!c||!Array.isArray(c))return u();a&&(n.innerHTML="");for(var m=0;m<c.length;m++){var g=c[m],h=document.createElement("div");h.classList.add("jp-carousel-comment"),h.setAttribute("id","jp-carousel-comment-"+g.id),h.innerHTML='<div class="comment-gravatar">'+g.gravatar_markup+'</div><div class="comment-content"><div class="comment-author">'+g.author_markup+'</div><div class="comment-date">'+g.date_gmt+"</div>"+g.content+"</div>",n.appendChild(h),clearInterval(o),o=setInterval(function(){p.container.scrollTop+150>window.innerHeight&&(q(e,t+10),clearInterval(o))},300)}c.length>0&&(r.show(n),i.innerText=c.length,i.classList.add("jp-carousel-show")),r.hide(l)}},s.onerror=u,s.send()}}function A(e){var t=e.attrs,r=e.el.querySelector("img");if(!r.hasAttribute("data-loaded"))if(r.setAttribute("itemprop","image"),r.setAttribute("data-loaded",1),t.previewImage&&t.previewImage!==t.src){r.src=t.previewImage,r.style.filter="blur(8px)";var o=new window.Image;o.addEventListener("load",function(){r.src=t.src,r.style.filter=""},{once:!0}),o.addEventListener("error",function(){r.style.filter=""},{once:!0}),o.src=t.src}else r.src=t.src}function _(e){var t=e.attrs.originalElement;if(t)if(t.complete&&0!==t.naturalHeight)T(e,t);else{var r=function(){t.removeEventListener("error",o),T(e,t)},o=function(){t.removeEventListener("load",r)};t.addEventListener("load",r,{once:!0}),t.addEventListener("error",o,{once:!0})}}
5155function T(e,r){var o=t.getBackgroundImage(r);o&&(e.backgroundImage=o,e.el.style.backgroundImage="url("+o+")",e.el.style.backgroundSize="cover",e.el.style.backgroundPosition="center")}function H(){p.commentField&&(p.commentField.value="")}function I(e,o){p.slides=[];var a={width:window.innerWidth,height:window.innerHeight-64};0!==o&&null!==e[o].getAttribute("data-gallery-src")&&((new Image).src=e[o].getAttribute("data-gallery-src")),Array.prototype.forEach.call(e,function(e,o){var i=r.closest(e,"a"),n=e.getAttribute("data-orig-file")||e.getAttribute("src-orig"),l=e.getAttribute("data-attachment-id")||e.getAttribute("data-id")||"0",s=document.querySelector('img[data-attachment-id="'+l+'"] + figcaption');s=s?s.innerHTML:e.getAttribute("data-image-caption");var c={originalElement:e,attachmentId:l,commentsOpened:e.getAttribute("data-comments-opened")||"0",imageMeta:r.getJSONAttribute(e,"data-image-meta")||{},title:e.getAttribute("data-image-title")||"",desc:e.getAttribute("data-image-description")||"",largeFile:e.getAttribute("data-large-file")||"",origFile:n||"",thumbSize:{width:e.naturalWidth,height:e.naturalHeight},caption:s||"",permalink:i&&i.getAttribute("href"),src:n||e.getAttribute("src")||""},u=r.closest(e,".tiled-gallery-item"),d=u&&u.querySelector(".tiled-gallery-caption"),m=d&&d.innerHTML;m&&(c.caption=m);var g=function(e){var t=e.getAttribute("data-orig-size")||"";if(t){var r=t.split(",");return{width:parseInt(r[0],10),height:parseInt(r[1],10)}}return{width:e.getAttribute("data-original-width")||e.getAttribute("width")||void 0,height:e.getAttribute("data-original-height")||e.getAttribute("height")||void 0}}(e);if(c.origWidth=g.width||c.thumbSize.width,c.origHeight=g.height||c.thumbSize.height,"undefined"!=typeof wpcom&&wpcom.carousel&&wpcom.carousel.generateImgSrc?c.src=wpcom.carousel.generateImgSrc(e,a):c.src=k({origFile:c.src,origWidth:c.origWidth,origHeight:c.origHeight,maxWidth:a.width,maxHeight:a.height,largeFile:c.largeFile}),e.setAttribute("data-gallery-src",c.src),"0"!==c.attachmentId){c.title=t.texturize(c.title),c.desc=t.texturize(c.desc),c.caption=t.texturize(c.caption);var h=new Image,f=document.createElement("div");f.classList.add("swiper-slide"),f.setAttribute("itemprop","associatedMedia"),f.setAttribute("itemscope",""),f.setAttribute("itemtype","https://schema.org/ImageObject");var v=document.createElement("div");v.classList.add("swiper-zoom-container"),p.gallery.appendChild(f),f.appendChild(v),v.appendChild(h),f.setAttribute("data-attachment-id",c.attachmentId),f.setAttribute("data-permalink",c.permalink),f.setAttribute("data-orig-file",c.origFile),c.previewImage=e.currentSrc||e.getAttribute("src")||"";var y={el:f,attrs:c,index:o};p.slides.push(y)}})}function M(e,t){if(!window.JetpackSwiper){var o=document.querySelector("#jp-carousel-loading-overlay");r.show(o);var a=document.createElement("script");return a.id="jetpack-carousel-swiper-js",a.src=window.jetpackSwiperLibraryPath.url,a.async=!0,a.onload=function(){r.hide(o),F(e,t)},a.onerror=function(){r.hide(o)},void document.head.appendChild(a)}F(e,t)}function F(t,o){var l,s={imgSelector:".gallery-item [data-attachment-id], .tiled-gallery-item [data-attachment-id], img[data-attachment-id], img[data-id]",startIndex:0},c=r.getJSONAttribute(t,"data-carousel-extra");if(!c)return;const u=t.querySelectorAll(s.imgSelector);if(u.length&&(w(),!p.isOpen)){for(var d in p.isOpen=!0,a=getComputedStyle(document.body).overflow,document.body.style.overflow="hidden",i=getComputedStyle(document.documentElement).overflow,document.documentElement.style.overflow="hidden",n=window.scrollY||window.pageYOffset||0,p.container.setAttribute("data-carousel-extra",JSON.stringify(c)),m(["open","view_image"]),o||{})s[d]=o[d];-1===s.startIndex&&(s.startIndex=0),r.emitEvent(p.overlay,"jp_carousel.beforeOpen"),p.gallery.innerHTML="",p.overlay.style.opacity=1,p.overlay.style.display="block",I(u,s.startIndex),(e=new window.JetpackSwiper(".jp-carousel-swiper-container",{centeredSlides:!0,zoom:!0,loop:p.slides.length>1,enabled:p.slides.length>1,pagination:{el:".jp-swiper-pagination",clickable:!0},navigation:{nextEl:".jp-swiper-button-next",prevEl:".jp-swiper-button-prev"},initialSlide:s.startIndex,on:{init:function(){L(s.startIndex)}},preventClicks:!1,preventClicksPropagation:!1,preventInteractionOnTransition:!r.isTouch(),threshold:5})).on("slideChange",function(e){p.isOpen&&(L(e.realIndex),p.overlay.classList.remove("jp-carousel-hide-control
5155s"))}),e.on("zoomChange",function(e,t){t>1&&p.overlay.classList.add("jp-carousel-hide-controls"),1===t&&p.overlay.classList.remove("jp-carousel-hide-controls")}),e.on("doubleTap",function(e){if(clearTimeout(l),1===e.zoom.scale)var t=setTimeout(function(){p.overlay.classList.remove("jp-carousel-hide-controls"),clearTimeout(t)},150)}),e.on("tap",function(){e.zoom.scale>1&&(l=setTimeout(function(){p.overlay.classList.toggle("jp-carousel-hide-controls")},150))}),r.fadeIn(p.overlay,function(){r.emitEvent(p.overlay,"jp_carousel.afterOpen")})}}function O(e){if("click"!==e.type){if("keydown"===e.type){const t=document.activeElement.parentElement,r=t&&t.classList.contains("tiled-gallery__item");" "!==e.key&&"Enter"!==e.key||!r||R(e)}}else R(e)}function N(e){return(e||"").split("?")[0].replace(/\/$/,"")}function W(e){"A"===e.tagName&&(e=e.querySelector("img")||e);var t=e.parentElement,o=t?t.parentElement:null,a=null;if(o&&o.classList.contains("wp-block-image")?a=t.getAttribute("href"):t&&t.classList.contains("wp-block-image")&&t.querySelector(":scope > a")&&(a=t.querySelector(":scope > a").getAttribute("href")),a){var i=N(a),n=N(e.getAttribute("data-orig-file")),l=N(e.getAttribute("data-permalink"));if(i!==n&&i!==l)return!1}return!(t&&t.classList.contains("gallery-caption")||r.matches(t,"figcaption"))}function R(e){if(window.CSS&&window.CSS.supports&&window.CSS.supports("display","grid")){var t,o=e.target,a=r.closest(o,c);if(a){if(!(t=a)||!t.getAttribute("data-carousel-extra"))return;if(!W(o))return;document.documentElement.style.height="auto",e.preventDefault(),e.stopPropagation();var i=r.closest(o,d),n=Array.prototype.indexOf.call(a.querySelectorAll(d),i);M(a,{startIndex:n})}}}document.body.addEventListener("click",O),document.body.addEventListener("keydown",O),document.querySelectorAll(u+"img").forEach(function(e){W(e)&&y(e)}),1===Number(jetpackCarouselStrings.single_image_gallery)&&(b(),document.body.addEventListener("is.post-load",function(){b()})),window.addEventListener("hashchange",function(){var e=/jp-carousel-(\d+)/;if(window.location.hash&&e.test(window.location.hash)){if(window.location.hash!==l||!p.isOpen)if(window.location.hash&&p.gallery&&!p.isOpen&&history.back)history.back();else{l=window.location.hash;for(var t=window.location.hash.match(e),r=parseInt(t[1],10),o=document.querySelectorAll(c),a=0;a<o.length;a++){for(var i,n=o[a],s=n.querySelectorAll("img"),u=0;u<s.length;u++)if(parseInt(s[u].getAttribute("data-attachment-id"),10)===r||parseInt(s[u].getAttribute("data-id"),10)===r){i=u;break}if(void 0!==i){S(n,i);break}}}}else p.isOpen&&x()}),window.location.hash&&r.emitEvent(window,"hashchange")}"loading"!==document.readyState?o():document.addEventListener("DOMContentLoaded",o)}();;
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.