1/* Detect-zoom 2 * ----------- 3 * Cross Browser Zoom and Pixel Ratio Detector 4 * Version 1.0.4 | Apr 1 2013 5 * dual-licensed under the WTFPL and MIT license 6 * Maintained by https://github/tombigel 7 * Original developer https://github.com/yonran 8 */ 9 10//AMD and CommonJS initialization copied from https://github.com/zohararad/audio5js 11(function (root, ns, factory) { 12 "use strict"; 13 14 if (typeof (module) !== 'undefined' && module.exports) { // CommonJS 15 module.exports = factory(ns, root); 16 } else if (typeof (define) === 'function' && define.amd) { // AMD 17 define("factory", function () { 18 return factory(ns, root); 19 }); 20 } else { 21 root[ns] = factory(ns, root); 22 } 23 24}(window, 'detectZoom', function () { 25 26 /** 27 * Use devicePixelRatio if supported by the browser 28 * @return {Number} 29 * @private 30 */ 31 var devicePixelRatio = function () { 32 return window.devicePixelRatio || 1; 33 }; 34 35 /** 36 * Fallback function to set default values 37 * @return {Object} 38 * @private 39 */ 40 var fallback = function () { 41 return { 42 zoom: 1, 43 devicePxPerCssPx: 1 44 }; 45 }; 46 /** 47 * IE 8 and 9: no trick needed! 48 * TODO: Test on IE10 and Windows 8 RT 49 * @return {Object} 50 * @private 51 **/ 52 var ie8 = function () { 53 var zoom = Math.round((screen.deviceXDPI / screen.logicalXDPI) * 100) / 100; 54 return { 55 zoom: zoom, 56 devicePxPerCssPx: zoom * devicePixelRatio() 57 }; 58 }; 59 60 /** 61 * For IE10 we need to change our technique again... 62 * thanks https://github.com/stefanvanburen 63 * @return {Object} 64 * @private 65 */ 66 var ie10 = function () { 67 var zoom = Math.round((document.documentElement.offsetHeight / window.innerHeight) * 100) / 100; 68 return { 69 zoom: zoom, 70 devicePxPerCssPx: zoom * devicePixelRatio() 71 }; 72 }; 73 74 /** 75 * Mobile WebKit 76 * the trick: window.innerWIdth is in CSS pixels, while 77 * screen.width and screen.height are in system pixels. 78 * And there are no scrollbars to mess up the measurement. 79 * @return {Object} 80 * @private 81 */ 82 var webkitMobile = function () { 83 var deviceWidth = (Math.abs(window.orientation) == 90) ? screen.height : screen.width; 84 var zoom = deviceWidth / window.innerWidth; 85 return { 86 zoom: zoom, 87 devicePxPerCssPx: zoom * devicePixelRatio() 88 }; 89 }; 90 91 /** 92 * Desktop Webkit 93 * the trick: an element's clientHeight is in CSS pixels, while you can 94 * set its line-height in system pixels using font-size and 95 * -webkit-text-size-adjust:none. 96 * device-pixel-ratio: http://www.webkit.org/blog/55/high-dpi-web-sites/ 97 * 98 * Previous trick (used before http://trac.webkit.org/changeset/100847): 99 * documentElement.scrollWidth is in CSS pixels, while 100 * document.width was in system pixels. Note that this is the 101 * layout width of the document, which is slightly different from viewport 102 * because document width does not include scrollbars and might be wider 103 * due to big elements. 104 * @return {Object} 105 * @private 106 */ 107 var webkit = function () { 108 var important = function (str) { 109 return str.replace(/;/g, " !important;"); 110 }; 111 112 var div = document.createElement('div'); 113 div.innerHTML = "1<br>2<br>3<br>4<br>5<br>6<br>7<br>8<br>9<br>0"; 114 div.setAttribute('style', important('font: 100px/1em sans-serif; -webkit-text-size-adjust: none; text-size-adjust: none; height: auto; width: 1em; padding: 0; overflow: visible;')); 115 116 // The container exists so that the div will be laid out in its own flow 117 // while not impacting the layout, viewport size, or display of the 118 // webpage as a whole. 119 // Add !important and relevant CSS rule resets 120 // so that other rules cannot affect the results. 121 var container = document.createElement('div'); 122 container.setAttribute('style', important('width:0; height:0; overflow:hidden; visibility:hidden; position: absolute;')); 123 container.appendChild(div); 124 125 document.body.appendChild(container); 126 var zoom = 1000 / div.clientHeight; 127 zoom = Math.round(zoom * 100) / 100; 128 document.body.removeChild(container); 129 130 return{ 131 zoom: zoom, 132 devicePxPerCssPx: zoom * devicePixelRatio() 133 }; 134 }; 135 136 /** 137 * no real trick; device-pixel-ratio is the ratio of device dpi / css dpi. 138 * (Note that this is a different interpretation than Webkit's device 139 * pixel ratio, which is the ratio device dpi / system dpi). 140 * 141 * Also, for Mozilla, there is no difference between the zoom factor and the device ratio. 142 * 143 * @return {Object} 144 * @private 145 */ 146 var firefox4 = function () { 147 var zoom = mediaQueryBinarySearch('min--moz-device-pixel-ratio', '', 0, 10, 20, 0.0001); 148 zoom = Math.round(zoom * 100) / 100; 149 return { 150 zoom: zoom, 151 devicePxPerCssPx: zoom 152 }; 153 }; 154 155 /** 156 * Firefox 18.x
157 * Mozilla added support for devicePixelRatio to Firefox 18, 158 * but it is affected by the zoom level, so, like in older 159 * Firefox we can't tell if we are in zoom mode or in a device 160 * with a different pixel ratio 161 * @return {Object} 162 * @private 163 */ 164 var firefox18 = function () { 165 return { 166 zoom: firefox4().zoom, 167 devicePxPerCssPx: devicePixelRatio() 168 }; 169 }; 170 171 /** 172 * works starting Opera 11.11 173 * the trick: outerWidth is the viewport width including scrollbars in 174 * system px, while innerWidth is the viewport width including scrollbars 175 * in CSS px 176 * @return {Object} 177 * @private 178 */ 179 var opera11 = function () { 180 var zoom = window.top.outerWidth / window.top.innerWidth; 181 zoom = Math.round(zoom * 100) / 100; 182 return { 183 zoom: zoom, 184 devicePxPerCssPx: zoom * devicePixelRatio() 185 }; 186 }; 187 188 /** 189 * Use a binary search through media queries to find zoom level in Firefox 190 * @param property 191 * @param unit 192 * @param a 193 * @param b 194 * @param maxIter 195 * @param epsilon 196 * @return {Number} 197 */ 198 var mediaQueryBinarySearch = function (property, unit, a, b, maxIter, epsilon) { 199 var matchMedia; 200 var head, style, div; 201 if (window.matchMedia) { 202 matchMedia = window.matchMedia; 203 } else { 204 head = document.getElementsByTagName('head')[0]; 205 style = document.createElement('style'); 206 head.appendChild(style); 207 208 div = document.createElement('div'); 209 div.className = 'mediaQueryBinarySearch'; 210 div.style.display = 'none'; 211 document.body.appendChild(div); 212 213 matchMedia = function (query) { 214 style.sheet.insertRule('@media ' + query + '{.mediaQueryBinarySearch ' + '{text-decoration: underline} }', 0); 215 var matched = getComputedStyle(div, null).textDecoration == 'underline'; 216 style.sheet.deleteRule(0); 217 return {matches: matched}; 218 }; 219 } 220 var ratio = binarySearch(a, b, maxIter); 221 if (div) { 222 head.removeChild(style); 223 document.body.removeChild(div); 224 } 225 return ratio; 226 227 function binarySearch(a, b, maxIter) { 228 var mid = (a + b) / 2; 229 if (maxIter <= 0 || b - a < epsilon) { 230 return mid; 231 } 232 var query = "(" + property + ":" + mid + unit + ")"; 233 if (matchMedia(query).matches) { 234 return binarySearch(mid, b, maxIter - 1); 235 } else { 236 return binarySearch(a, mid, maxIter - 1); 237 } 238 } 239 }; 240 241 /** 242 * Generate detection function 243 * @private 244 */ 245 var detectFunction = (function () { 246 var func = fallback; 247 //IE8+ 248 if (!isNaN(screen.logicalXDPI) && !isNaN(screen.systemXDPI)) { 249 func = ie8; 250 } 251 // IE10+ / Touch 252 else if (window.navigator.msMaxTouchPoints) { 253 func = ie10; 254 } 255 //Mobile Webkit 256 else if ('orientation' in window && typeof document.body.style.webkitMarquee === 'string') { 257 func = webkitMobile; 258 } 259 //WebKit 260 else if (typeof document.body.style.webkitMarquee === 'string') { 261 func = webkit; 262 } 263 //Opera 264 else if (navigator.userAgent.indexOf('Opera') >= 0) { 265 func = opera11; 266 } 267 //Last one is Firefox 268 //FF 18.x 269 else if (window.devicePixelRatio) { 270 func = firefox18; 271 } 272 //FF 4.0 - 17.x 273 else if (firefox4().zoom > 0.001) { 274 func = firefox4; 275 } 276 277 return func; 278 }()); 279 280 281 return ({ 282 283 /** 284 * Ratios.zoom shorthand 285 * @return {Number} Zoom level 286 */ 287 zoom: function () { 288 return detectFunction().zoom; 289 }, 290 291 /** 292 * Ratios.devicePxPerCssPx shorthand 293 * @return {Number} devicePxPerCssPx level 294 */ 295 device: function () { 296 return detectFunction().devicePxPerCssPx; 297 } 298 }); 299})); 300 301var wpcom_img_zoomer = { 302 zoomed: false, 303 timer: null, 304 interval: 1000, // zoom polling interval in millisecond 305 306 // Should we apply width/height attributes to control the image size? 307 imgNeedsSizeAtts: function( img ) {
308 // Do not overwrite existing width/height attributes. 309 if ( img.getAttribute('width') !== null || img.getAttribute('height') !== null ) 310 return false; 311 // Do not apply the attributes if the image is already constrained by a parent element. 312 if ( img.width < img.naturalWidth || img.height < img.naturalHeight ) 313 return false; 314 return true; 315 }, 316 317 init: function() { 318 var t = this; 319 try{ 320 t.zoomImages(); 321 t.timer = setInterval( function() { t.zoomImages(); }, t.interval ); 322 } 323 catch(e){ 324 } 325 }, 326 327 stop: function() { 328 if ( this.timer ) 329 clearInterval( this.timer ); 330 }, 331 332 getScale: function() { 333 var scale = detectZoom.device(); 334 // Round up to 1.5 or the next integer below the cap. 335 if ( scale <= 1.0 ) scale = 1.0; 336 else if ( scale <= 1.5 ) scale = 1.5; 337 else if ( scale <= 2.0 ) scale = 2.0; 338 else if ( scale <= 3.0 ) scale = 3.0; 339 else if ( scale <= 4.0 ) scale = 4.0; 340 else scale = 5.0; 341 return scale; 342 }, 343 344 shouldZoom: function( scale ) { 345 var t = this; 346 // Do not operate on hidden frames. 347 if ( "innerWidth" in window && !window.innerWidth ) 348 return false; 349 // Don't do anything until scale > 1 350 if ( scale == 1.0 && t.zoomed == false ) 351 return false; 352 return true; 353 }, 354 355 zoomImages: function() { 356 var t = this; 357 var scale = t.getScale(); 358 if ( ! t.shouldZoom( scale ) ){ 359 return; 360 } 361 t.zoomed = true; 362 // Loop through all the <img> elements on the page. 363 var imgs = document.getElementsByTagName("img"); 364 365 for ( var i = 0; i < imgs.length; i++ ) { 366 // Wait for original images to load 367 if ( "complete" in imgs[i] && ! imgs[i].complete ) 368 continue; 369 370 // Skip images that don't need processing. 371 var imgScale = imgs[i].getAttribute("scale"); 372 if ( imgScale == scale || imgScale == "0" ) 373 continue; 374 375 // Skip images that have already failed at this scale 376 var scaleFail = imgs[i].getAttribute("scale-fail"); 377 if ( scaleFail && scaleFail <= scale ) 378 continue; 379 380 // Skip images that have no dimensions yet. 381 if ( ! ( imgs[i].width && imgs[i].height ) ) 382 continue; 383 384 // Skip images from Lazy Load plugins 385 if ( ! imgScale && imgs[i].getAttribute("data-lazy-src") && (imgs[i].getAttribute("data-lazy-src") !== imgs[i].getAttribute("src"))) 386 continue; 387 388 if ( t.scaleImage( imgs[i], scale ) ) { 389 // Mark the img as having been processed at this scale. 390 imgs[i].setAttribute("scale", scale); 391 } 392 else { 393 // Set the flag to skip this image. 394 imgs[i].setAttribute("scale", "0"); 395 } 396 } 397 }, 398 399 scaleImage: function( img, scale ) { 400 var t = this; 401 var newSrc = img.src; 402 403 // Skip slideshow images 404 if ( img.parentNode.className.match(/slideshow-slide/) ) 405 return false; 406 407 // Scale gravatars that have ?s= or ?size= 408 if ( img.src.match( /^https?:\/\/([^\/]*\.)?gravatar\.com\/.+[?&](s|size)=/ ) ) { 409 newSrc = img.src.replace( /([?&](s|size)=)(\d+)/, function( $0, $1, $2, $3 ) { 410 // Stash the original size 411 var originalAtt = "originals", 412 originalSize = img.getAttribute(originalAtt); 413 if ( originalSize === null ) { 414 originalSize = $3; 415 img.setAttribute(originalAtt, originalSize); 416 if ( t.imgNeedsSizeAtts( img ) ) { 417 // Fix width and height attributes to rendered dimensions. 418 img.width = img.width; 419 img.height = img.height; 420 } 421 } 422 // Get the width/height of the image in CSS pixels 423 var size = img.clientWidth; 424 // Convert CSS pixels to device pixels 425 var targetSize = Math.ceil(img.clientWidth * scale); 426 // Don't go smaller than the original size 427 targetSize = Math.max( targetSize, originalSize ); 428 // Don't go larger than the service supports 429 targetSize = Math.min( targetSize, 512 ); 430 return $1 + targetSize; 431 }); 432 } 433 434 // Scale resize queries (*.files.wordpress.com) that have ?w= or ?h= 435 else if ( img.src.match( /^https?:\/\/([^\/]+)\.files\.wordpress\.com\/.+[?&][wh]=/ ) ) { 436 if ( img.src.match( /[?&]crop/ ) ) 437 return false; 438 var changedAttrs = {}; 439 var matches = img.src.match( /([?&]([wh])=)(\d+)/g ); 440 for ( var i = 0; i < matches.length; i++ ) { 441 var lr = matches[i].split( '=' ); 442 var thisAttr = lr[0].replace(/[?&]/g, '' ); 443 var thisVal = lr[1]; 444 445 // Stash the original size 446 var originalAtt = 'original' + thisAttr, originalSize = img.getAttribute( originalAtt ); 447 if ( originalSize === null ) { 448 originalSize = thisVal; 449 img.setAttribute(originalAtt, originalSize); 450 if ( t.imgNeedsSizeAtts( img ) ) { 451 // Fix width and height attributes to rendered dimensions. 452 img.width = img.width;
453 img.height = img.height; 454 } 455 } 456 // Get the width/height of the image in CSS pixels 457 var size = thisAttr == 'w' ? img.clientWidth : img.clientHeight; 458 var naturalSize = ( thisAttr == 'w' ? img.naturalWidth : img.naturalHeight ); 459 // Convert CSS pixels to device pixels 460 var targetSize = Math.ceil(size * scale); 461 // Don't go smaller than the original size 462 targetSize = Math.max( targetSize, originalSize ); 463 // Don't go bigger unless the current one is actually lacking 464 if ( scale > img.getAttribute("scale") && targetSize <= naturalSize ) 465 targetSize = thisVal; 466 // Don't try to go bigger if the image is already smaller than was requested 467 if ( naturalSize < thisVal ) 468 targetSize = thisVal; 469 if ( targetSize != thisVal ) 470 changedAttrs[ thisAttr ] = targetSize; 471 } 472 var w = changedAttrs.w || false; 473 var h = changedAttrs.h || false; 474 475 if ( w ) { 476 newSrc = img.src.replace(/([?&])w=\d+/g, function( $0, $1 ) { 477 return $1 + 'w=' + w; 478 }); 479 } 480 if ( h ) { 481 newSrc = newSrc.replace(/([?&])h=\d+/g, function( $0, $1 ) { 482 return $1 + 'h=' + h; 483 }); 484 } 485 } 486 487 // Scale mshots that have width 488 else if ( img.src.match(/^https?:\/\/([^\/]+\.)*(wordpress|wp)\.com\/mshots\/.+[?&]w=\d+/) ) { 489 newSrc = img.src.replace( /([?&]w=)(\d+)/, function($0, $1, $2) { 490 // Stash the original size 491 var originalAtt = 'originalw', originalSize = img.getAttribute(originalAtt); 492 if ( originalSize === null ) { 493 originalSize = $2; 494 img.setAttribute(originalAtt, originalSize); 495 if ( t.imgNeedsSizeAtts( img ) ) { 496 // Fix width and height attributes to rendered dimensions. 497 img.width = img.width; 498 img.height = img.height; 499 } 500 } 501 // Get the width of the image in CSS pixels 502 var size = img.clientWidth; 503 // Convert CSS pixels to device pixels 504 var targetSize = Math.ceil(size * scale); 505 // Don't go smaller than the original size 506 targetSize = Math.max( targetSize, originalSize ); 507 // Don't go bigger unless the current one is actually lacking 508 if ( scale > img.getAttribute("scale") && targetSize <= img.naturalWidth ) 509 targetSize = $2; 510 if ( $2 != targetSize ) 511 return $1 + targetSize; 512 return $0; 513 }); 514 515 // Update height attribute to match width 516 newSrc = newSrc.replace( /([?&]h=)(\d+)/, function($0, $1, $2) { 517 if ( newSrc == img.src ) { 518 return $0; 519 } 520 // Stash the original size 521 var originalAtt = 'originalh', originalSize = img.getAttribute(originalAtt); 522 if ( originalSize === null ) { 523 originalSize = $2; 524 img.setAttribute(originalAtt, originalSize); 525 } 526 // Get the height of the image in CSS pixels 527 var size = img.clientHeight; 528 // Convert CSS pixels to device pixels 529 var targetSize = Math.ceil(size * scale); 530 // Don't go smaller than the original size 531 targetSize = Math.max( targetSize, originalSize ); 532 // Don't go bigger unless the current one is actually lacking 533 if ( scale > img.getAttribute("scale") && targetSize <= img.naturalHeight ) 534 targetSize = $2; 535 if ( $2 != targetSize ) 536 return $1 + targetSize; 537 return $0; 538 }); 539 } 540 541 // Scale simple imgpress queries (s0.wp.com) that only specify w/h/fit 542 else if ( img.src.match(/^https?:\/\/([^\/.]+\.)*(wp|wordpress)\.com\/imgpress\?(.+)/) ) { 543 var imgpressSafeFunctions = ["zoom", "url", "h", "w", "fit", "filter", "brightness", "contrast", "colorize", "smooth", "unsharpmask"]; 544 // Search the query string for unsupported functions. 545 var qs = RegExp.$3.split('&'); 546 for ( var q in qs ) { 547 q = qs[q].split('=')[0]; 548 if ( imgpressSafeFunctions.indexOf(q) == -1 ) { 549 return false; 550 } 551 } 552 // Fix width and height attributes to rendered dimensions. 553 img.width = img.width; 554 img.height = img.height; 555 // Compute new src 556 if ( scale == 1 ) 557 newSrc = img.src.replace(/\?(zoom=[^&]+&)?/, '?'); 558 else 559 newSrc = img.src.replace(/\?(zoom=[^&]+&)?/, '?zoom=' + scale + '&'); 560 } 561 562 // Scale LaTeX images or Photon queries (i#.wp.com) 563 else if ( 564 img.src.match(/^https?:\/\/([^\/.]+\.)*(wp|wordpress)\.com\/latex\.php\?(latex|zoom)=(.+)/) || 565 img.src.match(/^https?:\/\/i[\d]{1}\.wp\.com\/(.+)/) 566 ) { 567 // Fix width and height attributes to rendered dimensions. 568 img.width = img.width;
569 img.height = img.height; 570 // Compute new src 571 if ( scale == 1 ) { 572 newSrc = img.src.replace(/\?(zoom=[^&]+&)?/, '?'); 573 } else { 574 newSrc = img.src; 575 576 var url_var = newSrc.match( /\?w=(\d+)/ ); 577 if ( url_var !== null && url_var[1] ) { 578 newSrc = newSrc.replace( new RegExp( 'w=' + url_var[1] ), 'w=' + img.width ); 579 } 580 581 url_var = newSrc.match( /\?h=(\d+)/ ); 582 if ( url_var !== null && url_var[1] ) { 583 newSrc = newSrc.replace( new RegExp( 'h=' + url_var[1] ), 'h=' + img.height ); 584 } 585 586 var zoom_arg = '&zoom=2'; 587 if ( !newSrc.match( /\?/ ) ) { 588 zoom_arg = '?zoom=2'; 589 } 590 img.setAttribute( 'srcset', newSrc + zoom_arg + ' ' + scale + 'x' ); 591 } 592 } 593 594 // Scale static assets that have a name matching *-1x.png or *@1x.png 595 else if ( img.src.match(/^https?:\/\/[^\/]+\/.*[-@]([12])x\.(gif|jpeg|jpg|png)(\?|$)/) ) { 596 // Fix width and height attributes to rendered dimensions. 597 img.width = img.width; 598 img.height = img.height; 599 var currentSize = RegExp.$1, newSize = currentSize; 600 if ( scale <= 1 ) 601 newSize = 1; 602 else 603 newSize = 2; 604 if ( currentSize != newSize ) 605 newSrc = img.src.replace(/([-@])[12]x\.(gif|jpeg|jpg|png)(\?|$)/, '$1'+newSize+'x.$2$3'); 606 } 607 608 else { 609 return false; 610 } 611 612 // Don't set img.src unless it has changed. This avoids unnecessary reloads. 613 if ( newSrc != img.src ) { 614 // Store the original img.src 615 var prevSrc, origSrc = img.getAttribute("src-orig"); 616 if ( !origSrc ) { 617 origSrc = img.src; 618 img.setAttribute("src-orig", origSrc); 619 } 620 // In case of error, revert img.src 621 prevSrc = img.src; 622 img.onerror = function(){ 623 img.src = prevSrc; 624 if ( img.getAttribute("scale-fail") < scale ) 625 img.setAttribute("scale-fail", scale); 626 img.onerror = null; 627 }; 628 // Finally load the new image 629 img.src = newSrc; 630 } 631 632 return true; 633 } 634}; 635 636wpcom_img_zoomer.init(); 637; 638// WARNING: This file is distributed verbatim in Jetpack. There should be nothing WordPress.com specific in this file. @hide-in-jetpack 639(function($){ // Open closure 640// Local vars 641var Scroller, ajaxurl, stats, type, text, totop; 642 643// IE requires special handling
644var isIE = ( -1 != navigator.userAgent.search( 'MSIE' ) ); 645if ( isIE ) { 646 var IEVersion = navigator.userAgent.match(/MSIE\s?(\d+)\.?\d*;/); 647 var IEVersion = parseInt( IEVersion[1] ); 648} 649 650// HTTP ajaxurl when site is HTTPS causes Access-Control-Allow-Origin failure in Desktop and iOS Safari 651if ( "https:" == document.location.protocol ) { 652 infiniteScroll.settings.ajaxurl = infiniteScroll.settings.ajaxurl.replace( "http://", "https://" ); 653} 654 655/** 656 * Loads new posts when users scroll near the bottom of the page. 657 */ 658Scroller = function( settings ) { 659 var self = this; 660 661 // Initialize our variables 662 this.id = settings.id; 663 this.body = $( document.body ); 664 this.window = $( window ); 665 this.element = $( '#' + settings.id ); 666 this.wrapperClass = settings.wrapper_class; 667 this.ready = true; 668 this.disabled = false; 669 this.page = 1; 670 this.offset = settings.offset; 671 this.currentday = settings.currentday; 672 this.order = settings.order; 673 this.throttle = false; 674 this.handle = '<div id="infinite-handle"><span><button>' + text.replace( '\\', '' ) + '</button></span></div>'; 675 this.click_handle = settings.click_handle; 676 this.google_analytics = settings.google_analytics; 677 this.history = settings.history; 678 this.origURL = window.location.href; 679 this.pageCache = {}; 680 681 // Footer settings 682 this.footer = $( '#infinite-footer' ); 683 this.footer.wrap = settings.footer; 684 685 // Core's native MediaElement.js implementation needs special handling 686 this.wpMediaelement = null; 687 688 // We have two type of infinite scroll 689 // cases 'scroll' and 'click' 690 691 if ( type == 'scroll' ) { 692 // Bind refresh to the scroll event 693 // Throttle to check for such case every 300ms 694 695 // On event the case becomes a fact 696 this.window.bind( 'scroll.infinity', function() { 697 this.throttle = true; 698 }); 699 700 // Go back top method 701 self.gotop(); 702 703 setInterval( function() { 704 if ( this.throttle ) { 705 // Once the case is the case, the action occurs and the fact is no more 706 this.throttle = false; 707 // Reveal or hide footer 708 self.thefooter(); 709 // Fire the refresh 710 self.refresh(); 711 self.determineURL(); // determine the url 712 } 713 }, 250 ); 714 715 // Ensure that enough posts are loaded to fill the initial viewport, to compensate for short posts and large displays. 716 self.ensureFilledViewport(); 717 this.body.bind( 'post-load', { self: self }, self.checkViewportOnLoad ); 718 } else if ( type == 'click' ) { 719 if ( this.click_handle ) { 720 this.element.append( this.handle ); 721 } 722 723 this.body.delegate( '#infinite-handle', 'click.infinity', function() { 724 // Handle the handle 725 if ( self.click_handle ) { 726 $( '#infinite-handle' ).remove(); 727 } 728 729 // Fire the refresh 730 self.refresh(); 731 }); 732 } 733 734 // Initialize any Core audio or video players loaded via IS 735 this.body.bind( 'post-load', { self: self }, self.initializeMejs ); 736}; 737 738/** 739 * Check whether we should fetch any additional posts. 740 */ 741Scroller.prototype.check = function() { 742 var container = this.element.offset(); 743 744 // If the container can't be found, stop otherwise errors result 745 if ( 'object' !== typeof container ) { 746 return false; 747 } 748 749 var bottom = this.window.scrollTop() + this.window.height(), 750 threshold = container.top + this.element.outerHeight(false) - (this.window.height() * 2); 751 752 return bottom > threshold; 753}; 754 755/** 756 * Renders the results from a successful response. 757 */ 758Scroller.prototype.render = function( response ) { 759 this.body.addClass( 'infinity-success' ); 760 761 // Check if we can wrap the html 762 this.element.append( response.html ); 763 this.body.trigger( 'post-load', response ); 764 this.ready = true; 765}; 766 767/** 768 * Returns the object used to query for new posts. 769 */ 770Scroller.prototype.query = function() { 771 return { 772 page : this.page, 773 currentday : this.currentday, 774 order : this.order, 775 scripts : window.infiniteScroll.settings.scripts, 776 styles : window.infiniteScroll.settings.styles,
777 query_args : window.infiniteScroll.settings.query_args, 778 last_post_date : window.infiniteScroll.settings.last_post_date 779 }; 780}; 781 782/** 783 * Scroll back to top. 784 */ 785Scroller.prototype.gotop = function() { 786 var blog = $( '#infinity-blog-title' ); 787 788 blog.attr( 'title', totop ); 789 790 // Scroll to top on blog title 791 blog.bind( 'click', function( e ) { 792 $( 'html, body' ).animate( { scrollTop: 0 }, 'fast' ); 793 e.preventDefault(); 794 }); 795}; 796 797 798/** 799 * The infinite footer. 800 */ 801Scroller.prototype.thefooter = function() { 802 var self = this, 803 width; 804 805 // Check if we have an id for the page wrapper 806 if ( $.type( this.footer.wrap ) === "string" ) { 807 width = $( 'body #' + this.footer.wrap ).outerWidth( false ); 808 809 // Make the footer match the width of the page 810 if ( width > 479 ) 811 this.footer.find( '.container' ).css( 'width', width ); 812 } 813 814 // Reveal footer 815 if ( this.window.scrollTop() >= 350 ) 816 self.footer.animate( { 'bottom': 0 }, 'fast' ); 817 else if ( this.window.scrollTop() < 350 ) 818 self.footer.animate( { 'bottom': '-50px' }, 'fast' ); 819}; 820 821 822/** 823 * Controls the flow of the refresh. Don't mess. 824 */ 825Scroller.prototype.refresh = function() { 826 var self = this, 827 query, jqxhr, load, loader, color; 828 829 // If we're disabled, ready, or don't pass the check, bail. 830 if ( this.disabled || ! this.ready || ! this.check() ) 831 return; 832 833 // Let's get going -- set ready to false to prevent 834 // multiple refreshes from occurring at once. 835 this.ready = false; 836 837 // Create a loader element to show it's working. 838 if ( this.click_handle ) { 839 loader = '<span class="infinite-loader"></span>'; 840 this.element.append( loader ); 841 842 loader = this.element.find( '.infinite-loader' ); 843 color = loader.css( 'color' ); 844 845 try { 846 loader.spin( 'medium-left', color ); 847 } catch ( error ) { } 848 } 849 850 // Generate our query vars. 851 query = $.extend({ 852 action: 'infinite_scroll' 853 }, this.query() ); 854 855 // Fire the ajax request. 856 jqxhr = $.post( infiniteScroll.settings.ajaxurl, query ); 857 858 // Allow refreshes to occur again if an error is triggered. 859 jqxhr.fail( function() { 860 if ( self.click_handle ) { 861 loader.hide(); 862 } 863 864 self.ready = true; 865 }); 866 867 // Success handler 868 jqxhr.done( function( response ) { 869 // On success, let's hide the loader circle. 870 if ( self.click_handle ) { 871 loader.hide(); 872 } 873 874 // Check for and parse our response. 875 if ( ! response ) 876 return; 877 878 response = $.parseJSON( response ); 879 880 if ( ! response || ! response.type ) 881 return; 882 883 // If there are no remaining posts... 884 if ( response.type == 'empty' ) { 885 // Disable the scroller. 886 self.disabled = true; 887 // Update body classes, allowing the footer to return to static positioning 888 self.body.addClass( 'infinity-end' ).removeClass( 'infinity-success' ); 889 890 // If we've succeeded... 891 } else if ( response.type == 'success' ) { 892 // If additional scripts are required by the incoming set of posts, parse them 893 if ( response.scripts ) { 894 $( response.scripts ).each( function() { 895 var elementToAppendTo = this.footer ? 'body' : 'head'; 896 897 // Add script handle to list of those already parsed 898 window.infiniteScroll.settings.scripts.push( this.handle ); 899 900 // Output extra data, if present 901 if ( this.extra_data ) { 902 var data = document.createElement('script'), 903 dataContent = document.createTextNode( "//<![CDATA[ \n" + this.extra_data + "\n//]]>" ); 904 905 data.type = 'text/javascript'; 906 data.appendChild( dataContent ); 907 908 document.getElementsByTagName( elementToAppendTo )[0].appendChild(data); 909 } 910 911 // Build script tag and append to DOM in requested location 912 var script = document.createElement('script'); 913 script.type = 'text/javascript'; 914 script.src = this.src; 915 script.id = this.handle; 916 917 // If MediaElement.js is loaded in by this set of posts, don't initialize the players a second time as it breaks them all 918 if ( 'wp-mediaelement' === this.handle ) { 919 self.body.unbind( 'post-load', self.initializeMejs ); 920 } 921 922 if ( 'wp-mediaelement' === this.handle && 'undefined' === typeof mejs ) { 923 self.wpMediaelement = {}; 924 self.wpMediaelement.tag = script; 925 self.wpMediaelement.element = elementToAppendTo; 926 setTimeout( self.maybeLoadMejs.bind( self ), 250 ); 927 } else { 928 document.getElementsByTagName( elementToAppendTo )[0].appendChild(script); 929 } 930 } ); 931 } 932 933 // If additional stylesheets are required by the incoming set of posts, parse them 934 if ( response.styles ) { 935 $( response.styles ).each( function() { 936 // Add stylesheet handle to list of those already parsed
937 window.infiniteScroll.settings.styles.push( this.handle ); 938 939 // Build link tag 940 var style = document.createElement('link'); 941 style.rel = 'stylesheet'; 942 style.href = this.src; 943 style.id = this.handle + '-css'; 944 945 // Destroy link tag if a conditional statement is present and either the browser isn't IE, or the conditional doesn't evaluate true 946 if ( this.conditional && ( ! isIE || ! eval( this.conditional.replace( /%ver/g, IEVersion ) ) ) ) 947 var style = false; 948 949 // Append link tag if necessary 950 if ( style ) 951 document.getElementsByTagName('head')[0].appendChild(style); 952 } ); 953 } 954 955 // stash the response in the page cache 956 self.pageCache[self.page] = response; 957 958 // Increment the page number 959 self.page++; 960 961 // Record pageview in WP Stats, if available. 962 if ( stats ) 963 new Image().src = document.location.protocol + '//pixel.wp.com/g.gif?' + stats + '&post=0&baba=' + Math.random(); 964 965 // Add new posts to the postflair object 966 if ( 'object' == typeof response.postflair && 'object' == typeof WPCOM_sharing_counts ) 967 WPCOM_sharing_counts = $.extend( WPCOM_sharing_counts, response.postflair ); 968 969 // Render the results 970 self.render.apply( self, arguments ); 971 972 // If 'click' type and there are still posts to fetch, add back the handle 973 if ( type == 'click' ) { 974 if ( response.lastbatch ) { 975 if ( self.click_handle ) { 976 $( '#infinite-handle' ).remove(); 977 } else { 978 self.body.trigger( 'infinite-scroll-posts-end' ); 979 } 980 } else { 981 if ( self.click_handle ) { 982 self.element.append( self.handle ); 983 } else { 984 self.body.trigger( 'infinite-scroll-posts-more' ); 985 } 986 } 987 } 988 989 // Update currentday to the latest value returned from the server 990 if ( response.currentday ) { 991 self.currentday = response.currentday; 992 } 993 994 // Fire Google Analytics pageview 995 if ( self.google_analytics ) { 996 var ga_url = self.history.path.replace( /%d/, self.page ); 997 if ( 'object' === typeof _gaq ) { 998 _gaq.push( [ '_trackPageview', ga_url ] ); 999 } 1000 if ( 'function' === typeof ga ) { 1001 ga( 'send', 'pageview', ga_url ); 1002 } 1003 } 1004 } 1005 }); 1006 1007 return jqxhr; 1008}; 1009 1010/** 1011 * Core's native media player uses MediaElement.js 1012 * The library's size is sufficient that it may not be loaded in time for Core's helper to invoke it, so we need to delay until `mejs` exists. 1013 */ 1014Scroller.prototype.maybeLoadMejs = function() { 1015 if ( null === this.wpMediaelement ) { 1016 return; 1017 } 1018 1019 if ( 'undefined' === typeof mejs ) { 1020 setTimeout( this.maybeLoadMejs, 250 ); 1021 } else { 1022 document.getElementsByTagName( this.wpMediaelement.element )[0].appendChild( this.wpMediaelement.tag ); 1023 this.wpMediaelement = null; 1024 1025 // Ensure any subsequent IS loads initialize the players 1026 this.body.bind( 'post-load', { self: this }, this.initializeMejs ); 1027 } 1028} 1029 1030/** 1031 * Initialize the MediaElement.js player for any posts not previously initialized 1032 */ 1033Scroller.prototype.initializeMejs = function( ev, response ) { 1034 // Are there media players in the incoming set of posts? 1035 if ( ! response.html || -1 === response.html.indexOf( 'wp-audio-shortcode' ) && -1 === response.html.indexOf( 'wp-video-shortcode' ) ) { 1036 return; 1037 } 1038 1039 // Don't bother if mejs isn't loaded for some reason 1040 if ( 'undefined' === typeof mejs ) { 1041 return; 1042 } 1043 1044 // Adapted from wp-includes/js/mediaelement/wp-mediaelement.js 1045 // Modified to not initialize already-initialized players, as Mejs doesn't handle that well 1046 $(function () { 1047 var settings = {}; 1048 1049 if ( typeof _wpmejsSettings !== 'undefined' ) { 1050 settings.pluginPath = _wpmejsSettings.pluginPath; 1051 } 1052 1053 settings.success = function (mejs) { 1054 var autoplay = mejs.attributes.autoplay && 'false' !== mejs.attributes.autoplay; 1055 if ( 'flash' === mejs.pluginType && autoplay ) { 1056 mejs.addEventListener( 'canplay', function () { 1057 mejs.play(); 1058 }, false ); 1059 } 1060 }; 1061 1062 $('.wp-audio-shortcode, .wp-video-shortcode').not( '.mejs-container' ).mediaelementplayer( settings ); 1063 }); 1064} 1065 1066/** 1067 * Trigger IS to load additional posts if the initial posts don't fill the window. 1068 * On large displays, or when posts are very short, the viewport may not be filled with posts, so we overcome this by loading additional posts when IS initializes. 1069 */ 1070Scroller.prototype.ensureFilledViewport = function() { 1071 var self = this, 1072 windowHeight = self.window.height(), 1073 postsHeight = self.element.height(), 1074 aveSetHeight = 0, 1075 wrapperQty = 0; 1076 1077 // Account for situations where postsHeight is 0 because child list elements are floated 1078 if ( postsHeight === 0 ) { 1079 $( self.element.selector + ' > li' ).each( function() { 1080 postsHeight += $( this ).height(); 1081 } ); 1082 1083 if ( postsHeight === 0 ) { 1084 self.body.unbind( 'post-load', self.checkViewportOnLoad ); 1085 return; 1086 } 1087 } 1088 1089 // Calculate average height of a set of posts to prevent more posts than needed from being loaded. 1090 $( '.' + self.wrapperClass ).each( function() { 1091 aveSetHeight += $( this ).height(); 1092 wrapperQty++; 1093 } ); 1094 1095 if ( wrapperQty > 0 ) 1096 aveSetHeight = aveSetHeight / wrapperQty; 1097 else 1098 aveSetHeight = 0; 1099 1100 // Load more posts if space permits, otherwise stop checking for a full viewport 1101 if ( postsHeight < windowHeight && ( postsHeight + aveSetHeight < windowHeight ) ) { 1102 self.ready = true; 1103 self.refresh(); 1104 } 1105 else { 1106 self.body.unbind( 'post-load', self.checkViewportOnLoad ); 1107 } 1108} 1109 1110/** 1111 * Event handler for ensureFilledViewport(), tied to the post-load trigger. 1112 * Necessary to ensure that the variable `this` contains the scroller when used in ensureFilledViewport(). Since this function is tied to an event, `this` becomes the DOM element the event is tied to. 1113 */ 1114Scroller.prototype.checkViewportOnLoad = function( ev ) { 1115 ev.data.self.ensureFilledViewport(); 1116} 1117 1118/** 1119 * Identify archive page that corresponds to majority of posts shown in the current browser window. 1120 */ 1121Scroller.prototype.determineURL = function () { 1122 var self = this, 1123 windowTop = $( window ).scrollTop(), 1124 windowBottom = windowTop + $( window ).height(), 1125 windowSize = windowBottom - windowTop, 1126 setsInView = [], 1127 setsHidden = [], 1128 pageNum = false;
1129 1130 // Find out which sets are in view 1131 $( '.' + self.wrapperClass ).each( function() { 1132 var id = $( this ).attr( 'id' ), 1133 setTop = $( this ).offset().top, 1134 setHeight = $( this ).outerHeight( false ), 1135 setBottom = 0, 1136 setPageNum = $( this ).data( 'page-num' ); 1137 1138 // Account for containers that have no height because their children are floated elements. 1139 if ( 0 === setHeight ) { 1140 $( '> *', this ).each( function() { 1141 setHeight += $( this ).outerHeight( false ); 1142 } ); 1143 } 1144 1145 // Determine position of bottom of set by adding its height to the scroll position of its top. 1146 setBottom = setTop + setHeight; 1147 1148 // Populate setsInView object. While this logic could all be combined into a single conditional statement, this is easier to understand. 1149 if ( setTop < windowTop && setBottom > windowBottom ) { // top of set is above window, bottom is below 1150 setsInView.push({'id': id, 'top': setTop, 'bottom': setBottom, 'pageNum': setPageNum }); 1151 } 1152 else if( setTop > windowTop && setTop < windowBottom ) { // top of set is between top (gt) and bottom (lt) 1153 setsInView.push({'id': id, 'top': setTop, 'bottom': setBottom, 'pageNum': setPageNum }); 1154 } 1155 else if( setBottom > windowTop && setBottom < windowBottom ) { // bottom of set is between top (gt) and bottom (lt) 1156 setsInView.push({'id': id, 'top': setTop, 'bottom': setBottom, 'pageNum': setPageNum }); 1157 } else { 1158 setsHidden.push({'id': id, 'top': setTop, 'bottom': setBottom, 'pageNum': setPageNum }); 1159 } 1160 } ); 1161 1162 $.each(setsHidden, function() { 1163 var $set = $('#' + this.id); 1164 if( $set.hasClass( 'is--replaced' ) ) { 1165 return; 1166 } 1167 1168 self.pageCache[ this.pageNum].html = $set.html(); 1169 1170 $set.css('min-height', ( this.bottom - this.top ) + 'px' ) 1171 .addClass('is--replaced') 1172 .empty(); 1173 }); 1174 1175 $.each(setsInView, function() { 1176 var $set = $('#' + this.id); 1177 1178 if( $set.hasClass('is--replaced') ) { 1179 $set.css('min-height', '').removeClass('is--replaced'); 1180 if( this.pageNum in self.pageCache ) { 1181 $set.html( self.pageCache[this.pageNum].html ); 1182 self.body.trigger( 'post-load', self.pageCache[this.pageNum] ); 1183 } 1184 } 1185 1186 }); 1187 1188 // Parse number of sets found in view in an attempt to update the URL to match the set that comprises the majority of the window. 1189 if ( 0 == setsInView.length ) { 1190 pageNum = -1; 1191 } 1192 else if ( 1 == setsInView.length ) { 1193 var setData = setsInView.pop(); 1194 1195 // If the first set of IS posts is in the same view as the posts loaded in the template by WordPress, determine how much of the view is comprised of IS-loaded posts 1196 if ( ( ( windowBottom - setData.top ) / windowSize ) < 0.5 ) 1197 pageNum = -1; 1198 else 1199 pageNum = setData.pageNum; 1200 } 1201 else { 1202 var majorityPercentageInView = 0; 1203 1204 // Identify the IS set that comprises the majority of the current window and set the URL to it. 1205 $.each( setsInView, function( i, setData ) { 1206 var topInView = 0, 1207 bottomInView = 0, 1208 percentOfView = 0; 1209 1210 // Figure percentage of view the current set represents 1211 if ( setData.top > windowTop && setData.top < windowBottom ) 1212 topInView = ( windowBottom - setData.top ) / windowSize; 1213 1214 if ( setData.bottom > windowTop && setData.bottom < windowBottom ) 1215 bottomInView = ( setData.bottom - windowTop ) / windowSize; 1216 1217 // Figure out largest percentage of view for current set 1218 if ( topInView >= bottomInView ) 1219 percentOfView = topInView; 1220 else if ( bottomInView >= topInView ) 1221 percentOfView = bottomInView; 1222 1223 // Does current set's percentage of view supplant the largest previously-found set? 1224 if ( percentOfView > majorityPercentageInView ) { 1225 pageNum = setData.pageNum; 1226 majorityPercentageInView = percentOfView; 1227 } 1228 } ); 1229 } 1230 1231 // If a page number could be determined, update the URL 1232 // -1 indicates that the original requested URL should be used. 1233 if ( 'number' == typeof pageNum ) { 1234 if ( pageNum != -1 ) 1235 pageNum++; 1236 1237 self.updateURL( pageNum ); 1238 } 1239} 1240 1241/** 1242 * Update address bar to reflect archive page URL for a given page number. 1243 * Checks if URL is different to prevent pollution of browser history. 1244 */ 1245Scroller.prototype.updateURL = function( page ) { 1246 // IE only supports pushState() in v10 and above, so don't bother if those conditions aren't met. 1247 if ( ! window.history.pushState ) { 1248 return; 1249 } 1250 var self = this, 1251 offset = self.offset > 0 ? self.offset - 1 : 0, 1252 pageSlug = -1 == page ? self.origURL : window.location.protocol + '//' + self.history.host + self.history.path.replace( /%d/, page + offset ) + self.history.parameters; 1253 1254 if ( window.location.href != pageSlug ) { 1255 history.pushState( null, null, pageSlug ); 1256 } 1257} 1258 1259/** 1260 * Ready, set, go! 1261 */ 1262$( document ).ready( function() { 1263 // Check for our variables 1264 if ( 'object' != typeof infiniteScroll ) 1265 return; 1266 1267 // Set ajaxurl (for brevity)
1268 ajaxurl = infiniteScroll.settings.ajaxurl; 1269 1270 // Set stats, used for tracking stats 1271 stats = infiniteScroll.settings.stats; 1272 1273 // Define what type of infinity we have, grab text for click-handle 1274 type = infiniteScroll.settings.type; 1275 text = infiniteScroll.settings.text; 1276 totop = infiniteScroll.settings.totop; 1277 1278 // Initialize the scroller (with the ID of the element from the theme) 1279 infiniteScroll.scroller = new Scroller( infiniteScroll.settings ); 1280 1281 /** 1282 * Monitor user scroll activity to update URL to correspond to archive page for current set of IS posts 1283 */ 1284 if( type == 'click' ) { 1285 var timer = null; 1286 $( window ).bind( 'scroll', function() { 1287 // run the real scroll handler once every 250 ms. 1288 if ( timer ) { return; } 1289 timer = setTimeout( function() { 1290 infiniteScroll.scroller.determineURL(); 1291 timer = null; 1292 } , 250 ); 1293 }); 1294 } 1295}); 1296 1297 1298})(jQuery); // Close closure 1299; 1300// WARNING: This file is distributed verbatim in Jetpack. @hide-in-jetpack 1301/*! 1302 * jQuery Cycle Plugin (with Transition Definitions) 1303 * Examples and documentation at: http://jquery.malsup.com/cycle/ 1304 * Copyright (c) 2007-2010 M. Alsup 1305 * Version: 2.9999.8 (26-OCT-2012) 1306 * Dual licensed under the MIT and GPL licenses. 1307 * http://jquery.malsup.com/license.html 1308 * Requires: jQuery v1.3.2 or later 1309 */ 1310;(function($, undefined) { 1311"use strict"; 1312 1313var ver = '2.9999.8'; 1314 1315// if $.support is not defined (pre jQuery 1.3) add what I need 1316if ($.support === undefined) { 1317 $.support = { 1318 opacity: !($.browser.msie) 1319 }; 1320} 1321 1322function debug(s) { 1323 if ($.fn.cycle.debug) 1324 log(s); 1325} 1326function log() { 1327 if (window.console && console.log) 1328 console.log('[cycle] ' + Array.prototype.join.call(arguments,' ')); 1329} 1330$.expr[':'].paused = function(el) { 1331 return el.cyclePause; 1332}; 1333 1334 1335// the options arg can be... 1336// a number - indicates an immediate transition should occur to the given slide index 1337// a string - 'pause', 'resume', 'toggle', 'next', 'prev', 'stop', 'destroy' or the name of a transition effect (ie, 'fade', 'zoom', etc) 1338// an object - properties to control the slideshow 1339// 1340// the arg2 arg can be... 1341// the name of an fx (only used in conjunction with a numeric value for 'options') 1342// the value true (only used in first arg == 'resume') and indicates 1343// that the resume should occur immediately (not wait for next timeout) 1344 1345$.fn.cycle = function(options, arg2) { 1346 var o = { s: this.selector, c: this.context }; 1347 1348 // in 1.3+ we can fix mistakes with the ready state 1349 if (this.length === 0 && options != 'stop') { 1350 if (!$.isReady && o.s) { 1351 log('DOM not ready, queuing slideshow'); 1352 $(function() { 1353 $(o.s,o.c).cycle(options,arg2); 1354 }); 1355 return this; 1356 } 1357 // is your DOM ready? http://docs.jquery.com/Tutorials:Introducing_$(document).ready() 1358 log('terminating; zero elements found by selector' + ($.isReady ? '' : ' (DOM not ready)')); 1359 return this; 1360 } 1361 1362 // iterate the matched nodeset 1363 return this.each(function() { 1364 var opts = handleArguments(this, options, arg2); 1365 if (opts === false) 1366 return; 1367 1368 opts.updateActivePagerLink = opts.updateActivePagerLink || $.fn.cycle.updateActivePagerLink; 1369 1370 // stop existing slideshow for this container (if there is one) 1371 if (this.cycleTimeout) 1372 clearTimeout(this.cycleTimeout); 1373 this.cycleTimeout = this.cyclePause = 0; 1374 this.cycleStop = 0; // issue #108 1375 1376 var $cont = $(this); 1377 var $slides = opts.slideExpr ? $(opts.slideExpr, this) : $cont.children(); 1378 var els = $slides.get(); 1379 1380 if (els.length < 2) { 1381 log('terminating; too few slides: ' + els.length); 1382 return; 1383 } 1384 1385 var opts2 = buildOptions($cont, $slides, els, opts, o); 1386 if (opts2 === false) 1387 return; 1388 1389 var startTime = opts2.continuous ? 10 : getTimeout(els[opts2.currSlide], els[opts2.nextSlide], opts2, !opts2.backwards); 1390 1391 // if it's an auto slideshow, kick it off 1392 if (startTime) { 1393 startTime += (opts2.delay || 0); 1394 if (startTime < 10) 1395 startTime = 10; 1396 debug('first timeout: ' + startTime); 1397 this.cycleTimeout = setTimeout(function(){go(els,opts2,0,!opts.backwards);}, startTime); 1398 } 1399 }); 1400}; 1401 1402function triggerPause(cont, byHover, onPager) { 1403 var opts = $(cont).data('cycle.opts'); 1404 if (!opts) 1405 return; 1406 var paused = !!cont.cyclePause; 1407 if (paused && opts.paused) 1408 opts.paused(cont, opts, byHover, onPager); 1409 else if (!paused && opts.resumed) 1410 opts.resumed(cont, opts, byHover, onPager); 1411} 1412 1413// process the args that were passed to the plugin fn 1414function handleArguments(cont, options, arg2) { 1415 if (cont.cycleStop === undefined) 1416 cont.cycleStop = 0; 1417 if (options === undefined || options === null) 1418 options = {}; 1419 if (options.constructor == String) { 1420 switch(options) { 1421 case 'destroy': 1422 case 'stop': 1423 var opts = $(cont).data('cycle.opts'); 1424 if (!opts) 1425 return false;
1426 cont.cycleStop++; // callbacks look for change 1427 if (cont.cycleTimeout) 1428 clearTimeout(cont.cycleTimeout); 1429 cont.cycleTimeout = 0; 1430 if (opts.elements) 1431 $(opts.elements).stop(); 1432 $(cont).removeData('cycle.opts'); 1433 if (options == 'destroy') 1434 destroy(cont, opts); 1435 return false; 1436 case 'toggle': 1437 cont.cyclePause = (cont.cyclePause === 1) ? 0 : 1; 1438 checkInstantResume(cont.cyclePause, arg2, cont); 1439 triggerPause(cont); 1440 return false; 1441 case 'pause': 1442 cont.cyclePause = 1; 1443 triggerPause(cont); 1444 return false; 1445 case 'resume': 1446 cont.cyclePause = 0; 1447 checkInstantResume(false, arg2, cont); 1448 triggerPause(cont); 1449 return false; 1450 case 'prev': 1451 case 'next': 1452 opts = $(cont).data('cycle.opts'); 1453 if (!opts) { 1454 log('options not found, "prev/next" ignored'); 1455 return false; 1456 } 1457 $.fn.cycle[options](opts); 1458 return false; 1459 default: 1460 options = { fx: options }; 1461 } 1462 return options; 1463 } 1464 else if (options.constructor == Number) { 1465 // go to the requested slide 1466 var num = options; 1467 options = $(cont).data('cycle.opts'); 1468 if (!options) { 1469 log('options not found, can not advance slide'); 1470 return false; 1471 } 1472 if (num < 0 || num >= options.elements.length) { 1473 log('invalid slide index: ' + num); 1474 return false; 1475 } 1476 options.nextSlide = num; 1477 if (cont.cycleTimeout) { 1478 clearTimeout(cont.cycleTimeout); 1479 cont.cycleTimeout = 0; 1480 } 1481 if (typeof arg2 == 'string') 1482 options.oneTimeFx = arg2; 1483 go(options.elements, options, 1, num >= options.currSlide); 1484 return false; 1485 } 1486 return options; 1487 1488 function checkInstantResume(isPaused, arg2, cont) { 1489 if (!isPaused && arg2 === true) { // resume now! 1490 var options = $(cont).data('cycle.opts'); 1491 if (!options) { 1492 log('options not found, can not resume'); 1493 return false; 1494 } 1495 if (cont.cycleTimeout) { 1496 clearTimeout(cont.cycleTimeout); 1497 cont.cycleTimeout = 0; 1498 } 1499 go(options.elements, options, 1, !options.backwards); 1500 } 1501 } 1502} 1503 1504function removeFilter(el, opts) { 1505 if (!$.support.opacity && opts.cleartype && el.style.filter) { 1506 try { el.style.removeAttribute('filter'); } 1507 catch(smother) {} // handle old opera versions 1508 } 1509} 1510 1511// unbind event handlers 1512function destroy(cont, opts) { 1513 if (opts.next) 1514 $(opts.next).unbind(opts.prevNextEvent); 1515 if (opts.prev) 1516 $(opts.prev).unbind(opts.prevNextEvent); 1517 1518 if (opts.pager || opts.pagerAnchorBuilder) 1519 $.each(opts.pagerAnchors || [], function() { 1520 this.unbind().remove(); 1521 }); 1522 opts.pagerAnchors = null; 1523 $(cont).unbind('mouseenter.cycle mouseleave.cycle'); 1524 if (opts.destroy) // callback 1525 opts.destroy(opts); 1526} 1527 1528// one-time initialization 1529function buildOptions($cont, $slides, els, options, o) { 1530 var startingSlideSpecified; 1531 // support metadata plugin (v1.0 and v2.0) 1532 var opts = $.extend({}, $.fn.cycle.defaults, options || {}, $.metadata ? $cont.metadata() : $.meta ? $cont.data() : {}); 1533 var meta = $.isFunction($cont.data) ? $cont.data(opts.metaAttr) : null; 1534 if (meta) 1535 opts = $.extend(opts, meta); 1536 if (opts.autostop) 1537 opts.countdown = opts.autostopCount || els.length; 1538 1539 var cont = $cont[0]; 1540 $cont.data('cycle.opts', opts); 1541 opts.$cont = $cont; 1542 opts.stopCount = cont.cycleStop; 1543 opts.elements = els; 1544 opts.before = opts.before ? [opts.before] : []; 1545 opts.after = opts.after ? [opts.after] : []; 1546 1547 // push some after callbacks 1548 if (!$.support.opacity && opts.cleartype) 1549 opts.after.push(function() { removeFilter(this, opts); }); 1550 if (opts.continuous) 1551 opts.after.push(function() { go(els,opts,0,!opts.backwards); }); 1552 1553 saveOriginalOpts(opts); 1554 1555 // clearType corrections 1556 if (!$.support.opacity && opts.cleartype && !opts.cleartypeNoBg) 1557 clearTypeFix($slides); 1558 1559 // container requires non-static position so that slides can be position within 1560 if ($cont.css('position') == 'static') 1561 $cont.css('position', 'relative'); 1562 if (opts.width) 1563 $cont.width(opts.width); 1564 if (opts.height && opts.height != 'auto') 1565 $cont.height(opts.height); 1566 1567 if (opts.startingSlide !== undefined) { 1568 opts.startingSlide = parseInt(opts.startingSlide,10); 1569 if (opts.startingSlide >= els.length || opts.startSlide < 0) 1570 opts.startingSlide = 0; // catch bogus input 1571 else 1572 startingSlideSpecified = true; 1573 } 1574 else if (opts.backwards) 1575 opts.startingSlide = els.length - 1; 1576 else 1577 opts.startingSlide = 0; 1578 1579 // if random, mix up the slide array 1580 if (opts.random) { 1581 opts.randomMap = []; 1582 for (var i = 0; i < els.length; i++) 1583 opts.randomMap.push(i); 1584 opts.randomMap.sort(function(a,b) {return Math.random() - 0.5;}); 1585 if (startingSlideSpecified) { 1586 // try to find the specified starting slide and if found set start slide index in the map accordingly 1587 for ( var cnt = 0; cnt < els.length; cnt++ ) { 1588 if ( opts.startingSlide == opts.randomMap[cnt] ) { 1589 opts.randomIndex = cnt; 1590 } 1591 } 1592 } 1593 else { 1594 opts.randomIndex = 1; 1595 opts.startingSlide = opts.randomMap[1]; 1596 } 1597 } 1598 else if (opts.startingSlide >= els.length) 1599 opts.startingSlide = 0; // catch bogus input 1600 opts.currSlide = opts.startingSlide || 0; 1601 var first = opts.startingSlide; 1602 1603 // set position and zIndex on all the slides
1604 $slides.css({position: 'absolute', top:0, left:0}).hide().each(function(i) { 1605 var z; 1606 if (opts.backwards) 1607 z = first ? i <= first ? els.length + (i-first) : first-i : els.length-i; 1608 else 1609 z = first ? i >= first ? els.length - (i-first) : first-i : els.length-i; 1610 $(this).css('z-index', z); 1611 }); 1612 1613 // make sure first slide is visible 1614 $(els[first]).css('opacity',1).show(); // opacity bit needed to handle restart use case 1615 removeFilter(els[first], opts); 1616 1617 // stretch slides 1618 if (opts.fit) { 1619 if (!opts.aspect) { 1620 if (opts.width) 1621 $slides.width(opts.width); 1622 if (opts.height && opts.height != 'auto') 1623 $slides.height(opts.height); 1624 } else { 1625 $slides.each(function(){ 1626 var $slide = $(this); 1627 var ratio = (opts.aspect === true) ? $slide.width()/$slide.height() : opts.aspect; 1628 if( opts.width && $slide.width() != opts.width ) { 1629 $slide.width( opts.width ); 1630 $slide.height( opts.width / ratio ); 1631 } 1632 1633 if( opts.height && $slide.height() < opts.height ) { 1634 $slide.height( opts.height ); 1635 $slide.width( opts.height * ratio ); 1636 } 1637 }); 1638 } 1639 } 1640 1641 if (opts.center && ((!opts.fit) || opts.aspect)) { 1642 $slides.each(function(){ 1643 var $slide = $(this); 1644 $slide.css({ 1645 "margin-left": opts.width ? 1646 ((opts.width - $slide.width()) / 2) + "px" : 1647 0, 1648 "margin-top": opts.height ? 1649 ((opts.height - $slide.height()) / 2) + "px" : 1650 0 1651 }); 1652 }); 1653 } 1654 1655 if (opts.center && !opts.fit && !opts.slideResize) { 1656 $slides.each(function(){ 1657 var $slide = $(this); 1658 $slide.css({ 1659 "margin-left": opts.width ? ((opts.width - $slide.width()) / 2) + "px" : 0, 1660 "margin-top": opts.height ? ((opts.height - $slide.height()) / 2) + "px" : 0 1661 }); 1662 }); 1663 } 1664 1665 // stretch container 1666 var reshape = (opts.containerResize || opts.containerResizeHeight) && !$cont.innerHeight(); 1667 if (reshape) { // do this only if container has no size http://tinyurl.com/da2oa9 1668 var maxw = 0, maxh = 0; 1669 for(var j=0; j < els.length; j++) { 1670 var $e = $(els[j]), e = $e[0], w = $e.outerWidth(), h = $e.outerHeight(); 1671 if (!w) w = e.offsetWidth || e.width || $e.attr('width'); 1672 if (!h) h = e.offsetHeight || e.height || $e.attr('height'); 1673 maxw = w > maxw ? w : maxw; 1674 maxh = h > maxh ? h : maxh; 1675 } 1676 if (opts.containerResize && maxw > 0 && maxh > 0) 1677 $cont.css({width:maxw+'px',height:maxh+'px'}); 1678 if (opts.containerResizeHeight && maxh > 0) 1679 $cont.css({height:maxh+'px'}); 1680 } 1681 1682 var pauseFlag = false; // https://github.com/malsup/cycle/issues/44 1683 if (opts.pause) 1684 $cont.bind('mouseenter.cycle', function(){ 1685 pauseFlag = true; 1686 this.cyclePause++; 1687 triggerPause(cont, true); 1688 }).bind('mouseleave.cycle', function(){ 1689 if (pauseFlag) 1690 this.cyclePause--; 1691 triggerPause(cont, true); 1692 }); 1693 1694 if (supportMultiTransitions(opts) === false) 1695 return false; 1696 1697 // apparently a lot of people use image slideshows without height/width attributes on the images. 1698 // Cycle 2.50+ requires the sizing info for every slide; this block tries to deal with that. 1699 var requeue = false; 1700 options.requeueAttempts = options.requeueAttempts || 0; 1701 $slides.each(function() { 1702 // try to get height/width of each slide 1703 var $el = $(this); 1704 this.cycleH = (opts.fit && opts.height) ? opts.height : ($el.height() || this.offsetHeight || this.height || $el.attr('height') || 0); 1705 this.cycleW = (opts.fit && opts.width) ? opts.width : ($el.width() || this.offsetWidth || this.width || $el.attr('width') || 0); 1706 1707 if ( $el.is('img') ) { 1708 // sigh.. sniffing, hacking, shrugging... this crappy hack tries to account for what browsers do when 1709 // an image is being downloaded and the markup did not include sizing info (height/width attributes); 1710 // there seems to be some "default" sizes used in this situation 1711 var loadingIE = ($.browser.msie && this.cycleW == 28 && this.cycleH == 30 && !this.complete); 1712 var loadingFF = ($.browser.mozilla && this.cycleW == 34 && this.cycleH == 19 && !this.complete); 1713 var loadingOp = ($.browser.opera && ((this.cycleW == 42 && this.cycleH == 19) || (this.cycleW == 37 && this.cycleH == 17)) && !this.complete); 1714 var loadingOther = (this.cycleH === 0 && this.cycleW === 0 && !this.complete); 1715 // don't requeue for images that are still loading but have a valid size 1716 if (loadingIE || loadingFF || loadingOp || loadingOther) { 1717 if (o.s && opts.requeueOnImageNotLoaded && ++options.requeueAttempts < 100) { // track retry count so we don't loop forever 1718 log(options.requeueAttempts,' - img slide not loaded, requeuing slideshow: ', this.src, this.cycleW, this.cycleH); 1719 setTimeout(function() {$(o.s,o.c).cycle(options);}, opts.requeueTimeout); 1720 requeue = true; 1721 return false; // break each loop 1722 } 1723 else { 1724 log('could not determine size of image: '+this.src, this.cycleW, this.cycleH); 1725 } 1726 } 1727 } 1728 return true; 1729 }); 1730 1731 if (requeue) 1732 return false;
1733 1734 opts.cssBefore = opts.cssBefore || {}; 1735 opts.cssAfter = opts.cssAfter || {}; 1736 opts.cssFirst = opts.cssFirst || {}; 1737 opts.animIn = opts.animIn || {}; 1738 opts.animOut = opts.animOut || {}; 1739 1740 $slides.not(':eq('+first+')').css(opts.cssBefore); 1741 $($slides[first]).css(opts.cssFirst); 1742 1743 if (opts.timeout) { 1744 opts.timeout = parseInt(opts.timeout,10); 1745 // ensure that timeout and speed settings are sane 1746 if (opts.speed.constructor == String) 1747 opts.speed = $.fx.speeds[opts.speed] || parseInt(opts.speed,10); 1748 if (!opts.sync) 1749 opts.speed = opts.speed / 2; 1750 1751 var buffer = opts.fx == 'none' ? 0 : opts.fx == 'shuffle' ? 500 : 250; 1752 while((opts.timeout - opts.speed) < buffer) // sanitize timeout 1753 opts.timeout += opts.speed; 1754 } 1755 if (opts.easing) 1756 opts.easeIn = opts.easeOut = opts.easing; 1757 if (!opts.speedIn) 1758 opts.speedIn = opts.speed; 1759 if (!opts.speedOut) 1760 opts.speedOut = opts.speed; 1761 1762 opts.slideCount = els.length; 1763 opts.currSlide = opts.lastSlide = first; 1764 if (opts.random) { 1765 if (++opts.randomIndex == els.length) 1766 opts.randomIndex = 0; 1767 opts.nextSlide = opts.randomMap[opts.randomIndex]; 1768 } 1769 else if (opts.backwards) 1770 opts.nextSlide = opts.startingSlide === 0 ? (els.length-1) : opts.startingSlide-1; 1771 else 1772 opts.nextSlide = opts.startingSlide >= (els.length-1) ? 0 : opts.startingSlide+1; 1773 1774 // run transition init fn 1775 if (!opts.multiFx) { 1776 var init = $.fn.cycle.transitions[opts.fx]; 1777 if ($.isFunction(init)) 1778 init($cont, $slides, opts); 1779 else if (opts.fx != 'custom' && !opts.multiFx) { 1780 log('unknown transition: ' + opts.fx,'; slideshow terminating'); 1781 return false; 1782 } 1783 } 1784 1785 // fire artificial events 1786 var e0 = $slides[first]; 1787 if (!opts.skipInitializationCallbacks) { 1788 if (opts.before.length) 1789 opts.before[0].apply(e0, [e0, e0, opts, true]); 1790 if (opts.after.length) 1791 opts.after[0].apply(e0, [e0, e0, opts, true]); 1792 } 1793 if (opts.next) 1794 $(opts.next).bind(opts.prevNextEvent,function(){return advance(opts,1);}); 1795 if (opts.prev) 1796 $(opts.prev).bind(opts.prevNextEvent,function(){return advance(opts,0);}); 1797 if (opts.pager || opts.pagerAnchorBuilder) 1798 buildPager(els,opts); 1799 1800 exposeAddSlide(opts, els); 1801 1802 return opts; 1803} 1804 1805// save off original opts so we can restore after clearing state 1806function saveOriginalOpts(opts) { 1807 opts.original = { before: [], after: [] }; 1808 opts.original.cssBefore = $.extend({}, opts.cssBefore); 1809 opts.original.cssAfter = $.extend({}, opts.cssAfter); 1810 opts.original.animIn = $.extend({}, opts.animIn); 1811 opts.original.animOut = $.extend({}, opts.animOut); 1812 $.each(opts.before, function() { opts.original.before.push(this); }); 1813 $.each(opts.after, function() { opts.original.after.push(this); }); 1814} 1815 1816function supportMultiTransitions(opts) { 1817 var i, tx, txs = $.fn.cycle.transitions; 1818 // look for multiple effects 1819 if (opts.fx.indexOf(',') > 0) { 1820 opts.multiFx = true; 1821 opts.fxs = opts.fx.replace(/\s*/g,'').split(','); 1822 // discard any bogus effect names 1823 for (i=0; i < opts.fxs.length; i++) { 1824 var fx = opts.fxs[i]; 1825 tx = txs[fx]; 1826 if (!tx || !txs.hasOwnProperty(fx) || !$.isFunction(tx)) { 1827 log('discarding unknown transition: ',fx); 1828 opts.fxs.splice(i,1); 1829 i--; 1830 } 1831 } 1832 // if we have an empty list then we threw everything away! 1833 if (!opts.fxs.length) { 1834 log('No valid transitions named; slideshow terminating.'); 1835 return false; 1836 } 1837 } 1838 else if (opts.fx == 'all') { // auto-gen the list of transitions 1839 opts.multiFx = true; 1840 opts.fxs = []; 1841 for (var p in txs) { 1842 if (txs.hasOwnProperty(p)) { 1843 tx = txs[p]; 1844 if (txs.hasOwnProperty(p) && $.isFunction(tx)) 1845 opts.fxs.push(p); 1846 } 1847 } 1848 } 1849 if (opts.multiFx && opts.randomizeEffects) { 1850 // munge the fxs array to make effect selection random 1851 var r1 = Math.floor(Math.random() * 20) + 30; 1852 for (i = 0; i < r1; i++) { 1853 var r2 = Math.floor(Math.random() * opts.fxs.length); 1854 opts.fxs.push(opts.fxs.splice(r2,1)[0]); 1855 } 1856 debug('randomized fx sequence: ',opts.fxs); 1857 } 1858 return true; 1859} 1860 1861// provide a mechanism for adding slides after the slideshow has started 1862function exposeAddSlide(opts, els) { 1863 opts.addSlide = function(newSlide, prepend) {
1864 var $s = $(newSlide), s = $s[0]; 1865 if (!opts.autostopCount) 1866 opts.countdown++; 1867 els[prepend?'unshift':'push'](s); 1868 if (opts.els) 1869 opts.els[prepend?'unshift':'push'](s); // shuffle needs this 1870 opts.slideCount = els.length; 1871 1872 // add the slide to the random map and resort 1873 if (opts.random) { 1874 opts.randomMap.push(opts.slideCount-1); 1875 opts.randomMap.sort(function(a,b) {return Math.random() - 0.5;}); 1876 } 1877 1878 $s.css('position','absolute'); 1879 $s[prepend?'prependTo':'appendTo'](opts.$cont); 1880 1881 if (prepend) { 1882 opts.currSlide++; 1883 opts.nextSlide++; 1884 } 1885 1886 if (!$.support.opacity && opts.cleartype && !opts.cleartypeNoBg) 1887 clearTypeFix($s); 1888 1889 if (opts.fit && opts.width) 1890 $s.width(opts.width); 1891 if (opts.fit && opts.height && opts.height != 'auto') 1892 $s.height(opts.height); 1893 s.cycleH = (opts.fit && opts.height) ? opts.height : $s.height(); 1894 s.cycleW = (opts.fit && opts.width) ? opts.width : $s.width(); 1895 1896 $s.css(opts.cssBefore); 1897 1898 if (opts.pager || opts.pagerAnchorBuilder) 1899 $.fn.cycle.createPagerAnchor(els.length-1, s, $(opts.pager), els, opts); 1900 1901 if ($.isFunction(opts.onAddSlide)) 1902 opts.onAddSlide($s); 1903 else 1904 $s.hide(); // default behavior 1905 }; 1906} 1907 1908// reset internal state; we do this on every pass in order to support multiple effects 1909$.fn.cycle.resetState = function(opts, fx) { 1910 fx = fx || opts.fx; 1911 opts.before = []; opts.after = []; 1912 opts.cssBefore = $.extend({}, opts.original.cssBefore); 1913 opts.cssAfter = $.extend({}, opts.original.cssAfter); 1914 opts.animIn = $.extend({}, opts.original.animIn); 1915 opts.animOut = $.extend({}, opts.original.animOut); 1916 opts.fxFn = null; 1917 $.each(opts.original.before, function() { opts.before.push(this); }); 1918 $.each(opts.original.after, function() { opts.after.push(this); }); 1919 1920 // re-init 1921 var init = $.fn.cycle.transitions[fx]; 1922 if ($.isFunction(init)) 1923 init(opts.$cont, $(opts.elements), opts); 1924}; 1925 1926// this is the main engine fn, it handles the timeouts, callbacks and slide index mgmt 1927function go(els, opts, manual, fwd) { 1928 var p = opts.$cont[0], curr = els[opts.currSlide], next = els[opts.nextSlide]; 1929 1930 // opts.busy is true if we're in the middle of an animation 1931 if (manual && opts.busy && opts.manualTrump) { 1932 // let manual transitions requests trump active ones 1933 debug('manualTrump in go(), stopping active transition'); 1934 $(els).stop(true,true); 1935 opts.busy = 0; 1936 clearTimeout(p.cycleTimeout); 1937 } 1938 1939 // don't begin another timeout-based transition if there is one active 1940 if (opts.busy) { 1941 debug('transition active, ignoring new tx request'); 1942 return; 1943 } 1944 1945 1946 // stop cycling if we have an outstanding stop request 1947 if (p.cycleStop != opts.stopCount || p.cycleTimeout === 0 && !manual) 1948 return; 1949 1950 // check to see if we should stop cycling based on autostop options 1951 if (!manual && !p.cyclePause && !opts.bounce && 1952 ((opts.autostop && (--opts.countdown <= 0)) || 1953 (opts.nowrap && !opts.random && opts.nextSlide < opts.currSlide))) { 1954 if (opts.end) 1955 opts.end(opts); 1956 return; 1957 } 1958 1959 // if slideshow is paused, only transition on a manual trigger 1960 var changed = false; 1961 if ((manual || !p.cyclePause) && (opts.nextSlide != opts.currSlide)) { 1962 changed = true; 1963 var fx = opts.fx; 1964 // keep trying to get the slide size if we don't have it yet 1965 curr.cycleH = curr.cycleH || $(curr).height(); 1966 curr.cycleW = curr.cycleW || $(curr).width(); 1967 next.cycleH = next.cycleH || $(next).height(); 1968 next.cycleW = next.cycleW || $(next).width(); 1969 1970 // support multiple transition types 1971 if (opts.multiFx) { 1972 if (fwd && (opts.lastFx === undefined || ++opts.lastFx >= opts.fxs.length)) 1973 opts.lastFx = 0; 1974 else if (!fwd && (opts.lastFx === undefined || --opts.lastFx < 0)) 1975 opts.lastFx = opts.fxs.length - 1; 1976 fx = opts.fxs[opts.lastFx]; 1977 } 1978 1979 // one-time fx overrides apply to: $('div').cycle(3,'zoom'); 1980 if (opts.oneTimeFx) { 1981 fx = opts.oneTimeFx; 1982 opts.oneTimeFx = null; 1983 } 1984 1985 $.fn.cycle.resetState(opts, fx); 1986 1987 // run the before callbacks 1988 if (opts.before.length) 1989 $.each(opts.before, function(i,o) { 1990 if (p.cycleStop != opts.stopCount) return; 1991 o.apply(next, [curr, next, opts, fwd]); 1992 }); 1993 1994 // stage the after callacks 1995 var after = function() { 1996 opts.busy = 0; 1997 $.each(opts.after, function(i,o) { 1998 if (p.cycleStop != opts.stopCount) return; 1999 o.apply(next, [curr, next, opts, fwd]); 2000 }); 2001 if (!p.cycleStop) { 2002 // queue next transition 2003 queueNext(); 2004 } 2005 }; 2006 2007 debug('tx firing('+fx+'); currSlide: ' + opts.currSlide + '; nextSlide: ' + opts.nextSlide); 2008 2009 // get ready to perform the transition 2010 opts.busy = 1; 2011 if (opts.fxFn) // fx function provided? 2012 opts.fxFn(curr, next, opts, after, fwd, manual && opts.fastOnEvent); 2013 else if ($.isFunction($.fn.cycle[opts.fx])) // fx plugin ? 2014 $.fn.cycle[opts.fx](curr, next, opts, after, fwd, manual && opts.fastOnEvent); 2015 else 2016 $.fn.cycle.custom(curr, next, opts, after, fwd, manual && opts.fastOnEvent); 2017 } 2018 else { 2019 queueNext(); 2020 } 2021 2022 if (changed || opts.nextSlide == opts.currSlide) { 2023 // calculate the next slide 2024 var roll; 2025 opts.lastSlide = opts.currSlide; 2026 if (opts.random) { 2027 opts.currSlide = opts.nextSlide; 2028 if (++opts.randomIndex == els.length) { 2029 opts.randomIndex = 0; 2030 opts.randomMap.sort(function(a,b) {return Math.random() - 0.5;}); 2031 } 2032 opts.nextSlide = opts.randomMap[opts.randomIndex]; 2033 if (opts.nextSlide == opts.currSlide) 2034 opts.nextSlide = (opts.currSlide == opts.slideCount - 1) ? 0 : opts.currSlide + 1; 2035 } 2036 else if (opts.backwards) { 2037 roll = (opts.nextSlide - 1) < 0; 2038 if (roll && opts.bounce) { 2039 opts.backwards = !opts.backwards; 2040 opts.nextSlide = 1; 2041 opts.currSlide = 0; 2042 } 2043 else { 2044 opts.nextSlide = roll ? (els.length-1) : opts.nextSlide-1; 2045 opts.currSlide = roll ? 0 : opts.nextSlide+1; 2046 } 2047 } 2048 else { // sequence 2049 roll = (opts.nextSlide + 1) == els.length; 2050 if (roll && opts.bounce) { 2051 opts.backwards = !opts.backwards; 2052 opts.nextSlide = els.length-2; 2053 opts.currSlide = els.length-1; 2054 } 2055 else { 2056 opts.nextSlide = roll ? 0 : opts.nextSlide+1; 2057 opts.currSlide = roll ? els.length-1 : opts.nextSlide-1; 2058 } 2059 } 2060 } 2061 if (changed && opts.pager) 2062 opts.updateActivePagerLink(opts.pager, opts.currSlide, opts.activePagerClass); 2063 2064 function queueNext() { 2065 // stage the next transition 2066 var ms = 0, timeout = opts.timeout; 2067 if (opts.timeout && !opts.continuous) { 2068 ms = getTimeout(els[opts.currSlide], els[opts.nextSlide], opts, fwd); 2069 if (opts.fx == 'shuffle') 2070 ms -= opts.speedOut; 2071 } 2072 else if (opts.continuous && p.cyclePause) // continuous shows work off an after callback, not this timer logic 2073 ms = 10; 2074 if (ms > 0) 2075 p.cycleTimeout = setTimeout(function(){ go(els, opts, 0, !opts.backwards); }, ms); 2076 } 2077} 2078 2079// invoked after transition 2080$.fn.cycle.updateActivePagerLink = function(pager, currSlide, clsName) { 2081 $(pager).each(function() { 2082 $(this).children().removeClass(clsName).eq(currSlide).addClass(clsName); 2083 }); 2084}; 2085 2086// calculate timeout value for current transition 2087function getTimeout(curr, next, opts, fwd) { 2088 if (opts.timeoutFn) { 2089 // call user provided calc fn 2090 var t = opts.timeoutFn.call(curr,curr,next,opts,fwd); 2091 while (opts.fx != 'none' && (t - opts.speed) < 250) // sanitize timeout 2092 t += opts.speed;
2093 debug('calculated timeout: ' + t + '; speed: ' + opts.speed); 2094 if (t !== false) 2095 return t; 2096 } 2097 return opts.timeout; 2098} 2099 2100// expose next/prev function, caller must pass in state 2101$.fn.cycle.next = function(opts) { advance(opts,1); }; 2102$.fn.cycle.prev = function(opts) { advance(opts,0);}; 2103 2104// advance slide forward or back 2105function advance(opts, moveForward) { 2106 var val = moveForward ? 1 : -1; 2107 var els = opts.elements; 2108 var p = opts.$cont[0], timeout = p.cycleTimeout; 2109 if (timeout) { 2110 clearTimeout(timeout); 2111 p.cycleTimeout = 0; 2112 } 2113 if (opts.random && val < 0) { 2114 // move back to the previously display slide 2115 opts.randomIndex--; 2116 if (--opts.randomIndex == -2) 2117 opts.randomIndex = els.length-2; 2118 else if (opts.randomIndex == -1) 2119 opts.randomIndex = els.length-1; 2120 opts.nextSlide = opts.randomMap[opts.randomIndex]; 2121 } 2122 else if (opts.random) { 2123 opts.nextSlide = opts.randomMap[opts.randomIndex]; 2124 } 2125 else { 2126 opts.nextSlide = opts.currSlide + val; 2127 if (opts.nextSlide < 0) { 2128 if (opts.nowrap) return false; 2129 opts.nextSlide = els.length - 1; 2130 } 2131 else if (opts.nextSlide >= els.length) { 2132 if (opts.nowrap) return false; 2133 opts.nextSlide = 0; 2134 } 2135 } 2136 2137 var cb = opts.onPrevNextEvent || opts.prevNextClick; // prevNextClick is deprecated 2138 if ($.isFunction(cb)) 2139 cb(val > 0, opts.nextSlide, els[opts.nextSlide]); 2140 go(els, opts, 1, moveForward); 2141 return false; 2142} 2143 2144function buildPager(els, opts) { 2145 var $p = $(opts.pager); 2146 $.each(els, function(i,o) { 2147 $.fn.cycle.createPagerAnchor(i,o,$p,els,opts); 2148 }); 2149 opts.updateActivePagerLink(opts.pager, opts.startingSlide, opts.activePagerClass); 2150} 2151 2152$.fn.cycle.createPagerAnchor = function(i, el, $p, els, opts) { 2153 var a; 2154 if ($.isFunction(opts.pagerAnchorBuilder)) { 2155 a = opts.pagerAnchorBuilder(i,el); 2156 debug('pagerAnchorBuilder('+i+', el) returned: ' + a); 2157 } 2158 else 2159 a = '<a href="#">'+(i+1)+'</a>'; 2160 2161 if (!a) 2162 return; 2163 var $a = $(a); 2164 // don't reparent if anchor is in the dom 2165 if ($a.parents('body').length === 0) { 2166 var arr = []; 2167 if ($p.length > 1) { 2168 $p.each(function() { 2169 var $clone = $a.clone(true); 2170 $(this).append($clone); 2171 arr.push($clone[0]); 2172 }); 2173 $a = $(arr); 2174 } 2175 else { 2176 $a.appendTo($p); 2177 } 2178 } 2179 2180 opts.pagerAnchors = opts.pagerAnchors || []; 2181 opts.pagerAnchors.push($a); 2182 2183 var pagerFn = function(e) { 2184 e.preventDefault(); 2185 opts.nextSlide = i; 2186 var p = opts.$cont[0], timeout = p.cycleTimeout; 2187 if (timeout) { 2188 clearTimeout(timeout); 2189 p.cycleTimeout = 0; 2190 } 2191 var cb = opts.onPagerEvent || opts.pagerClick; // pagerClick is deprecated 2192 if ($.isFunction(cb)) 2193 cb(opts.nextSlide, els[opts.nextSlide]); 2194 go(els,opts,1,opts.currSlide < i); // trigger the trans 2195// return false; // <== allow bubble 2196 }; 2197 2198 if ( /mouseenter|mouseover/i.test(opts.pagerEvent) ) { 2199 $a.hover(pagerFn, function(){/* no-op */} ); 2200 } 2201 else { 2202 $a.bind(opts.pagerEvent, pagerFn); 2203 } 2204 2205 if ( ! /^click/.test(opts.pagerEvent) && !opts.allowPagerClickBubble) 2206 $a.bind('click.cycle', function(){return false;}); // suppress click 2207 2208 var cont = opts.$cont[0]; 2209 var pauseFlag = false; // https://github.com/malsup/cycle/issues/44 2210 if (opts.pauseOnPagerHover) { 2211 $a.hover( 2212 function() { 2213 pauseFlag = true; 2214 cont.cyclePause++; 2215 triggerPause(cont,true,true); 2216 }, function() { 2217 if (pauseFlag) 2218 cont.cyclePause--; 2219 triggerPause(cont,true,true); 2220 } 2221 ); 2222 } 2223}; 2224 2225// helper fn to calculate the number of slides between the current and the next 2226$.fn.cycle.hopsFromLast = function(opts, fwd) { 2227 var hops, l = opts.lastSlide, c = opts.currSlide; 2228 if (fwd) 2229 hops = c > l ? c - l : opts.slideCount - l; 2230 else 2231 hops = c < l ? l - c : l + opts.slideCount - c; 2232 return hops; 2233}; 2234 2235// fix clearType problems in ie6 by setting an explicit bg color 2236// (otherwise text slides look horrible during a fade transition) 2237function clearTypeFix($slides) { 2238 debug('applying clearType background-color hack'); 2239 function hex(s) { 2240 s = parseInt(s,10).toString(16); 2241 return s.length < 2 ? '0'+s : s; 2242 } 2243 function getBg(e) { 2244 for ( ; e && e.nodeName.toLowerCase() != 'html'; e = e.parentNode) { 2245 var v = $.css(e,'background-color'); 2246 if (v && v.indexOf('rgb') >= 0 ) { 2247 var rgb = v.match(/\d+/g); 2248 return '#'+ hex(rgb[0]) + hex(rgb[1]) + hex(rgb[2]); 2249 } 2250 if (v && v != 'transparent') 2251 return v; 2252 } 2253 return '#ffffff'; 2254 } 2255 $slides.each(function() { $(this).css('background-color', getBg(this)); }); 2256} 2257 2258// reset common props before the next transition 2259$.fn.cycle.commonReset = function(curr,next,opts,w,h,rev) { 2260 $(opts.elements).not(curr).hide(); 2261 if (typeof opts.cssBefore.opacity == 'undefined') 2262 opts.cssBefore.opacity = 1; 2263 opts.cssBefore.display = 'block'; 2264 if (opts.slideResize && w !== false && next.cycleW > 0) 2265 opts.cssBefore.width = next.cycleW; 2266 if (opts.slideResize && h !== false && next.cycleH > 0) 2267 opts.cssBefore.height = next.cycleH; 2268 opts.cssAfter = opts.cssAfter || {}; 2269 opts.cssAfter.display = 'none'; 2270 $(curr).css('zIndex',opts.slideCount + (rev === true ? 1 : 0)); 2271 $(next).css('zIndex',opts.slideCount + (rev === true ? 0 : 1)); 2272}; 2273 2274// the actual fn for effecting a transition 2275$.fn.cycle.custom = function(curr, next, opts, cb, fwd, speedOverride) { 2276 var $l = $(curr), $n = $(next); 2277 var speedIn = opts.speedIn, speedOut = opts.speedOut, easeIn = opts.easeIn, easeOut = opts.easeOut; 2278 $n.css(opts.cssBefore); 2279 if (speedOverride) { 2280 if (typeof speedOverride == 'number') 2281 speedIn = speedOut = speedOverride; 2282 else 2283 speedIn = speedOut = 1; 2284 easeIn = easeOut = null; 2285 } 2286 var fn = function() { 2287 $n.animate(opts.animIn, speedIn, easeIn, function() { 2288 cb(); 2289 }); 2290 }; 2291 $l.animate(opts.animOut, speedOut, easeOut, function() { 2292 $l.css(opts.cssAfter); 2293 if (!opts.sync) 2294 fn(); 2295 }); 2296 if (opts.sync) fn(); 2297}; 2298 2299// transition definitions - only fade is defined here, transition pack defines the rest 2300$.fn.cycle.transitions = { 2301 fade: function($cont, $slides, opts) { 2302 $slides.not(':eq('+opts.currSlide+')').css('opacity',0); 2303 opts.before.push(function(curr,next,opts) { 2304 $.fn.cycle.commonReset(curr,next,opts); 2305 opts.cssBefore.opacity = 0; 2306 }); 2307 opts.animIn = { opacity: 1 }; 2308 opts.animOut = { opacity: 0 }; 2309 opts.cssBefore = { top: 0, left: 0 }; 2310 } 2311}; 2312 2313$.fn.cycle.ver = function() { return ver; }; 2314 2315// override these globally if you like (they are all optional) 2316$.fn.cycle.defaults = {
2317 activePagerClass: 'activeSlide', // class name used for the active pager link 2318 after: null, // transition callback (scope set to element that was shown): function(currSlideElement, nextSlideElement, options, forwardFlag) 2319 allowPagerClickBubble: false, // allows or prevents click event on pager anchors from bubbling 2320 animIn: null, // properties that define how the slide animates in 2321 animOut: null, // properties that define how the slide animates out 2322 aspect: false, // preserve aspect ratio during fit resizing, cropping if necessary (must be used with fit option) 2323 autostop: 0, // true to end slideshow after X transitions (where X == slide count) 2324 autostopCount: 0, // number of transitions (optionally used with autostop to define X) 2325 backwards: false, // true to start slideshow at last slide and move backwards through the stack 2326 before: null, // transition callback (scope set to element to be shown): function(currSlideElement, nextSlideElement, options, forwardFlag) 2327 center: null, // set to true to have cycle add top/left margin to each slide (use with width and height options) 2328 cleartype: !$.support.opacity, // true if clearType corrections should be applied (for IE) 2329 cleartypeNoBg: false, // set to true to disable extra cleartype fixing (leave false to force background color setting on slides) 2330 containerResize: 1, // resize container to fit largest slide 2331 containerResizeHeight: 0, // resize containers height to fit the largest slide but leave the width dynamic 2332 continuous: 0, // true to start next transition immediately after current one completes 2333 cssAfter: null, // properties that defined the state of the slide after transitioning out 2334 cssBefore: null, // properties that define the initial state of the slide before transitioning in 2335 delay: 0, // additional delay (in ms) for first transition (hint: can be negative) 2336 easeIn: null, // easing for "in" transition 2337 easeOut: null, // easing for "out" transition 2338 easing: null, // easing method for both in and out transitions 2339 end: null, // callback invoked when the slideshow terminates (use with autostop or nowrap options): function(options) 2340 fastOnEvent: 0, // force fast transitions when triggered manually (via pager or prev/next); value == time in ms 2341 fit: 0, // force slides to fit container 2342 fx: 'fade', // name of transition effect (or comma separated names, ex: 'fade,scrollUp,shuffle') 2343 fxFn: null, // function used to control the transition: function(currSlideElement, nextSlideElement, options, afterCalback, forwardFlag) 2344 height: 'auto', // container height (if the 'fit' option is true, the slides will be set to this height as well) 2345 manualTrump: true, // causes manual transition to stop an active transition instead of being ignored 2346 metaAttr: 'cycle', // data- attribute that holds the option data for the slideshow 2347 next: null, // element, jQuery object, or jQuery selector string for the element to use as event trigger for next slide 2348 nowrap: 0, // true to prevent slideshow from wrapping 2349 onPagerEvent: null, // callback fn for pager events: function(zeroBasedSlideIndex, slideElement) 2350 onPrevNextEvent: null, // callback fn for prev/next events: function(isNext, zeroBasedSlideIndex, slideElement) 2351 pager: null, // element, jQuery object, or jQuery selector string for the element to use as pager container 2352 pagerAnchorBuilder: null, // callback fn for building anchor links: function(index, DOMelement) 2353 pagerEvent: 'click.cycle', // name of event which drives the pager navigation 2354 pause: 0, // true to enable "pause on hover" 2355 pauseOnPagerHover: 0, // true to pause when hovering over pager link 2356 prev: null, // element, jQuery object, or jQuery selector string for the element to use as event trigger for previous slide 2357 prevNextEvent: 'click.cycle',// event which drives the manual transition to the previous or next slide 2358 random: 0, // true for random, false for sequence (not applicable to shuffle fx) 2359 randomizeEffects: 1, // valid when multiple effects are used; true to make the effect sequence random 2360 requeueOnImageNotLoaded: true, // requeue the slideshow if any image slides are not yet loaded 2361 requeueTimeout: 250, // ms delay for requeue 2362 rev: 0, // causes animations to transition in reverse (for effects that support it such as scrollHorz/scrollVert/shuffle) 2363 shuffle: null, // coords for shuffle animation, ex: { top:15, left: 200 } 2364 skipInitializationCallbacks: false, // set to true to disable the first before/after callback that occurs prior to any transition 2365 slideExpr: null, // expression for selecting slides (if something other than all children is required) 2366 slideResize: 1, // force slide width/height to fixed size before every transition 2367 speed: 1000, // speed of the transition (any valid fx speed value) 2368 speedIn: null, // speed of the 'in' transition 2369 speedOut: null, // speed of the 'out' transition 2370 startingSlide: undefined,// zero-based index of the first slide to be displayed 2371 sync: 1, // true if in/out transitions should occur simultaneously 2372 timeout: 4000, // milliseconds between slide transitions (0 to disable auto advance) 2373 timeoutFn: null, // callback for determining per-slide timeout value: function(currSlideElement, nextSlideElement, options, forwardFlag) 2374 updateActivePagerLink: null,// callback fn invoked to update the active pager link (adds/removes activePagerClass style) 2375 width: null // container width (if the 'fit' option is true, the slides will be set to this width as well) 2376}; 2377 2378}
2378)(jQuery); 2379 2380 2381/*! 2382 * jQuery Cycle Plugin Transition Definitions 2383 * This script is a plugin for the jQuery Cycle Plugin 2384 * Examples and documentation at: http://malsup.com/jquery/cycle/ 2385 * Copyright (c) 2007-2010 M. Alsup 2386 * Version: 2.73 2387 * Dual licensed under the MIT and GPL licenses: 2388 * http://www.opensource.org/licenses/mit-license.php 2389 * http://www.gnu.org/licenses/gpl.html 2390 */ 2391(function($) { 2392"use strict"; 2393 2394// 2395// These functions define slide initialization and properties for the named 2396// transitions. To save file size feel free to remove any of these that you 2397// don't need. 2398// 2399$.fn.cycle.transitions.none = function($cont, $slides, opts) { 2400 opts.fxFn = function(curr,next,opts,after){ 2401 $(next).show(); 2402 $(curr).hide(); 2403 after(); 2404 }; 2405}; 2406 2407// not a cross-fade, fadeout only fades out the top slide 2408$.fn.cycle.transitions.fadeout = function($cont, $slides, opts) { 2409 $slides.not(':eq('+opts.currSlide+')').css({ display: 'block', 'opacity': 1 }); 2410 opts.before.push(function(curr,next,opts,w,h,rev) { 2411 $(curr).css('zIndex',opts.slideCount + (rev !== true ? 1 : 0)); 2412 $(next).css('zIndex',opts.slideCount + (rev !== true ? 0 : 1)); 2413 }); 2414 opts.animIn.opacity = 1; 2415 opts.animOut.opacity = 0; 2416 opts.cssBefore.opacity = 1; 2417 opts.cssBefore.display = 'block'; 2418 opts.cssAfter.zIndex = 0; 2419}; 2420 2421// scrollUp/Down/Left/Right 2422$.fn.cycle.transitions.scrollUp = function($cont, $slides, opts) { 2423 $cont.css('overflow','hidden'); 2424 opts.before.push($.fn.cycle.commonReset); 2425 var h = $cont.height(); 2426 opts.cssBefore.top = h; 2427 opts.cssBefore.left = 0; 2428 opts.cssFirst.top = 0; 2429 opts.animIn.top = 0; 2430 opts.animOut.top = -h; 2431}; 2432$.fn.cycle.transitions.scrollDown = function($cont, $slides, opts) { 2433 $cont.css('overflow','hidden'); 2434 opts.before.push($.fn.cycle.commonReset); 2435 var h = $cont.height(); 2436 opts.cssFirst.top = 0; 2437 opts.cssBefore.top = -h; 2438 opts.cssBefore.left = 0; 2439 opts.animIn.top = 0; 2440 opts.animOut.top = h; 2441}; 2442$.fn.cycle.transitions.scrollLeft = function($cont, $slides, opts) { 2443 $cont.css('overflow','hidden'); 2444 opts.before.push($.fn.cycle.commonReset); 2445 var w = $cont.width(); 2446 opts.cssFirst.left = 0; 2447 opts.cssBefore.left = w; 2448 opts.cssBefore.top = 0; 2449 opts.animIn.left = 0; 2450 opts.animOut.left = 0-w; 2451}; 2452$.fn.cycle.transitions.scrollRight = function($cont, $slides, opts) { 2453 $cont.css('overflow','hidden'); 2454 opts.before.push($.fn.cycle.commonReset); 2455 var w = $cont.width(); 2456 opts.cssFirst.left = 0; 2457 opts.cssBefore.left = -w; 2458 opts.cssBefore.top = 0; 2459 opts.animIn.left = 0; 2460 opts.animOut.left = w; 2461}; 2462$.fn.cycle.transitions.scrollHorz = function($cont, $slides, opts) { 2463 $cont.css('overflow','hidden').width(); 2464 opts.before.push(function(curr, next, opts, fwd) { 2465 if (opts.rev) 2466 fwd = !fwd; 2467 $.fn.cycle.commonReset(curr,next,opts); 2468 opts.cssBefore.left = fwd ? (next.cycleW-1) : (1-next.cycleW); 2469 opts.animOut.left = fwd ? -curr.cycleW : curr.cycleW; 2470 }); 2471 opts.cssFirst.left = 0; 2472 opts.cssBefore.top = 0; 2473 opts.animIn.left = 0; 2474 opts.animOut.top = 0; 2475}; 2476$.fn.cycle.transitions.scrollVert = function($cont, $slides, opts) { 2477 $cont.css('overflow','hidden'); 2478 opts.before.push(function(curr, next, opts, fwd) { 2479 if (opts.rev) 2480 fwd = !fwd; 2481 $.fn.cycle.commonReset(curr,next,opts); 2482 opts.cssBefore.top = fwd ? (1-next.cycleH) : (next.cycleH-1); 2483 opts.animOut.top = fwd ? curr.cycleH : -curr.cycleH; 2484 }); 2485 opts.cssFirst.top = 0; 2486 opts.cssBefore.left = 0; 2487 opts.animIn.top = 0; 2488 opts.animOut.left = 0; 2489}; 2490 2491// slideX/slideY 2492$.fn.cycle.transitions.slideX = function($cont, $slides, opts) { 2493 opts.before.push(function(curr, next, opts) { 2494 $(opts.elements).not(curr).hide(); 2495 $.fn.cycle.commonReset(curr,next,opts,false,true); 2496 opts.animIn.width = next.cycleW; 2497 }); 2498 opts.cssBefore.left = 0; 2499 opts.cssBefore.top = 0; 2500 opts.cssBefore.width = 0; 2501 opts.animIn.width = 'show'; 2502 opts.animOut.width = 0; 2503}; 2504$.fn.cycle.transitions.slideY = function($cont, $slides, opts) { 2505 opts.before.push(function(curr, next, opts) { 2506 $(opts.elements).not(curr).hide(); 2507 $.fn.cycle.commonReset(curr,next,opts,true,false); 2508 opts.animIn.height = next.cycleH; 2509 }); 2510 opts.cssBefore.left = 0; 2511 opts.cssBefore.top = 0; 2512 opts.cssBefore.height = 0; 2513 opts.animIn.height = 'show'; 2514 opts.animOut.height = 0; 2515}; 2516 2517// shuffle 2518$.fn.cycle.transitions.shuffle = function($cont, $slides, opts) { 2519 var i, w = $cont.css('overflow', 'visible').width(); 2520 $slides.css({left: 0, top: 0}); 2521 opts.before.push(function(curr,next,opts) { 2522 $.fn.cycle.commonReset(curr,next,opts,true,true,true); 2523 }); 2524 // only adjust speed once! 2525 if (!opts.speedAdjusted) { 2526 opts.speed = opts.speed / 2; // shuffle has 2 transitions 2527 opts.speedAdjusted = true; 2528 } 2529 opts.random = 0; 2530 opts.shuffle = opts.shuffle || {left:-w, top:15}; 2531 opts.els = []; 2532 for (i=0; i < $slides.length; i++) 2533 opts.els.push($slides[i]); 2534 2535 for (i=0; i < opts.currSlide; i++) 2536 opts.els.push(opts.els.shift()); 2537 2538 // custom transition fn (hat tip to Benjamin Sterling for this bit of sweetness!) 2539 opts.fxFn = function(curr, next, opts, cb, fwd) { 2540 if (opts.rev) 2541 fwd = !fwd; 2542 var $el = fwd ? $(curr) : $(next); 2543 $(next).css(opts.cssBefore); 2544 var count = opts.slideCount; 2545 $el.animate(opts.shuffle, opts.speedIn, opts.easeIn, function() { 2546 var hops = $.fn.cycle.hopsFromLast(opts, fwd); 2547 for (var k=0; k < hops; k++) { 2548 if (fwd) 2549 opts.els.push(opts.els.shift()); 2550 else 2551 opts.els.unshift(opts.els.pop()); 2552 } 2553 if (fwd) { 2554 for (var i=0, len=opts.els.length; i < len; i++) 2555 $(opts.els[i]).css('z-index', len-i+count); 2556 } 2557 else { 2558 var z = $(curr).css('z-index'); 2559 $el.css('z-index', parseInt(z,10)+1+count); 2560 } 2561 $el.animate({left:0, top:0}, opts.speedOut, opts.easeOut, function() {
2562 $(fwd ? this : curr).hide(); 2563 if (cb) cb(); 2564 }); 2565 }); 2566 }; 2567 $.extend(opts.cssBefore, { display: 'block', opacity: 1, top: 0, left: 0 }); 2568}; 2569 2570// turnUp/Down/Left/Right 2571$.fn.cycle.transitions.turnUp = function($cont, $slides, opts) { 2572 opts.before.push(function(curr, next, opts) { 2573 $.fn.cycle.commonReset(curr,next,opts,true,false); 2574 opts.cssBefore.top = next.cycleH; 2575 opts.animIn.height = next.cycleH; 2576 opts.animOut.width = next.cycleW; 2577 }); 2578 opts.cssFirst.top = 0; 2579 opts.cssBefore.left = 0; 2580 opts.cssBefore.height = 0; 2581 opts.animIn.top = 0; 2582 opts.animOut.height = 0; 2583}; 2584$.fn.cycle.transitions.turnDown = function($cont, $slides, opts) { 2585 opts.before.push(function(curr, next, opts) { 2586 $.fn.cycle.commonReset(curr,next,opts,true,false); 2587 opts.animIn.height = next.cycleH; 2588 opts.animOut.top = curr.cycleH; 2589 }); 2590 opts.cssFirst.top = 0; 2591 opts.cssBefore.left = 0; 2592 opts.cssBefore.top = 0; 2593 opts.cssBefore.height = 0; 2594 opts.animOut.height = 0; 2595}; 2596$.fn.cycle.transitions.turnLeft = function($cont, $slides, opts) { 2597 opts.before.push(function(curr, next, opts) { 2598 $.fn.cycle.commonReset(curr,next,opts,false,true); 2599 opts.cssBefore.left = next.cycleW; 2600 opts.animIn.width = next.cycleW; 2601 }); 2602 opts.cssBefore.top = 0; 2603 opts.cssBefore.width = 0; 2604 opts.animIn.left = 0; 2605 opts.animOut.width = 0; 2606}; 2607$.fn.cycle.transitions.turnRight = function($cont, $slides, opts) { 2608 opts.before.push(function(curr, next, opts) { 2609 $.fn.cycle.commonReset(curr,next,opts,false,true); 2610 opts.animIn.width = next.cycleW; 2611 opts.animOut.left = curr.cycleW; 2612 }); 2613 $.extend(opts.cssBefore, { top: 0, left: 0, width: 0 }); 2614 opts.animIn.left = 0; 2615 opts.animOut.width = 0; 2616}; 2617 2618// zoom 2619$.fn.cycle.transitions.zoom = function($cont, $slides, opts) { 2620 opts.before.push(function(curr, next, opts) { 2621 $.fn.cycle.commonReset(curr,next,opts,false,false,true); 2622 opts.cssBefore.top = next.cycleH/2; 2623 opts.cssBefore.left = next.cycleW/2; 2624 $.extend(opts.animIn, { top: 0, left: 0, width: next.cycleW, height: next.cycleH }); 2625 $.extend(opts.animOut, { width: 0, height: 0, top: curr.cycleH/2, left: curr.cycleW/2 }); 2626 }); 2627 opts.cssFirst.top = 0; 2628 opts.cssFirst.left = 0; 2629 opts.cssBefore.width = 0; 2630 opts.cssBefore.height = 0; 2631}; 2632 2633// fadeZoom 2634$.fn.cycle.transitions.fadeZoom = function($cont, $slides, opts) { 2635 opts.before.push(function(curr, next, opts) { 2636 $.fn.cycle.commonReset(curr,next,opts,false,false); 2637 opts.cssBefore.left = next.cycleW/2; 2638 opts.cssBefore.top = next.cycleH/2; 2639 $.extend(opts.animIn, { top: 0, left: 0, width: next.cycleW, height: next.cycleH }); 2640 }); 2641 opts.cssBefore.width = 0; 2642 opts.cssBefore.height = 0; 2643 opts.animOut.opacity = 0; 2644}; 2645 2646// blindX 2647$.fn.cycle.transitions.blindX = function($cont, $slides, opts) { 2648 var w = $cont.css('overflow','hidden').width(); 2649 opts.before.push(function(curr, next, opts) { 2650 $.fn.cycle.commonReset(curr,next,opts); 2651 opts.animIn.width = next.cycleW; 2652 opts.animOut.left = curr.cycleW; 2653 }); 2654 opts.cssBefore.left = w; 2655 opts.cssBefore.top = 0; 2656 opts.animIn.left = 0; 2657 opts.animOut.left = w; 2658}; 2659// blindY 2660$.fn.cycle.transitions.blindY = function($cont, $slides, opts) { 2661 var h = $cont.css('overflow','hidden').height(); 2662 opts.before.push(function(curr, next, opts) { 2663 $.fn.cycle.commonReset(curr,next,opts); 2664 opts.animIn.height = next.cycleH; 2665 opts.animOut.top = curr.cycleH; 2666 }); 2667 opts.cssBefore.top = h; 2668 opts.cssBefore.left = 0; 2669 opts.animIn.top = 0; 2670 opts.animOut.top = h; 2671}; 2672// blindZ 2673$.fn.cycle.transitions.blindZ = function($cont, $slides, opts) { 2674 var h = $cont.css('overflow','hidden').height(); 2675 var w = $cont.width(); 2676 opts.before.push(function(curr, next, opts) { 2677 $.fn.cycle.commonReset(curr,next,opts); 2678 opts.animIn.height = next.cycleH; 2679 opts.animOut.top = curr.cycleH; 2680 }); 2681 opts.cssBefore.top = h; 2682 opts.cssBefore.left = w; 2683 opts.animIn.top = 0; 2684 opts.animIn.left = 0; 2685 opts.animOut.top = h; 2686 opts.animOut.left = w; 2687}; 2688 2689// growX - grow horizontally from centered 0 width 2690$.fn.cycle.transitions.growX = function($cont, $slides, opts) { 2691 opts.before.push(function(curr, next, opts) { 2692 $.fn.cycle.commonReset(curr,next,opts,false,true); 2693 opts.cssBefore.left = this.cycleW/2; 2694 opts.animIn.left = 0; 2695 opts.animIn.width = this.cycleW; 2696 opts.animOut.left = 0; 2697 }); 2698 opts.cssBefore.top = 0; 2699 opts.cssBefore.width = 0; 2700}; 2701// growY - grow vertically from centered 0 height 2702$.fn.cycle.transitions.growY = function($cont, $slides, opts) { 2703 opts.before.push(function(curr, next, opts) { 2704 $.fn.cycle.commonReset(curr,next,opts,true,false); 2705 opts.cssBefore.top = this.cycleH/2; 2706 opts.animIn.top = 0; 2707 opts.animIn.height = this.cycleH; 2708 opts.animOut.top = 0; 2709 }); 2710 opts.cssBefore.height = 0; 2711 opts.cssBefore.left = 0; 2712}; 2713 2714// curtainX - squeeze in both edges horizontally 2715$.fn.cycle.transitions.curtainX = function($cont, $slides, opts) { 2716 opts.before.push(function(curr, next, opts) { 2717 $.fn.cycle.commonReset(curr,next,opts,false,true,true); 2718 opts.cssBefore.left = next.cycleW/2; 2719 opts.animIn.left = 0; 2720 opts.animIn.width = this.cycleW; 2721 opts.animOut.left = curr.cycleW/2; 2722 opts.animOut.width = 0; 2723 }); 2724 opts.cssBefore.top = 0; 2725 opts.cssBefore.width = 0; 2726}; 2727// curtainY - squeeze in both edges vertically 2728$.fn.cycle.transitions.curtainY = function($cont, $slides, opts) { 2729 opts.before.push(function(curr, next, opts) { 2730 $.fn.cycle.commonReset(curr,next,opts,true,false,true); 2731 opts.cssBefore.top = next.cycleH/2; 2732 opts.animIn.top = 0; 2733 opts.animIn.height = next.cycleH; 2734 opts.animOut.top = curr.cycleH/2; 2735 opts.animOut.height = 0; 2736 }); 2737 opts.cssBefore.height = 0; 2738 opts.cssBefore.left = 0; 2739}; 2740 2741// cover - curr slide covered by next slide
2742$.fn.cycle.transitions.cover = function($cont, $slides, opts) { 2743 var d = opts.direction || 'left'; 2744 var w = $cont.css('overflow','hidden').width(); 2745 var h = $cont.height(); 2746 opts.before.push(function(curr, next, opts) { 2747 $.fn.cycle.commonReset(curr,next,opts); 2748 opts.cssAfter.display = ''; 2749 if (d == 'right') 2750 opts.cssBefore.left = -w; 2751 else if (d == 'up') 2752 opts.cssBefore.top = h; 2753 else if (d == 'down') 2754 opts.cssBefore.top = -h; 2755 else 2756 opts.cssBefore.left = w; 2757 }); 2758 opts.animIn.left = 0; 2759 opts.animIn.top = 0; 2760 opts.cssBefore.top = 0; 2761 opts.cssBefore.left = 0; 2762}; 2763 2764// uncover - curr slide moves off next slide 2765$.fn.cycle.transitions.uncover = function($cont, $slides, opts) { 2766 var d = opts.direction || 'left'; 2767 var w = $cont.css('overflow','hidden').width(); 2768 var h = $cont.height(); 2769 opts.before.push(function(curr, next, opts) { 2770 $.fn.cycle.commonReset(curr,next,opts,true,true,true); 2771 if (d == 'right') 2772 opts.animOut.left = w; 2773 else if (d == 'up') 2774 opts.animOut.top = -h; 2775 else if (d == 'down') 2776 opts.animOut.top = h; 2777 else 2778 opts.animOut.left = -w; 2779 }); 2780 opts.animIn.left = 0; 2781 opts.animIn.top = 0; 2782 opts.cssBefore.top = 0; 2783 opts.cssBefore.left = 0; 2784}; 2785 2786// toss - move top slide and fade away 2787$.fn.cycle.transitions.toss = function($cont, $slides, opts) { 2788 var w = $cont.css('overflow','visible').width(); 2789 var h = $cont.height(); 2790 opts.before.push(function(curr, next, opts) { 2791 $.fn.cycle.commonReset(curr,next,opts,true,true,true); 2792 // provide default toss settings if animOut not provided 2793 if (!opts.animOut.left && !opts.animOut.top) 2794 $.extend(opts.animOut, { left: w*2, top: -h/2, opacity: 0 }); 2795 else 2796 opts.animOut.opacity = 0; 2797 }); 2798 opts.cssBefore.left = 0; 2799 opts.cssBefore.top = 0; 2800 opts.animIn.left = 0; 2801}; 2802 2803// wipe - clip animation 2804$.fn.cycle.transitions.wipe = function($cont, $slides, opts) { 2805 var w = $cont.css('overflow','hidden').width(); 2806 var h = $cont.height(); 2807 opts.cssBefore = opts.cssBefore || {}; 2808 var clip; 2809 if (opts.clip) { 2810 if (/l2r/.test(opts.clip)) 2811 clip = 'rect(0px 0px '+h+'px 0px)'; 2812 else if (/r2l/.test(opts.clip)) 2813 clip = 'rect(0px '+w+'px '+h+'px '+w+'px)'; 2814 else if (/t2b/.test(opts.clip)) 2815 clip = 'rect(0px '+w+'px 0px 0px)'; 2816 else if (/b2t/.test(opts.clip)) 2817 clip = 'rect('+h+'px '+w+'px '+h+'px 0px)'; 2818 else if (/zoom/.test(opts.clip)) { 2819 var top = parseInt(h/2,10); 2820 var left = parseInt(w/2,10); 2821 clip = 'rect('+top+'px '+left+'px '+top+'px '+left+'px)'; 2822 } 2823 } 2824 2825 opts.cssBefore.clip = opts.cssBefore.clip || clip || 'rect(0px 0px 0px 0px)'; 2826 2827 var d = opts.cssBefore.clip.match(/(\d+)/g); 2828 var t = parseInt(d[0],10), r = parseInt(d[1],10), b = parseInt(d[2],10), l = parseInt(d[3],10); 2829 2830 opts.before.push(function(curr, next, opts) { 2831 if (curr == next) return; 2832 var $curr = $(curr), $next = $(next); 2833 $.fn.cycle.commonReset(curr,next,opts,true,true,false); 2834 opts.cssAfter.display = 'block'; 2835 2836 var step = 1, count = parseInt((opts.speedIn / 13),10) - 1; 2837 (function f() { 2838 var tt = t ? t - parseInt(step * (t/count),10) : 0; 2839 var ll = l ? l - parseInt(step * (l/count),10) : 0; 2840 var bb = b < h ? b + parseInt(step * ((h-b)/count || 1),10) : h; 2841 var rr = r < w ? r + parseInt(step * ((w-r)/count || 1),10) : w; 2842 $next.css({ clip: 'rect('+tt+'px '+rr+'px '+bb+'px '+ll+'px)' }); 2843 (step++ <= count) ? setTimeout(f, 13) : $curr.css('display', 'none'); 2844 })(); 2845 }); 2846 $.extend(opts.cssBefore, { display: 'block', opacity: 1, top: 0, left: 0 }); 2847 opts.animIn = { left: 0 }; 2848 opts.animOut = { left: 0 }; 2849}; 2850 2851})(jQuery); 2852; 2853/* jshint onevar:false, loopfunc:true */ 2854/* global jetpackSlideshowSettings, escape */ 2855 2856// WARNING: This file is distributed verbatim in Jetpack. @hide-in-jetpack 2857function JetpackSlideshow( element, transition, autostart ) { 2858 this.element = element; 2859 this.images = []; 2860 this.controls = {}; 2861 this.transition = transition || 'fade'; 2862 this.autostart = autostart; 2863} 2864 2865JetpackSlideshow.prototype.showLoadingImage = function( toggle ) { 2866 if ( toggle ) { 2867 this.loadingImage_ = document.createElement( 'div' ); 2868 this.loadingImage_.className = 'slideshow-loading'; 2869 var img = document.createElement( 'img' ); 2870 img.src = jetpackSlideshowSettings.spinner; 2871 this.loadingImage_.appendChild( img ); 2872 this.loadingImage_.appendChild( this.makeZeroWidthSpan() ); 2873 this.element.append( this.loadingImage_ ); 2874 } else if ( this.loadingImage_ ) { 2875 this.loadingImage_.parentNode.removeChild( this.loadingImage_ ); 2876 this.loadingImage_ = null; 2877 } 2878}; 2879 2880JetpackSlideshow.prototype.init = function() { 2881 this.showLoadingImage(true); 2882 2883 var self = this; 2884 // Set up DOM. 2885 for ( var i = 0; i < this.images.length; i++ ) { 2886 var imageInfo = this.images[i]; 2887 var img = document.createElement( 'img' ); 2888 img.src = imageInfo.src; 2889 img.title = typeof( imageInfo.title ) !== 'undefined' ? imageInfo.title : ''; 2890 img.alt = typeof( imageInfo.alt ) !== 'undefined' ? imageInfo.alt : ''; 2891 img.align = 'middle'; 2892 img.nopin = 'nopin'; 2893 var caption = document.createElement( 'div' ); 2894 caption.className = 'slideshow-slide-caption'; 2895 caption.innerHTML = imageInfo.caption; 2896 var container = document.createElement('div'); 2897 container.className = 'slideshow-slide'; 2898 2899 // Hide loading image once first image has loaded. 2900 if ( i === 0 ) { 2901 if ( img.complete ) { 2902 // IE, image in cache 2903 setTimeout( function() { 2904 self.finishInit_(); 2905 }, 1); 2906 } else { 2907 jQuery( img ).load(function() { 2908 self.finishInit_(); 2909 }); 2910 } 2911 } 2912 container.appendChild( img ); 2913 // I'm not sure where these were coming from, but IE adds 2914 // bad values for width/height for portrait-mode images 2915 img.removeAttribute('width'); 2916 img.removeAttribute('height'); 2917 container.appendChild( this.makeZeroWidthSpan() );
2918 container.appendChild( caption ); 2919 this.element.append( container ); 2920 } 2921}; 2922 2923JetpackSlideshow.prototype.makeZeroWidthSpan = function() { 2924 var emptySpan = document.createElement( 'span' ); 2925 emptySpan.className = 'slideshow-line-height-hack'; 2926 // Having a NBSP makes IE act weird during transitions, but other 2927 // browsers ignore a text node with a space in it as whitespace. 2928 if ( -1 !== window.navigator.userAgent.indexOf( 'MSIE ' ) ) { 2929 emptySpan.appendChild( document.createTextNode(' ') ); 2930 } else { 2931 emptySpan.innerHTML = ' '; 2932 } 2933 return emptySpan; 2934}; 2935 2936JetpackSlideshow.prototype.finishInit_ = function() { 2937 this.showLoadingImage( false ); 2938 this.renderControls_(); 2939 2940 var self = this; 2941 if ( this.images.length > 1 ) { 2942 // Initialize Cycle instance. 2943 this.element.cycle( { 2944 fx: this.transition, 2945 prev: this.controls.prev, 2946 next: this.controls.next, 2947 slideExpr: '.slideshow-slide', 2948 onPrevNextEvent: function() { 2949 return self.onCyclePrevNextClick_.apply( self, arguments ); 2950 } 2951 } ); 2952 2953 var slideshow = this.element; 2954 2955 if ( ! this.autostart ) { 2956 slideshow.cycle( 'pause' ); 2957 jQuery(this.controls.stop).removeClass( 'running' ); 2958 jQuery(this.controls.stop).addClass( 'paused' ); 2959 } 2960 2961 jQuery( this.controls.stop ).click( function() { 2962 var button = jQuery(this); 2963 if ( ! button.hasClass( 'paused' ) ) { 2964 slideshow.cycle( 'pause' ); 2965 button.removeClass( 'running' ); 2966 button.addClass( 'paused' ); 2967 } else { 2968 button.addClass( 'running' ); 2969 button.removeClass( 'paused' ); 2970 slideshow.cycle( 'resume', true ); 2971 } 2972 return false; 2973 } ); 2974 } else { 2975 this.element.children( ':first' ).show(); 2976 this.element.css( 'position', 'relative' ); 2977 } 2978 this.initialized_ = true; 2979}; 2980 2981JetpackSlideshow.prototype.renderControls_ = function() { 2982 if ( this.controlsDiv_ ) { 2983 return; 2984 } 2985 2986 var controlsDiv = document.createElement( 'div' ); 2987 controlsDiv.className = 'slideshow-controls'; 2988 2989 var controls = [ 'prev', 'stop', 'next' ]; 2990 for ( var i = 0; i < controls.length; i++ ) { 2991 var controlName = controls[i]; 2992 var a = document.createElement( 'a' ); 2993 a.href = '#'; 2994 controlsDiv.appendChild( a ); 2995 this.controls[controlName] = a; 2996 } 2997 this.element.append( controlsDiv ); 2998 this.controlsDiv_ = controlsDiv; 2999}; 3000 3001JetpackSlideshow.prototype.onCyclePrevNextClick_ = function( isNext, i/*, slideElement*/ ) { 3002 // If blog_id not present don't track page views 3003 if ( ! jetpackSlideshowSettings.blog_id ) { 3004 return; 3005 } 3006 3007 var postid = this.images[i].id; 3008 var stats = new Image(); 3009 stats.src = document.location.protocol + 3010 '//pixel.wp.com/g.gif?host=' + 3011 escape( document.location.host ) + 3012 '&rand=' + Math.random() + 3013 '&blog=' + jetpackSlideshowSettings.blog_id + 3014 '&subd=' + jetpackSlideshowSettings.blog_subdomain + 3015 '&user_id=' + jetpackSlideshowSettings.user_id + 3016 '&post=' + postid + 3017 '&ref=' + escape( document.location ); 3018}; 3019 3020( function ( $ ) { 3021 function jetpack_slideshow_init() { 3022 $( '.jetpack-slideshow-noscript' ).remove(); 3023 3024 $( '.jetpack-slideshow' ).each( function () { 3025 var container = $( this ); 3026 3027 if ( container.data( 'processed' ) ) { 3028 return; 3029 } 3030 3031 var slideshow = new JetpackSlideshow( container, container.data( 'trans' ), container.data( 'autostart' ) ); 3032 slideshow.images = container.data( 'gallery' ); 3033 slideshow.init(); 3034 3035 container.data( 'processed', true ); 3036 } ); 3037 } 3038 3039 $( document ).ready( jetpack_slideshow_init ); 3040 $( 'body' ).on( 'post-load', jetpack_slideshow_init ); 3041} )( jQuery ); 3042; 3043/*jslint indent: 2, browser: true, bitwise: true, plusplus: true */ 3044 3045/*! Copyright Twitter Inc. and other contributors. Licensed under MIT *//* 3046https://github.com/twitter/twemoji/blob/gh-pages/LICENSE 3047*/ 3048 3049// WARNING: this file is generated automatically via 3050// `node twemoji-generator.js` 3051// please update its `createTwemoji` function 3052// at the bottom of the same file instead. 3053var twemoji = (function ( ) { 3054 'use strict'; 3055 3056 /*jshint maxparams:4 */ 3057 3058 var 3059 // the exported module object 3060 twemoji = { 3061 3062 3063 ///////////////////////// 3064 // properties // 3065 ///////////////////////// 3066 3067 // default assets url, by default will be Twitter Inc. CDN 3068 base: (location.protocol === 'https:' ? 'https:' : 'http:') + 3069 '//twemoji.maxcdn.com/', 3070 3071 // default assets file extensions, by default '.png' 3072 ext: '.svg', 3073 3074 // default assets/folder size, by default "36x36" 3075 // available via Twitter CDN: 16, 36, 72 3076 size: 'svg', 3077 3078 // basic utilities / helpers to convert code points 3079 // to JavaScript surrogates and vice versa 3080 convert: { 3081 3082 /** 3083 * Given an HEX codepoint, returns UTF16 surrogate pairs. 3084 * 3085 * @param string generic codepoint, i.e. '1F4A9' 3086 * @return string codepoint transformed into utf16 surrogates pair, 3087 * i.e. \uD83D\uDCA9 3088 * 3089 * @example 3090 * twemoji.convert.fromCodePoint('1f1e8'); 3091 * // "\ud83c\udde8" 3092 * 3093 * '1f1e8-1f1f3'.split('-').map(twemoji.convert.fromCodePoint).join('') 3094 * // "\ud83c\udde8\ud83c\uddf3" 3095 */ 3096 fromCodePoint: fromCodePoint, 3097 3098 /** 3099 * Given UTF16 surrogate pairs, returns the equivalent HEX codepoint. 3100 * 3101 * @param string generic utf16 surrogates pair, i.e. \uD83D\uDCA9 3102 * @param string optional separator for double code points, default='-' 3103 * @return string utf16 transformed into codepoint, i.e. '1F4A9' 3104 * 3105 * @example 3106 * twemoji.convert.toCodePoint('\ud83c\udde8\ud83c\uddf3'); 3107 * // "1f1e8-1f1f3" 3108 * 3109 * twemoji.convert.toCodePoint('\ud83c\udde8\ud83c\uddf3', '~'); 3110 * // "1f1e8~1f1f3" 3111 */ 3112 toCodePoint: toCodePoint 3113 }, 3114 3115
3116 ///////////////////////// 3117 // methods // 3118 ///////////////////////// 3119 3120 /** 3121 * User first: used to remove missing images 3122 * preserving the original text intent when 3123 * a fallback for network problems is desired. 3124 * Automatically added to Image nodes via DOM 3125 * It could be recycled for string operations via: 3126 * $('img.emoji').on('error', twemoji.onerror) 3127 */ 3128 onerror: function onerror() { 3129 if (this.parentNode) { 3130 this.parentNode.replaceChild(createText(this.alt), this); 3131 } 3132 }, 3133 3134 /** 3135 * Main method/logic to generate either <img> tags or HTMLImage nodes. 3136 * "emojify" a generic text or DOM Element. 3137 * 3138 * @overloads 3139 * 3140 * String replacement for `innerHTML` or server side operations 3141 * twemoji.parse(string); 3142 * twemoji.parse(string, Function); 3143 * twemoji.parse(string, Object); 3144 * 3145 * HTMLElement tree parsing for safer operations over existing DOM 3146 * twemoji.parse(HTMLElement); 3147 * twemoji.parse(HTMLElement, Function); 3148 * twemoji.parse(HTMLElement, Object); 3149 * 3150 * @param string|HTMLElement the source to parse and enrich with emoji. 3151 * 3152 * string replace emoji matches with <img> tags. 3153 * Mainly used to inject emoji via `innerHTML` 3154 * It does **not** parse the string or validate it, 3155 * it simply replaces found emoji with a tag. 3156 * NOTE: be sure this won't affect security. 3157 * 3158 * HTMLElement walk through the DOM tree and find emoji 3159 * that are inside **text node only** (nodeType === 3) 3160 * Mainly used to put emoji in already generated DOM 3161 * without compromising surrounding nodes and 3162 * **avoiding** the usage of `innerHTML`. 3163 * NOTE: Using DOM elements instead of strings should 3164 * improve security without compromising too much 3165 * performance compared with a less safe `innerHTML`. 3166 * 3167 * @param Function|Object [optional] 3168 * either the callback that will be invoked or an object 3169 * with all properties to use per each found emoji. 3170 * 3171 * Function if specified, this will be invoked per each emoji 3172 * that has been found through the RegExp except 3173 * those follwed by the invariant \uFE0E ("as text"). 3174 * Once invoked, parameters will be: 3175 * 3176 * codePoint:string the lower case HEX code point 3177 * i.e. "1f4a9" 3178 * 3179 * options:Object all info for this parsing operation 3180 * 3181 * variant:char the optional \uFE0F ("as image") 3182 * variant, in case this info 3183 * is anyhow meaningful. 3184 * By default this is ignored. 3185 * 3186 * If such callback will return a falsy value instead 3187 * of a valid `src` to use for the image, nothing will 3188 * actually change for that specific emoji. 3189 * 3190 * 3191 * Object if specified, an object containing the following properties 3192 * 3193 * callback Function the callback to invoke per each found emoji. 3194 * base string the base url, by default twemoji.base
3195 * ext string the image extension, by default twemoji.ext 3196 * size string the assets size, by default twemoji.size 3197 * 3198 * @example 3199 * 3200 * twemoji.parse("I \u2764\uFE0F emoji!"); 3201 * // I <img class="emoji" draggable="false" alt="â¤ï¸" src="/assets/2764.gif"> emoji! 3202 * 3203 * 3204 * twemoji.parse("I \u2764\uFE0F emoji!", function(icon, options, variant) { 3205 * return '/assets/' + icon + '.gif'; 3206 * }); 3207 * // I <img class="emoji" draggable="false" alt="â¤ï¸" src="/assets/2764.gif"> emoji! 3208 * 3209 * 3210 * twemoji.parse("I \u2764\uFE0F emoji!", { 3211 * size: 72, 3212 * callback: function(icon, options, variant) { 3213 * return '/assets/' + options.size + '/' + icon + options.ext; 3214 * } 3215 * }); 3216 * // I <img class="emoji" draggable="false" alt="â¤ï¸" src="/assets/72x72/2764.png"> emoji! 3217 * 3218 */ 3219 parse: parse, 3220 3221 /** 3222 * Given a string, invokes the callback argument 3223 * per each emoji found in such string. 3224 * This is the most raw version used by 3225 * the .parse(string) method itself. 3226 * 3227 * @param string generic string to parse 3228 * @param Function a generic callback that will be 3229 * invoked to replace the content. 3230 * This calback wil receive standard 3231 * String.prototype.replace(str, callback) 3232 * arguments such: 3233 * callback( 3234 * match, // the emoji match 3235 * icon, // the emoji text (same as text) 3236 * variant // either '\uFE0E' or '\uFE0F', if present 3237 * ); 3238 * 3239 * and others commonly received via replace. 3240 * 3241 * NOTE: When the variant \uFE0E is found, remember this is an explicit intent 3242 * from the user: the emoji should **not** be replaced with an image. 3243 * In \uFE0F case one, it's the opposite, it should be graphic. 3244 * This utility convetion is that only \uFE0E are not translated into images. 3245 */ 3246 replace: replace, 3247 3248 /** 3249 * Simplify string tests against emoji. 3250 * 3251 * @param string some text that might contain emoji 3252 * @return boolean true if any emoji was found, false otherwise. 3253 * 3254 * @example 3255 * 3256 * if (twemoji.test(someContent)) { 3257 * console.log("emoji All The Things!"); 3258 * } 3259 */ 3260 test: test 3261 }, 3262 3263 // RegExp based on emoji's official Unicode standards 3264 // http://www.unicode.org/Public/UNIDATA/EmojiSources.txt 3265 re = /((?:\ud83c\udde8\ud83c\uddf3|\ud83c\uddfa\ud83c\uddf8|\ud83c\uddf7\ud83c\uddfa|\ud83c\uddf0\ud83c\uddf7|\ud83c\uddef\ud83c\uddf5|\ud83c\uddee\ud83c\uddf9|\ud83c\uddec\ud83c\udde7|\ud83c\uddeb\ud83c\uddf7|\ud83c\uddea\ud83c\uddf8|\ud83c\udde9\ud83c\uddea|\u0039\u20e3|\u0038\u20e3|\u0037\u20e3|\u0036\u20e3|\u0035\u20e3|\u0034\u20e3|\u0033\u20e3|\u0032\u20e3|\u0031\u20e3|\u0030\u20e3|\u0023\u20e3|\ud83d\udeb3|\ud83d\udeb1|\ud83d\udeb0|\ud83d\udeaf|\ud83d\udeae|\ud83d\udea6|\ud83d\udea3|\ud83d\udea1|\ud83d\udea0|\ud83d\ude9f|\ud83d\ude9e|\ud83d\ude9d|\ud83d\ude9c|\ud83d\ude9b|\ud83d\ude98|\ud83d\ude96|\ud83d\ude94|\ud83d\ude90|\ud83d\ude8e|\ud83d\ude8d|\ud83d\ude8b|\ud83d\ude8a|\ud83d\ude88|\ud83d\ude86|\ud83d\ude82|\ud83d\ude81|\ud83d\ude36|\ud83d\ude34|\ud83d\ude2f|\ud83d\ude2e|\ud83d\ude2c|\ud83d\ude27|\ud83d\ude26|\ud83d\ude1f|\ud83d\ude1b|\ud83d\ude19|\ud83d\ude17|\ud83d\ude15|\ud83d\ude11|\ud83d\ude10|\ud83d\ude0e|\ud83d\ude08|\ud83d\ude07|\ud83d\ude00|\ud83d\udd67|\ud83d\udd66|\ud83d\udd65|\ud83d\udd64|\ud83d\udd63|\ud83d\udd62|\ud83d\udd61|\ud83d\udd60|\ud83d\udd5f|\ud83d\udd5e|\ud83d\udd5d|\ud83d\udd5c|\ud83d\udd2d|\ud83d\udd2c|\ud83d\udd15|\ud83d\udd09|\ud83d\udd08|\ud83d\udd07|\ud83d\udd06|\ud83d\udd05|\ud83d\udd04|\ud83d\udd02|\ud83d\udd01|\ud83d\udd00|\ud83d\udcf5|\ud83d\udcef|\ud83d\udced|\ud83d\udcec|\ud83d\udcb7|\ud83d\udcb6|\ud83d\udcad|\ud83d\udc6d|\ud83d\udc6c|\ud83d\udc65|\ud83d\udc2a|\ud83d\udc16|\ud83d\udc15|\ud83d\udc13|\ud83d\udc10|\ud83d\udc0f|\ud83d\udc0b|\ud83d\udc0a|\ud83d\udc09|\ud83d\udc08|\ud83d\udc07|\ud83d\udc06|\ud83d\udc05|\ud83d\udc04|\ud83d\udc03|\ud83d\udc02|\ud83d\udc01|\ud83d\udc00|\ud83c\udfe4|\ud83c\udfc9|\ud83c\udfc7|\ud83c\udf7c|\ud83c\udf50|\ud83c\udf4b|\ud83c\udf33|\ud83c\udf32|\ud83c\udf1e|\ud83c\udf1d|\ud83c\udf1c|\ud83c\udf1a|\ud83c\udf18|\ud83c\udccf|\ud83c\udd70|\ud83c\udd71|\ud83c\udd7e|\ud83c\udd8e|\ud83c\udd91|\ud83c\udd92|\ud83c\udd93|\ud83c\udd94|\ud83c\udd95|\ud83c\udd96|\ud83c\udd97|\ud83c\udd98|\ud83c\udd99|\ud83c\udd9a|\ud83d\ude0d|\ud83d\udec5|\ud83d\udec4|\ud83d\udec3|\ud83d\udec2|\ud83d\udec1|\ud83d\udebf|\ud83d\udeb8|\ud83d\udeb7|\ud83d\udeb5|\ud83c\ude01|\ud83c\ude02|\ud83c\ude32|\ud83c\ude33|\ud83c\ude34|\ud83c\ude35|\ud83c\ude36|\ud83c\ude37|\ud83c\ude38|\ud83c\ude39|\ud83c\ude3a|\ud83c\ude50|\ud83c\ude51|\ud83c\udf00|\ud83c\udf01|\ud83c\udf02|\ud83c\udf03|\ud83c\udf04|\ud83c\udf05|\ud83c\udf06|\ud83c\udf07|\ud83c\udf08|\ud83c\udf09|\ud83c\udf0a|\ud83c\udf0b|\ud83c\udf0c|\ud83c\udf0f|\ud83c\udf11|\ud83c\udf13|\ud83c\udf14|\ud83c\udf15|\ud83c\udf19|\ud83c\udf1b|\ud83c\udf1f|\ud83c\udf20|\ud83c\udf30|\ud83c\udf31|\ud83c\udf34|\ud83c\udf35|\ud83c\udf37|\ud83c\udf38|\ud83c\udf39|\ud83c\udf3a|\ud83c\udf3b|\ud83c\udf3c|\ud83c\udf3d|\ud83c\udf3e|\ud83c\udf3f|\ud83c\udf40|\ud83c\udf41|\ud83c\udf42|\ud83c\udf43|\ud83c\udf44|\ud83c\udf45|\ud83c\udf46|\ud83c\udf47|\ud83c\udf48|\ud83c\udf49|\ud83c\udf4a|\ud83c\udf4c|\ud83c\udf4d|\ud83c\udf4e|\ud83c\udf4f|\ud83c\udf51|\ud83c\udf52|\ud83c\udf53|\ud83c\udf54|\ud83c\udf55|\ud83c\udf56|\ud83c\udf57|\ud83c\udf58|\ud83c\udf59|\ud83c\udf5a|\ud83c\udf5b|\ud83c\udf5c|\ud83c\udf5d|\ud83c\udf5e|\ud83c\udf5f|\ud83c\udf60|\ud83c\udf61|\ud83c\udf62|\ud83c\udf63|\ud83c\udf64|\ud83c\udf65|\ud83c\udf66|\ud83c\udf67|\ud83c\udf68|\ud83c\udf69|\ud83c\udf6a|\ud83c\udf6b|\ud83c\udf6c|\ud83c\udf6d|\ud83c\udf6e|\ud83c\udf6f|\ud83c\udf70|\ud83c\udf71|\ud83c\udf72|\ud83c\udf73|\ud83c\udf74|\ud83c\udf75|\ud83c\udf76|\ud83c\udf77|\ud83c\udf78|\ud83c\udf79|\ud83c\udf7a|\ud83c\udf7b|\ud83c\udf80|\ud83c\udf81|\ud83c\udf82|\ud83c\udf83|\ud83c\udf84|\ud83c\udf85|\ud83c\udf86|\ud83c\udf87|\ud83c\udf88|\ud83c\udf89|\ud83c\udf8a|\ud83c\udf8b|\ud83c\udf8c|\ud83c\udf8d|\ud83c\udf8e|\ud83c\udf8f|\ud83c\udf90|\ud83c\udf91|\ud83c\udf92|\ud83c\udf93|\ud83c\udfa0|\ud83c\udfa1|\ud83c\udfa2|\ud83c\udfa3|\ud83c\udfa4|\ud83c\udfa5|\ud83c\udfa6|\ud83c\udfa7|\ud83c\udfa8|\ud83c\udfa9|\ud83c\udfaa|\ud83c\udfab|\ud83c\udfac|\ud83c\udfad|\ud83c\udfae|\ud83c\udfaf|\ud83c\udfb0|\ud83c\udfb1|\ud83c\udfb2|\ud83c\udfb3|\ud83c\udfb4|\ud83c\udfb5|\ud83c\udfb6|\ud83c\udfb7|\ud83c\udfb8|\ud83c\udfb9|\ud83c\udfba|\ud83c\udfbb|\ud83c\udfbc|\ud83c\udfbd|\ud83c\udfbe|\ud83c\udfbf|\ud83c\udfc0|\ud83c\udfc1|\ud83c\udfc2|\ud83c\udfc3|\ud83c\udfc4|\ud83c\udfc6|\ud83c\udfc8|\ud83c\udfca|\ud83c\udfe0|\ud83c\udfe1|\ud83c\udfe2|\ud83c\udfe3|\ud83c\udfe5|\ud83c\udfe6|\ud83c\udfe7|\ud83c\udfe8|\ud83c\udfe9|\ud83c\udfea|\ud83c\udfeb|\ud83c\udfec|\ud83c\udfed|\ud83c\udfee|\ud83c\udfef|\ud83c\udff0|\ud83d\udc0c|\ud83d\udc0d|\ud83d\udc0e|\ud83d\udc11|\ud83d\udc12|\ud83d\udc14|\ud83d\udc17|\ud83d\udc18|\ud83d\udc19|\ud83d\udc1a|\ud83d\udc1b|\ud83d\udc1c|\ud83d\udc1d|\ud83d\udc1e|\ud83d\udc1f|\ud83d\udc20|\ud83d\udc21|\ud83d\udc22|\ud83d\udc23|\ud83d\udc24|\ud83d\udc25|\ud83d\udc26|\ud83d\udc27|\ud83d\udc28|\ud83d\udc29|\ud83d\udc2b|\ud83d\udc2c|\ud83d\udc2d|\ud83d\udc2e|\ud83d\udc2f|\ud83d\udc30|\ud83d\udc31|\ud83d\udc32|\ud83d\udc33|\ud83d\udc34|\ud83d\udc35|\ud83d\udc36|\ud83d\udc37|\ud83d\udc38|\ud83d\udc39|\ud83d\udc3a|\ud83d\udc3b|\ud83d\udc3c|\ud83d\udc3d|\ud83d\udc3e|\ud83d\udc40|\ud83d\udc42|\ud83d\udc43|\ud83d\udc44|\ud83d\udc45|\ud83d\udc46|\ud83d\udc47|\ud83d\udc48|\ud83d\udc49|\ud83d\udc4a|\ud83d\udc4b|\ud83d\udc4c|\ud83d\udc4d|\ud83d\udc4e|\ud83d\udc4f|\ud83d\udc50|\ud83d\udc51|\ud83d\udc52|\ud83d\udc53|\ud83d\udc54|\ud83d\udc55|\ud83d\udc56|\ud83d\udc57|\ud83d\udc58|\ud83d\udc59|\ud83d\udc5a|\ud83d\udc5b|\ud83d\udc5c|\ud83d\udc5d|\ud83d\udc5e|\ud83d\udc5f|\ud83d\udc60|\ud83d\udc61|\ud83d\udc62|\ud83d\udc63|\ud83d\udc64|\ud83d\udc66|\ud83d\udc67|\ud83d\udc68|\ud83d\udc69|\ud83d\udc6a|\ud83d\udc6b|\ud83d\udc6e|\ud83d\udc6f|\ud83d\udc70|\ud83d\udc71|\ud83d\udc72|\ud83d\udc73|\ud83d\udc74|\ud83d\udc75|\ud83d\udc76|\ud83d\udc77|\ud83d\udc78|\ud83d\udc79|\ud83d\udc7a|\ud83d\udc7b|\ud83d\udc7c|\ud83d\udc7d|\ud83d\udc7e|\ud83d\udc7f|\ud83d\udc80|\ud83d\udc81|\ud83d\udc82|\ud83d\udc83|\ud83d\udc84|\ud83d\udc85|\ud83d\udc86|\ud83d\udc87|\ud83d\udc88|\ud83d\udc89|\ud83d\udc8a|\ud83d\udc8b|\ud83d\udc8c|\ud83d\udc8d|\ud83d\udc8e|\ud83d\udc8f|\ud83d\udc90|\ud83d\udc91|\ud83d\udc92|\ud83d\udc93|\ud83d\udc94|\ud83d\udc95|\ud83d\udc96|\ud83d\udc97|\ud83d\udc98|\ud83d\udc99|\ud83d\udc9a|\ud83d\udc9b|\ud83d\udc9c|\ud83d\udc9d|\ud83d\udc9e|\ud83d\udc9f|\ud83d\udca0|\ud83d\udca1|\ud83d\udca2|\ud83d\udca3|\ud83d\udca4|\ud83d\udca5|\ud83d\udca6|\ud83d\udca7|\ud83d\udca8|\ud83d\udca9|\ud83d\udcaa|\ud83d\udcab|\ud83d\udcac|\ud83d\udcae|\ud83d\udcaf|\ud83d\udcb0|\ud83d\udcb1|\ud83d\udcb2|\ud83d\udcb3|\ud83d\udcb4|\ud83d\udcb5|\ud83d\udcb8|\ud83d\udcb9|\ud83d\udcba|\ud83d\udcbb|\ud83d\udcbc|\ud83d\udcbd|\ud83d\udcbe|\ud83d\udcbf|\ud83d\udcc0|\ud83d\udcc1|\ud83d\udcc2|\ud83d\udcc3|\ud83d\udcc4|\ud83d\udcc5|\ud83d\udcc6|\ud83d\udcc7|\ud83d\udcc8|\ud83d\udcc9|\ud83d\udcca|\ud83d\udccb|\ud83d\udccc|\ud83d\udccd|\ud83d\udcce|\ud83d\udccf|\ud83d\udcd0|\ud83d\udcd1|\ud83d\udcd2|\ud83d\udcd3|\ud83d\udcd4|\ud83d\udcd5|\ud83d\udcd6|\ud83d\udcd7|\ud83d\udcd8|\ud83d\udcd9|\ud83d\udcda|\ud83d\udcdb|\ud83d\udcdc|\ud83d\udcdd|\ud83d\udcde|\ud83d\udcdf|\ud83d\udce0|\ud83d\udce1|\ud83d\udce2|\ud83d\udce3|\ud83d\udce4|\ud83d\udce5|\ud83d\udce6|\ud83d\udce7|\ud83d\udce8|\ud83d\udce9|\ud83d\udcea|\ud83d\udceb|\ud83d\udcee|\ud83d\udcf0|\ud83d\udcf1|\ud83d\udcf2|\ud83d\udcf3|\ud83d\udcf4|\ud83d\udcf6|\ud83d\udcf7|\ud83d\udcf9|\ud83d\udcfa|\ud83d\udcfb|\ud83d\udcfc|\ud83d\udd03|\ud83d\udd0a|\ud83d\udd0b|\ud83d\udd0c|\ud83d\udd0d|\ud83d\udd0e|\ud83d\udd0f|\ud83d\udd10|\ud83d\udd11|\ud83d\udd12|\ud83d\udd13|\ud83d\udd14|\ud83d\udd16|\ud83d\udd17|\ud83d\udd18|\ud83d\udd19|\ud83d\udd1a|\ud83d\udd1b|\ud83d\udd1c|\ud83d\udd1d|\ud83d\udd1e|\ud83d\udd1f|\ud83d\udd20|\ud83d\udd21|\ud83d\udd22|\ud83d\udd23|\ud83d\udd24|\ud83d\udd25|\ud83d\udd26|\ud83d\udd27|\ud83d\udd28|\ud83d\udd29|\ud83d\udd2a|\ud83d\udd2b|\ud83d\udd2e|\ud83d\udd2f|\ud83d\udd30|\ud83d\udd31|\ud83d\udd32|\ud83d\udd33|\ud83d\udd34|\ud83d\udd35|\ud83d\udd36|\ud83d\udd37|\ud83d\udd38|\ud83d\udd39|\ud83d\udd3a|\ud83d\udd3b|\ud83d\udd3c|\ud83d\udd3d|\ud83d\udd50|\ud83d\udd51|\ud83d\udd52|\ud83d\udd53|\ud83d\udd54|\ud83d\udd55|\ud83d\udd56|\ud83d\udd57|\ud83d\udd58|\ud83d\udd59|\ud83d\udd5a|\ud83d\udd5b|\ud83d\uddfb|\ud83d\uddfc|\ud83d\uddfd|\ud83d\uddfe|\ud83d\uddff|\ud83d\ude01|\ud83d\ude02|\ud83d\ude03|\ud83d\ude04|\ud83d\ude05|\ud83d\ude06|\ud83d\ude09|\ud83d\ude0a|\ud83d\ude0b|\ud83d\ude0c|\ud83d\udeb4|\ud83d\ude0f|\ud83d\ude12|\ud83d\ude13|\ud83d\ude14|\ud83d\ude16|\ud83d\ude18|\ud83d\ude1a|\ud83d\ude1c|\ud83d\ude1d|\ud83d\ude1e|\ud83d\ude20|\ud83d\ude21|\ud83d\ude22|\ud83d\ude23|\ud83d\ude24|\ud83d\ude25|\ud83d\ude28|\ud83d\ude29|\ud83d\ude2a|\ud83d\ude2b|\ud83d\ude2d|\ud83d\ude30|\ud83d\ude31|\ud83d\ude32|\ud83d\ude33|\ud83d\ude35|\ud83d\ude37|\ud83d\ude38|\ud83d\ude39|\ud83d\ude3a|\ud83d\ude3b|\ud83d\ude3c|\ud83d\ude3d|\ud83d\ude3e|\ud83d\ude3f|\ud83d\ude40|\ud83d\ude45|\ud83d\ude46|\ud83d\ude47|\ud83d\ude48|\ud83d\ude49|\ud83d\ude4a|\ud83d\ude4b|\ud83d\ude4c|\ud83d\ude4d|\ud83d\ude4e|\ud83d\ude4f|\ud83d\ude80|\ud83d\ude83|\ud83d\ude84|\ud83d\ude85|\ud83d\ude87|\ud83d\ude89|\ud83d\ude8c|\ud83d\ude8f|\ud83d\ude91|\ud83d\ude92|\ud83d\ude93|\ud83d\ude95|\ud83d\ude97|\ud83d\ude99|\ud83d\ude9a|\ud83d\udea2|\ud83d\udea4|\ud83d\udea5|\ud83d\udea7|\ud83d\udea8|\ud83d\udea9|\ud83d\udeaa|\ud83d\udeab|\ud83d\udeac|\ud83d\udead|\ud83d\udeb2|\ud83d\udeb6|\ud83d\udeb9|\ud83d\udeba|\ud83d\udebb|\ud83d\udebc|\ud83d\udebd|\ud83d\udebe|\ud83d\udec0|\ud83c\udde6|\ud83c\udde7|\ud83c\udde8|\ud83c\udde9|\ud83c\uddea|\ud83c\uddeb|\ud83c\uddec|\ud83c\udded|\ud83c\uddee|\ud83c\uddef|\ud83c\uddf0|\ud83c\uddf1|\ud83c\uddf2|\ud83c\uddf3|\ud83c\uddf4|\ud83c\uddf5|\ud83c\uddf6|\ud83c\uddf7|\ud83c\uddf8|\ud83c\uddf9|\ud83c\uddfa|\ud83c\uddfb|\ud83c\uddfc|\ud83c\uddfd|\ud83c\uddfe|\ud83c\uddff|\ud83c\udf0d|\ud83c\udf0e|\ud83c\udf10|\ud83c\udf12|\ud83c\udf16|\ud83c\udf17|\ud83c\udf18|\ud83c\udf1a|\ud83c\udf1c|\ud83c\udf1d|\ud83c\udf1e|\ud83c\udf32|\ud83c\udf33|\ud83c\udf4b|\ud83c\udf50|\ud83c\udf7c|\ud83c\udfc7|\ud83c\udfc9|\ud83c\udfe4|\ud83d\udc00|\ud83d\udc01|\ud83d\udc02|\ud83d\udc03|\ud83d\udc04|\ud83d\udc05|\ud83d\udc06|\ud83d\udc07|\ud83d\udc08|\ud83d\udc09|\ud83d\udc0a|\ud83d\udc0b|\ud83d\udc0f|\ud83d\udc10|\ud83d\udc13|\ud83d\udc15|\ud83d\udc16|\ud83d\udc2a|\ud83d\udc65|\ud83d\udc6c|\ud83d\udc6d|\ud83d\udcad|\ud83d\udcb6|\ud83d\udcb7|\ud83d\udcec|\ud83d\udced|\ud83d\udcef|\ud83d\udcf5|\ud83d\udd00|\ud83d\udd01|\ud83d\udd02|\ud83d\udd04|\ud83d\udd05|\ud83d\udd06|\ud83d\udd07|\ud83d\udd08|\ud83d\udd09|\ud83d\udd15|\ud83d\udd2c|\ud83d\udd2d|\ud83d\udd5c|\ud83d\udd5d|\ud83d\udd5e|\ud83d\udd5f|\ud83d\udd60|\ud83d\udd61|\ud83d\udd62|\ud83d\udd63|\ud83d\udd64|\ud83d\udd65|\ud83d\udd66|\ud83d\udd67|\ud83d\ude00|\ud83d\ude07|\ud83d\ude08|\ud83d\ude0e|\ud83d\ude10|\ud83d\ude11|\ud83d\ude15|\ud83d\ude17|\ud83d\ude19|\ud83d\ude1b|\ud83d\ude1f|\ud83d\ude26|\ud83d\ude27|\ud83d\ude2c|\ud83d\ude2e|\ud83d\ude2f|\ud83d\ude34|\ud83d\ude36|\ud83d\ude81|\ud83d\ude82|\ud83d\ude86|\ud83d\ude88|\ud83d\ude8a|\ud83d\ude8b|\ud83d\ude8d|\ud83d\ude8e|\ud83d\ude90|\ud83d\ude94|\ud83d\ude96|\ud83d\ude98|\ud83d\ude9b|\ud83d\ude9c|\ud83d\ude9d|\ud83d\ude9e|\ud83d\ude9f|\ud83d\udea0|\ud83d\udea1|\ud83d\udea3|\ud83d\udea6|\ud83d\udeae|\ud83d\udeaf|\ud83d\udeb0|\ud83d\udeb1|\ud83d\udeb3|\ud83d\udeb4|\ud83d\udeb5|\ud83d\udeb7|\ud83d\udeb8|\ud83d\udebf|\ud83d\udec1|\ud83d\udec2|\ud83d\udec3|\ud83d\udec4|\ud83d\udec5|\ud83c\udf17|\ud83c\udf16|\ud83c\udde6|\ud83c\udde7|\ud83c\udde8|\ud83c\udde9|\ud83c\uddea|\ud83c\uddeb|\ud83c\uddec|\ud83c\udded|\ud83c\uddee|\ud83c\uddef|\ud83c\uddf0|\ud83c\uddf1|\ud83c\uddf2|\ud83c\uddf3|\ud83c\uddf4|\ud83c\uddf5|\ud83c\uddf6|\ud83c\uddf7|\ud83c\uddf8|\ud83c\uddf9|\ud83c\uddfa|\ud83c\uddfb|\ud83c\uddfc|\ud83c\uddfd|\ud83c\uddfe|\ud83c\uddff|\ud83c\udf0d|\ud83c\udf0e|\ud83c\udf10|\ud83c\udf12|\ud83c\udf16|\ud83c\udf17|\ud83c\udf18|\ud83c\udf1a|\ud83c\udf1c|\ud83c\udf1d|\ud83c\udf1e|\ud83c\udf32|\ud83c\udf33|\ud83c\udf4b|\ud83c\udf50|\ud83c\udf7c|\ud83c\udfc7|\ud83c\udfc9|\ud83c\udfe4|\ud83d\udc00|\ud83d\udc01|\ud83d\udc02|\ud83d\udc03|\ud83d\udc04|\ud83d\udc05|\ud83d\udc06|\ud83d\udc07|\ud83d\udc08|\ud83d\udc09|\ud83d\udc0a|\ud83d\udc0b|\ud83d\udc0f|\ud83d\udc10|\ud83d\udc13|\ud83d\udc15|\ud83d\udc16|\ud83d\udc2a|\ud83d\udc65|\ud83d\udc6c|\ud83d\udc6d|\ud83d\udcad|\ud83d\udcb6|\ud83d\udcb7|\ud83d\udcec|\ud83d\udced|\ud83d\udcef|\ud83d\udcf5|\ud83d\udd00|\ud83d\udd01|\ud83d\udd02|\ud83d\udd04|\ud83d\udd05|\ud83d\udd06|\ud83d\udd07|\ud83d\udd08|\ud83d\udd09|\ud83d\udd15|\ud83d\udd2c|\ud83d\udd2d|\ud83d\udd5c|\ud83d\udd5d|\ud83d\udd5e|\ud83d\udd5f|\ud83d\udd60|\ud83d\udd61|\ud83d\udd62|\ud83d\udd63|\ud83d\udd64|\ud83d\udd65|\ud83d\udd66|\ud83d\udd67|\ud83d\ude00|\ud83d\ude07|\ud83d\ude08|\ud83d\ude0e|\ud83d\ude10|\ud83d\ude11|\ud83d\ude15|\ud83d\ude17|\ud83d\ude19|\ud83d\ude1b|\ud83d\ude1f|\ud83d\ude26|\ud83d\ude27|\ud83d\ude2c|\ud83d\ude2e|\ud83d\ude2f|\ud83d\ude34|\ud83d\ude36|\ud83d\ude81|\ud83d\ude82|\ud83d\ude86|\ud83d\ude88|\ud83d\ude8a|\ud83d\ude8b|\ud83d\ude8d|\ud83d\ude8e|\ud83d\ude90|\ud83d\ude94|\ud83d\ude96|\ud83d\ude98|\ud83d\ude9b|\ud83d\ude9c|\ud83d\ude9d|\ud83d\ude9e|\ud83d\ude9f|\ud83d\udea0|\ud83d\udea1|\ud83d\udea3|\ud83d\udea6|\ud83d\udeae|\ud83d\udeaf|\ud83d\udeb0|\ud83d\udeb1|\ud83d\udeb3|\ud83d\udeb4|\ud83d\udeb5|\ud83d\udeb7|\ud83d\udeb8|\ud83d\udebf|\ud83d\udec1|\ud83d\udec2|\ud83d\udec3|\ud83d\udec4|\ud83d\udec5|\ud83c\udf12|\ud83c\udf10|\ud83c\udde6|\ud83c\udde7|\ud83c\udde8|\ud83c\udde9|\ud83c\uddea|\ud83c\uddeb|\ud83c\uddec|\ud83c\udded|\ud83c\uddee|\ud83c\uddef|\ud83c\uddf0|\ud83c\uddf1|\ud83c\uddf2|\ud83c\uddf3|\ud83c\uddf4|\ud83c\uddf5|\ud83c\uddf6|\ud83c\uddf7|\ud83c\uddf8|\ud83c\uddf9|\u
3265d83c\uddfa|\ud83c\uddfb|\ud83c\uddfc|\ud83c\uddfd|\ud83c\uddfe|\ud83c\uddff|\ud83c\udf0d|\ud83c\udf0e|\ue50a|\ue50a|\ue50a|\u27bf|\u3030|\u27b0|\u2797|\u2796|\u2795|\u2755|\u2754|\u2753|\u274e|\u274c|\u2728|\u270b|\u270a|\u2705|\u26ce|\u27bf|\u23f3|\u23f0|\u23ec|\u23eb|\u23ea|\u23e9|\u2122|\u27bf|\u00a9|\u00ae)|(?:(?:\ud83c\udc04|\ud83c\udd7f|\ud83c\ude1a|\ud83c\ude2f|\u3299|\u3297|\u303d|\u2b55|\u2b50|\u2b1c|\u2b1b|\u2b07|\u2b06|\u2b05|\u2935|\u2934|\u27a1|\u2764|\u2757|\u2747|\u2744|\u2734|\u2733|\u2716|\u2714|\u2712|\u270f|\u270c|\u2709|\u2708|\u2702|\u26fd|\u26fa|\u26f5|\u26f3|\u26f2|\u26ea|\u26d4|\u26c5|\u26c4|\u26be|\u26bd|\u26ab|\u26aa|\u26a1|\u26a0|\u2693|\u267b|\u2668|\u2666|\u2665|\u2663|\u2660|\u2653|\u2652|\u2651|\u2650|\u264f|\u264e|\u264d|\u264c|\u264b|\u264a|\u2649|\u2648|\u263a|\u261d|\u2615|\u2614|\u2611|\u260e|\u2601|\u2600|\u25fe|\u25fd|\u25fc|\u25fb|\u25c0|\u25b6|\u25ab|\u25aa|\u24c2|\u231b|\u231a|\u21aa|\u21a9|\u2199|\u2198|\u2197|\u2196|\u2195|\u2194|\u2139|\u2049|\u203c|\u267f)([\uFE0E\uFE0F]?)))/g, 3266 3267 // nodes with type 1 which should **not** be parsed 3268 shouldntBeParsed = /IFRAME|NOFRAMES|NOSCRIPT|SCRIPT|STYLE/, 3269 3270 // just a private shortcut 3271 fromCharCode = String.fromCharCode; 3272 3273 return twemoji; 3274 3275 3276 ///////////////////////// 3277 // private functions // 3278 // declaration // 3279 ///////////////////////// 3280 3281 /** 3282 * Shortcut to create text nodes 3283 * @param string text used to create DOM text node 3284 * @return Node a DOM node with that text 3285 */ 3286 function createText(text) { 3287 return document.createTextNode(text); 3288 } 3289 3290 /** 3291 * Default callback used to generate emoji src 3292 * based on Twitter CDN 3293 * @param string the emoji codepoint string 3294 * @param string the default size to use, i.e. "36x36" 3295 * @param string optional "\uFE0F" variant char, ignored by default 3296 * @return string the image source to use 3297 */ 3298 function defaultImageSrcGenerator(icon, options) { 3299 return ''.concat(options.base, options.size, '/', icon, options.ext); 3300 } 3301 3302 /** 3303 * Given a generic DOM nodeType 1, walk through all children 3304 * and store every nodeType 3 (#text) found in the tree. 3305 * @param Element a DOM Element with probably some text in it 3306 * @param Array the list of previously discovered text nodes 3307 * @return Array same list with new discovered nodes, if any 3308 */ 3309 function grabAllTextNodes(node, allText) { 3310 var 3311 childNodes = node.childNodes, 3312 length = childNodes.length, 3313 subnode, 3314 nodeType; 3315 while (length--) { 3316 subnode = childNodes[length]; 3317 nodeType = subnode.nodeType; 3318 // parse emoji only in text nodes 3319 if (nodeType === 3) { 3320 // collect them to process emoji later 3321 allText.push(subnode); 3322 } 3323 // ignore all nodes that are not type 1 or that 3324 // should not be parsed as script, style, and others 3325 else if (nodeType === 1 && !shouldntBeParsed.test(subnode.nodeName)) { 3326 grabAllTextNodes(subnode, allText); 3327 } 3328 } 3329 return allText; 3330 } 3331 3332 /** 3333 * Used to both remove the possible variant 3334 * and to convert utf16 into code points 3335 * @param string the emoji surrogate pair 3336 * @param string the optional variant char, if any 3337 */ 3338 function grabTheRightIcon(icon, variant) { 3339 // if variant is present as \uFE0F 3340 return toCodePoint( 3341 variant === '\uFE0F' ? 3342 // the icon should not contain it 3343 icon.slice(0, -1) : 3344 icon 3345 ); 3346 } 3347 3348 /** 3349 * DOM version of the same logic / parser: 3350 * emojify all found sub-text nodes placing images node instead. 3351 * @param Element generic DOM node with some text in some child node 3352 * @param Object options containing info about how to parse 3353 * 3354 * .callback Function the callback to invoke per each found emoji. 3355 * .base string the base url, by default twemoji.base 3356 * .ext string the image extension, by default twemoji.ext 3357 * .size string the assets size, by default twemoji.size 3358 * 3359 * @return Element same generic node with emoji in place, if any. 3360 */ 3361 function parseNode(node, options) { 3362 var 3363 allText = grabAllTextNodes(node, []), 3364 length = allText.length, 3365 fragment, 3366 subnode, 3367 text, 3368 match, 3369 i, 3370 index, 3371 img, 3372 alt, 3373 icon, 3374 variant, 3375 src; 3376 while (length--) { 3377 fragment = document.createDocumentFragment(); 3378 subnode = allText[length]; 3379 text = subnode.nodeValue; 3380 i = 0; 3381 while ((match = re.exec(text))) { 3382 index = match.index; 3383 if (index !== i) { 3384 fragment.appendChild( 3385 createText(text.slice(i, index)) 3386 ); 3387 } 3388 alt = match[0]; 3389 icon = match[1]; 3390 variant = match[2]; 3391 i = index + alt.length; 3392 if (variant !== '\uFE0E') { 3393 src = options.callback( 3394 grabTheRightIcon(icon, variant), 3395 options, 3396 variant 3397 ); 3398 if (src) { 3399 img = new Image(); 3400 img.onerror = twemoji.onerror; 3401 img.className = 'emoji'; 3402 img.setAttribute('draggable', 'false'); 3403 img.alt = alt; 3404 img.src = src; 3405 } 3406 } 3407 fragment.appendChild(img || createText(alt)); 3408 img = null; 3409 } 3410 // is there actually anything to replace in here ? 3411 if (0 < i) { 3412 // any text left to be added ? 3413 if (i < text.length) { 3414 fragment.appendChild( 3415 createText(text.slice(i)) 3416 ); 3417 } 3418 // replace the text node only, leave intact 3419 // anything else surrounding such text 3420 subnode.parentNode.replaceChild(fragment, subnode); 3421 } 3422 } 3423 return node; 3424 } 3425 3426 /** 3427 * String/HTML version of the same logic / parser: 3428 * emojify a generic text placing images tags instead of surrogates pair. 3429 * @param string generic string with possibly some emoji in it 3430 * @param Object options containing info about how to parse 3431 * 3432 * .callback Function the callback to invoke per each found emoji.
3433 * .base string the base url, by default twemoji.base 3434 * .ext string the image extension, by default twemoji.ext 3435 * .size string the assets size, by default twemoji.size 3436 * 3437 * @return the string with <img tags> replacing all found and parsed emoji 3438 */ 3439 function parseString(str, options) { 3440 return replace(str, function (match, icon, variant) { 3441 var src; 3442 // verify the variant is not the FE0E one 3443 // this variant means "emoji as text" and should not 3444 // require any action/replacement 3445 // http://unicode.org/Public/UNIDATA/StandardizedVariants.html 3446 if (variant !== '\uFE0E') { 3447 src = options.callback( 3448 grabTheRightIcon(icon, variant), 3449 options, 3450 variant 3451 ); 3452 if (src) { 3453 // recycle the match string replacing the emoji 3454 // with its image counter part 3455 match = '<img '.concat( 3456 'class="emoji" ', 3457 'draggable="false" ', 3458 // needs to preserve user original intent 3459 // when variants should be copied and pasted too 3460 'alt="', 3461 match, 3462 '" ', 3463 'src="', 3464 src, 3465 '"', 3466 '>' 3467 ); 3468 } 3469 } 3470 return match; 3471 }); 3472 } 3473 3474 /** 3475 * Given a generic value, creates its squared counterpart if it's a number. 3476 * As example, number 36 will return '36x36'. 3477 * @param any a generic value. 3478 * @return any a string representing asset size, i.e. "36x36" 3479 * only in case the value was a number. 3480 * Returns initial value otherwise. 3481 */ 3482 function toSizeSquaredAsset(value) { 3483 return typeof value === 'number' ? 3484 value + 'x' + value : 3485 value; 3486 } 3487 3488 3489 ///////////////////////// 3490 // exported functions // 3491 // declaration // 3492 ///////////////////////// 3493 3494 function fromCodePoint(codepoint) { 3495 var code = typeof codepoint === 'string' ? 3496 parseInt(codepoint, 16) : codepoint; 3497 if (code < 0x10000) { 3498 return fromCharCode(code); 3499 } 3500 code -= 0x10000; 3501 return fromCharCode( 3502 0xD800 + (code >> 10), 3503 0xDC00 + (code & 0x3FF) 3504 ); 3505 } 3506 3507 function parse(what, how) { 3508 if (!how || typeof how === 'function') { 3509 how = {callback: how}; 3510 } 3511 // if first argument is string, inject html <img> tags 3512 // otherwise use the DOM tree and parse text nodes only 3513 return (typeof what === 'string' ? parseString : parseNode)(what, { 3514 callback: how.callback || defaultImageSrcGenerator, 3515 base: typeof how.base === 'string' ? how.base : twemoji.base, 3516 ext: how.ext || twemoji.ext, 3517 size: "svg" // toSizeSquaredAsset(how.size || twemoji.size) 3518 }); 3519 } 3520 3521 function replace(text, callback) { 3522 return String(text).replace(re, callback); 3523 } 3524 3525 function test(text) { 3526 // IE6 needs a reset before too 3527 re.lastIndex = 0; 3528 var result = re.test(text); 3529 re.lastIndex = 0; 3530 return result; 3531 } 3532 3533 function toCodePoint(unicodeSurrogates, sep) { 3534 var 3535 r = [], 3536 c = 0, 3537 p = 0, 3538 i = 0; 3539 while (i < unicodeSurrogates.length) { 3540 c = unicodeSurrogates.charCodeAt(i++); 3541 if (p) { 3542 r.push((0x10000 + ((p - 0xD800) << 10) + (c - 0xDC00)).toString(16)); 3543 p = 0; 3544 } else if (0xD800 <= c && c <= 0xDBFF) { 3545 p = c; 3546 } else { 3547 r.push(c.toString(16)); 3548 } 3549 } 3550 return r.join(sep || '-'); 3551 } 3552 3553}()); 3554 3555; 3556var JetpackEmoji = { 3557 EMOJI_SIZE: 72, 3558 BASE_URL: '//s0.wp.com/wp-content/mu-plugins/emoji/twemoji/', 3559 3560 parse: function( element, size, base_url ) { 3561 twemoji.parse( element, { 3562 size: size || this.EMOJI_SIZE, 3563 base: base_url || this.BASE_URL, 3564 callback: function(icon, options, variant) { 3565 // Ignore some standard characters that TinyMCE recommends in its character map. 3566 // https://teamtinker.wordpress.com/2014/10/29/emoji-launch-week/#comment-2103 3567 switch ( icon ) { 3568 case 'a9': 3569 case 'ae': 3570 case '2122': 3571 case '2194': 3572 case '2660': 3573 case '2663': 3574 case '2665': 3575 case '2666': 3576 return false;
3577 } 3578 3579 // directly from twemoji 3580 return ''.concat(options.base, options.size, '/', icon, options.ext); 3581 } 3582 } ); 3583 } 3584} 3585; 3586(function() { 3587 var emoji = { 3588 init: function() { 3589 if ( typeof JetpackEmoji === 'undefined' ) { 3590 console.error( 'JetpackEmoji not found.' ); 3591 return; 3592 } 3593 3594 var size, base_url; 3595 if ( typeof JetpackEmojiSettings !== 'undefined' ) { 3596 size = JetpackEmojiSettings.size || null; 3597 base_url = JetpackEmojiSettings.base_url || null; 3598 } 3599 3600 JetpackEmoji.parse( document.body, size, base_url ); 3601 3602 if ( typeof infiniteScroll !== 'undefined' ) { 3603 jQuery( document.body ).on( 'post-load', function( response ) { 3604 // TODO: ideally, we should only target the newly added elements 3605 JetpackEmoji.parse( document.body, size, base_url ); 3606 } ); 3607 } 3608 } 3609 }; 3610 3611 if ( window.addEventListener ) { 3612 window.addEventListener( 'load', emoji.init, false ); 3613 } else if ( window.attachEvent ) { 3614 window.attachEvent( 'onload', emoji.init ); 3615 } 3616})(); 3617; 3618/* SWFObject v2.2 <http://code.google.com/p/swfobject/> 3619 is released under the MIT License <http://www.opensource.org/licenses/mit-license.php> 3620*/ 3621var swfobject=function(){var D="undefined",r="object",S="Shockwave Flash",W="ShockwaveFlash.ShockwaveFlash",q="application/x-shockwave-flash",R="SWFObjectExprInst",x="onreadystatechange",O=window,j=document,t=navigator,T=false,U=[h],o=[],N=[],I=[],l,Q,E,B,J=false,a=false,n,G,m=true,M=function(){var aa=typeof j.getElementById!=D&&typeof j.getElementsByTagName!=D&&typeof j.createElement!=D,ah=t.userAgent.toLowerCase(),Y=t.platform.toLowerCase(),ae=Y?/win/.test(Y):/win/.test(ah),ac=Y?/mac/.test(Y):/mac/.test(ah),af=/webkit/.test(ah)?parseFloat(ah.replace(/^.*webkit\/(\d+(\.\d+)?).*$/,"$1")):false,X=!+"\v1",ag=[0,0,0],ab=null;if(typeof t.plugins!=D&&typeof t.plugins[S]==r){ab=t.plugins[S].description;if(ab&&!(typeof t.mimeTypes!=D&&t.mimeTypes[q]&&!t.mimeTypes[q].enabledPlugin)){T=true;X=false;ab=ab.replace(/^.*\s+(\S+\s+\S+$)/,"$1");ag[0]=parseInt(ab.replace(/^(.*)\..*$/,"$1"),10);ag[1]=parseInt(ab.replace(/^.*\.(.*)\s.*$/,"$1"),10);ag[2]=/[a-zA-Z]/.test(ab)?parseInt(ab.replace(/^.*[a-zA-Z]+(.*)$/,"$1"),10):0}}else{if(typeof O.ActiveXObject!=D){try{var ad=new ActiveXObject(W);if(ad){ab=ad.GetVariable("$version");if(ab){X=true;ab=ab.split(" ")[1].split(",");ag=[parseInt(ab[0],10),parseInt(ab[1],10),parseInt(ab[2],10)]}}}catch(Z){}}}return{w3:aa,pv:ag,wk:af,ie:X,win:ae,mac:ac}}(),k=function(){if(!M.w3){return}if((typeof j.readyState!=D&&j.readyState=="complete")||(typeof j.readyState==D&&(j.getElementsByTagName("body")[0]||j.body))){f()}if(!J){if(typeof j.addEventListener!=D){j.addEventListener("DOMContentLoaded",f,false)}if(M.ie&&M.win){j.attachEvent(x,function(){if(j.readyState=="complete"){j.detachEvent(x,arguments.callee);f()}});if(O==top){(function(){if(J){return}try{j.documentElement.doScroll("left")}catch(X){setTimeout(arguments.callee,0);return}f()})()}}if(M.wk){(function(){if(J){return}if(!/loaded|complete/.test(j.readyState)){setTimeout(arguments.callee,0);return}f()})()}s(f)}}();function f(){if(J){return}try{var Z=j.getElementsByTagName("body")[0].appendChild(C("span"));Z.parentNode.removeChild(Z)}catch(aa){return}J=true;var X=U.length;for(var Y=0;Y<X;Y++){U[Y]()}}function K(X){if(J){X()}else{U[U.length]=X}}function s(Y){if(typeof O.addEventListener!=D){O.addEventListener("load",Y,false)}else{if(typeof j.addEventListener!=D){j.addEventListener("load",Y,false)}else{if(typeof O.attachEvent!=D){i(O,"onload",Y)}else{if(typeof O.onload=="function"){var X=O.onload;O.onload=function(){X();Y()}}else{O.onload=Y}}}}}function h(){if(T){V()}else{H()}}function V(){var X=j.getElementsByTagName("body")[0];var aa=C(r);aa.setAttribute("type",q);var Z=X.appendChild(aa);if(Z){var Y=0;(function(){if(typeof Z.GetVariable!=D){var ab=Z.GetVariable("$version");if(ab){ab=ab.split(" ")[1].split(",");M.pv=[parseInt(ab[0],10),parseInt(ab[1],10),parseInt(ab[2],10)]}}else{if(Y<10){Y++;setTimeout(arguments.callee,10);return}}X.removeChild(aa);Z=null;H()})()}else{H()}}function H(){var ag=o.length;if(ag>0){for(var af=0;af<ag;af++){var Y=o[af].id;var ab=o[af].callbackFn;var aa={success:false,id:Y};if(M.pv[0]>0){var ae=c(Y);if(ae){if(F(o[af].swfVersion)&&!(M.wk&&M.wk<312)){w(Y,true);if(ab){aa.success=true;aa.ref=z(Y);ab(aa)}}
3621else{if(o[af].expressInstall&&A()){var ai={};ai.data=o[af].expressInstall;ai.width=ae.getAttribute("width")||"0";ai.height=ae.getAttribute("height")||"0";if(ae.getAttribute("class")){ai.styleclass=ae.getAttribute("class")}if(ae.getAttribute("align")){ai.align=ae.getAttribute("align")}var ah={};var X=ae.getElementsByTagName("param");var ac=X.length;for(var ad=0;ad<ac;ad++){if(X[ad].getAttribute("name").toLowerCase()!="movie"){ah[X[ad].getAttribute("name")]=X[ad].getAttribute("value")}}P(ai,ah,Y,ab)}else{p(ae);if(ab){ab(aa)}}}}}else{w(Y,true);if(ab){var Z=z(Y);if(Z&&typeof Z.SetVariable!=D){aa.success=true;aa.ref=Z}ab(aa)}}}}}function z(aa){var X=null;var Y=c(aa);if(Y&&Y.nodeName=="OBJECT"){if(typeof Y.SetVariable!=D){X=Y}else{var Z=Y.getElementsByTagName(r)[0];if(Z){X=Z}}}return X}function A(){return !a&&F("6.0.65")&&(M.win||M.mac)&&!(M.wk&&M.wk<312)}function P(aa,ab,X,Z){a=true;E=Z||null;B={success:false,id:X};var ae=c(X);if(ae){if(ae.nodeName=="OBJECT"){l=g(ae);Q=null}else{l=ae;Q=X}aa.id=R;if(typeof aa.width==D||(!/%$/.test(aa.width)&&parseInt(aa.width,10)<310)){aa.width="310"}if(typeof aa.height==D||(!/%$/.test(aa.height)&&parseInt(aa.height,10)<137)){aa.height="137"}j.title=j.title.slice(0,47)+" - Flash Player Installation";var ad=M.ie&&M.win?"ActiveX":"PlugIn",ac="MMredirectURL="+encodeURI(O.location).toString().replace(/&/g,"%26")+"&MMplayerType="+ad+"&MMdoctitle="+j.title;if(typeof ab.flashvars!=D){ab.flashvars+="&"+ac}else{ab.flashvars=ac}if(M.ie&&M.win&&ae.readyState!=4){var Y=C("div");X+="SWFObjectNew";Y.setAttribute("id",X);ae.parentNode.insertBefore(Y,ae);ae.style.display="none";(function(){if(ae.readyState==4){ae.parentNode.removeChild(ae)}else{setTimeout(arguments.callee,10)}})()}u(aa,ab,X)}}function p(Y){if(M.ie&&M.win&&Y.readyState!=4){var X=C("div");Y.parentNode.insertBefore(X,Y);X.parentNode.replaceChild(g(Y),X);Y.style.display="none";(function(){if(Y.readyState==4){Y.parentNode.removeChild(Y)}else{setTimeout(arguments.callee,10)}})()}else{Y.parentNode.replaceChild(g(Y),Y)}}function g(ab){var aa=C("div");if(M.win&&M.ie){aa.innerHTML=ab.innerHTML}else{var Y=ab.getElementsByTagName(r)[0];if(Y){var ad=Y.childNodes;if(ad){var X=ad.length;for(var Z=0;Z<X;Z++){if(!(ad[Z].nodeType==1&&ad[Z].nodeName=="PARAM")&&!(ad[Z].nodeType==8)){aa.appendChild(ad[Z].cloneNode(true))}}}}}return aa}function u(ai,ag,Y){var X,aa=c(Y);if(M.wk&&M.wk<312){return X}if(aa){if(typeof ai.id==D){ai.id=Y}if(M.ie&&M.win){var ah="";for(var ae in ai){if(ai[ae]!=Object.prototype[ae]){if(ae.toLowerCase()=="data"){ag.movie=ai[ae]}else{if(ae.toLowerCase()=="styleclass"){ah+=' class="'+ai[ae]+'"'}else{if(ae.toLowerCase()!="classid"){ah+=" "+ae+'="'+ai[ae]+'"'}}}}}var af="";for(var ad in ag){if(ag[ad]!=Object.prototype[ad]){af+='<param name="'+ad+'" value="'+ag[ad]+'" />'}}aa.outerHTML='<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"'+ah+">"+af+"</object>";N[N.length]=ai.id;X=c(ai.id)}else{var Z=C(r);Z.setAttribute("type",q);for(var ac in ai){if(ai[ac]!=Object.prototype[ac]){if(ac.toLowerCase()=="styleclass"){Z.setAttribute("class",ai[ac])}else{if(ac.toLowerCase()!="classid"){Z.setAttribute(ac,ai[ac])}}}}for(var ab in ag){if(ag[ab]!=Object.prototype[ab]&&ab.toLowerCase()!="movie"){e(Z,ab,ag[ab])}}aa.parentNode.replaceChild(Z,aa);X=Z}}return X}function e(Z,X,Y){var aa=C("param");aa.setAttribute("name",X);aa.setAttribute("value",Y);Z.appendChild(aa)}function y(Y){var X=c(Y);if(X&&X.nodeName=="OBJECT"){if(M.ie&&M.win){X.style.display="none";(function(){if(X.readyState==4){b(Y)}else{setTimeout(arguments.callee,10)}})()}else{X.parentNode.removeChild(X)}}}function b(Z){var Y=c(Z);if(Y){for(var X in Y){if(typeof Y[X]=="function"){Y[X]=null}}Y.parentNode.removeChild(Y)}}function c(Z){var X=null;try{X=j.getElementById(Z)}catch(Y){}return X}function C(X){return j.createElement(X)}function i(Z,X,Y){Z.attachEvent(X,Y);I[I.length]=[Z,X,Y]}function F(Z){var Y=M.pv,X=Z.split(".");X[0]=parseInt(X[0],10);X[1]=parseInt(X[1],10)||0;X[2]=parseInt(X[2],10)||0;return(Y[0]>X[0]||(Y[0]==X[0]&&Y[1]>X[1])||(Y[0]==X[0]&&Y[1]==X[1]&&Y[2]>=X[2]))?true:false}function v(ac,Y,ad,ab){if(M.ie&&M.mac){return}var aa=j.getElementsByTagName("head")[0];if(!aa){return}var X=(ad&&typeof ad=="string")?ad:"screen";if(ab){n=null;G=null}if(!n||G!=X){var Z=C("style");Z.setAttribute("type","text/css");Z.setAttribute("media",X);n=aa.appendChild(Z);if(M.ie&&M.win&&typeof j.styleSheets!=D&&j.styleSheets.length>0){n=j.styleSheets[j.styleSheets.length-1]}G=X}if(M.ie&&M.win){if(n&&typeof n.addRule==r){n.addRule(ac,Y)}}else{if(n&&typeof j.createTextNode!=D){n.appendChild(j.createTextNode(ac+" {"+Y+"}"))}}}function w(Z,X){if(!m){return}var Y=X?"visible":"hidden";if(J&&c(Z)){c(Z).style.visibility=Y}else{v("#"+Z,"visibility:"+Y)}}function L(Y){var Z=/[\\\"<>\.;]/;var X=Z.exec(Y)!=null;return X&&typeof encodeURIComponent!=D?encodeURIComponent(Y):Y}var d=function(){if(M.ie&&M.win){window.attachEvent("onunload",function(){var ac=I.length;for(var ab=0;ab<ac;ab++){I[ab][0].detachEvent(I[ab][1],I[ab][2])}var Z=N.length;for(var aa=0;aa<Z;aa++){y(N[aa])}for(var Y in M){M[Y]=null}M=null;for(var X in swfobject){swfobject[X]=null}swfobject=null})}}();return{registerObject:function(ab,X,aa,Z){if(M.w3&&ab&&X){var Y={};Y.id=ab;Y.swfVersion=X;Y.expressInstall=aa;Y.callbackFn=Z;o[o.length]=Y;w(ab,false)}else{if(Z){Z({success:false,id:ab})}}},getObjectById:function(X){if(M.w3){return z(X)}},embedSWF:function(ab,ah,ae,ag,Y,aa,Z,ad,af,ac){var X={success:false,id:ah};if(M.w3&&!(M.wk&&M.wk<312)&&ab&&ah&&ae&&ag&&Y){w(ah,false);K(function(){ae+="";ag+="";var aj={};if(af&&typeof af===r){for(var al in af){aj[al]=af[al]}}aj.data=ab;aj.width=ae;aj.height=ag;var am={};if(ad&&typeof ad===r){for(var ak in ad){am[ak]=ad[ak]}}if(Z&&typeof Z===r){for(var ai in Z){if(typeof am.flashvars!=D){am.flashvars+="&"+ai+"="+Z[ai]}else{am.flashvars=ai+"="+Z[ai]}}}if(F(Y)){var an=u(aj,am,ah);if(aj.id==ah){w(ah,true)}X.success=true;X.ref=an}else{if(aa&&A()){aj.data=aa;P(aj,am,ah,ac);return}else{w(ah,true)}}if(ac){ac(X)}})}else{if(ac){ac(X)}}},switchOffAutoHideShow:function(){m=false},ua:M,getFlashPlayerVersion:function(){return{major:M.pv[0],minor:M.pv[1],release:M.pv[2]}},hasFlashPlayerVersion:F,createSWF:function(Z,Y,X){if(M.w3){return u(Z,Y,X)}else{return undefined}},showExpressInstall:function(Z,aa,X,Y){if(M.w3&&A()){P(Z,aa,X,Y)}},removeSWF:function(X){if(M.w3){y(X)}},createCSS:function(aa,Z,Y,X){if(M.w3){v(aa,Z,Y,X)}},addDomLoadEvent:K,addLoadEvent:s,getQueryParamValue:function(aa){var Z=j.location.search||j.location.hash;if(Z){if(/\?/.test(Z)){Z=Z.split("?")[1]}if(aa==null){return L(Z)}var Y=Z.split("&");for(var X=0;X<Y.length;X++){if(Y[X].substring(0,Y[X].indexOf("="))==aa){return L(Y[X].substring((Y[X].indexOf("=")+1)))}}}return""},expressInstallCallback:function(){if(a){var X=c(R);if(X&&l){X.parentNode.replaceChild(l,X);if(Q){w(Q,true);if(M.ie&&M.win){l.style.display="block"}}if(E){E(B)}}a=false}}}}();; 3622/*! 3623 * VideoPress JavaScript Loader 1.09 3624 * 3625 * Copyright 2011 Automattic Inc. 3626 * Licensed under GNU General Public License (GPL) Version 2 or later 3627 * http://www.gnu.org/licenses/gpl-2.0.html 3628 */ 3629 3630// jQuery.type() was introduced in 1.4.3, WP 3.0 has 1.4.2 3631// To maintain backwards compatibility, insert our own version if it doesn't exist 3632if ( typeof jQuery.type != 'function' ) { 3633 jQuery.extend({ 3634 class2type: {}, 3635 3636 type: function( obj ) { 3637 return obj == null ? 3638 String( obj ) : 3639 jQuery.class2type[ toString.call(obj) ] || "object"; 3640 } 3641 }); 3642 3643 jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) { 3644 jQuery.class2type[ "[object " + name + "]" ] = name.toLowerCase(); 3645 }); 3646 3647} 3648 3649jQuery.extend({VideoPress: { 3650 error:{ 3651 messages:{ 3652 age:"You are of insufficient age to view this video.", 3653 error:"Unable to download and play video", 3654 flash:"Error loading Flash on your system", 3655 freedom:'You do not have sufficient <a href="http://www.gnu.org/philosophy/free-sw.html">Freedom levels</a> to view this video.', 3656 incompatible:'VideoPress requires either HTML5 video or <a href="http://www.adobe.com/go/getflashplayer">
3656Adobe Flash Player 10</a> or above for playback.', 3657 incapable:"Your device is incapable of playing the requested video.", 3658 network:"A network error prevented video download and playback" 3659 } 3660 }, 3661 support:{ 3662 flash: function() { 3663 if ( typeof swfobject !== "undefined" && swfobject.hasFlashPlayerVersion( jQuery.VideoPress.video.flash.min_version ) ) { 3664 return true; 3665 } else { 3666 return false; 3667 } 3668 }, 3669 html5Video: function(sourcetype) { 3670 var v = document.createElement("video"); 3671 if ( !!v.canPlayType ) { 3672 if ( jQuery.type(sourcetype)==="string" ) { 3673 return !!v.canPlayType(sourcetype).replace(/no/,""); 3674 } 3675 return true; 3676 } else { 3677 return false; 3678 } 3679 } 3680 }, 3681 data:[], 3682 analytics:{ 3683 wpcom:{ 3684 base_uri:"//pixel.wp.com/v.gif?", 3685 params:function(guid, filetype) { 3686 var data = jQuery.VideoPress.data[guid]; 3687 if ( !jQuery.isPlainObject(data) ) { 3688 return; 3689 } 3690 3691 var params = {blog:data.blog,post:data.post,page_url:top.document.URL}; 3692 if ( filetype==="mp4" && data.mp4 && data.mp4.size ) { 3693 params.video_fmt = "fmt_" + data.mp4.size; 3694 } else { 3695 params.video_fmt = "fmt_std"; 3696 } 3697 return params; 3698 }, 3699 send:function(params) { 3700 var beacon = new Image(); 3701 beacon.src = jQuery.VideoPress.analytics.wpcom.base_uri + jQuery.param(params); 3702 beacon=null; 3703 } 3704 }, 3705 ga:{ 3706 is_active:function(){ 3707 if ( (typeof _gaq !== "undefined") && jQuery.type( _gaq )==="array" ) { 3708 return true; 3709 } else { 3710 return false; 3711 } 3712 } 3713 }, 3714 /*comscore:{ 3715 is_active()function(){ 3716 if ( typeof COMSCORE !== "undefined" ) 3717 return true; 3718 } 3719 }*/ 3720 impression:function(guid) { 3721 var params = jQuery.VideoPress.analytics.wpcom.params( guid, "mp4" ); 3722 if ( !jQuery.isPlainObject( params ) ) { 3723 return; 3724 } 3725 params.video_impression = 1; 3726 jQuery.VideoPress.analytics.wpcom.send( params ); 3727 }, 3728 played:function(guid, filetype) { 3729 var params = jQuery.VideoPress.analytics.wpcom.params( guid, filetype ); 3730 if ( !jQuery.isPlainObject( params ) ) { 3731 return; 3732 } 3733 params.video_play = 1; 3734 jQuery.VideoPress.analytics.wpcom.send( params ); 3735 3736 if ( jQuery.VideoPress.analytics.ga.is_active() ) { 3737 /* Google Analytics tracks unique events per visit. 3738 * Unique video value omitted since two videos on the same page that are both played would only be recorded as one play event. 3739 */ 3740 _gaq.push( ["_trackEvent", "Videos", "Play" ] ); 3741 } 3742 }, 3743 watched:function( guid, filetype, current_time, initial_time ) { 3744 if ( jQuery.VideoPress.data[guid].playback === undefined ) { 3745 var start = 0; 3746 if ( initial_time !== undefined && jQuery.type(initial_time)==="number" && initial_time > 0 ) { 3747 if ( current_time > initial_time ) { 3748 start = current_time - initial_time; 3749 } 3750 } 3751 jQuery.VideoPress.data[guid].playback = { last_observed:current_time, time_elapsed:start }; 3752 } 3753 var time_watched = current_time - jQuery.VideoPress.data[guid].playback.last_observed; 3754 if ( time_watched > 0 ) { 3755 jQuery.VideoPress.data[guid].playback.time_elapsed += time_watched; 3756 jQuery.VideoPress.data[guid].playback.last_observed = current_time; 3757 if ( jQuery.VideoPress.data[guid].playback.time_elapsed > 15 ) { 3758 var params = jQuery.VideoPress.analytics.wpcom.params( guid, filetype ); 3759 if ( !jQuery.isPlainObject( params ) ) { 3760 return; 3761 } 3762 params.t = 15; 3763 jQuery.VideoPress.analytics.wpcom.send( params ); 3764 jQuery.VideoPress.data[guid].playback.time_elapsed -= 15; 3765 } else if ( current_time === jQuery.VideoPress.data[guid].duration ) { 3766 jQuery.VideoPress.analytics.wpcom.send( params ); 3767 jQuery.VideoPress.data[guid].playback.time_elapsed = 0; 3768 delete jQuery.VideoPress.data[guid].playback; 3769 } 3770 } 3771 } 3772 }, 3773 requirements:{ 3774 isSufficientAge: function( container_el, min_age ) { 3775 var birthday = new Date( parseInt( jQuery( "select[name=year]", container_el ).val() ), parseInt( jQuery( "select[name=month]", container_el ).val() ), parseInt( jQuery( "select[name=day]", container_el ).val() ) ); 3776 var allowed_age = new Date( Date.now() - (1000*60*60*24*365*min_age) ); 3777 if ( birthday > allowed_age ) { 3778 container_el.html( '<p class="error" style="color:#fff;font-weight:bold">' + jQuery.VideoPress.error.messages.age + "</p>"); 3779 } else { 3780 jQuery.VideoPress.video.play(container_el); 3781 } 3782 }, 3783 allowedDomain: function (allowed_domains) { 3784 if ( jQuery.type(allowed_domains)==="array" ) { 3785 if ( jQuery.inArray( top.document.location.hostname, allowed_domains )===-1 ) { 3786 return false;
3787 } 3788 } 3789 return true; 3790 } 3791 }, 3792 video:{ 3793 flash:{ 3794 // Protocol and domain for player_uri and expressinstall set in video.play() 3795 player_uri: ( 'https:' == location.protocol ? 'https://v0.wordpress.com' : 'http://s0.videopress.com' ) + "/player.swf?v=1.04", 3796 min_version:"10.0.0", 3797 params:{wmode:"direct",quality:"autohigh",seamlesstabbing:"true",allowfullscreen:"true",allowscriptaccess:"always",overstretch:"true"}, 3798 expressinstall: ( 'https:' == location.protocol ? 'https://v0.wordpress.com' : 'http://s0.videopress.com' ) + "/playerProductInstall.swf", 3799 embedCallback: function(event) { 3800 if ( event.success===false ) { 3801 jQuery("#" + event.id).html("<p>" + jQuery.VideoPress.error.messages.flash + "</p>"); 3802 } 3803 } 3804 }, 3805 types:{mp4:'video/mp4; codecs="avc1.64001E, mp4a.40.2"',ogv:'video/ogg; codecs="theora, vorbis"'}, 3806 canPlay:function () { 3807 if ( jQuery.VideoPress.support.flash() ) { 3808 jQuery.VideoPress.video.playerSupport = "flash"; 3809 } else if ( jQuery.VideoPress.support.html5Video() ) { 3810 if ( jQuery.VideoPress.support.html5Video( jQuery.VideoPress.video.types.mp4 ) ) { 3811 jQuery.VideoPress.video.playerSupport = "mp4"; 3812 } else if ( jQuery.VideoPress.support.html5Video( jQuery.VideoPress.video.types.ogv ) ) { 3813 jQuery.VideoPress.video.playerSupport = "ogv"; 3814 } else { 3815 jQuery.VideoPress.video.playerSupport = "html5"; 3816 } 3817 } else { 3818 jQuery.VideoPress.video.playerSupport = ""; 3819 } 3820 }, 3821 prepare: function ( guid, config, count ) { 3822 var video = jQuery.VideoPress.data[guid][count]; 3823 if ( config.container === undefined || jQuery.type(video)!=="object" ) { 3824 return; 3825 } 3826 3827 var width = 0; 3828 if ( config.width !== undefined ) { 3829 width = config.width; 3830 } else { 3831 config.container.width(); 3832 } 3833 3834 3835 var height = 0; 3836 if ( config.height !== undefined ) { 3837 height = config.height; 3838 } else { 3839 config.container.height(); 3840 } 3841 3842 var div_id = "#v-" + guid + '-' + count; 3843 3844 var parent_width = jQuery( div_id ).parent().width(); 3845 var diffw = 0; 3846 var diffh = 0; 3847 var ratio = 0; 3848 if ( width > parent_width ) { 3849 diffw = width - parent_width + 11; 3850 ratio = ( width * 1.0 ) / ( height * 1.0 ); 3851 diffh = diffw / ratio; 3852 3853 width -= diffw; 3854 height -= Math.round( diffh ); 3855 } 3856 3857 if ( width < 60 || height < 60 ) { 3858 width = 400; 3859 height = 300; 3860 } 3861 3862 jQuery.VideoPress.data[guid][count].dimensions = {}; 3863 3864 if( 0 == ratio ) { 3865 jQuery.VideoPress.data[guid][count].dimensions.width = width; 3866 jQuery.VideoPress.data[guid][count].dimensions.height = height; 3867 } 3868 else { 3869 jQuery.VideoPress.data[guid][count].dimensions.width = width - 7; 3870 jQuery.VideoPress.data[guid][count].dimensions.height = height - Math.round( 7 / ratio ); 3871 3872 jQuery( div_id ).width( width ); 3873 jQuery( div_id ).height( height + 50 ); 3874 3875 jQuery( div_id + "-placeholder" ).width( jQuery.VideoPress.data[guid][count].dimensions.width ); 3876 jQuery( div_id + "-placeholder" ).height( jQuery.VideoPress.data[guid][count].dimensions.height ); 3877 3878 jQuery( div_id + "-placeholder img.videopress-poster" ).width( jQuery.VideoPress.data[guid][count].dimensions.width ); 3879 jQuery( div_id + "-placeholder img.videopress-poster" ).height( jQuery.VideoPress.data[guid][count].dimensions.height ); 3880 } 3881 3882 config.container.data( "guid", guid ); 3883 config.container.data( "count", count ); 3884 if ( jQuery.VideoPress.video.playerSupport === undefined ) { 3885 jQuery.VideoPress.video.canPlay(); 3886 } 3887 3888 if ( config.freedom===true && jQuery.type(video.ogv)==="string" ) { 3889 jQuery.VideoPress.video.insert( config.container, guid, count, video, "ogv", jQuery.VideoPress.data[guid][count].dimensions.width, jQuery.VideoPress.data[guid].dimensions.height ); 3890 config.container.data( "player", "ogv" ); 3891 } else if ( jQuery.VideoPress.video.playerSupport === "flash" ) { 3892 config.container.data( "player", "flash" ); 3893 config.container.append( '<div id="v-' + guid + "-" + count + '-video">' ); 3894 } else if ( jQuery.inArray( jQuery.VideoPress.video.playerSupport, ["html5","mp4","ogv"] ) && ( jQuery.type(video.mp4.uri)==="str
3894ing" || jQuery.type(video.ogv.uri)==="string" ) ) { 3895 var load_type = "html5"; 3896 if ( jQuery.VideoPress.video.playerSupport==="mp4" && video.mp4!==undefined && jQuery.type(video.mp4.uri)==="string" ) { 3897 load_type = "mp4"; 3898 } else if ( jQuery.VideoPress.video.playerSupport==="ogv" && video.ogv!==undefined && jQuery.type(video.ogv.uri)==="string" ) { 3899 load_type = "ogv"; 3900 } 3901 jQuery.VideoPress.video.insert( config.container, guid, count, video, load_type, jQuery.VideoPress.data[guid][count].dimensions.width, jQuery.VideoPress.data[guid][count].dimensions.height ); 3902 config.container.data( "player", load_type ); 3903 load_type=null; 3904 } else { 3905 config.container.html('<p class="videopress-error">' + jQuery.VideoPress.error.messages.incompatible + '</p>'); 3906 return false; 3907 } 3908 return true; 3909 }, 3910 insert: function( container_el, guid, count, video_data, video_type, width, height ) { 3911 var video_id = "v-" + guid + "-" + count + "-video"; 3912 var video_el = jQuery("<video />"); 3913 video_el.attr( "id", video_id ); 3914 video_el.attr( "width", width ); 3915 video_el.attr( "height", height ); 3916 video_el.attr( "poster", video_data.poster ); 3917 if ( video_type==="ogv" ) { 3918 video_el.attr( "preload", "metadata" ); 3919 } else { 3920 video_el.attr( "preload", "none" ); 3921 } 3922 video_el.attr( "controls", "true" ); 3923 video_el.attr( "x-webkit-airplay", "allow" ); 3924 if ( video_type==="mp4" && video_data.mp4!==undefined && jQuery.type(video_data.mp4.uri)==="string" ) { 3925 video_el.attr( "src", video_data.mp4.uri ); 3926 } else if ( video_type==="ogv" && video_data.ogv!==undefined && jQuery.type(video_data.ogv.uri)==="string" ) { 3927 video_el.attr( "src", video_data.ogv.uri ); 3928 } else { 3929 // Purposely omit source type attribute since the browser does not seem to support specifics such as canPlayType 3930 if ( video_data.mp4!==undefined && jQuery.type(video_data.mp4.uri)==="string" ) { 3931 video_el.append( '<source src="' + video_data.mp4.uri + '" />' ); 3932 } 3933 if ( video_data.ogv!==undefined && jQuery.type(video_data.ogv.uri)==="string" ) { 3934 video_el.append( '<source src="' + video_data.ogv.uri + '" />' ); 3935 } 3936 } 3937 3938 if ( video_data.tracks !== undefined ) { 3939 video_el.append( video_data.tracks ); 3940 } 3941 video_el.append( '<p class="videopress-error">' + jQuery.VideoPress.error.messages.incompatible + "</p>" ); 3942 video_el.hide(); 3943 container_el.append( video_el ); 3944 video_el=null; 3945 video_id=null; 3946 }, 3947 play: function( container_el ) { 3948 var player = container_el.data( "player" ); 3949 if ( player===undefined ) { 3950 player="flash"; 3951 } 3952 3953 var guid = container_el.data( "guid" ); 3954 var count = container_el.data( "count" ); 3955 3956 if ( player === "flash" ) { 3957 jQuery( "#" + container_el.attr("id") + "-placeholder", container_el ).remove(); 3958 3959 var player_uri = jQuery.VideoPress.video.flash.player_uri; 3960 var expressinstall = jQuery.VideoPress.video.flash.expressinstall; 3961 3962 swfobject.embedSWF( player_uri, "v-" + guid + "-" + count + "-video", jQuery.VideoPress.data[guid][count].dimensions.width, jQuery.VideoPress.data[guid][count].dimensions.height, jQuery.VideoPress.video.flash.min_version, expressinstall, {guid:guid,autoPlay:"true",isDynamicSeeking:"true",hd:jQuery.VideoPress.data[guid][count].hd}, jQuery.VideoPress.video.flash.params, null, jQuery.VideoPress.video.flash.embedCallback ); 3963 } else if ( jQuery.inArray( player, ["html5", "mp4", "ogv"] ) ) { 3964 var video_el = jQuery("video", container_el); 3965 if ( video_el ) { 3966 jQuery( "#" + container_el.attr("id") + "-placeholder", container_el ).remove(); 3967 if ( player==="html5" ) { 3968 player = "mp4"; 3969 } 3970 jQuery.VideoPress.video.playHTML5( video_el, guid, player ); 3971 } 3972 } else { 3973 jQuery( "#" + container_el.attr("id") + "-placeholder", container_el ).remove(); 3974 container_el.append( '<p class="videopress-error">Unable to play video. No suitable player.</p>' ); 3975 } 3976 3977 var play_event = new CustomEvent( 'videopress_play_video', { 'detail': { 'video_id': guid } } ); 3978 window.dispatchEvent( play_event ); 3979 }, 3980 playHTML5: function( video_el, guid, filetype ) { 3981 video_el.show(); 3982 video_el[0].load(); 3983 3984 /* It seems load() sometimes does not work, but play() will trigger load. 3985 * Tried attaching play() to a data event but data might not load 3986 * So we trigger play() even if there is not enough data loaded to begin playback 3987 */ 3988 video_el[0].play(); 3989 jQuery.VideoPress.analytics.played(guid, filetype); 3990 video_el.bind( "error stalled", function(e) { 3991 var message = jQuery.VideoPress.error.messages.error; 3992 try { 3993 // provide a more detailed error message if a failure reason is communicated 3994 switch (e.target.error.code) { 3995 case e.target.error.MEDIA_ERR_NETWORK: 3996 message = jQuery.VideoPress.error.messages.network; 3997 break; 3998 case e.target.error.MEDIA_ERR_DECODE: 3999 case e.target.error.MEDIA_ERR_SRC_NOT_SUPPORTED: 4000 message = jQuery.VideoPress.error.messages.incapable + " " + filetype.toUpperCase() + "."; 4001 break; 4002 default: 4003 break; 4004 } 4005 } catch( err ){} 4006 // provide an opportunity to silence an error with an empty string 4007 if ( message.length > 0 ) { 4008 video_el.html( '<p class="videopress-error">' + message + "</p>" ); 4009 } 4010 message=null; 4011 } ); 4012 video_el.bind( "durationchange", {guid:guid}, function( event ) { 4013 var duration = jQuery(event.target).attr("duration"); 4014 if ( jQuery.type(duration)==="number" ) { 4015 jQuery.VideoPress.data[event.data.guid].duration = duration; 4016 } 4017 duration=null; 4018 } ); 4019 4020 /* Only record stats after video data has loaded 4021 * If html5 video seems to work but we could not match on a specific codec descriptor then there may be multiple source elements. Browser chooses a source at runtime in source order. We check the loaded video filetype instead of assuming MP4. 4022 */ 4023 video_el.one( "loadeddata", {guid:guid, filetype:filetype}, function( event ){ 4024 var filetype = event.data.filetype; 4025 var loaded_file = jQuery(event.target).attr("currentSrc"); 4026 if ( jQuery.type(loaded_file)==="string" && loaded_file.length > 3 ) { 4027 var ext = loaded_file.substr( loaded_file.lastIndexOf(".") + 1 ).toLowerCase(); 4028 if ( jQuery.inArray( ext, ["mp4","ogv"] ) ) { 4029 filetype = ext; 4030 } 4031 ext=null; 4032 } 4033 video_el.bind( "play", {guid:event.data.guid,filetype:filetype}, function( event ) { 4034 jQuery.VideoPress.analytics.played(event.data.guid, event.data.filetype); 4035 } ); 4036 video_el.bind( "timeupdate", {guid:event.data.guid,filetype:filetype}, function( event ) { 4037 var target = jQuery(event.target); 4038 jQuery.VideoPress.analytics.watched( event.data.guid, event.data.filetype, target.attr("currentTime"), target.attr("initialTime") ); 4039 target=null; 4040 } ); 4041 video_el.bind( "ended", {guid:event.data.guid,filetype:filetype}, function( event ) { 4042 jQuery.VideoPress.analytics.watched( event.data.guid, event.data.filetype, jQuery.VideoPress.data[guid].duration, jQuery(event.target).attr("initialTime") ); 4043 } ); 4044 } ); 4045 } 4046 } 4047}}); 4048; 4049/* jshint sub: true, onevar: false, multistr: true, devel: true, smarttabs: true */ 4050/* global jetpackCarouselStrings, DocumentTouch, jetpackLikesWidgetQueue */ 4051 4052// @start-hide-in-jetpack 4053if (typeof wpcom === 'undefined') { 4054 var wpcom = {}; 4055} 4056wpcom.carousel = (function(/*$*/) { 4057 var prebuilt_widths = jetpackCarouselStrings.widths; 4058 var pageviews_stats_args = jetpackCarouselStrings.stats_query_args; 4059 4060 var findFirstLargeEnoughWidth = function(original_w, original_h, dest_w, dest_h) { 4061 var inverse_ratio = original_h / original_w; 4062 4063 for ( var i = 0; i < prebuilt_widths.length; ++i ) { 4064 if ( prebuilt_widths[i] >= dest_w || prebuilt_widths[i] * inverse_ratio >
4064= dest_h ) { 4065 return prebuilt_widths[i]; 4066 } 4067 } 4068 4069 return original_w; 4070 }; 4071 4072 var addWidthToImageURL = function(url, width) { 4073 width = parseInt(width, 10); 4074 // Give devices with a higher devicePixelRatio higher-res images (Retina display = 2, Android phones = 1.5, etc) 4075 if ('undefined' !== typeof window.devicePixelRatio && window.devicePixelRatio > 1) { 4076 width = Math.round( width * window.devicePixelRatio ); 4077 } 4078 url = addArgToURL(url, 'w', width); 4079 url = addArgToURL(url, 'h', ''); 4080 return url; 4081 }; 4082 4083 var addArgToURL = function(url, arg, value) { 4084 var re = new RegExp(arg+'=[^?&]+'); 4085 if ( url.match(re) ) { 4086 return url.replace(re, arg + '=' + value); 4087 } else { 4088 var divider = url.indexOf('?') !== -1 ? '&' : '?'; 4089 return url + divider + arg + '=' + value; 4090 } 4091 }; 4092 4093 var stat = function ( names ) { 4094 if ( typeof names !== 'string' ) { 4095 names = names.join( ',' ); 4096 } 4097 4098 new Image().src = window.location.protocol + 4099 '//pixel.wp.com/g.gif?v=wpcom-no-pv' + 4100 '&x_carousel=' + names + 4101 '&baba=' + Math.random(); 4102 }; 4103 4104 var pageview = function ( post_id ) { 4105 new Image().src = window.location.protocol + 4106 '//pixel.wp.com/g.gif?host=' + encodeURIComponent( window.location.host ) + 4107 '&ref=' + encodeURIComponent( document.referrer ) + 4108 '&rand=' + Math.random() + 4109 '&' + pageviews_stats_args + 4110 '&post=' + encodeURIComponent( post_id ); 4111 }; 4112 4113 4114 return { 4115 findFirstLargeEnoughWidth: findFirstLargeEnoughWidth, 4116 addWidthToImageURL: addWidthToImageURL, 4117 stat: stat, 4118 pageview: pageview 4119 }; 4120 4121})(jQuery); 4122// @end-hide-in-jetpack 4123 4124jQuery(document).ready(function($) { 4125 4126 // gallery faded layer and container elements 4127 var overlay, comments, gallery, container, nextButton, previousButton, info, transitionBegin, 4128 caption, resizeTimeout, photo_info, close_hint, commentInterval, lastSelectedSlide, 4129 screenPadding = 110, originalOverflow = $('body').css('overflow'), originalHOverflow = $('html').css('overflow'), proportion = 85, 4130 last_known_location_hash = '', imageMeta, titleAndDescription, commentForm, leftColWrapper; 4131 4132 if ( window.innerWidth <= 760 ) { 4133 screenPadding = Math.round( ( window.innerWidth / 760 ) * 110 ); 4134 4135 if ( screenPadding < 40 && ( ( 'ontouchstart' in window ) || window.DocumentTouch && document instanceof DocumentTouch ) ) { 4136 screenPadding = 0; 4137 } 4138 } 4139 4140 var keyListener = function(e){ 4141 switch(e.which){ 4142 case 38: // up 4143 e.preventDefault(); 4144 container.scrollTop(container.scrollTop() - 100); 4145 break; 4146 case 40: // down 4147 e.preventDefault(); 4148 container.scrollTop(container.scrollTop() + 100); 4149 break; 4150 case 39: // right 4151 e.preventDefault(); 4152 gallery.jp_carousel('clearCommentTextAreaValue'); 4153 gallery.jp_carousel('next'); 4154 break; 4155 case 37: // left 4156 case 8: // backspace 4157 e.preventDefault(); 4158 gallery.jp_carousel('clearCommentTextAreaValue'); 4159 gallery.jp_carousel('previous'); 4160 break; 4161 case 27: // escape 4162 e.preventDefault(); 4163 gallery.jp_carousel('clearCommentTextAreaValue'); 4164 container.jp_carousel('close'); 4165 break; 4166 default: 4167 // making jslint happy 4168 break; 4169 } 4170 }; 4171 4172 var resizeListener = function(/*e*/){ 4173 clearTimeout(resizeTimeout); 4174 resizeTimeout = setTimeout(function(){ 4175 gallery 4176 .jp_carousel('slides') 4177 .jp_carousel('fitSlide', true); 4178 gallery.jp_carousel('updateSlidePositions', true); 4179 gallery.jp_carousel('fitMeta', true); 4180 }, 200); 4181 }; 4182 4183 var prepareGallery = function( /*dataCarouselExtra*/ ){ 4184 if (!overlay) { 4185 overlay = $('<div></div>') 4186 .addClass('jp-carousel-overlay') 4187 .css({ 4188 'position' : 'absolute', 4189 'top' : 0, 4190 'right' : 0, 4191 'bottom' : 0, 4192 'left' : 0 4193 }); 4194 4195 var buttons = '<a class="jp-carousel-commentlink" href="#">' + jetpackCarouselStrings.comment + '</a>'; 4196 if ( 1 === Number( jetpackCarouselStrings.is_logged_in ) ) { 4197// @start-hide-in-jetpack 4198 if ( 1 === Number( jetpackCarouselStrings.is_public && 1 === Number( jetpackCarouselStrings.reblog_enabled ) ) ) { 4199 buttons += '<a class="jp-carousel-reblog" href="#">' + jetpackCarouselStrings.reblog + '</a>'; 4200 } 4201// @end-hide-in-jetpack 4202 } 4203
4204 buttons = $('<div class="jp-carousel-buttons">' + buttons + '</div>'); 4205 4206 caption = $('<h2></h2>'); 4207 photo_info = $('<div class="jp-carousel-photo-info"></div>').append(caption); 4208 4209 imageMeta = $('<div></div>') 4210 .addClass('jp-carousel-image-meta') 4211 .css({ 4212 'float' : 'right', 4213 'margin-top' : '20px', 4214 'width' : '250px' 4215 }); 4216 4217 imageMeta 4218 .append( buttons ) 4219 .append( '<ul class=\'jp-carousel-image-exif\' style=\'display:none;\'></ul>' ) 4220 .append( '<a class=\'jp-carousel-image-download\' style=\'display:none;\'></a>' ) 4221 .append( '<div class=\'jp-carousel-image-map\' style=\'display:none;\'></div>' ); 4222 4223 titleAndDescription = $('<div></div>') 4224 .addClass('jp-carousel-titleanddesc') 4225 .css({ 4226 'width' : '100%', 4227 'margin-top' : imageMeta.css('margin-top') 4228 }); 4229 4230 var commentFormMarkup = '<div id="jp-carousel-comment-form-container">'; 4231 4232 if ( jetpackCarouselStrings.local_comments_commenting_as && jetpackCarouselStrings.local_comments_commenting_as.length ) { 4233 // Jetpack comments not enabled, fallback to local comments 4234 4235 if ( 1 !== Number( jetpackCarouselStrings.is_logged_in ) && 1 === Number( jetpackCarouselStrings.comment_registration ) ) { 4236 commentFormMarkup += '<div id="jp-carousel-comment-form-commenting-as">' + jetpackCarouselStrings.local_comments_commenting_as + '</div>'; 4237 } else { 4238 commentFormMarkup += '<form id="jp-carousel-comment-form">'; 4239 commentFormMarkup += '<textarea name="comment" class="jp-carousel-comment-form-field jp-carousel-comment-form-textarea" id="jp-carousel-comment-form-comment-field" placeholder="' + jetpackCarouselStrings.write_comment + '"></textarea>'; 4240 commentFormMarkup += '<div id="jp-carousel-comment-form-submit-and-info-wrapper">'; 4241 commentFormMarkup += '<div id="jp-carousel-comment-form-commenting-as">' + jetpackCarouselStrings.local_comments_commenting_as + '</div>'; 4242 commentFormMarkup += '<input type="submit" name="submit" class="jp-carousel-comment-form-button" id="jp-carousel-comment-form-button-submit" value="'+jetpackCarouselStrings.post_comment+'" />'; 4243 commentFormMarkup += '<span id="jp-carousel-comment-form-spinner"> </span>'; 4244 commentFormMarkup += '<div id="jp-carousel-comment-post-results"></div>'; 4245 commentFormMarkup += '</div>'; 4246 commentFormMarkup += '</form>'; 4247 } 4248 } 4249 commentFormMarkup += '</div>'; 4250 4251 commentForm = $(commentFormMarkup) 4252 .css({ 4253 'width' : '100%', 4254 'margin-top' : '20px', 4255 'color' : '#999' 4256 }); 4257 4258 comments = $('<div></div>') 4259 .addClass('jp-carousel-comments') 4260 .css({ 4261 'width' : '100%', 4262 'bottom' : '10px', 4263 'margin-top' : '20px' 4264 }); 4265 4266 var commentsLoading = $('<div id="jp-carousel-comments-loading"><span>'+jetpackCarouselStrings.loading_comments+'</span></div>') 4267 .css({ 4268 'width' : '100%', 4269 'bottom' : '10px', 4270 'margin-top' : '20px' 4271 }); 4272 4273 var leftWidth = ( $(window).width() - ( screenPadding * 2 ) ) - (imageMeta.width() + 40); 4274 leftWidth += 'px'; 4275 4276 leftColWrapper = $('<div></div>') 4277 .addClass('jp-carousel-left-column-wrapper') 4278 .css({ 4279 'width' : Math.floor( leftWidth ) 4280 }) 4281 .append(titleAndDescription) 4282 .append(commentForm) 4283 .append(comments) 4284 .append(commentsLoading); 4285 4286 var fadeaway = $('<div></div>') 4287 .addClass('jp-carousel-fadeaway'); 4288 4289 info = $('<div></div>') 4290 .addClass('jp-carousel-info') 4291 .css({ 4292 'top' : Math.floor( ($(window).height() / 100) * proportion ), 4293 'left' : screenPadding, 4294 'right' : screenPadding 4295 }) 4296 .append(photo_info) 4297 .append(imageMeta); 4298 4299 if ( window.innerWidth <= 760 ) { 4300 photo_info.remove().insertAfter( titleAndDescription ); 4301 info.prepend( leftColWrapper ); 4302 } 4303 else { 4304 info.append( leftColWrapper ); 4305 } 4306 4307 var targetBottomPos = ( $(window).height() - parseInt( info.css('top'), 10 ) ) + 'px'; 4308 4309 nextButton = $('<div><span></span></div>') 4310 .addClass('jp-carousel-next-button') 4311 .css({ 4312 'right' : '15px' 4313 }); 4314 4315 previousButton = $('<div><span></span></div>') 4316 .addClass('jp-carousel-previous-button') 4317 .css({ 4318 'left' : 0 4319 }); 4320 4321 nextButton.add( previousButton ).css( { 4322 'position' : 'fixed', 4323 'top' : '40px', 4324 'bottom' : targetBottomPos, 4325 'width' : screenPadding 4326 } ); 4327 4328 gallery = $('<div></div>') 4329 .addClass('jp-carousel') 4330 .css({ 4331 'position' : 'absolute', 4332 'top' : 0, 4333 'bottom' : targetBottomPos, 4334 'left' : 0, 4335 'right' : 0 4336 }); 4337 4338 close_hint = $('<div class="jp-carousel-close-hint"><span>×</span></div>') 4339 .css({ 4340 position : 'fixed' 4341 }); 4342
4343 container = $('<div></div>') 4344 .addClass('jp-carousel-wrap') 4345 .addClass( 'jp-carousel-transitions' ); 4346 4347 if ( 'white' === jetpackCarouselStrings.background_color ) { 4348 container.addClass('jp-carousel-light'); 4349 } 4350 4351 container.css({ 4352 'position' : 'fixed', 4353 'top' : 0, 4354 'right' : 0, 4355 'bottom' : 0, 4356 'left' : 0, 4357 'z-index' : 2147483647, 4358 'overflow-x' : 'hidden', 4359 'overflow-y' : 'auto', 4360 'direction' : 'ltr' 4361 }) 4362 .hide() 4363 .append(overlay) 4364 .append(gallery) 4365 .append(fadeaway) 4366 .append(info) 4367 .append(nextButton) 4368 .append(previousButton) 4369 .append(close_hint) 4370 .appendTo($('body')) 4371 .click(function(e){ 4372 var target = $(e.target), wrap = target.parents('div.jp-carousel-wrap'), data = wrap.data('carousel-extra'), 4373 slide = wrap.find('div.selected'), attachment_id = slide.data('attachment-id'); 4374 data = data || []; 4375 4376 if ( target.is(gallery) || target.parents().add(target).is(close_hint) ) { 4377 container.jp_carousel('close'); 4378// @start-hide-in-jetpack 4379 } else if ( target.hasClass('jp-carousel-reblog') ) { 4380 e.preventDefault(); 4381 e.stopPropagation(); 4382 if ( !target.hasClass('reblogged') ) { 4383 target.jp_carousel('show_reblog_box'); 4384 wpcom.carousel.stat('reblog_show_box'); 4385 } 4386 } else if ( target.parents('#carousel-reblog-box').length ) { 4387 if ( target.is('a.cancel') ) { 4388 e.preventDefault(); 4389 e.stopPropagation(); 4390 target.jp_carousel('hide_reblog_box'); 4391 wpcom.carousel.stat('reblog_cancel'); 4392 } else if ( target.is( 'input[type="submit"]' ) ) { 4393 e.preventDefault(); 4394 e.stopPropagation(); 4395 4396 var note = $('#carousel-reblog-box textarea').val(); 4397 if ( jetpackCarouselStrings.reblog_add_thoughts === note ) { 4398 note = ''; 4399 } 4400 4401 $('#carousel-reblog-submit').val( jetpackCarouselStrings.reblogging ); 4402 $('#carousel-reblog-submit').prop('disabled', true); 4403 $( '#carousel-reblog-box div.submit span.canceltext' ).spin( 'small' ); 4404 4405 $.post( jetpackCarouselStrings.ajaxurl, { 4406 'action': 'post_reblog', 4407 'reblog_source': 'carousel', 4408 'original_blog_id': $('#carousel-reblog-box input#carousel-reblog-blog-id').val(), 4409 'original_post_id': $('.jp-carousel div.selected').data('attachment-id'), 4410 'blog_id': $('#carousel-reblog-box select').val(), 4411 'blog_url': $('#carousel-reblog-box input#carousel-reblog-blog-url').val(), 4412 'blog_title': $('#carousel-reblog-box input#carousel-reblog-blog-title').val(), 4413 'post_url': $('#carousel-reblog-box input#carousel-reblog-post-url').val(), 4414 'post_title': slide.data( 'caption' ) || $('#carousel-reblog-box input#carousel-reblog-post-title').val(), 4415 'note': note, 4416 '_wpnonce': $('#carousel-reblog-box #_wpnonce').val() 4417 }, 4418 function(/*result*/) { 4419 $('#carousel-reblog-box').css({ 'height': $('#carousel-reblog-box').height() + 'px' }).slideUp('fast'); 4420 $('a.jp-carousel-reblog').html( jetpackCarouselStrings.reblogged ).removeClass( 'reblog' ).addClass( 'reblogged' ); 4421 $( '#carousel-reblog-box div.submit span.canceltext' ).spin( false ); 4422 $('#carousel-reblog-submit').val( jetpackCarouselStrings.post_reblog ); 4423 $('div.jp-carousel-info').children().not('#carousel-reblog-box').fadeIn('fast'); 4424 slide.data('reblogged', 1); 4425 $('div.gallery').find('img[data-attachment-id="' + slide.data('attachment-id') + '"]').data('reblogged', 1); 4426 4427 4428 }, 'json' ); 4429 wpcom.carousel.stat('reblog_submit'); 4430 } 4431 } else if ( target.hasClass( 'jp-carousel-image-download' ) ) { 4432 wpcom.carousel.stat( 'download_original_click' ); 4433// @end-hide-in-jetpack 4434 } else if ( target.hasClass('jp-carousel-commentlink') ) { 4435 e.preventDefault(); 4436 e.stopPropagation(); 4437 $(window).unbind('keydown', keyListener); 4438 container.animate({scrollTop: parseInt(info.position()['top'], 10)}, 'fast'); 4439 $('#jp-carousel-comment-form-submit-and-info-wrapper').slideDown('fast'); 4440 $('#jp-carousel-comment-form-comment-field').focus(); 4441 } else if ( target.hasClass('jp-carousel-comment-login') ) { 4442 var url = jetpackCarouselStrings.login_url + '%23jp-carousel-' + attachment_id; 4443 4444 window.location.href = url; 4445 } else if ( target.parents('#jp-carousel-comment-form-container').length ) { 4446 var textarea = $('#jp-carousel-comment-form-comment-field') 4447 .blur(function(){ 4448 $(window).bind('keydown', keyListener); 4449 }) 4450 .focus(function(){ 4451 $(window).unbind('keydown', keyListener); 4452 }); 4453 4454 var emailField = $('#jp-carousel-comment-form-email-field') 4455 .blur(function(){ 4456 $(window).bind('keydown', keyListener); 4457 }) 4458 .focus(function(){ 4459 $(window).unbind('keydown', keyListener); 4460 }); 4461 4462 var authorField = $('#jp-carousel-comment-form-author-field') 4463 .blur(function(){ 4464 $(window).bind('keydown', keyListener); 4465 }) 4466 .focus(function(){ 4467 $(window).unbind('keydown', keyListener); 4468 }); 4469 4470 var urlField = $('#jp-carousel-comment-form-url-field') 4471 .blur(function(){ 4472 $(window).bind('keydown', keyListener); 4473 }) 4474 .focus(function(){ 4475 $(window).unbind('keydown', keyListener); 4476 }); 4477 4478 if ( textarea && textarea.attr('id') === target.attr('id')) { 4479 // For first page load 4480 $(window).unbind('keydown', keyListener); 4481 $('#jp-carousel-comment-form-submit-and-info-wrapper').slideDown('fast'); 4482 } else if ( target.is( 'input[type="submit"]' ) ) { 4483 e.preventDefault(); 4484 e.stopPropagation(); 4485 4486 $('#jp-carousel-comment-form-spinner').spin('small', 'white'); 4487 4488 var ajaxData = { 4489 action: 'post_attachment_comment', 4490 nonce: jetpackCarouselStrings.nonce, 4491 blog_id: data['blog_id'], 4492 id: attachment_id, 4493 comment: textarea.val() 4494 }; 4495 4496 if ( ! ajaxData['comment'].length ) { 4497 gallery.jp_carousel('postCommentError', {'field': 'jp-carousel-comment-form-comment-field', 'error': jetpackCarouselStrings.no_comment_text}); 4498 return; 4499 } 4500 4501 if ( 1 !== Number( jetpackCarouselStrings.is_logged_in ) ) { 4502 ajaxData['email'] = emailField.val(); 4503 ajaxData['author'] = authorField.val(); 4504 ajaxData['url'] = urlField.val(); 4505 4506 if ( 1 === Number( jetpackCarouselStrings.require_name_email ) ) { 4507 if ( ! ajaxData['email'].length || ! ajaxData['email'].match('@') ) { 4508 gallery.jp_carousel('postCommentError', {'field': 'jp-carousel-comment-form-email-field', 'error': jetpackCarouselStrings.no_comment_email}); 4509 return; 4510 } else if ( ! ajaxData['author'].length ) { 4511 gallery.jp_carousel('postCommentError', {'field': 'jp-carousel-comment-form-author-field', 'error': jetpackCarouselStrings.no_comment_author}); 4512 return; 4513 } 4514 } 4515 } 4516 4517 $.ajax({ 4518 type: 'POST', 4519 url: jetpackCarouselStrings.ajaxurl, 4520 data: ajaxData, 4521 dataType: 'json', 4522 success: function(response/*, status, xhr*/) { 4523 if ( 'approved' === response.comment_status ) {
4524 $('#jp-carousel-comment-post-results').slideUp('fast').html('<span class="jp-carousel-comment-post-success">' + jetpackCarouselStrings.comment_approved + '</span>').slideDown('fast'); 4525 } else if ( 'unapproved' === response.comment_status ) { 4526 $('#jp-carousel-comment-post-results').slideUp('fast').html('<span class="jp-carousel-comment-post-success">' + jetpackCarouselStrings.comment_unapproved + '</span>').slideDown('fast'); 4527 } else { 4528 // 'deleted', 'spam', false 4529 $('#jp-carousel-comment-post-results').slideUp('fast').html('<span class="jp-carousel-comment-post-error">' + jetpackCarouselStrings.comment_post_error + '</span>').slideDown('fast'); 4530 } 4531 gallery.jp_carousel('clearCommentTextAreaValue'); 4532 gallery.jp_carousel('getComments', {attachment_id: attachment_id, offset: 0, clear: true}); 4533 $('#jp-carousel-comment-form-button-submit').val(jetpackCarouselStrings.post_comment); 4534 $('#jp-carousel-comment-form-spinner').spin(false); 4535 }, 4536 error: function(/*xhr, status, error*/) { 4537 // TODO: Add error handling and display here 4538 gallery.jp_carousel('postCommentError', {'field': 'jp-carousel-comment-form-comment-field', 'error': jetpackCarouselStrings.comment_post_error}); 4539 return; 4540 } 4541 }); 4542 } 4543 } else if ( ! target.parents( '.jp-carousel-info' ).length ) { 4544 container.jp_carousel('next'); 4545 } 4546 }) 4547 .bind('jp_carousel.afterOpen', function(){ 4548 $(window).bind('keydown', keyListener); 4549 $(window).bind('resize', resizeListener); 4550 gallery.opened = true; 4551 4552 resizeListener(); 4553 }) 4554 .bind('jp_carousel.beforeClose', function(){ 4555 var scroll = $(window).scrollTop(); 4556 4557 $(window).unbind('keydown', keyListener); 4558 $(window).unbind('resize', resizeListener); 4559 $(window).scrollTop(scroll); 4560 gallery.jp_carousel( 'hide_reblog_box' ); // @hide-in-jetpack 4561 }) 4562 .bind('jp_carousel.afterClose', function(){ 4563 if ( history.pushState ) { 4564 history.pushState('', document.title, window.location.pathname + window.location.search); 4565 } else { 4566 last_known_location_hash = ''; 4567 window.location.hash = ''; 4568 } 4569 gallery.opened = false; 4570 }) 4571 .on( 'transitionend.jp-carousel ', '.jp-carousel-slide', function ( e ) { 4572 // If the movement transitions take more than twice the allotted time, disable them. 4573 // There is some wiggle room in the 2x, since some of that time is taken up in 4574 // JavaScript, setting up the transition and calling the events. 4575 if ( 'transform' === e.originalEvent.propertyName ) { 4576 var transitionMultiplier = ( ( Date.now() - transitionBegin ) / 1000 ) / e.originalEvent.elapsedTime; 4577 4578 container.off( 'transitionend.jp-carousel' ); 4579 4580 if ( transitionMultiplier >= 2 ) { 4581 $( '.jp-carousel-transitions' ).removeClass( 'jp-carousel-transitions' ); 4582 } 4583 } 4584 } ); 4585 4586 $( '.jp-carousel-wrap' ).touchwipe( { 4587 wipeLeft : function ( e ) { 4588 e.preventDefault(); 4589 gallery.jp_carousel( 'next' ); 4590 }, 4591 wipeRight : function ( e ) { 4592 e.preventDefault(); 4593 gallery.jp_carousel( 'previous' ); 4594 }, 4595 preventDefaultEvents : false 4596 } ); 4597 4598 $( '.jetpack-likes-widget-unloaded' ).each( function() { 4599 jetpackLikesWidgetQueue.push( this.id ); 4600 }); 4601 4602 nextButton.add(previousButton).click(function(e){ 4603 e.preventDefault(); 4604 e.stopPropagation(); 4605 if ( nextButton.is(this) ) { 4606 gallery.jp_carousel('next'); 4607 } else { 4608 gallery.jp_carousel('previous'); 4609 } 4610 }); 4611 } 4612 }; 4613 4614 var methods = { 4615 testForData: function(gallery) { 4616 gallery = $( gallery ); // make sure we have it as a jQuery object. 4617 return !( ! gallery.length || ! gallery.data( 'carousel-extra' ) ); 4618 }, 4619 4620 testIfOpened: function() { 4621 return !!( 'undefined' !== typeof(gallery) && 'undefined' !== typeof(gallery.opened) && gallery.opened ); 4622 }, 4623 4624 openOrSelectSlide: function( index ) { 4625 // The `open` method triggers an asynchronous effect, so we will get an 4626 // error if we try to use `open` then `selectSlideAtIndex` immediately 4627 // after it. We can only use `selectSlideAtIndex` if the carousel is 4628 // already open. 4629 if ( ! $( this ).jp_carousel( 'testIfOpened' ) ) { 4630 // The `open` method selects the correct slide during the 4631 // initialization. 4632 $( this ).jp_carousel( 'open', { start_index: index } ); 4633 } else { 4634 gallery.jp_carousel( 'selectSlideAtIndex', index ); 4635 } 4636 }, 4637 4638 open: function(options) { 4639 var settings = { 4640 'items_selector' : '.gallery-item [data-attachment-id], .tiled-gallery-item [data-attachment-id]', 4641 'start_index': 0 4642 }, 4643 data = $(this).data('carousel-extra'); 4644 4645 if ( !data ) { 4646 return; // don't run if the default gallery functions weren't used 4647 } 4648 4649 prepareGallery( data ); 4650 4651 if ( gallery.jp_carousel( 'testIfOpened' ) ) { 4652 return; // don't open if already opened 4653 } 4654 4655 // make sure to stop the page from scrolling behind the carousel overlay, so we don't trigger 4656 // infiniscroll for it when enabled (Reader, theme infiniscroll, etc). 4657 originalOverflow = $('body').css('overflow'); 4658 $('body').css('overflow', 'hidden'); 4659 // prevent html from overflowing on some of the new themes. 4660 originalHOverflow = $('html').css('overflow'); 4661 $('html').css('overflow', 'hidden'); 4662 4663 // Re-apply inline-block style here and give an initial value for the width 4664 // This value will get replaced with a more appropriate value once the slide is loaded 4665 // This avoids the likes widget appearing initially full width below the comment button and then shuffling up 4666 jQuery( '.slim-likes-widget' ).find( 'iframe' ).css( 'display', 'inline-block' ).css( 'width', '60px' ); 4667 4668 container.data('carousel-extra', data); 4669// @start-hide-in-jetpack 4670 wpcom.carousel.stat( ['open', 'view_image'] ); 4671// @end-hide-in-jetpack 4672 4673 return this.each(function() { 4674 // If options exist, lets merge them 4675 // with our default settings 4676 var $this = $(this); 4677 4678 if ( options ) { 4679 $.extend( settings, options ); 4680 } 4681 if ( -1 === settings.start_index ) { 4682 settings.start_index = 0; //-1 returned if can't find index, so start from beginning 4683 } 4684 4685 container.trigger('jp_carousel.beforeOpen').fadeIn('fast',function(){ 4686 container.trigger('jp_carousel.afterOpen'); 4687 gallery 4688 .jp_carousel('initSlides', $this.find(settings.items_selector), settings.start_index) 4689 .jp_carousel('selectSlideAtIndex', settings.start_index); 4690 }); 4691 gallery.html(''); 4692 }); 4693 }, 4694 4695 selectSlideAtIndex : function(index){ 4696 var slides = this.jp_carousel('slides'), selected = slides.eq(index); 4697 4698 if ( 0 === selected.length ) { 4699 selected = slides.eq(0); 4700 } 4701 4702 gallery.jp_carousel('selectSlide', selected, false); 4703 return this; 4704 }, 4705 4706 close : function(){ 4707 // make sure to let the page scroll again 4708 $('body').css('overflow', originalOverflow); 4709 $('html').css('overflow', originalHOverflow); 4710 return container 4711 .trigger('jp_carousel.beforeClose') 4712 .fadeOut('fast', function(){ 4713 container.trigger('jp_carousel.afterClose'); 4714 }); 4715 4716 }, 4717 4718 next : function(){ 4719 var slide = gallery.jp_carousel( 'nextSlide' ); 4720 container.animate({scrollTop:0}, 'fast'); 4721 gallery.jp_carousel( 'hide_reblog_box' ); // @hide-in-jetpack 4722 4723 if ( slide ) { 4724 this.jp_carousel('selectSlide', slide); 4725 wpcom.carousel.stat( ['next', 'view_image'] ); // @hide-in-jetpack 4726 } 4727 }, 4728 4729 previous : function(){ 4730 var slide = gallery.jp_carousel( 'prevSlide' ); 4731 container.animate({scrollTop:0}, 'fast'); 4732 gallery.jp_carousel( 'hide_reblog_box' ); // @hide-in-jetpack 4733 4734 if ( slide ) { 4735 this.jp_carousel('selectSlide', slide); 4736 wpcom.carousel.stat( ['previous', 'view_image'] ); // @hide-in-jetpack 4737 } 4738 }, 4739 4740 resetButtons : function(current) { 4741 if ( current.data('liked') ) { 4742 $('.jp-carousel-buttons a.jp-carousel-like').addClass('liked').text(jetpackCarouselStrings.unlike); 4743 } else { 4744 $('.jp-carousel-buttons a.jp-carousel-like').removeClass('liked').text(jetpackCarouselStrings.like); 4745 } 4746// @start-hide-in-jetpack 4747 if ( current.data( 'reblogged' ) ) { 4748 $('.jp-carousel-buttons a.jp-carousel-reblog').addClass( 'reblogged' ).text( jetpackCarouselStrings.reblogged ); 4749 } else { 4750 $('.jp-carousel-buttons a.jp-carousel-reblog').removeClass( 'reblogged' ).text( jetpackCarouselStrings.reblog ); 4751 } 4752 4753 // Must also take care of reblog/reblogged here 4754// @end-hide-in-jetpack 4755 }, 4756 4757 selectedSlide : function(){ 4758 return this.find('.selected'); 4759 }, 4760 4761 setSlidePosition : function(x) { 4762 transitionBegin = Date.now(); 4763 4764 return this.css({ 4765 '-webkit-transform':'translate3d(' + x + 'px,0,0)', 4766 '-moz-transform':'translate3d(' + x + 'px,0,0)', 4767 '-ms-transform':'translate(' + x + 'px,0)', 4768 '-o-transform':'translate(' + x + 'px,0)', 4769 'transform':'translate3d(' + x + 'px,0,0)' 4770 }); 4771 }, 4772 4773 updateSlidePositions : function(animate) { 4774 var current = this.jp_carousel( 'selectedSlide' ), 4775 galleryWidth = gallery.width(), 4776 currentWidth = current.width(), 4777 previous = gallery.jp_carousel( 'prevSlide' ), 4778 next = gallery.jp_carousel( 'nextSlide' ), 4779 previousPrevious = previous.prev(), 4780 nextNext = next.next(), 4781 left = Math.floor( ( galleryWidth - currentWidth ) * 0.5 ); 4782 4783 current.jp_carousel( 'setSlidePosition', left ).show(); 4784 4785 // minimum width 4786 gallery.jp_carousel( 'fitInfo', animate ); 4787 4788 // prep the slides 4789 var direction = lastSelectedSlide.is( current.prevAll() ) ? 1 : -1; 4790 4791 // Since we preload the `previousPrevious` and `nextNext` slides, we need 4792 // to make sure they technically visible in the DOM, but invisible to the 4793 // user. To hide them from the user, we position them outside the edges 4794 // of the window. 4795 // 4796 // This section of code only applies when there are more than three 4797 // slides. Otherwise, the `previousPrevious` and `nextNext` slides will 4798 // overlap with the `previous` and `next` slides which must be visible 4799 // regardless. 4800 if ( 1 === direction ) { 4801 if ( ! nextNext.is( previous ) ) { 4802 nextNext.jp_carousel( 'setSlidePosition', galleryWidth + next.width() ).show(); 4803 } 4804 4805 if ( ! previousPrevious.is( next ) ) { 4806 previousPrevious.jp_carousel( 'setSlidePosition', -previousPrevious.width() - currentWidth ).show(); 4807 } 4808 } else { 4809 if ( ! nextNext.is( previous ) ) { 4810 nextNext.jp_carousel( 'setSlidePosition', galleryWidth + currentWidth ).show(); 4811 } 4812 } 4813 4814 previous.jp_carousel( 'setSlidePosition', Math.floor( -previous.width() + ( screenPadding * 0.75 ) ) ).show(); 4815 next.jp_carousel( 'setSlidePosition', Math.ceil( galleryWidth - ( screenPadding * 0.75 ) ) ).show(); 4816 }, 4817 4818 selectSlide : function(slide, animate){ 4819 lastSelectedSlide = this.find( '.selected' ).removeClass( 'selected' ); 4820 4821 var slides = gallery.jp_carousel( 'slides' ).css({ 'position': 'fixed' }), 4822 current = $( slide ).addClass( 'selected' ).css({ 'position': 'relative' }), 4823 attachmentId = current.data( 'attachment-id' ), 4824 previous = gallery.jp_carousel( 'prevSlide' ), 4825 next = gallery.jp_carousel( 'nextSlide' ), 4826 previousPrevious = previous.prev(), 4827 nextNext = next.next(), 4828 animated, 4829 captionHtml; 4830 4831 // center the main image 4832 gallery.jp_carousel( 'loadFullImage', current ); 4833 4834 caption.hide(); 4835 4836 if ( next.length === 0 && slides.length <= 2 ) { 4837 $( '.jp-carousel-next-button' ).hide(); 4838 } else { 4839 $( '.jp-carousel-next-button' ).show(); 4840 } 4841 4842 if ( previous.length === 0 && slides.length <= 2 ) { 4843 $( '.jp-carousel-previous-button' ).hide(); 4844 } else { 4845 $( '.jp-carousel-previous-button' ).show(); 4846 } 4847 4848 animated = current 4849 .add( previous ) 4850 .add( previousPrevious ) 4851 .add( next ) 4852 .add( nextNext ) 4853 .jp_carousel( 'loadSlide' ); 4854 4855 // slide the whole view to the x we want 4856 slides.not( animated ).hide(); 4857 4858 gallery.jp_carousel( 'updateSlidePositions', animate ); 4859 4860 gallery.jp_carousel( 'resetButtons', current ); 4861 container.trigger( 'jp_carousel.selectSlide', [current] ); 4862 4863 gallery.jp_carousel( 'getTitleDesc', { 4864 title: current.data( 'title' ), 4865 desc: current.data( 'desc' ) 4866 }); 4867 4868 // Lazy-load the Likes iframe for the current, next, and previous slides. 4869 gallery.jp_carousel( 'loadLikes', attachmentId ); 4870 gallery.jp_carousel( 'updateLikesWidgetVisibility', attachmentId ); 4871 4872 if ( next.length > 0 ) { 4873 gallery.jp_carousel( 'loadLikes', next.data( 'attachment-id' ) ); 4874 } 4875 4876 if ( previous.length > 0 ) { 4877 gallery.jp_carousel( 'loadLikes', previous.data( 'attachment-id' ) ); 4878 } 4879 4880 var imageMeta = current.data( 'image-meta' ); 4881 gallery.jp_carousel( 'updateExif', imageMeta ); 4882 gallery.jp_carousel( 'updateFullSizeLink', current ); 4883 gallery.jp_carousel( 'updateMap', imageMeta ); 4884 gallery.jp_carousel( 'testCommentsOpened', current.data( 'comments-opened' ) ); 4885 gallery.jp_carousel( 'getComments', { 4886 'attachment_id': attachmentId, 4887 'offset': 0, 4888 'clear': true 4889 });
4890 $( '#jp-carousel-comment-post-results' ).slideUp(); 4891 4892 // $('<div />').text(sometext).html() is a trick to go to HTML to plain 4893 // text (including HTML entities decode, etc) 4894 if ( current.data( 'caption' ) ) { 4895 captionHtml = $( '<div />' ).text( current.data( 'caption' ) ).html(); 4896 4897 if ( captionHtml === $( '<div />' ).text( current.data( 'title' ) ).html() ) { 4898 $( '.jp-carousel-titleanddesc-title' ).fadeOut( 'fast' ).empty(); 4899 } 4900 4901 if ( captionHtml === $( '<div />' ).text( current.data( 'desc' ) ).html() ) { 4902 $( '.jp-carousel-titleanddesc-desc' ).fadeOut( 'fast' ).empty(); 4903 } 4904 4905 caption.html( current.data( 'caption' ) ).fadeIn( 'slow' ); 4906 } else { 4907 caption.fadeOut( 'fast' ).empty(); 4908 } 4909 4910 wpcom.carousel.pageview( attachmentId ); // @hide-in-jetpack 4911 4912 // Load the images for the next and previous slides. 4913 $( next ).add( previous ).each( function() { 4914 gallery.jp_carousel( 'loadFullImage', $( this ) ); 4915 }); 4916 4917 window.location.hash = last_known_location_hash = '#jp-carousel-' + attachmentId; 4918 }, 4919 4920 slides : function(){ 4921 return this.find('.jp-carousel-slide'); 4922 }, 4923 4924 slideDimensions : function(){ 4925 return { 4926 width: $(window).width() - (screenPadding * 2), 4927 height: Math.floor( $(window).height() / 100 * proportion - 60 ) 4928 }; 4929 }, 4930 4931 loadSlide : function() { 4932 return this.each(function(){ 4933 var slide = $(this); 4934 slide.find('img') 4935 .one('load', function(){ 4936 // set the width/height of the image if it's too big 4937 slide 4938 .jp_carousel('fitSlide',false); 4939 }); 4940 }); 4941 }, 4942 4943 bestFit : function(){ 4944 var max = gallery.jp_carousel('slideDimensions'), 4945 orig = this.jp_carousel('originalDimensions'), 4946 orig_ratio = orig.width / orig.height, 4947 w_ratio = 1, 4948 h_ratio = 1, 4949 width, height; 4950 4951 if ( orig.width > max.width ) { 4952 w_ratio = max.width / orig.width; 4953 } 4954 if ( orig.height > max.height ) { 4955 h_ratio = max.height / orig.height; 4956 } 4957 4958 if ( w_ratio < h_ratio ) { 4959 width = max.width; 4960 height = Math.floor( width / orig_ratio ); 4961 } else if ( h_ratio < w_ratio ) { 4962 height = max.height; 4963 width = Math.floor( height * orig_ratio ); 4964 } else { 4965 width = orig.width; 4966 height = orig.height; 4967 } 4968 4969 return { 4970 width: width, 4971 height: height 4972 }; 4973 }, 4974 4975 fitInfo : function(/*animated*/){ 4976 var current = this.jp_carousel('selectedSlide'), 4977 size = current.jp_carousel('bestFit'); 4978 4979 photo_info.css({ 4980 'left' : Math.floor( (info.width() - size.width) * 0.5 ), 4981 'width' : Math.floor( size.width ) 4982 }); 4983 4984 return this; 4985 }, 4986 4987 fitMeta : function(animated){ 4988 var newInfoTop = { top: Math.floor( $(window).height() / 100 * proportion + 5 ) + 'px' }; 4989 var newLeftWidth = { width: ( info.width() - (imageMeta.width() + 80) ) + 'px' }; 4990 4991 if (animated) { 4992 info.animate(newInfoTop); 4993 leftColWrapper.animate(newLeftWidth); 4994 } else { 4995 info.animate(newInfoTop); 4996 leftColWrapper.css(newLeftWidth); 4997 } 4998 }, 4999 5000 fitSlide : function(/*animated*/){ 5001 return this.each(function(){ 5002 var $this = $(this), 5003 dimensions = $this.jp_carousel('bestFit'), 5004 method = 'css', 5005 max = gallery.jp_carousel('slideDimensions'); 5006 5007 dimensions.left = 0; 5008 dimensions.top = Math.floor( (max.height - dimensions.height) * 0.5 ) + 40; 5009 $this[method](dimensions); 5010 }); 5011 }, 5012 5013 texturize : function(text) { 5014 text = '' + text; // make sure we get a string. Title "1" came in as int 1, for example, which did not support .replace(). 5015 text = text.replace(/'/g, '’').replace(/'/g, '’').replace(/[\u2019]/g, '’'); 5016 text = text.replace(/"/g, '”').replace(/"/g, '”').replace(/"/g, '”').replace(/[\u201D]/g, '”'); 5017 text = text.replace(/([\w]+)=&#[\d]+;(.+?)&#[\d]+;/g, '$1="$2"'); // untexturize allowed HTML tags params double-quotes 5018 return $.trim(text); 5019 }, 5020 5021 initSlides : function(items, start_index){ 5022 if ( items.length < 2 ) { 5023 $( '.jp-carousel-next-button, .jp-carousel-previous-button' ).hide(); 5024 } else { 5025 $( '.jp-carousel-next-button, .jp-carousel-previous-button' ).show(); 5026 } 5027 5028 // Calculate the new src. 5029 items.each(function(/*i*/){ 5030 var src_item = $(this), 5031 orig_size = src_item.data('orig-size') || '', 5032 max = gallery.jp_carousel('slideDimensions'), 5033 parts = orig_size.split(','), 5034 medium_file = src_item.data('medium-file') || '', 5035 large_file = src_item.data('large-file') || '', 5036 src; 5037 orig_size = {width: parseInt(parts[0], 10), height: parseInt(parts[1], 10)}; 5038 5039// @start-hide-in-jetpack 5040 if ( 'undefined' !== typeof wpcom ) { 5041 src = src_item.attr('src') || src_item.attr('original') || src_item.data('original') || src_item.data('lazy-src'); 5042 if (src.indexOf('imgpress') !== -1) { 5043 src = src_item.data('orig-file'); 5044 } 5045 src = wpcom.carousel.addWidthToImageURL( src, wpcom.carousel.findFirstLargeEnoughWidth( orig_size.width, orig_size.height, max.width, max.height ) ); 5046 } else { 5047// @end-hide-in-jetpack 5048 src = src_item.data('orig-file'); 5049 5050 src = gallery.jp_carousel('selectBestImageSize', { 5051 orig_file : src, 5052 orig_width : orig_size.width, 5053 orig_height : orig_size.height, 5054 max_width : max.width, 5055 max_height : max.height, 5056 medium_file : medium_file, 5057 large_file : large_file 5058 }); 5059// @start-hide-in-jetpack 5060 } // end else of if ( 'undefined' != typeof wpcom ) 5061// @end-hide-in-jetpack 5062 5063 // Set the final src 5064 $(this).data( 'gallery-src', src ); 5065 }); 5066 5067 // If the start_index is not 0 then preload the clicked image first. 5068 if ( 0 !== start_index ) { 5069 $('<img/>')[0].src = $(items[start_index]).data('gallery-src'); 5070 } 5071 5072 var useInPageThumbnails = items.first().closest( '.tiled-gallery.type-rectangular' ).length > 0; 5073 5074 // create the 'slide' 5075 items.each(function(i){ 5076 var src_item = $(this), 5077 liked = src_item.data('liked') || 0, // @hide-in-jetpack 5078 reblogged = src_item.data( 'reblogged' ) || 0, // @hide-in-jetpack 5079 attachment_id = src_item.data('attachment-id') || 0, 5080 comments_opened = src_item.data('comments-opened') || 0, 5081 image_meta = src_item.data('image-meta') || {}, 5082 orig_size = src_item.data('orig-size') || '',
5083 thumb_size = { width : src_item[0].naturalWidth, height : src_item[0].naturalHeight }, 5084 title = src_item.data('image-title') || '', 5085 description = src_item.data('image-description') || '', 5086 caption = src_item.parents('.gallery-item').find('.gallery-caption').html() || '', 5087 src = src_item.data('gallery-src') || '', 5088 medium_file = src_item.data('medium-file') || '', 5089 large_file = src_item.data('large-file') || '', 5090 orig_file = src_item.data('orig-file') || ''; 5091 5092 var tiledCaption = src_item.parents('div.tiled-gallery-item').find('div.tiled-gallery-caption').html(); 5093 if ( tiledCaption ) { 5094 caption = tiledCaption; 5095 } 5096 5097 if ( attachment_id && orig_size.length ) { 5098 title = gallery.jp_carousel('texturize', title); 5099 description = gallery.jp_carousel('texturize', description); 5100 caption = gallery.jp_carousel('texturize', caption); 5101 5102 // Initially, the image is a 1x1 transparent gif. The preview is shown as a background image on the slide itself. 5103 var image = $( '<img/>' ) 5104 .attr( 'src', 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7' ) 5105 .css( 'width', '100%' ) 5106 .css( 'height', '100%' ); 5107 5108 var slide = $('<div class="jp-carousel-slide"></div>') 5109 .hide() 5110 .css({ 5111 //'position' : 'fixed', 5112 'left' : i < start_index ? -1000 : gallery.width() 5113 }) 5114 .append( image ) 5115 .appendTo(gallery) 5116 .data('src', src ) 5117 .data('title', title) 5118 .data('desc', description) 5119 .data('caption', caption) 5120 .data('attachment-id', attachment_id) 5121 .data('permalink', src_item.parents('a').attr('href')) 5122 .data('orig-size', orig_size) 5123 .data('comments-opened', comments_opened) 5124 .data('image-meta', image_meta) 5125 .data('medium-file', medium_file) 5126 .data('large-file', large_file) 5127 .data('orig-file', orig_file) 5128 .data('thumb-size', thumb_size) 5129 .data('liked', liked) // @hide-in-jetpack 5130 .data( 'reblogged', reblogged ) // @hide-in-jetpack 5131 ; 5132 5133 if ( useInPageThumbnails ) { 5134 // Use the image already loaded in the gallery as a preview. 5135 slide 5136 .data( 'preview-image', src_item.attr( 'src' ) ) 5137 .css( { 5138 'background-image' : 'url("' + src_item.attr( 'src' ) + '")', 5139 'background-size' : '100% 100%', 5140 'background-position' : 'center center' 5141 } ); 5142 } 5143 5144 slide.jp_carousel( 'fitSlide', false ); 5145 } 5146 }); 5147 return this; 5148 }, 5149 5150 selectBestImageSize: function(args) { 5151 if ( 'object' !== typeof args ) { 5152 args = {}; 5153 } 5154 5155 if ( 'undefined' === typeof args.orig_file ) { 5156 return ''; 5157 } 5158 5159 if ( 'undefined' === typeof args.orig_width || 'undefined' === typeof args.max_width ) { 5160 return args.orig_file; 5161 } 5162 5163 if ( 'undefined' === typeof args.medium_file || 'undefined' === typeof args.large_file ) { 5164 return args.orig_file; 5165 } 5166 5167 var medium_size = args.medium_file.replace(/-([\d]+x[\d]+)\..+$/, '$1'), 5168 medium_size_parts = (medium_size !== args.medium_file) ? medium_size.split('x') : [args.orig_width, 0], 5169 medium_width = parseInt( medium_size_parts[0], 10 ), 5170 medium_height = parseInt( medium_size_parts[1], 10 ), 5171 large_size = args.large_file.replace(/-([\d]+x[\d]+)\..+$/, '$1'), 5172 large_size_parts = (large_size !== args.large_file) ? large_size.split('x') : [args.orig_width, 0], 5173 large_width = parseInt( large_size_parts[0], 10 ), 5174 large_height = parseInt( large_size_parts[1], 10 ); 5175 5176 // Give devices with a higher devicePixelRatio higher-res images (Retina display = 2, Android phones = 1.5, etc) 5177 if ( 'undefined' !== typeof window.devicePixelRatio && window.devicePixelRatio > 1 ) { 5178 args.max_width = args.max_width * window.devicePixelRatio; 5179 args.max_height = args.max_height * window.devicePixelRatio; 5180 } 5181 5182 if ( large_width >= args.max_width || large_height >= args.max_height ) { 5183 return args.large_file; 5184 } 5185 5186 if ( medium_width >= args.max_width || medium_height >= args.max_height ) { 5187 return args.medium_file; 5188 } 5189 5190 return args.orig_file; 5191 }, 5192// @start-hide-in-jetpack 5193 show_reblog_box: function() { 5194 $('#carousel-reblog-box textarea').val(jetpackCarouselStrings.reblog_add_thoughts); 5195 //t.addClass('selected'); 5196 $('#carousel-reblog-box p.response').remove(); 5197 $('#carousel-reblog-box div.submit, #carousel-reblog-box div.submit span.canceltext').show(); 5198 $('#carousel-reblog-box div.submit input[type=submit]').prop('disabled', false); 5199 5200 var current = $('.jp-carousel div.selected'); 5201 $('#carousel-reblog-box input#carousel-reblog-post-url').val( current.data('permalink') ); 5202 $('#carousel-reblog-box input#carousel-reblog-post-title').val( $('div.jp-carousel-info').children('h2').text() ); 5203 5204 $('div.jp-carousel-info').append( $('#carousel-reblog-box') ).children().fadeOut('fast'); 5205 $('#carousel-reblog-box').fadeIn('fast'); 5206 }, 5207 5208 hide_reblog_box: function () { 5209 $( 'div.jp-carousel-info' ).children().not( '#carousel-reblog-box' ).fadeIn( 'fast' ); 5210 $( '#carousel-reblog-box' ).fadeOut( 'fast' ); 5211 }, 5212// @end-hide-in-jetpack 5213 5214 originalDimensions: function() { 5215 var splitted = $(this).data('orig-size').split(','); 5216 return {width: parseInt(splitted[0], 10), height: parseInt(splitted[1], 10)}; 5217 }, 5218 5219 format: function( args ) { 5220 if ( 'object' !== typeof args ) { 5221 args = {}; 5222 } 5223 if ( ! args.text || 'undefined' === typeof args.text ) { 5224 return; 5225 } 5226 if ( ! args.replacements || 'undefined' === typeof args.replacements ) { 5227 return args.text; 5228 } 5229 return args.text.replace(/{(\d+)}/g, function( match, number ) { 5230 return typeof args.replacements[number] !== 'undefined' ? args.replacements[number] : match; 5231 }); 5232 }, 5233 5234 shutterSpeed: function(d) { 5235 if (d >= 1) { 5236 return Math.round(d*10)/10 + 's'; // round to one decimal if value >
5236 1s by multiplying it by 10, rounding, then dividing by 10 again 5237 } 5238 var df = 1, top = 1, bot = 1; 5239 var tol = 1e-8; 5240 // iterate while value not reached and difference (positive or negative, hence the Math.abs) between value 5241 // and approximated value greater than given tolerance 5242 while (df !== d && Math.abs(df-d) > tol) { 5243 if (df < d) { 5244 top += 1; 5245 } else { 5246 bot += 1; 5247 top = parseInt(d * bot, 10); 5248 } 5249 df = top / bot; 5250 } 5251 if (top > 1) { 5252 bot = Math.round(bot / top); 5253 top = 1; 5254 } 5255 if (bot <= 1) { 5256 return '1s'; 5257 } 5258 return top + '/' + bot + 's'; 5259 }, 5260 5261 parseTitleDesc: function( value ) { 5262 if ( !value.match(' ') && value.match('_') ) { 5263 return ''; 5264 } 5265 // Prefix list originally based on http://commons.wikimedia.org/wiki/MediaWiki:Filename-prefix-blacklist 5266 $([ 5267 'CIMG', // Casio 5268 'DSC_', // Nikon 5269 'DSCF', // Fuji 5270 'DSCN', // Nikon 5271 'DUW', // some mobile phones 5272 'GEDC', // GE 5273 'IMG', // generic 5274 'JD', // Jenoptik 5275 'MGP', // Pentax 5276 'PICT', // misc. 5277 'Imagen', // misc. 5278 'Foto', // misc. 5279 'DSC', // misc. 5280 'Scan', // Scanners 5281 'SANY', // Sanyo 5282 'SAM', // Samsung 5283 'Screen Shot [0-9]+' // Mac screenshots 5284 ]) 5285 .each(function(key, val){ 5286 var regex = new RegExp('^' + val); 5287 if ( regex.test(value) ) { 5288 value = ''; 5289 return; 5290 } 5291 }); 5292 return value; 5293 }, 5294 5295 getTitleDesc: function( data ) { 5296 var title ='', desc = '', markup = '', target; 5297 5298 target = $( 'div.jp-carousel-titleanddesc', 'div.jp-carousel-wrap' ); 5299 target.hide(); 5300 5301 title = gallery.jp_carousel('parseTitleDesc', data.title) || ''; 5302 desc = gallery.jp_carousel('parseTitleDesc', data.desc) || ''; 5303 5304 if ( title.length || desc.length ) { 5305 // $('<div />').text(sometext).html() is a trick to go to HTML to plain text (including HTML entities decode, etc) 5306 if ( $('<div />').text(title).html() === $('<div />').text(desc).html() ) { 5307 title = ''; 5308 } 5309 5310 markup = ( title.length ) ? '<div class="jp-carousel-titleanddesc-title">' + title + '</div>' : ''; 5311 markup += ( desc.length ) ? '<div class="jp-carousel-titleanddesc-desc">' + desc + '</div>' : ''; 5312 5313 target.html( markup ).fadeIn('slow'); 5314 } 5315 5316 $( 'div#jp-carousel-comment-form-container' ).css('margin-top', '20px'); 5317 $( 'div#jp-carousel-comments-loading' ).css('margin-top', '20px'); 5318 }, 5319 5320 updateLikesWidgetVisibility: function ( attachmentId ) { 5321 // Only do this if likes is enabled 5322 if ( 'undefined' === typeof jetpackLikesWidgetQueue ) { 5323 return; 5324 } 5325 5326 // Hide all likes widgets except for the one for the attachmentId passed in 5327 $( '.jp-carousel-buttons .jetpack-likes-widget-wrapper' ).css( 'display', 'none' ).each( function () { 5328 var widgetWrapper = $( this ); 5329 if ( widgetWrapper.attr( 'data-attachment-id' ) == attachmentId ) { // jshint ignore:line 5330 widgetWrapper.css( 'display', 'inline-block' ); 5331 return false; 5332 } 5333 }); 5334 }, 5335 5336 loadLikes : function ( attachmentId ) { 5337 var dataCarouselExtra = $( '.jp-carousel-wrap' ).data( 'carousel-extra' ); 5338 var blogId = dataCarouselExtra.likes_blog_id; 5339 5340 if ( $( '#like-post-wrapper-' + blogId + '-' + attachmentId ).length === 0 ) { 5341 // Add the iframe the first time the slide is shown. 5342 var protocol = 'http'; 5343 var originDomain = 'http://wordpress.com'; 5344 5345 if ( dataCarouselExtra.permalink.length ) { 5346 protocol = dataCarouselExtra.permalink.split( ':' )[0]; 5347 5348 if ( ( protocol !== 'http' ) && ( protocol !== 'https' ) ) { 5349 protocol = 'http'; 5350 } 5351 5352 var parts = dataCarouselExtra.permalink.split( '/' ); 5353 5354 if ( parts.length >= 2 ) { 5355 originDomain = protocol + '://' + parts[2]; 5356 } 5357 } 5358 5359 var dataSource = protocol + '://widgets.wp.com/likes/#blog_id=' + encodeURIComponent( blogId ) + 5360 '&post_id=' + encodeURIComponent( attachmentId ) + 5361 '&slim=1&origin=' + encodeURIComponent( originDomain ); 5362 5363 if ( 'en' !== jetpackCarouselStrings.lang ) { 5364 dataSource += '&lang=' + encodeURIComponent( jetpackCarouselStrings.lang ); 5365 } 5366 5367 var likesWidget = $( '<iframe class=\'post-likes-widget jetpack-likes-widget jetpack-resizeable\'></iframe>' ) 5368 .attr( 'name', 'like-post-frame-' + blogId + '-' + attachmentId ) 5369 .attr( 'src', dataSource ) 5370 .css( 'display', 'inline-block' ); 5371 5372 var likesWidgetWrapper = $( '<div/>' ) 5373 .addClass( 'jetpack-likes-widget-wrapper jetpack-likes-widget-unloaded slim-likes-widget' ) 5374 .attr( 'id', 'like-post-wrapper-' + blogId + '-' + attachmentId ) 5375 .attr( 'data-src', dataSource ) 5376 .attr( 'data-name', 'like-post-frame-' + blogId + '-' + attachmentId ) 5377 .attr( 'data-attachment-id', attachmentId ) 5378 .css( 'display', 'none' ) 5379 .css( 'vertical-align', 'middle' ) 5380 .append( likesWidget ) 5381 .append( '<div class=\'post-likes-widget-placeholder\'></div>' ); 5382 5383 $( '.jp-carousel-buttons' ).append( likesWidgetWrapper ); 5384 } 5385 5386 }, 5387 5388 // updateExif updates the contents of the exif UL (.jp-carousel-image-exif) 5389 updateExif: function( meta ) { 5390 if ( !meta || 1 !== Number( jetpackCarouselStrings.display_exif ) ) { 5391 return false;
5392 } 5393 5394 var $ul = $( '<ul class=\'jp-carousel-image-exif\'></ul>' ); 5395 5396 $.each( meta, function( key, val ) { 5397 if ( 0 === parseFloat(val) || !val.length || -1 === $.inArray( key, [ 'camera', 'aperture', 'shutter_speed', 'focal_length' ] ) ) { 5398 return; 5399 } 5400 5401 switch( key ) { 5402 case 'focal_length': 5403 val = val + 'mm'; 5404 break; 5405 case 'shutter_speed': 5406 val = gallery.jp_carousel('shutterSpeed', val); 5407 break; 5408 case 'aperture': 5409 val = 'f/' + val; 5410 break; 5411 } 5412 5413 $ul.append( '<li><h5>' + jetpackCarouselStrings[key] + '</h5>' + val + '</li>' ); 5414 }); 5415 5416 // Update (replace) the content of the ul 5417 $( 'div.jp-carousel-image-meta ul.jp-carousel-image-exif' ).replaceWith( $ul ); 5418 }, 5419 5420 // updateFullSizeLink updates the contents of the jp-carousel-image-download link 5421 updateFullSizeLink: function(current) { 5422 if(!current || !current.data) { 5423 return false; 5424 } 5425 var original = current.data('orig-file').replace(/\?.+$/, ''), 5426 origSize = current.data('orig-size').split(','), 5427 permalink = $( '<a>'+gallery.jp_carousel('format', {'text': jetpackCarouselStrings.download_original, 'replacements': origSize})+'</a>' ) 5428 .addClass( 'jp-carousel-image-download' ) 5429 .attr( 'href', original ) 5430 .attr( 'target', '_blank' ); 5431 5432 // Update (replace) the content of the anchor 5433 $( 'div.jp-carousel-image-meta a.jp-carousel-image-download' ).replaceWith( permalink ); 5434 }, 5435 5436 updateMap: function( meta ) { 5437 if ( !meta.latitude || !meta.longitude || 1 !== Number( jetpackCarouselStrings.display_geo ) ) { 5438 return; 5439 } 5440 5441 var latitude = meta.latitude, 5442 longitude = meta.longitude, 5443 $metabox = $( 'div.jp-carousel-image-meta', 'div.jp-carousel-wrap' ), 5444 $mapbox = $( '<div></div>' ), 5445 style = '&scale=2&style=feature:all|element:all|invert_lightness:true|hue:0x0077FF|saturation:-50|lightness:-5|gamma:0.91'; 5446 5447 $mapbox 5448 .addClass( 'jp-carousel-image-map' ) 5449 .html( '<img width="154" height="154" src="https://maps.googleapis.com/maps/api/staticmap?\ 5450 center=' + latitude + ',' + longitude + '&\ 5451 zoom=8&\ 5452 size=154x154&\ 5453 sensor=false&\ 5454 markers=size:medium%7Ccolor:blue%7C' + latitude + ',' + longitude + style +'" class="gmap-main" />\ 5455 \ 5456 <div class="gmap-topright"><div class="imgclip"><img width="175" height="154" src="https://maps.googleapis.com/maps/api/staticmap?\ 5457 center=' + latitude + ',' + longitude + '&\ 5458 zoom=3&\ 5459 size=175x154&\ 5460 sensor=false&\ 5461 markers=size:small%7Ccolor:blue%7C' + latitude + ',' + longitude + style + '"c /></div></div>\ 5462 \ 5463 ' ) 5464 .prependTo( $metabox ); 5465 }, 5466 5467 testCommentsOpened: function( opened ) { 5468 if ( 1 === parseInt( opened, 10 ) ) { 5469// @start-hide-in-jetpack 5470 if ( 1 === Number( jetpackCarouselStrings.is_logged_in ) ) { 5471 $('.jp-carousel-commentlink').fadeIn('fast'); 5472 } else { 5473// @end-hide-in-jetpack 5474 $('.jp-carousel-buttons').fadeIn('fast'); 5475// @start-hide-in-jetpack 5476 } 5477// @end-hide-in-jetpack 5478 commentForm.fadeIn('fast'); 5479 } else { 5480// @start-hide-in-jetpack 5481 if ( 1 === Number( jetpackCarouselStrings.is_logged_in ) ) { 5482 $('.jp-carousel-commentlink').fadeOut('fast'); 5483 } else { 5484// @end-hide-in-jetpack 5485 $('.jp-carousel-buttons').fadeOut('fast'); 5486// @start-hide-in-jetpack 5487 } 5488// @end-hide-in-jetpack 5489 commentForm.fadeOut('fast'); 5490 } 5491 }, 5492 5493 getComments: function( args ) { 5494 clearInterval( commentInterval ); 5495 5496 if ( 'object' !== typeof args ) { 5497 return; 5498 } 5499 5500 if ( 'undefined' === typeof args.attachment_id || ! args.attachment_id ) { 5501 return; 5502 } 5503 5504 if ( ! args.offset || 'undefined' === typeof args.offset || args.offset < 1 ) { 5505 args.offset = 0; 5506 } 5507 5508 var comments = $('.jp-carousel-comments'), 5509 commentsLoading = $('#jp-carousel-comments-loading').show(); 5510 5511 if ( args.clear ) { 5512 comments.hide().empty(); 5513 } 5514 5515 $.ajax({ 5516 type: 'GET', 5517 url: jetpackCarouselStrings.ajaxurl, 5518 dataType: 'json', 5519 data: { 5520 action: 'get_attachment_comments', 5521 nonce: jetpackCarouselStrings.nonce, 5522 id: args.attachment_id, 5523 offset: args.offset 5524 }, 5525 success: function(data/*, status, xhr*/) { 5526 if ( args.clear ) { 5527 comments.fadeOut('fast').empty(); 5528 } 5529 5530 $( data ).each(function(){ 5531 var comment = $('<div></div>') 5532 .addClass('jp-carousel-comment') 5533 .attr('id', 'jp-carousel-comment-' + this['id']) 5534 .html( 5535 '<div class="comment-gravatar">' + 5536 this['gravatar_markup'] + 5537 '</div>' + 5538 '<div class="comment-author">' + 5539 this['author_markup'] + 5540 '</div>' + 5541 '<div class="comment-date">' + 5542 this['date_gmt'] + 5543 '</div>' + 5544 '<div class="comment-content">' + 5545 this['content'] + 5546 '</div>' 5547 ); 5548 comments.append(comment); 5549 5550 // Set the interval to check for a new page of comments. 5551 clearInterval( commentInterval ); 5552 commentInterval = setInterval( function() { 5553 if ( ( $('.jp-carousel-overlay').height() - 150 ) < $('.jp-carousel-wrap').scrollTop() + $(window).height() ) { 5554 gallery.jp_carousel('getComments',{ attachment_id: args.attachment_id, offset: args.offset + 10, clear: false }); 5555 clearInterval( commentInterval ); 5556 } 5557 }, 300 ); 5558 }); 5559 5560 // Verify (late) that the user didn't repeatldy click the arrows really fast, in which case the requested 5561 // attachment id might no longer match the current attachment id by the time we get the data back or a now 5562 // registered infiniscroll event kicks in, so we don't ever display comments for the wrong image by mistake. 5563 var current = $('.jp-carousel div.selected'); 5564 if ( current && current.data && current.data('attachment-id') != args.attachment_id ) { // jshint ignore:line 5565 comments.fadeOut('fast'); 5566 comments.empty(); 5567 return; 5568 } 5569 5570 // Increase the height of the background, semi-transparent overlay to match the new length of the comments list. 5571 $('.jp-carousel-overlay').height( $(window).height() + titleAndDescription.height() + commentForm.height() + ( (comments.height() > 0) ? comments.height() : imageMeta.height() ) + 200 ); 5572 5573 comments.show(); 5574 commentsLoading.hide(); 5575 }, 5576 error: function(xhr, status, error) { 5577 // TODO: proper error handling 5578 console.log( 'Comment get fail...', xhr, status, error ); 5579 comments.fadeIn('fast'); 5580 commentsLoading.fadeOut('fast'); 5581 } 5582 }); 5583 }, 5584 5585 postCommentError: function(args) { 5586 if ( 'object' !== typeof args ) { 5587 args = {}; 5588 } 5589 if ( ! args.field || 'undefined' === typeof args.field || ! args.error || 'undefined' === typeof args.error ) { 5590 return; 5591 }
5592 $('#jp-carousel-comment-post-results').slideUp('fast').html('<span class="jp-carousel-comment-post-error">'+args.error+'</span>').slideDown('fast'); 5593 $('#jp-carousel-comment-form-spinner').spin(false); 5594 }, 5595 5596 setCommentIframeSrc: function(attachment_id) { 5597 var iframe = $('#jp-carousel-comment-iframe'); 5598 // Set the proper irame src for the current attachment id 5599 if (iframe && iframe.length) { 5600 iframe.attr('src', iframe.attr('src').replace(/(postid=)\d+/, '$1'+attachment_id) ); 5601 iframe.attr('src', iframe.attr('src').replace(/(%23.+)?$/, '%23jp-carousel-'+attachment_id) ); 5602 } 5603 }, 5604 5605 clearCommentTextAreaValue: function() { 5606 var commentTextArea = $('#jp-carousel-comment-form-comment-field'); 5607 if ( commentTextArea ) { 5608 commentTextArea.val(''); 5609 } 5610 }, 5611 5612 nextSlide : function () { 5613 var slides = this.jp_carousel( 'slides' ); 5614 var selected = this.jp_carousel( 'selectedSlide' ); 5615 5616 if ( selected.length === 0 || ( slides.length > 2 && selected.is( slides.last() ) ) ) { 5617 return slides.first(); 5618 } 5619 5620 return selected.next(); 5621 }, 5622 5623 prevSlide : function () { 5624 var slides = this.jp_carousel( 'slides' ); 5625 var selected = this.jp_carousel( 'selectedSlide' ); 5626 5627 if ( selected.length === 0 || ( slides.length > 2 && selected.is( slides.first() ) ) ) { 5628 return slides.last(); 5629 } 5630 5631 return selected.prev(); 5632 }, 5633 5634 loadFullImage : function ( slide ) { 5635 var image = slide.find( 'img:first' ); 5636 5637 if ( ! image.data( 'loaded' ) ) { 5638 // If the width of the slide is smaller than the width of the "thumbnail" we're already using, 5639 // don't load the full image. 5640 5641 image.on( 'load.jetpack', function () { 5642 image.off( 'load.jetpack' ); 5643 $( this ).closest( '.jp-carousel-slide' ).css( 'background-image', '' ); 5644 } ); 5645 5646 if ( ! slide.data( 'preview-image' ) || ( slide.data( 'thumb-size' ) && slide.width() > slide.data( 'thumb-size' ).width ) ) { 5647 image.attr( 'src', image.closest( '.jp-carousel-slide' ).data( 'src' ) ); 5648 } else { 5649 image.attr( 'src', slide.data( 'preview-image' ) ); 5650 } 5651 5652 image.data( 'loaded', 1 ); 5653 } 5654 } 5655 }; 5656 5657 $.fn.jp_carousel = function(method){ 5658 // ask for the HTML of the gallery 5659 // Method calling logic 5660 if ( methods[method] ) { 5661 return methods[ method ].apply( this, Array.prototype.slice.call( arguments, 1 )); 5662 } else if ( typeof method === 'object' || ! method ) { 5663 return methods.open.apply( this, arguments ); 5664 } else { 5665 $.error( 'Method ' + method + ' does not exist on jQuery.jp_carousel' ); 5666 } 5667 5668 }; 5669 5670 // register the event listener for starting the gallery 5671 $( document.body ).on( 'click', 'div.gallery,div.tiled-gallery', function(e) { 5672 if ( ! $(this).jp_carousel( 'testForData', e.currentTarget ) ) { 5673 return; 5674 } 5675 if ( $(e.target).parent().hasClass('gallery-caption') ) { 5676 return; 5677 } 5678 e.preventDefault(); 5679 $(this).jp_carousel('open', {start_index: $(this).find('.gallery-item, .tiled-gallery-item').index($(e.target).parents('.gallery-item, .tiled-gallery-item'))}); 5680 }); 5681 5682 // Makes carousel work on page load and when back button leads to same URL with carousel hash (ie: no actual document.ready trigger) 5683 $( window ).on( 'hashchange', function () { 5684 var hashRegExp = /jp-carousel-(\d+)/, 5685 matches, attachmentId, galleries, selectedThumbnail; 5686 5687 if ( ! window.location.hash || ! hashRegExp.test( window.location.hash ) ) { 5688 return; 5689 } 5690 5691 if ( window.location.hash === last_known_location_hash ) { 5692 return; 5693 } 5694 5695 last_known_location_hash = window.location.hash; 5696 matches = window.location.hash.match( hashRegExp ); 5697 attachmentId = parseInt( matches[1], 10 ); 5698 galleries = $( 'div.gallery, div.tiled-gallery' ); 5699 5700 // Find the first thumbnail that matches the attachment ID in the location 5701 // hash, then open the gallery that contains it. 5702 galleries.each( function( _, galleryEl ) { 5703 $( galleryEl ).find('img').each( function( imageIndex, imageEl ) { 5704 if ( $( imageEl ).data( 'attachment-id' ) === parseInt( attachmentId, 10 ) ) { 5705 selectedThumbnail = { index: imageIndex, gallery: galleryEl }; 5706 return false; 5707 } 5708 }); 5709 5710 if ( selectedThumbnail ) { 5711 $( selectedThumbnail.gallery ) 5712 .jp_carousel( 'openOrSelectSlide', selectedThumbnail.index ); 5713 } 5714 }); 5715 }); 5716 5717 if ( window.location.hash ) { 5718 $( window ).trigger( 'hashchange' ); 5719 } 5720}); 5721 5722/** 5723 * jQuery Plugin to obtain touch gestures from iPhone, iPod Touch and iPad, should also work with Android mobile phones (not tested yet!) 5724 * Common usage: wipe images (left and right to show the previous or next image) 5725 * 5726 * @author Andreas Waltl, netCU Internetagentur (http://www.netcu.de) 5727 * Version 1.1.1, modified to pass the touchmove event to the callbacks. 5728 */ 5729(function($) { 5730$.fn.touchwipe = function(settings) { 5731 var config = { 5732 min_move_x: 20, 5733 min_move_y: 20, 5734 wipeLeft: function(/*e*/) { }, 5735 wipeRight: function(/*e*/) { }, 5736 wipeUp: function(/*e*/) { }, 5737 wipeDown: function(/*e*/) { }, 5738 preventDefaultEvents: true 5739 }; 5740 5741 if (settings) { 5742 $.extend(config, settings); 5743 } 5744 5745 this.each(function() { 5746 var startX; 5747 var startY; 5748 var isMoving = false;
5749 5750 function cancelTouch() { 5751 this.removeEventListener('touchmove', onTouchMove); 5752 startX = null; 5753 isMoving = false; 5754 } 5755 5756 function onTouchMove(e) { 5757 if(config.preventDefaultEvents) { 5758 e.preventDefault(); 5759 } 5760 if(isMoving) { 5761 var x = e.touches[0].pageX; 5762 var y = e.touches[0].pageY; 5763 var dx = startX - x; 5764 var dy = startY - y; 5765 if(Math.abs(dx) >= config.min_move_x) { 5766 cancelTouch(); 5767 if(dx > 0) { 5768 config.wipeLeft(e); 5769 } else { 5770 config.wipeRight(e); 5771 } 5772 } 5773 else if(Math.abs(dy) >= config.min_move_y) { 5774 cancelTouch(); 5775 if(dy > 0) { 5776 config.wipeDown(e); 5777 } else { 5778 config.wipeUp(e); 5779 } 5780 } 5781 } 5782 } 5783 5784 function onTouchStart(e) 5785 { 5786 if (e.touches.length === 1) { 5787 startX = e.touches[0].pageX; 5788 startY = e.touches[0].pageY; 5789 isMoving = true; 5790 this.addEventListener('touchmove', onTouchMove, false); 5791 } 5792 } 5793 if ('ontouchstart' in document.documentElement) { 5794 this.addEventListener('touchstart', onTouchStart, false); 5795 } 5796 }); 5797 5798 return this; 5799}; 5800})(jQuery); 5801;
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.