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 clientHintSupport: { 303 gravatar: false, 304 files: false, 305 photon: false, 306 mshots: false, 307 staticAssets: false, 308 latex: false, 309 imgpress: false, 310 }, 311 useHints: false, 312 zoomed: false, 313 timer: null, 314 interval: 1000, // zoom polling interval in millisecond 315 316 // Should we apply width/height attributes to control the image size? 317 imgNeedsSizeAtts: function( img ) {
318 // Do not overwrite existing width/height attributes. 319 if ( img.getAttribute('width') !== null || img.getAttribute('height') !== null ) 320 return false; 321 // Do not apply the attributes if the image is already constrained by a parent element. 322 if ( img.width < img.naturalWidth || img.height < img.naturalHeight ) 323 return false; 324 return true; 325 }, 326 327 hintsFor: function( service ) { 328 if ( this.useHints === false ) { 329 return false; 330 } 331 if ( this.hints() === false ) { 332 return false; 333 } 334 if ( typeof this.clientHintSupport[service] === "undefined" ) { 335 return false; 336 } 337 if ( this.clientHintSupport[service] === true ) { 338 return true; 339 } 340 return false; 341 }, 342 343 hints: function() { 344 try { 345 var chrome = window.navigator.userAgent.match(/\sChrome\/([0-9]+)\.[.0-9]+\s/) 346 if (chrome !== null) { 347 var version = parseInt(chrome[1], 10) 348 if (isNaN(version) === false && version >= 46) { 349 return true 350 } 351 } 352 } catch (e) { 353 return false 354 } 355 return false 356 }, 357 358 init: function() { 359 var t = this; 360 try{ 361 t.zoomImages(); 362 t.timer = setInterval( function() { t.zoomImages(); }, t.interval ); 363 } 364 catch(e){ 365 } 366 }, 367 368 stop: function() { 369 if ( this.timer ) 370 clearInterval( this.timer ); 371 }, 372 373 getScale: function() { 374 var scale = detectZoom.device(); 375 // Round up to 1.5 or the next integer below the cap. 376 if ( scale <= 1.0 ) scale = 1.0; 377 else if ( scale <= 1.5 ) scale = 1.5; 378 else if ( scale <= 2.0 ) scale = 2.0; 379 else if ( scale <= 3.0 ) scale = 3.0; 380 else if ( scale <= 4.0 ) scale = 4.0; 381 else scale = 5.0; 382 return scale; 383 }, 384 385 shouldZoom: function( scale ) { 386 var t = this; 387 // Do not operate on hidden frames. 388 if ( "innerWidth" in window && !window.innerWidth ) 389 return false; 390 // Don't do anything until scale > 1 391 if ( scale == 1.0 && t.zoomed == false ) 392 return false; 393 return true; 394 }, 395 396 zoomImages: function() { 397 var t = this; 398 var scale = t.getScale(); 399 if ( ! t.shouldZoom( scale ) ){ 400 return; 401 } 402 t.zoomed = true; 403 // Loop through all the <img> elements on the page. 404 var imgs = document.getElementsByTagName("img"); 405 406 for ( var i = 0; i < imgs.length; i++ ) { 407 // Wait for original images to load 408 if ( "complete" in imgs[i] && ! imgs[i].complete ) 409 continue; 410 411 // Skip images that have srcset attributes. 412 if ( imgs[i].hasAttribute('srcset') ) { 413 continue; 414 } 415 416 // Skip images that don't need processing. 417 var imgScale = imgs[i].getAttribute("scale"); 418 if ( imgScale == scale || imgScale == "0" ) 419 continue; 420 421 // Skip images that have already failed at this scale 422 var scaleFail = imgs[i].getAttribute("scale-fail"); 423 if ( scaleFail && scaleFail <= scale ) 424 continue; 425 426 // Skip images that have no dimensions yet. 427 if ( ! ( imgs[i].width && imgs[i].height ) ) 428 continue; 429 430 // Skip images from Lazy Load plugins 431 if ( ! imgScale && imgs[i].getAttribute("data-lazy-src") && (imgs[i].getAttribute("data-lazy-src") !== imgs[i].getAttribute("src"))) 432 continue; 433 434 if ( t.scaleImage( imgs[i], scale ) ) { 435 // Mark the img as having been processed at this scale. 436 imgs[i].setAttribute("scale", scale); 437 } 438 else { 439 // Set the flag to skip this image. 440 imgs[i].setAttribute("scale", "0"); 441 } 442 } 443 }, 444 445 scaleImage: function( img, scale ) { 446 var t = this; 447 var newSrc = img.src; 448 449 var isFiles = false; 450 var isLatex = false; 451 var isPhoton = false; 452 453 // Skip slideshow images 454 if ( img.parentNode.className.match(/slideshow-slide/) ) 455 return false; 456 457 // Scale gravatars that have ?s= or ?size= 458 if ( img.src.match( /^https?:\/\/([^\/]*\.)?gravatar\.com\/.+[?&](s|size)=/ ) ) { 459 if ( this.hintsFor( "gravatar" ) === true ) { 460 return false; 461 } 462 newSrc = img.src.replace( /([?&](s|size)=)(\d+)/, function( $0, $1, $2, $3 ) { 463 // Stash the original size 464 var originalAtt = "originals", 465 originalSize = img.getAttribute(originalAtt); 466 if ( originalSize === null ) { 467 originalSize = $3; 468 img.setAttribute(originalAtt, originalSize); 469 if ( t.imgNeedsSizeAtts( img ) ) { 470 // Fix width and height attributes to rendered dimensions. 471 img.width = img.width;
472 img.height = img.height; 473 } 474 } 475 // Get the width/height of the image in CSS pixels 476 var size = img.clientWidth; 477 // Convert CSS pixels to device pixels 478 var targetSize = Math.ceil(img.clientWidth * scale); 479 // Don't go smaller than the original size 480 targetSize = Math.max( targetSize, originalSize ); 481 // Don't go larger than the service supports 482 targetSize = Math.min( targetSize, 512 ); 483 return $1 + targetSize; 484 }); 485 } 486 487 // Scale mshots that have width 488 else if ( img.src.match(/^https?:\/\/([^\/]+\.)*(wordpress|wp)\.com\/mshots\/.+[?&]w=\d+/) ) { 489 if ( this.hintsFor( "mshots" ) === true ) { 490 return false; 491 } 492 newSrc = img.src.replace( /([?&]w=)(\d+)/, function($0, $1, $2) { 493 // Stash the original size 494 var originalAtt = 'originalw', originalSize = img.getAttribute(originalAtt); 495 if ( originalSize === null ) { 496 originalSize = $2; 497 img.setAttribute(originalAtt, originalSize); 498 if ( t.imgNeedsSizeAtts( img ) ) { 499 // Fix width and height attributes to rendered dimensions. 500 img.width = img.width; 501 img.height = img.height; 502 } 503 } 504 // Get the width of the image in CSS pixels 505 var size = img.clientWidth; 506 // Convert CSS pixels to device pixels 507 var targetSize = Math.ceil(size * scale); 508 // Don't go smaller than the original size 509 targetSize = Math.max( targetSize, originalSize ); 510 // Don't go bigger unless the current one is actually lacking 511 if ( scale > img.getAttribute("scale") && targetSize <= img.naturalWidth ) 512 targetSize = $2; 513 if ( $2 != targetSize ) 514 return $1 + targetSize; 515 return $0; 516 }); 517 518 // Update height attribute to match width 519 newSrc = newSrc.replace( /([?&]h=)(\d+)/, function($0, $1, $2) { 520 if ( newSrc == img.src ) { 521 return $0; 522 } 523 // Stash the original size 524 var originalAtt = 'originalh', originalSize = img.getAttribute(originalAtt); 525 if ( originalSize === null ) { 526 originalSize = $2; 527 img.setAttribute(originalAtt, originalSize); 528 } 529 // Get the height of the image in CSS pixels 530 var size = img.clientHeight; 531 // Convert CSS pixels to device pixels 532 var targetSize = Math.ceil(size * scale); 533 // Don't go smaller than the original size 534 targetSize = Math.max( targetSize, originalSize ); 535 // Don't go bigger unless the current one is actually lacking 536 if ( scale > img.getAttribute("scale") && targetSize <= img.naturalHeight ) 537 targetSize = $2; 538 if ( $2 != targetSize ) 539 return $1 + targetSize; 540 return $0; 541 }); 542 } 543 544 // Scale simple imgpress queries (s0.wp.com) that only specify w/h/fit 545 else if ( img.src.match(/^https?:\/\/([^\/.]+\.)*(wp|wordpress)\.com\/imgpress\?(.+)/) ) { 546 if ( this.hintsFor( "imgpress" ) === true ) { 547 return false; 548 } 549 var imgpressSafeFunctions = ["zoom", "url", "h", "w", "fit", "filter", "brightness", "contrast", "colorize", "smooth", "unsharpmask"]; 550 // Search the query string for unsupported functions. 551 var qs = RegExp.$3.split('&'); 552 for ( var q in qs ) { 553 q = qs[q].split('=')[0]; 554 if ( imgpressSafeFunctions.indexOf(q) == -1 ) { 555 return false; 556 } 557 } 558 // Fix width and height attributes to rendered dimensions. 559 img.width = img.width; 560 img.height = img.height; 561 // Compute new src 562 if ( scale == 1 ) 563 newSrc = img.src.replace(/\?(zoom=[^&]+&)?/, '?'); 564 else 565 newSrc = img.src.replace(/\?(zoom=[^&]+&)?/, '?zoom=' + scale + '&'); 566 } 567 568 // Scale files.wordpress.com, LaTeX, or Photon images (i#.wp.com) 569 else if ( 570 ( isFiles = img.src.match(/^https?:\/\/([^\/]+)\.files\.wordpress\.com\/.+[?&][wh]=/) ) || 571 ( isLatex = img.src.match(/^https?:\/\/([^\/.]+\.)*(wp|wordpress)\.com\/latex\.php\?(latex|zoom)=(.+)/) ) || 572 ( isPhoton = img.src.match(/^https?:\/\/i[\d]{1}\.wp\.com\/(.+)/) ) 573 ) { 574 if ( false !== isFiles && this.hintsFor( "files" ) === true ) { 575 return false 576 } 577 if ( false !== isLatex && this.hintsFor( "latex" ) === true ) { 578 return false 579 } 580 if ( false !== isPhoton && this.hintsFor( "photon" ) === true ) { 581 return false 582 } 583 // Fix width and height attributes to rendered dimensions. 584 img.width = img.width;
585 img.height = img.height; 586 // Compute new src 587 if ( scale == 1 ) { 588 newSrc = img.src.replace(/\?(zoom=[^&]+&)?/, '?'); 589 } else { 590 newSrc = img.src; 591 592 var url_var = newSrc.match( /([?&]w=)(\d+)/ ); 593 if ( url_var !== null && url_var[2] ) { 594 newSrc = newSrc.replace( url_var[0], url_var[1] + img.width ); 595 } 596 597 url_var = newSrc.match( /([?&]h=)(\d+)/ ); 598 if ( url_var !== null && url_var[2] ) { 599 newSrc = newSrc.replace( url_var[0], url_var[1] + img.height ); 600 } 601 602 var zoom_arg = '&zoom=2'; 603 if ( !newSrc.match( /\?/ ) ) { 604 zoom_arg = '?zoom=2'; 605 } 606 img.setAttribute( 'srcset', newSrc + zoom_arg + ' ' + scale + 'x' ); 607 } 608 } 609 610 // Scale static assets that have a name matching *-1x.png or *@1x.png 611 else if ( img.src.match(/^https?:\/\/[^\/]+\/.*[-@]([12])x\.(gif|jpeg|jpg|png)(\?|$)/) ) { 612 if ( this.hintsFor( "staticAssets" ) === true ) { 613 return false; 614 } 615 // Fix width and height attributes to rendered dimensions. 616 img.width = img.width; 617 img.height = img.height; 618 var currentSize = RegExp.$1, newSize = currentSize; 619 if ( scale <= 1 ) 620 newSize = 1; 621 else 622 newSize = 2; 623 if ( currentSize != newSize ) 624 newSrc = img.src.replace(/([-@])[12]x\.(gif|jpeg|jpg|png)(\?|$)/, '$1'+newSize+'x.$2$3'); 625 } 626 627 else { 628 return false; 629 } 630 631 // Don't set img.src unless it has changed. This avoids unnecessary reloads. 632 if ( newSrc != img.src ) { 633 // Store the original img.src 634 var prevSrc, origSrc = img.getAttribute("src-orig"); 635 if ( !origSrc ) { 636 origSrc = img.src; 637 img.setAttribute("src-orig", origSrc); 638 } 639 // In case of error, revert img.src 640 prevSrc = img.src; 641 img.onerror = function(){ 642 img.src = prevSrc; 643 if ( img.getAttribute("scale-fail") < scale ) 644 img.setAttribute("scale-fail", scale); 645 img.onerror = null; 646 }; 647 // Finally load the new image 648 img.src = newSrc; 649 } 650 651 return true; 652 } 653}; 654 655wpcom_img_zoomer.init(); 656; 657/* global pm, wpcom_reblog */ 658 659var jetpackLikesWidgetQueue = []; 660var jetpackLikesWidgetBatch = []; 661var jetpackLikesMasterReady = false; 662 663function JetpackLikespostMessage( message, target ) { 664 if ( 'string' === typeof message ){ 665 try { 666 message = JSON.parse( message ); 667 } catch(e) { 668 return; 669 } 670 } 671 672 pm( { 673 target: target, 674 type: 'likesMessage', 675 data: message, 676 origin: '*' 677 } ); 678} 679 680function JetpackLikesBatchHandler() { 681 var requests = []; 682 jQuery( 'div.jetpack-likes-widget-unloaded' ).each( function() { 683 if ( jetpackLikesWidgetBatch.indexOf( this.id ) > -1 ) { 684 return; 685 } 686 jetpackLikesWidgetBatch.push( this.id ); 687 var regex = /like-(post|comment)-wrapper-(\d+)-(\d+)-(\w+)/, 688 match = regex.exec( this.id ), 689 info; 690 691 if ( ! match || match.length !== 5 ) { 692 return; 693 } 694 695 info = { 696 blog_id: match[2], 697 width: this.width 698 }; 699 700 if ( 'post' === match[1] ) { 701 info.post_id = match[3]; 702 } else if ( 'comment' === match[1] ) { 703 info.comment_id = match[3]; 704 } 705 706 info.obj_id = match[4]; 707 708 requests.push( info ); 709 }); 710 711 if ( requests.length > 0 ) { 712 JetpackLikespostMessage( { event: 'initialBatch', requests: requests }, window.frames['likes-master'] ); 713 } 714} 715 716function JetpackLikesMessageListener( event, message ) { 717 var allowedOrigin, $container, $list, offset, rowLength, height, scrollbarWidth; 718 719 if ( 'undefined' === typeof event.event ) { 720 return; 721 } 722 723 // We only allow messages from one origin 724 allowedOrigin = window.location.protocol + 'https://widgets.wp.com'; 725 if ( allowedOrigin !== message.origin ) { 726 return; 727 } 728 729 if ( 'masterReady' === event.event ) { 730 jQuery( document ).ready( function() { 731 jetpackLikesMasterReady = true; 732 733 var stylesData = { 734 event: 'injectStyles' 735 }, 736 $sdTextColor = jQuery( '.sd-text-color' ), 737 $sdLinkColor = jQuery( '.sd-link-color' ); 738 739 if ( jQuery( 'iframe.admin-bar-likes-widget' ).length > 0 ) { 740 JetpackLikespostMessage( { event: 'adminBarEnabled' }, window.frames[ 'likes-master' ] ); 741 742 stylesData.adminBarStyles = { 743 background: jQuery( '#wpadminbar .quicklinks li#wp-admin-bar-wpl-like > a' ).css( 'background' ),
744 isRtl: ( 'rtl' === jQuery( '#wpadminbar' ).css( 'direction' ) ) 745 }; 746 } 747 748 // enable reblogs if we're on a single post page 749 if ( jQuery( 'body' ).hasClass( 'single' ) ) { 750 JetpackLikespostMessage( { event: 'reblogsEnabled' }, window.frames[ 'likes-master' ] ); 751 } 752 753 if ( ! window.addEventListener ) { 754 jQuery( '#wp-admin-bar-admin-bar-likes-widget' ).hide(); 755 } 756 757 stylesData.textStyles = { 758 color: $sdTextColor.css( 'color' ), 759 fontFamily: $sdTextColor.css( 'font-family' ), 760 fontSize: $sdTextColor.css( 'font-size' ), 761 direction: $sdTextColor.css( 'direction' ), 762 fontWeight: $sdTextColor.css( 'font-weight' ), 763 fontStyle: $sdTextColor.css( 'font-style' ), 764 textDecoration: $sdTextColor.css('text-decoration') 765 }; 766 767 stylesData.linkStyles = { 768 color: $sdLinkColor.css('color'), 769 fontFamily: $sdLinkColor.css('font-family'), 770 fontSize: $sdLinkColor.css('font-size'), 771 textDecoration: $sdLinkColor.css('text-decoration'), 772 fontWeight: $sdLinkColor.css( 'font-weight' ), 773 fontStyle: $sdLinkColor.css( 'font-style' ) 774 }; 775 776 JetpackLikespostMessage( stylesData, window.frames[ 'likes-master' ] ); 777 778 JetpackLikesBatchHandler(); 779 780 jQuery( document ).on( 'inview', 'div.jetpack-likes-widget-unloaded', function() { 781 jetpackLikesWidgetQueue.push( this.id ); 782 }); 783 }); 784 } 785 786 if ( 'showLikeWidget' === event.event ) { 787 jQuery( '#' + event.id + ' .post-likes-widget-placeholder' ).fadeOut( 'fast', function() { 788 jQuery( '#' + event.id + ' .post-likes-widget' ).fadeIn( 'fast', function() { 789 JetpackLikespostMessage( { event: 'likeWidgetDisplayed', blog_id: event.blog_id, post_id: event.post_id, obj_id: event.obj_id }, window.frames['likes-master'] ); 790 }); 791 }); 792 } 793 794 if ( 'clickReblogFlair' === event.event ) { 795 wpcom_reblog.toggle_reblog_box_flair( event.obj_id ); 796 } 797 798 if ( 'showOtherGravatars' === event.event ) { 799 $container = jQuery( '#likes-other-gravatars' ); 800 $list = $container.find( 'ul' ); 801 802 $container.hide(); 803 $list.html( '' ); 804 805 $container.find( '.likes-text span' ).text( event.total ); 806 807 jQuery.each( event.likers, function( i, liker ) { 808 var element = jQuery( '<li><a><img /></a></li>' ); 809 element.addClass( liker.css_class ); 810 811 element.find( 'a' ). 812 attr({ 813 href: liker.profile_URL, 814 rel: 'nofollow', 815 target: '_parent' 816 }). 817 addClass( 'wpl-liker' ); 818 819 element.find( 'img' ). 820 attr({ 821 src: liker.avatar_URL, 822 alt: liker.name 823 }). 824 css({ 825 width: '30px', 826 height: '30px', 827 paddingRight: '3px' 828 }); 829 830 $list.append( element ); 831 } ); 832 833 offset = jQuery( '[name=\'' + event.parent + '\']' ).offset(); 834 835 $container.css( 'left', offset.left + event.position.left - 10 + 'px' ); 836 $container.css( 'top', offset.top + event.position.top - 33 + 'px' ); 837 838 rowLength = Math.floor( event.width / 37 ); 839 height = ( Math.ceil( event.likers.length / rowLength ) * 37 ) + 13; 840 if ( height > 204 ) { 841 height = 204; 842 } 843 844 $container.css( 'height', height + 'px' ); 845 $container.css( 'width', rowLength * 37 - 7 + 'px' ); 846 847 $list.css( 'width', rowLength * 37 + 'px' ); 848 849 $container.fadeIn( 'slow' ); 850 851 scrollbarWidth = $list[0].offsetWidth - $list[0].clientWidth; 852 if ( scrollbarWidth > 0 ) { 853 $container.width( $container.width() + scrollbarWidth ); 854 $list.width( $list.width() + scrollbarWidth ); 855 } 856 } 857} 858 859pm.bind( 'likesMessage', JetpackLikesMessageListener ); 860 861jQuery( document ).click( function( e ) { 862 var $container = jQuery( '#likes-other-gravatars' ); 863 864 if ( $container.has( e.target ).length === 0 ) { 865 $container.fadeOut( 'slow' ); 866 } 867}); 868 869function JetpackLikesWidgetQueueHandler() { 870 var $wrapper, wrapperID, found; 871 if ( ! jetpackLikesMasterReady ) { 872 setTimeout( JetpackLikesWidgetQueueHandler, 500 ); 873 return; 874 } 875 876 if ( jetpackLikesWidgetQueue.length > 0 ) { 877 // We may have a widget that needs creating now 878 found = false; 879 while( jetpackLikesWidgetQueue.length > 0 ) { 880 // Grab the first member of the queue that isn't already loading. 881 wrapperID = jetpackLikesWidgetQueue.splice( 0, 1 )[0]; 882 if ( jQuery( '#' + wrapperID ).hasClass( 'jetpack-likes-widget-unloaded' ) ) { 883 found = true; 884 break; 885 } 886 } 887 if ( ! found ) { 888 setTimeout( JetpackLikesWidgetQueueHandler, 500 ); 889 return; 890 } 891 } else if ( jQuery( 'div.jetpack-likes-widget-unloaded' ).length > 0 ) { 892 // Grab any unloaded widgets for a batch request 893 JetpackLikesBatchHandler(); 894 895 // Get the next unloaded widget 896 wrapperID = jQuery( 'div.jetpack-likes-widget-unloaded' ).first()[0].id; 897 if ( ! wrapperID ) { 898 // Everything is currently loaded 899 setTimeout( JetpackLikesWidgetQueueHandler, 500 ); 900 return; 901 } 902 } 903 904 if ( 'undefined' === typeof wrapperID ) { 905 setTimeout( JetpackLikesWidgetQueueHandler, 500 ); 906 return; 907 } 908 909 $wrapper = jQuery( '#' + wrapperID );
910 $wrapper.find( 'iframe' ).remove(); 911 912 if ( $wrapper.hasClass( 'slim-likes-widget' ) ) { 913 $wrapper.find( '.post-likes-widget-placeholder' ).after( '<iframe class="post-likes-widget jetpack-likes-widget" name="' + $wrapper.data( 'name' ) + '" height="22px" width="68px" frameBorder="0" scrolling="no" src="' + $wrapper.data( 'src' ) + '"></iframe>' ); 914 } else { 915 $wrapper.find( '.post-likes-widget-placeholder' ).after( '<iframe class="post-likes-widget jetpack-likes-widget" name="' + $wrapper.data( 'name' ) + '" height="55px" width="100%" frameBorder="0" src="' + $wrapper.data( 'src' ) + '"></iframe>' ); 916 } 917 918 $wrapper.removeClass( 'jetpack-likes-widget-unloaded' ).addClass( 'jetpack-likes-widget-loading' ); 919 920 $wrapper.find( 'iframe' ).load( function( e ) { 921 var $iframe = jQuery( e.target ); 922 $wrapper.removeClass( 'jetpack-likes-widget-loading' ).addClass( 'jetpack-likes-widget-loaded' ); 923 924 JetpackLikespostMessage( { event: 'loadLikeWidget', name: $iframe.attr( 'name' ), width: $iframe.width() }, window.frames[ 'likes-master' ] ); 925 926 if ( $wrapper.hasClass( 'slim-likes-widget' ) ) { 927 $wrapper.find( 'iframe' ).Jetpack( 'resizeable' ); 928 } 929 }); 930 setTimeout( JetpackLikesWidgetQueueHandler, 250 ); 931} 932JetpackLikesWidgetQueueHandler(); 933; 934// WARNING: This file is distributed verbatim in Jetpack. There should be nothing WordPress.com specific in this file. @hide-in-jetpack 935(function($){ // Open closure 936// Local vars 937var Scroller, ajaxurl, stats, type, text, totop; 938 939// IE requires special handling
940var isIE = ( -1 != navigator.userAgent.search( 'MSIE' ) ); 941if ( isIE ) { 942 var IEVersion = navigator.userAgent.match(/MSIE\s?(\d+)\.?\d*;/); 943 var IEVersion = parseInt( IEVersion[1] ); 944} 945 946// HTTP ajaxurl when site is HTTPS causes Access-Control-Allow-Origin failure in Desktop and iOS Safari 947if ( "https:" == document.location.protocol ) { 948 infiniteScroll.settings.ajaxurl = infiniteScroll.settings.ajaxurl.replace( "http://", "https://" ); 949} 950 951/** 952 * Loads new posts when users scroll near the bottom of the page. 953 */ 954Scroller = function( settings ) { 955 var self = this; 956 957 // Initialize our variables 958 this.id = settings.id; 959 this.body = $( document.body ); 960 this.window = $( window ); 961 this.element = $( '#' + settings.id ); 962 this.wrapperClass = settings.wrapper_class; 963 this.ready = true; 964 this.disabled = false; 965 this.page = 1; 966 this.offset = settings.offset; 967 this.currentday = settings.currentday; 968 this.order = settings.order; 969 this.throttle = false; 970 this.handle = '<div id="infinite-handle"><span><button>' + text.replace( '\\', '' ) + '</button></span></div>'; 971 this.click_handle = settings.click_handle; 972 this.google_analytics = settings.google_analytics; 973 this.history = settings.history; 974 this.origURL = window.location.href; 975 this.pageCache = {}; 976 977 // Footer settings 978 this.footer = $( '#infinite-footer' ); 979 this.footer.wrap = settings.footer; 980 981 // Core's native MediaElement.js implementation needs special handling 982 this.wpMediaelement = null; 983 984 // We have two type of infinite scroll 985 // cases 'scroll' and 'click' 986 987 if ( type == 'scroll' ) { 988 // Bind refresh to the scroll event 989 // Throttle to check for such case every 300ms 990 991 // On event the case becomes a fact 992 this.window.bind( 'scroll.infinity', function() { 993 this.throttle = true; 994 }); 995 996 // Go back top method 997 self.gotop(); 998 999 setInterval( function() { 1000 if ( this.throttle ) { 1001 // Once the case is the case, the action occurs and the fact is no more 1002 this.throttle = false; 1003 // Reveal or hide footer 1004 self.thefooter(); 1005 // Fire the refresh 1006 self.refresh(); 1007 self.determineURL(); // determine the url 1008 } 1009 }, 250 ); 1010 1011 // Ensure that enough posts are loaded to fill the initial viewport, to compensate for short posts and large displays. 1012 self.ensureFilledViewport(); 1013 this.body.bind( 'post-load', { self: self }, self.checkViewportOnLoad ); 1014 } else if ( type == 'click' ) { 1015 if ( this.click_handle ) { 1016 this.element.append( this.handle ); 1017 } 1018 1019 this.body.delegate( '#infinite-handle', 'click.infinity', function() { 1020 // Handle the handle 1021 if ( self.click_handle ) { 1022 $( '#infinite-handle' ).remove(); 1023 } 1024 1025 // Fire the refresh 1026 self.refresh(); 1027 }); 1028 } 1029 1030 // Initialize any Core audio or video players loaded via IS 1031 this.body.bind( 'post-load', { self: self }, self.initializeMejs ); 1032}; 1033 1034/** 1035 * Check whether we should fetch any additional posts. 1036 */ 1037Scroller.prototype.check = function() { 1038 var container = this.element.offset(); 1039 1040 // If the container can't be found, stop otherwise errors result 1041 if ( 'object' !== typeof container ) { 1042 return false; 1043 } 1044 1045 var bottom = this.window.scrollTop() + this.window.height(), 1046 threshold = container.top + this.element.outerHeight(false) - (this.window.height() * 2); 1047 1048 return bottom > threshold; 1049}; 1050 1051/** 1052 * Renders the results from a successful response. 1053 */ 1054Scroller.prototype.render = function( response ) { 1055 this.body.addClass( 'infinity-success' ); 1056 1057 // Check if we can wrap the html 1058 this.element.append( response.html ); 1059 this.body.trigger( 'post-load', response ); 1060 this.ready = true; 1061}; 1062 1063/** 1064 * Returns the object used to query for new posts. 1065 */ 1066Scroller.prototype.query = function() { 1067 return { 1068 page : this.page + this.offset, // Load the next page. 1069 currentday : this.currentday, 1070 order : this.order, 1071 scripts : window.infiniteScroll.settings.scripts, 1072 styles : window.infiniteScroll.settings.styles,
1073 query_args : window.infiniteScroll.settings.query_args, 1074 query_before : window.infiniteScroll.settings.query_before, 1075 last_post_date: window.infiniteScroll.settings.last_post_date 1076 }; 1077}; 1078 1079/** 1080 * Scroll back to top. 1081 */ 1082Scroller.prototype.gotop = function() { 1083 var blog = $( '#infinity-blog-title' ); 1084 1085 blog.attr( 'title', totop ); 1086 1087 // Scroll to top on blog title 1088 blog.bind( 'click', function( e ) { 1089 $( 'html, body' ).animate( { scrollTop: 0 }, 'fast' ); 1090 e.preventDefault(); 1091 }); 1092}; 1093 1094 1095/** 1096 * The infinite footer. 1097 */ 1098Scroller.prototype.thefooter = function() { 1099 var self = this, 1100 width; 1101 1102 // Check if we have an id for the page wrapper 1103 if ( $.type( this.footer.wrap ) === "string" ) { 1104 width = $( 'body #' + this.footer.wrap ).outerWidth( false ); 1105 1106 // Make the footer match the width of the page 1107 if ( width > 479 ) 1108 this.footer.find( '.container' ).css( 'width', width ); 1109 } 1110 1111 // Reveal footer 1112 if ( this.window.scrollTop() >= 350 ) 1113 self.footer.animate( { 'bottom': 0 }, 'fast' ); 1114 else if ( this.window.scrollTop() < 350 ) 1115 self.footer.animate( { 'bottom': '-50px' }, 'fast' ); 1116}; 1117 1118 1119/** 1120 * Controls the flow of the refresh. Don't mess. 1121 */ 1122Scroller.prototype.refresh = function() { 1123 var self = this, 1124 query, jqxhr, load, loader, color, customized; 1125 1126 // If we're disabled, ready, or don't pass the check, bail. 1127 if ( this.disabled || ! this.ready || ! this.check() ) 1128 return; 1129 1130 // Let's get going -- set ready to false to prevent 1131 // multiple refreshes from occurring at once. 1132 this.ready = false; 1133 1134 // Create a loader element to show it's working. 1135 if ( this.click_handle ) { 1136 loader = '<span class="infinite-loader"></span>'; 1137 this.element.append( loader ); 1138 1139 loader = this.element.find( '.infinite-loader' ); 1140 color = loader.css( 'color' ); 1141 1142 try { 1143 loader.spin( 'medium-left', color ); 1144 } catch ( error ) { } 1145 } 1146 1147 // Generate our query vars. 1148 query = $.extend({ 1149 action: 'infinite_scroll' 1150 }, this.query() ); 1151 1152 // Inject Customizer state. 1153 if ( 'undefined' !== typeof wp && wp.customize && wp.customize.settings.theme ) { 1154 customized = {}; 1155 query.wp_customize = 'on'; 1156 query.theme = wp.customize.settings.theme.stylesheet; 1157 wp.customize.each( function( setting ) { 1158 if ( setting._dirty ) { 1159 customized[ setting.id ] = setting(); 1160 } 1161 } ); 1162 query.customized = JSON.stringify( customized ); 1163 query.nonce = wp.customize.settings.nonce.preview; 1164 } 1165 1166 // Fire the ajax request. 1167 jqxhr = $.post( infiniteScroll.settings.ajaxurl, query ); 1168 1169 // Allow refreshes to occur again if an error is triggered. 1170 jqxhr.fail( function() { 1171 if ( self.click_handle ) { 1172 loader.hide(); 1173 } 1174 1175 self.ready = true; 1176 }); 1177 1178 // Success handler 1179 jqxhr.done( function( response ) { 1180 // On success, let's hide the loader circle. 1181 if ( self.click_handle ) { 1182 loader.hide(); 1183 } 1184 1185 // Check for and parse our response. 1186 if ( ! response || ! response.type ) { 1187 return; 1188 } 1189 1190 // If we've succeeded... 1191 if ( response.type == 'success' ) { 1192 // If additional scripts are required by the incoming set of posts, parse them 1193 if ( response.scripts ) { 1194 $( response.scripts ).each( function() { 1195 var elementToAppendTo = this.footer ? 'body' : 'head'; 1196 1197 // Add script handle to list of those already parsed 1198 window.infiniteScroll.settings.scripts.push( this.handle ); 1199 1200 // Output extra data, if present 1201 if ( this.extra_data ) { 1202 var data = document.createElement('script'), 1203 dataContent = document.createTextNode( "//<![CDATA[ \n" + this.extra_data + "\n//]]>" ); 1204 1205 data.type = 'text/javascript'; 1206 data.appendChild( dataContent ); 1207 1208 document.getElementsByTagName( elementToAppendTo )[0].appendChild(data); 1209 } 1210 1211 // Build script tag and append to DOM in requested location 1212 var script = document.createElement('script'); 1213 script.type = 'text/javascript'; 1214 script.src = this.src; 1215 script.id = this.handle; 1216 1217 // If MediaElement.js is loaded in by this set of posts, don't initialize the players a second time as it breaks them all 1218 if ( 'wp-mediaelement' === this.handle ) { 1219 self.body.unbind( 'post-load', self.initializeMejs ); 1220 } 1221 1222 if ( 'wp-mediaelement' === this.handle && 'undefined' === typeof mejs ) { 1223 self.wpMediaelement = {}; 1224 self.wpMediaelement.tag = script; 1225 self.wpMediaelement.element = elementToAppendTo; 1226 setTimeout( self.maybeLoadMejs.bind( self ), 250 ); 1227 } else { 1228 document.getElementsByTagName( elementToAppendTo )[0].appendChild(script); 1229 } 1230 } ); 1231 } 1232 1233 // If additional stylesheets are required by the incoming set of posts, parse them 1234 if ( response.styles ) { 1235 $( response.styles ).each( function() { 1236 // Add stylesheet handle to list of those already parsed
1237 window.infiniteScroll.settings.styles.push( this.handle ); 1238 1239 // Build link tag 1240 var style = document.createElement('link'); 1241 style.rel = 'stylesheet'; 1242 style.href = this.src; 1243 style.id = this.handle + '-css'; 1244 1245 // Destroy link tag if a conditional statement is present and either the browser isn't IE, or the conditional doesn't evaluate true 1246 if ( this.conditional && ( ! isIE || ! eval( this.conditional.replace( /%ver/g, IEVersion ) ) ) ) 1247 var style = false; 1248 1249 // Append link tag if necessary 1250 if ( style ) 1251 document.getElementsByTagName('head')[0].appendChild(style); 1252 } ); 1253 } 1254 1255 // stash the response in the page cache 1256 self.pageCache[self.page+self.offset] = response; 1257 1258 // Increment the page number 1259 self.page++; 1260 1261 // Record pageview in WP Stats, if available. 1262 if ( stats ) 1263 new Image().src = document.location.protocol + 'https://pixel.wp.com/g.gif?' + stats + '&post=0&baba=' + Math.random(); 1264 1265 // Add new posts to the postflair object 1266 if ( 'object' == typeof response.postflair && 'object' == typeof WPCOM_sharing_counts ) 1267 WPCOM_sharing_counts = $.extend( WPCOM_sharing_counts, response.postflair ); 1268 1269 // Render the results 1270 self.render.apply( self, arguments ); 1271 1272 // If 'click' type and there are still posts to fetch, add back the handle 1273 if ( type == 'click' ) { 1274 if ( response.lastbatch ) { 1275 if ( self.click_handle ) { 1276 $( '#infinite-handle' ).remove(); 1277 // Update body classes 1278 self.body.addClass( 'infinity-end' ).removeClass( 'infinity-success' ); 1279 } else { 1280 self.body.trigger( 'infinite-scroll-posts-end' ); 1281 } 1282 } else { 1283 if ( self.click_handle ) { 1284 self.element.append( self.handle ); 1285 } else { 1286 self.body.trigger( 'infinite-scroll-posts-more' ); 1287 } 1288 } 1289 } else if ( response.lastbatch ) { 1290 self.disabled = true; 1291 self.body.addClass( 'infinity-end' ).removeClass( 'infinity-success' ); 1292 } 1293 1294 // Update currentday to the latest value returned from the server 1295 if ( response.currentday ) { 1296 self.currentday = response.currentday; 1297 } 1298 1299 // Fire Google Analytics pageview 1300 if ( self.google_analytics ) { 1301 var ga_url = self.history.path.replace( /%d/, self.page ); 1302 if ( 'object' === typeof _gaq ) { 1303 _gaq.push( [ '_trackPageview', ga_url ] ); 1304 } 1305 if ( 'function' === typeof ga ) { 1306 ga( 'send', 'pageview', ga_url ); 1307 } 1308 } 1309 } 1310 }); 1311 1312 return jqxhr; 1313}; 1314 1315/** 1316 * Core's native media player uses MediaElement.js 1317 * 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. 1318 */ 1319Scroller.prototype.maybeLoadMejs = function() { 1320 if ( null === this.wpMediaelement ) { 1321 return; 1322 } 1323 1324 if ( 'undefined' === typeof mejs ) { 1325 setTimeout( this.maybeLoadMejs, 250 ); 1326 } else { 1327 document.getElementsByTagName( this.wpMediaelement.element )[0].appendChild( this.wpMediaelement.tag ); 1328 this.wpMediaelement = null; 1329 1330 // Ensure any subsequent IS loads initialize the players 1331 this.body.bind( 'post-load', { self: this }, this.initializeMejs ); 1332 } 1333} 1334 1335/** 1336 * Initialize the MediaElement.js player for any posts not previously initialized 1337 */ 1338Scroller.prototype.initializeMejs = function( ev, response ) { 1339 // Are there media players in the incoming set of posts? 1340 if ( ! response.html || -1 === response.html.indexOf( 'wp-audio-shortcode' ) && -1 === response.html.indexOf( 'wp-video-shortcode' ) ) { 1341 return; 1342 } 1343 1344 // Don't bother if mejs isn't loaded for some reason 1345 if ( 'undefined' === typeof mejs ) { 1346 return; 1347 } 1348 1349 // Adapted from wp-includes/js/mediaelement/wp-mediaelement.js 1350 // Modified to not initialize already-initialized players, as Mejs doesn't handle that well 1351 $(function () { 1352 var settings = {}; 1353 1354 if ( typeof _wpmejsSettings !== 'undefined' ) { 1355 settings.pluginPath = _wpmejsSettings.pluginPath; 1356 } 1357 1358 settings.success = function (mejs) { 1359 var autoplay = mejs.attributes.autoplay && 'false' !== mejs.attributes.autoplay; 1360 if ( 'flash' === mejs.pluginType && autoplay ) { 1361 mejs.addEventListener( 'canplay', function () { 1362 mejs.play(); 1363 }, false ); 1364 } 1365 }; 1366 1367 $('.wp-audio-shortcode, .wp-video-shortcode').not( '.mejs-container' ).mediaelementplayer( settings ); 1368 }); 1369} 1370 1371/** 1372 * Trigger IS to load additional posts if the initial posts don't fill the window. 1373 * 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. 1374 */ 1375Scroller.prototype.ensureFilledViewport = function() { 1376 var self = this, 1377 windowHeight = self.window.height(), 1378 postsHeight = self.element.height(), 1379 aveSetHeight = 0, 1380 wrapperQty = 0; 1381 1382 // Account for situations where postsHeight is 0 because child list elements are floated 1383 if ( postsHeight === 0 ) { 1384 $( self.element.selector + ' > li' ).each( function() { 1385 postsHeight += $( this ).height(); 1386 } ); 1387 1388 if ( postsHeight === 0 ) { 1389 self.body.unbind( 'post-load', self.checkViewportOnLoad ); 1390 return; 1391 } 1392 } 1393 1394 // Calculate average height of a set of posts to prevent more posts than needed from being loaded. 1395 $( '.' + self.wrapperClass ).each( function() { 1396 aveSetHeight += $( this ).height(); 1397 wrapperQty++; 1398 } ); 1399 1400 if ( wrapperQty > 0 ) 1401 aveSetHeight = aveSetHeight / wrapperQty; 1402 else 1403 aveSetHeight = 0; 1404 1405 // Load more posts if space permits, otherwise stop checking for a full viewport 1406 if ( postsHeight < windowHeight && ( postsHeight + aveSetHeight < windowHeight ) ) { 1407 self.ready = true; 1408 self.refresh(); 1409 } 1410 else { 1411 self.body.unbind( 'post-load', self.checkViewportOnLoad ); 1412 } 1413} 1414 1415/** 1416 * Event handler for ensureFilledViewport(), tied to the post-load trigger. 1417 * 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. 1418 */ 1419Scroller.prototype.checkViewportOnLoad = function( ev ) { 1420 ev.data.self.ensureFilledViewport(); 1421} 1422 1423function fullscreenState() { 1424 return document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement || document.msFullscreenElement 1425 ? 1 1426 : 0; 1427} 1428 1429var previousFullScrenState = fullscreenState(); 1430 1431/** 1432 * Identify archive page that corresponds to majority of posts shown in the current browser window. 1433 */ 1434Scroller.prototype.determineURL = function () { 1435 var self = this, 1436 windowTop = $( window ).scrollTop(), 1437 windowBottom = windowTop + $( window ).height(), 1438 windowSize = windowBottom - windowTop, 1439 setsInView = [], 1440 setsHidden = [], 1441 pageNum = false, 1442 currentFullScreenState = fullscreenState(); 1443 1444 // xor - check if the state has changed 1445 if ( previousFullScrenState ^ currentFullScreenState ) { 1446 // If we just switched to/from fullscreen, 1447 // don't do the div clearing/caching or the
1448 // URL setting. Doing so can break video playback 1449 // if the video goes to fullscreen. 1450 1451 previousFullScrenState = currentFullScreenState; 1452 return; 1453 } 1454 previousFullScrenState = currentFullScreenState; 1455 1456 // Find out which sets are in view 1457 $( '.' + self.wrapperClass ).each( function() { 1458 var id = $( this ).attr( 'id' ), 1459 setTop = $( this ).offset().top, 1460 setHeight = $( this ).outerHeight( false ), 1461 setBottom = 0, 1462 setPageNum = $( this ).data( 'page-num' ); 1463 1464 // Account for containers that have no height because their children are floated elements. 1465 if ( 0 === setHeight ) { 1466 $( '> *', this ).each( function() { 1467 setHeight += $( this ).outerHeight( false ); 1468 } ); 1469 } 1470 1471 // Determine position of bottom of set by adding its height to the scroll position of its top. 1472 setBottom = setTop + setHeight; 1473 1474 // Populate setsInView object. While this logic could all be combined into a single conditional statement, this is easier to understand. 1475 if ( setTop < windowTop && setBottom > windowBottom ) { // top of set is above window, bottom is below 1476 setsInView.push({'id': id, 'top': setTop, 'bottom': setBottom, 'pageNum': setPageNum }); 1477 } 1478 else if( setTop > windowTop && setTop < windowBottom ) { // top of set is between top (gt) and bottom (lt) 1479 setsInView.push({'id': id, 'top': setTop, 'bottom': setBottom, 'pageNum': setPageNum }); 1480 } 1481 else if( setBottom > windowTop && setBottom < windowBottom ) { // bottom of set is between top (gt) and bottom (lt) 1482 setsInView.push({'id': id, 'top': setTop, 'bottom': setBottom, 'pageNum': setPageNum }); 1483 } else { 1484 setsHidden.push({'id': id, 'top': setTop, 'bottom': setBottom, 'pageNum': setPageNum }); 1485 } 1486 } ); 1487 1488 $.each(setsHidden, function() { 1489 var $set = $('#' + this.id); 1490 if( $set.hasClass( 'is--replaced' ) ) { 1491 return; 1492 } 1493 1494 self.pageCache[ this.pageNum].html = $set.html(); 1495 1496 $set.css('min-height', ( this.bottom - this.top ) + 'px' ) 1497 .addClass('is--replaced') 1498 .empty(); 1499 }); 1500 1501 $.each(setsInView, function() { 1502 var $set = $('#' + this.id); 1503 1504 if( $set.hasClass('is--replaced') ) { 1505 $set.css('min-height', '').removeClass('is--replaced'); 1506 if( this.pageNum in self.pageCache ) { 1507 $set.html( self.pageCache[this.pageNum].html ); 1508 self.body.trigger( 'post-load', self.pageCache[this.pageNum] ); 1509 } 1510 } 1511 1512 }); 1513 1514 // 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. 1515 if ( 0 == setsInView.length ) { 1516 pageNum = -1; 1517 } 1518 else if ( 1 == setsInView.length ) { 1519 var setData = setsInView.pop(); 1520 1521 // 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 1522 if ( ( ( windowBottom - setData.top ) / windowSize ) < 0.5 ) 1523 pageNum = -1; 1524 else 1525 pageNum = setData.pageNum; 1526 } 1527 else { 1528 var majorityPercentageInView = 0; 1529 1530 // Identify the IS set that comprises the majority of the current window and set the URL to it. 1531 $.each( setsInView, function( i, setData ) { 1532 var topInView = 0, 1533 bottomInView = 0, 1534 percentOfView = 0; 1535 1536 // Figure percentage of view the current set represents 1537 if ( setData.top > windowTop && setData.top < windowBottom ) 1538 topInView = ( windowBottom - setData.top ) / windowSize; 1539 1540 if ( setData.bottom > windowTop && setData.bottom < windowBottom ) 1541 bottomInView = ( setData.bottom - windowTop ) / windowSize; 1542 1543 // Figure out largest percentage of view for current set 1544 if ( topInView >= bottomInView ) 1545 percentOfView = topInView; 1546 else if ( bottomInView >= topInView ) 1547 percentOfView = bottomInView; 1548 1549 // Does current set's percentage of view supplant the largest previously-found set? 1550 if ( percentOfView > majorityPercentageInView ) { 1551 pageNum = setData.pageNum; 1552 majorityPercentageInView = percentOfView; 1553 } 1554 } ); 1555 } 1556 1557 // If a page number could be determined, update the URL 1558 // -1 indicates that the original requested URL should be used. 1559 if ( 'number' == typeof pageNum ) { 1560 self.updateURL( pageNum ); 1561 } 1562} 1563 1564/** 1565 * Update address bar to reflect archive page URL for a given page number. 1566 * Checks if URL is different to prevent pollution of browser history. 1567 */ 1568Scroller.prototype.updateURL = function( page ) { 1569 // IE only supports pushState() in v10 and above, so don't bother if those conditions aren't met. 1570 if ( ! window.history.pushState ) { 1571 return; 1572 } 1573 var self = this, 1574 pageSlug = -1 == page ? self.origURL : window.location.protocol + '//' + self.history.host + self.history.path.replace( /%d/, page ) + self.history.parameters; 1575 1576 if ( window.location.href != pageSlug ) { 1577 history.pushState( null, null, pageSlug ); 1578 } 1579} 1580 1581/** 1582 * Pause scrolling. 1583 */ 1584Scroller.prototype.pause = function() { 1585 this.disabled = true; 1586}; 1587 1588/** 1589 * Resume scrolling. 1590 */ 1591Scroller.prototype.resume = function() { 1592 this.disabled = false;
1593}; 1594 1595/** 1596 * Ready, set, go! 1597 */ 1598$( document ).ready( function() { 1599 // Check for our variables 1600 if ( 'object' != typeof infiniteScroll ) 1601 return; 1602 1603 $( document.body ).addClass( infiniteScroll.settings.body_class ); 1604 1605 // Set ajaxurl (for brevity) 1606 ajaxurl = infiniteScroll.settings.ajaxurl; 1607 1608 // Set stats, used for tracking stats 1609 stats = infiniteScroll.settings.stats; 1610 1611 // Define what type of infinity we have, grab text for click-handle 1612 type = infiniteScroll.settings.type; 1613 text = infiniteScroll.settings.text; 1614 totop = infiniteScroll.settings.totop; 1615 1616 // Initialize the scroller (with the ID of the element from the theme) 1617 infiniteScroll.scroller = new Scroller( infiniteScroll.settings ); 1618 1619 /** 1620 * Monitor user scroll activity to update URL to correspond to archive page for current set of IS posts 1621 */ 1622 if( type == 'click' ) { 1623 var timer = null; 1624 $( window ).bind( 'scroll', function() { 1625 // run the real scroll handler once every 250 ms. 1626 if ( timer ) { return; } 1627 timer = setTimeout( function() { 1628 infiniteScroll.scroller.determineURL(); 1629 timer = null; 1630 } , 250 ); 1631 }); 1632 } 1633 1634 // Integrate with Selective Refresh in the Customizer. 1635 if ( 'undefined' !== typeof wp && wp.customize && wp.customize.selectiveRefresh ) { 1636 1637 /** 1638 * Handle rendering of selective refresh partials. 1639 * 1640 * Make sure that when a partial is rendered, the Jetpack post-load event 1641 * will be triggered so that any dynamic elements will be re-constructed, 1642 * such as ME.js elements, Photon replacements, social sharing, and more. 1643 * Note that this is applying here not strictly to posts being loaded. 1644 * If a widget contains a ME.js element and it is previewed via selective 1645 * refresh, the post-load would get triggered allowing any dynamic elements 1646 * therein to also be re-constructed. 1647 * 1648 * @param {wp.customize.selectiveRefresh.Placement} placement 1649 */ 1650 wp.customize.selectiveRefresh.bind( 'partial-content-rendered', function( placement ) { 1651 var content; 1652 if ( 'string' === typeof placement.addedContent ) { 1653 content = placement.addedContent; 1654 } else if ( placement.container ) { 1655 content = $( placement.container ).html(); 1656 } 1657 1658 if ( content ) { 1659 $( document.body ).trigger( 'post-load', { html: content } ); 1660 } 1661 } ); 1662 1663 /* 1664 * Add partials for posts added via infinite scroll. 1665 * 1666 * This is unnecessary when MutationObserver is supported by the browser 1667 * since then this will be handled by Selective Refresh in core. 1668 */ 1669 if ( 'undefined' === typeof MutationObserver ) { 1670 $( document.body ).on( 'post-load', function( e, response ) { 1671 var rootElement = null; 1672 if ( response.html && -1 !== response.html.indexOf( 'data-customize-partial' ) ) { 1673 if ( infiniteScroll.settings.id ) { 1674 rootElement = $( '#' + infiniteScroll.settings.id ); 1675 } 1676 wp.customize.selectiveRefresh.addPartials( rootElement ); 1677 } 1678 } ); 1679 } 1680 } 1681}); 1682 1683 1684})(jQuery); // Close closure 1685; 1686/* jshint ignore:start */ 1687!function(d,s,id){ 1688 var js,fjs=d.getElementsByTagName(s)[0],p=/^http:/.test(d.location)?'http':'https'; 1689 if(!d.getElementById(id)){ 1690 js=d.createElement(s); 1691 js.id=id;js.src=p+"://platform.twitter.com/widgets.js"; 1692 fjs.parentNode.insertBefore(js,fjs); 1693 } 1694}(document,"script","twitter-wjs"); 1695/* jshint ignore:end */ 1696; 1697/*** 1698 * Warning: This file is remotely enqueued in Jetpack's Masterbar module. 1699 * Changing it will also affect Jetpack sites. 1700 */ 1701jQuery( document ).ready( function( $, wpcom ) { 1702 var masterbar, 1703 menupops = $( 'li#wp-admin-bar-blog.menupop, li#wp-admin-bar-newdash.menupop, li#wp-admin-bar-my-account.menupop' ), 1704 newmenu = $( '#wp-admin-bar-new-post-types' ); 1705 1706 // Unbind hoverIntent, we want clickable menus. 1707 menupops 1708 .unbind( 'mouseenter mouseleave' ) 1709 .removeProp( 'hoverIntent_t' ) 1710 .removeProp( 'hoverIntent_s' ) 1711 .on( 'mouseover', function(e) { 1712 var li = $(e.target).closest( 'li.menupop' ); 1713 menupops.not(li).removeClass( 'ab-hover' ); 1714 li.toggleClass( 'ab-hover' ); 1715 } ) 1716 .on( 'click touchstart', function(e) { 1717 var $target = $( e.target ); 1718 1719 if ( masterbar.focusSubMenus( $target ) ) { 1720 return; 1721 } 1722 1723 e.preventDefault(); 1724 masterbar.toggleMenu( $target ); 1725 } ); 1726 1727 masterbar = { 1728 focusSubMenus: function( $target ) { 1729 // Handle selection of menu items 1730 if ( ! $target.closest( 'ul' ).hasClass( 'ab-top-menu' ) ) { 1731 $target 1732 .closest( 'li' ); 1733 1734 return true; 1735 } 1736 1737 return false;
1738 }, 1739 1740 toggleMenu: function( $target ) { 1741 var $li = $target.closest( 'li.menupop' ), 1742 $html = $( 'html' ); 1743 1744 $( 'body' ).off( 'click.ab-menu' ); 1745 $( '#wpadminbar li.menupop' ).not($li).removeClass( 'ab-active wpnt-stayopen wpnt-show' ); 1746 1747 if ( $li.hasClass( 'ab-active' ) ) { 1748 $li.removeClass( 'ab-active' ); 1749 $html.removeClass( 'ab-menu-open' ); 1750 } else { 1751 $li.addClass( 'ab-active' ); 1752 $html.addClass( 'ab-menu-open' ); 1753 1754 $( 'body' ).on( 'click.ab-menu', function( e ) { 1755 if ( ! $( e.target ).parents( '#wpadminbar' ).length ) { 1756 e.preventDefault(); 1757 masterbar.toggleMenu( $li ); 1758 $( 'body' ).off( 'click.ab-menu' ); 1759 } 1760 } ); 1761 } 1762 } 1763 }; 1764} );; 1765/*globals JSON */ 1766( function( $ ) { 1767 var eventName = 'wpcom_masterbar_click'; 1768 1769 var linksTracksEvents = { 1770 //top level items 1771 'wp-admin-bar-blog' : 'my_sites', 1772 'wp-admin-bar-newdash' : 'reader', 1773 'wp-admin-bar-ab-new-post' : 'write_button', 1774 'wp-admin-bar-my-account' : 'my_account', 1775 'wp-admin-bar-notes' : 'notifications', 1776 //my sites - top items 1777 'wp-admin-bar-switch-site' : 'my_sites_switch_site', 1778 'wp-admin-bar-blog-info' : 'my_sites_site_info', 1779 'wp-admin-bar-site-view' : 'my_sites_view_site', 1780 'wp-admin-bar-blog-stats' : 'my_sites_site_stats', 1781 'wp-admin-bar-plan' : 'my_sites_plan', 1782 'wp-admin-bar-plan-badge' : 'my_sites_plan_badge', 1783 //my sites - manage 1784 'wp-admin-bar-edit-page' : 'my_sites_manage_site_pages', 1785 'wp-admin-bar-new-page-badge' : 'my_sites_manage_add_page', 1786 'wp-admin-bar-edit-post' : 'my_sites_manage_blog_posts', 1787 'wp-admin-bar-new-post-badge' : 'my_sites_manage_add_post', 1788 'wp-admin-bar-edit-attachment' : 'my_sites_manage_media', 1789 'wp-admin-bar-new-attachment-badge' : 'my_sites_manage_add_media', 1790 'wp-admin-bar-comments' : 'my_sites_manage_comments', 1791 'wp-admin-bar-edit-jetpack-testimonial' : 'my_sites_manage_testimonials', 1792 'wp-admin-bar-new-jetpack-testimonial' : 'my_sites_manage_add_testimonial', 1793 'wp-admin-bar-edit-jetpack-portfolio' : 'my_sites_manage_portfolio', 1794 'wp-admin-bar-new-jetpack-portfolio' : 'my_sites_manage_add_portfolio', 1795 //my sites - personalize 1796 'wp-admin-bar-themes' : 'my_sites_personalize_themes', 1797 'wp-admin-bar-cmz' : 'my_sites_personalize_themes_customize', 1798 //my sites - configure 1799 'wp-admin-bar-sharing' : 'my_sites_configure_sharing', 1800 'wp-admin-bar-people' : 'my_sites_configure_people', 1801 'wp-admin-bar-people-add' : 'my_sites_configure_people_add_button', 1802 'wp-admin-bar-plugins' : 'my_sites_configure_plugins', 1803 'wp-admin-bar-domains' : 'my_sites_configure_domains', 1804 'wp-admin-bar-domains-add' : 'my_sites_configure_add_domain', 1805 'wp-admin-bar-blog-settings' : 'my_sites_configure_settings', 1806 'wp-admin-bar-legacy-dashboard' : 'my_sites_configure_wp_admin', 1807 //reader 1808 'wp-admin-bar-followed-sites' : 'reader_followed_sites', 1809 'wp-admin-bar-reader-followed-sites-manage': 'reader_manage_followed_sites', 1810 'wp-admin-bar-discover-discover' : 'reader_discover', 1811 'wp-admin-bar-discover-search' : 'reader_search', 1812 'wp-admin-bar-my-activity-my-likes' : 'reader_my_likes', 1813 //account 1814 'wp-admin-bar-user-info' : 'my_account_user_name', 1815 // account - profile 1816 'wp-admin-bar-my-profile' : 'my_account_profile_my_profile', 1817 'wp-admin-bar-account-settings' : 'my_account_profile_account_settings', 1818 'wp-admin-bar-billing' : 'my_account_profile_manage_purchases', 1819 'wp-admin-bar-security' : 'my_account_profile_security', 1820 'wp-admin-bar-notifications' : 'my_account_profile_notifications', 1821 //account - special 1822 'wp-admin-bar-get-apps' : 'my_account_special_get_apps', 1823 'wp-admin-bar-next-steps' : 'my_account_special_next_steps', 1824 'wp-admin-bar-help' : 'my_account_special_help', 1825 }; 1826 1827 var notesTracksEvents = { 1828 openSite: function( data ) { 1829 return { 1830 clicked: 'masterbar_notifications_panel_site', 1831 site_id: data.siteId 1832 }; 1833 }, 1834 openPost: function( data ) { 1835 return { 1836 clicked: 'masterbar_notifications_panel_post', 1837 site_id: data.siteId, 1838 post_id: data.postId 1839 }; 1840 }, 1841 openComment: function( data ) { 1842 return { 1843 clicked: 'masterbar_notifications_panel_comment', 1844 site_id: data.siteId, 1845 post_id: data.postId, 1846 comment_id: data.commentId 1847 }; 1848 } 1849 }; 1850 1851 function recordTracksEvent( eventProps ) { 1852 eventProps = eventProps || {}; 1853 window._tkq = window._tkq || []; 1854 window._tkq.push( [ 'recordEvent', eventName, eventProps ] ); 1855 } 1856 1857 function parseJson( s, defaultValue ) { 1858 try { 1859 return JSON.parse( s ); 1860 } catch ( e ) { 1861 return defaultValue; 1862 } 1863 } 1864 1865 $( document ).ready( function() { 1866 var trackableLinks = '.mb-trackable .ab-item:not(div),' + 1867 '#wp-admin-bar-notes .ab-item,' + 1868 '#wp-admin-bar-user-info .ab-item,' + 1869 '.mb-trackable .ab-secondary'; 1870 1871 $( trackableLinks ).on( 'click touchstart', function( e ) { 1872 var $target = $( e.target ), 1873 $parent = $target.closest( 'li' ); 1874 1875 if ( ! $parent ) { 1876 return; 1877 } 1878 1879 var trackingId = $target.attr( 'ID' ) || $parent.attr( 'ID' ); 1880 1881 if ( ! linksTracksEvents.hasOwnProperty( trackingId ) ) { 1882 return; 1883 } 1884 1885 var eventProps = { 'clicked': linksTracksEvents[ trackingId ] }; 1886 1887 recordTracksEvent( eventProps ); 1888 } ); 1889 } ); 1890 1891 // listen for postMessage events from the notifications iframe 1892 $( window ).on( 'message', function( e ) { 1893 var event = ! e.data && e.originalEvent.data ? e.originalEvent : e; 1894 if ( event.origin !== 'https://widgets.wp.com' ) { 1895 return; 1896 } 1897 1898 var data = ( 'string' === typeof event.data ) ? parseJson( event.data, {} ) : event.data; 1899 if ( 'notesIframeMessage' !== data.type ) { 1900 return; 1901 } 1902 1903 var eventData = notesTracksEvents[ data.action ]; 1904 if ( ! eventData ) { 1905 return; 1906 } 1907 1908 recordTracksEvent( eventData( data ) ); 1909 } ); 1910 1911} )( jQuery ); 1912; 1913var wpcom = window.wpcom || {}; 1914wpcom.actionbar = {}; 1915wpcom.actionbar.data = actionbardata; 1916 1917// This might be better in another file, but is here for now 1918(function($){ 1919 var fbd = wpcom.actionbar.data, 1920 d = document, 1921 docHeight = $( d ).height(), 1922 b = d.getElementsByTagName( 'body' )[0], 1923 lastScrollTop = 0, 1924 lastScrollDir, fb, fhtml, fbhtml, fbHtmlLi, 1925 followingbtn, followbtn, fbdf, action, 1926 slkhtml = '', foldhtml = '', reporthtml = '', 1927 customizeIcon, editIcon, statsIcon, themeHtml = '', signupHtml = '', loginHtml = '', 1928 viewReaderHtml = '', editSubsHtml = '', editFollowsHtml = '', 1929 toggleactionbar, $actionbar; 1930 1931 // Don't show actionbar when iframed 1932 if ( window != window.top ) { 1933 return; 1934 } 1935 1936 fhtml = '<ul>'; 1937 1938 // Customize Icon 1939 customizeIcon = '<svg class="gridicon gridicon__customize" height="20px" width="20px" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><g><path d="M2 6c0-1.505.78-3.08 2-4 0 .845.69 2 2 2 1.657 0 3 1.343 3 3 0 .386-.08.752-.212 1.09.74.594 1.476 1.19 2.19 1.81L8.9 11.98c-.62-.716-1.214-1.454-1.807-2.192C6.753 9.92 6.387 10 6 10c-2.21 0-4-1.79-4-4zm12.152 6.848l1.34-1.34c.607.304 1.283.492 2.008.492 2.485 0 4.5-2.015 4.5-4.5 0-.725-.188-1.4-.493-2.007L18 9l-2-2 3.507-3.507C18.9 3.188 18.225 3 17.5 3 15.015 3 13 5.
1939015 13 7.5c0 .725.188 1.4.493 2.007L3 20l2 2 6.848-6.848c1.885 1.928 3.874 3.753 5.977 5.45l1.425 1.148 1.5-1.5-1.15-1.425c-1.695-2.103-3.52-4.092-5.448-5.977z" data-reactid=".2.1.1:0.1b.0"></path></g></svg>'; 1940 1941 if ( fbd.canCustomizeSite && fbd.isLoggedIn ) { 1942 fhtml += '<li class="actnbr-btn actnbr-customize"><a href="'+ fbd.customizeLink +'">' + customizeIcon + '<span>' + fbd.i18n.customize + '<span></a></li>'; 1943 } 1944 1945 // Edit Icon 1946 editIcon = '<svg class="gridicon gridicon__pencil" height="20px" width="20px" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><g><path d="M13 6l5 5-9.507 9.507c-.686-.686-.69-1.794-.012-2.485l-.002-.003c-.69.676-1.8.673-2.485-.013-.677-.677-.686-1.762-.036-2.455l-.008-.008c-.694.65-1.78.64-2.456-.036L13 6zm7.586-.414l-2.172-2.172c-.78-.78-2.047-.78-2.828 0L14 5l5 5 1.586-1.586c.78-.78.78-2.047 0-2.828zM3 18v3h3c0-1.657-1.343-3-3-3z"></path></g></svg>'; 1947 1948 if ( fbd.canEditPost ) { 1949 fhtml += '<li class="actnbr-btn actnbr-edit"><a href="'+ fbd.editLink +'">' + editIcon + '<span>' + fbd.i18n.edit + '</span></a></li>'; 1950 } 1951 1952 // Stats Icon 1953 statsIcon = '<svg class="gridicon gridicon__stats-alt" height="20px" width="20px" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><g><path d="M21,21H3v-2h18V21z M8,10H4v7h4V10z M14,3h-4v14h4V3z M20,6h-4v11h4V6z"/></path></g></svg>'; 1954 1955 if ( fbd.canEditPost ) { 1956 fhtml += '<li class="actnbr-btn actnbr-stats"><a href="'+ fbd.statsLink +'">' + statsIcon + '<span>' + fbd.i18n.stats + '</span></a></li>'; 1957 } 1958 1959 // Follow/Unfollow Icon 1960 followingbtn = '<svg class="gridicon gridicon__following" height="24px" width="24px" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><g><path d="M23 13.482L15.508 21 12 17.4l1.412-1.388 2.106 2.188 6.094-6.094L23 13.482zm-7.455 1.862L20 10.89V2H2v14c0 1.1.9 2 2 2h4.538l4.913-4.832 2.095 2.176zM8 13H4v-1h4v1zm3-2H4v-1h7v1zm0-2H4V8h7v1zm7-3H4V4h14v2z"/></g></svg>'; 1961 followbtn = '<svg class="gridicon gridicon__follow" height="24px" width="24px" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><g><path d="M23 16v2h-3v3h-2v-3h-3v-2h3v-3h2v3h3zM20 2v9h-4v3h-3v4H4c-1.1 0-2-.9-2-2V2h18zM8 13v-1H4v1h4zm3-3H4v1h7v-1zm0-2H4v1h7V8zm7-4H4v2h14V4z"/></g></svg>'; 1962 1963 fbhtml = '<a class="actnbr-action actnbr-actn-follow" href="">' + followbtn + '<span>' + fbd.i18n.follow + '</span></a>'; 1964 if ( fbd.isFollowing ) { 1965 fbhtml = '<a class="actnbr-action actnbr-actn-following" href="">' + followingbtn + '<span>' + fbd.i18n.following + '</span></a>'; 1966 } 1967 1968 // Show follow/unfollow icon on top level, when this is not your own site 1969 if ( fbd.canFollow && ! ( fbd.canEditPost || fbd.canCustomizeSite ) ) { 1970 fhtml += '<li class="actnbr-btn actnbr-hidden"> \ 1971 ' + fbhtml + ' \ 1972 <div class="actnbr-popover tip tip-top-left actnbr-notice"> \ 1973 <div class="tip-arrow"></div> \ 1974 <div class="tip-inner actnbr-follow-bubble"></div> \ 1975 </div> \ 1976 </li>'; 1977 } 1978 1979 if ( ! fbd.canCustomizeSite ) { 1980 // Report Link 1981 reporthtml = '<li class="flb-report"><a href="http://en.wordpress.com/abuse/">' + fbd.i18n.report + '</a></li>'; 1982 } 1983 1984 // Show shortlink on single posts 1985 if ( fbd.isSingular ) { 1986 slkhtml = '<li class="actnbr-shortlink"><a href="' + fbd.shortlink + '">' + fbd.i18n.shortlink + '</a></li>' 1987 } 1988 1989 // Set up fold/unfold menu item 1990 foldhtml = '<li class="actnbr-fold"><a href="">' + fbd.i18n.foldBar + '</a></li>' 1991 if ( fbd.isFolded ) { 1992 foldhtml = '<li class="actnbr-fold"><a href="">' + fbd.i18n.unfoldBar + '</a></li>' 1993 } 1994 if ( ! fbd.isLoggedIn && ! fbd.canFollow ) { 1995 foldhtml = ''; 1996 } 1997 1998 if ( fbd.isLoggedIn ) { 1999 if ( '' != fbd.themeURL ) { 2000 themeHtml = '<li class="actnbr-theme"><a href="' + fbd.themeURL + '">' + fbd.i18n.themeInfo.replace( /{theme}/, fbd.themeName ) + '</a></li>'; 2001 } 2002 if ( fbd.canFollow ) { 2003 if ( fbd.isSingular ) { 2004 viewReaderHtml = '<li class="actnbr-reader"><a href="https://wordpress.com/read/blogs/' + fbd.siteID + '/posts/' + fbd.postID +'">' + fbd.i18n.viewReadPost + '</a></li>'; 2005 } else { 2006 viewReaderHtml = '<li class="actnbr-reader"><a href="https://wordpress.com/read/' + ( fbd.feedID ? 'feeds/' + fbd.feedID : 'blogs/' + fbd.siteID ) + '">' + fbd.i18n.viewReader + '</a></li>'; 2007 } 2008 } 2009 editFollowsHtml = '<li class="actnbr-follows"><a href="https://wordpress.com/following/edit">' + fbd.i18n.editSubs + '</a></li>'; 2010 } else { 2011 loginHtml += '<li class="actnbr-login"><a href="' + fbd.loginURL + '">' + fbd.i18n.login + '</a></li>'; 2012 signupHtml = '<li class="actnbr-signup"><a href="' + fbd.signupURL + '">' + fbd.i18n.signup + '</a></li>'; 2013 editSubsHtml = '<li class="actnbr-subs"><a href="https://subscribe.wordpress.com/">' + fbd.i18n.editSubs + '</a></li>'; 2014 } 2015 2016 // Hide follow/unfollow completely for static sites, and sites not allowing followers (VIP, private, etc). 2017 if ( ! fbd.canFollow ) { 2018 fbHtmlLi = ''; 2019 } else { 2020 fbHtmlLi = '<li class="actnbr-folded-follow">' + fbhtml + '</li>'; 2021 } 2022 2023 // Ellipsis Menu 2024 fhtml += '<li class="actnbr-ellipsis actnbr-hidden"> \ 2025 <svg class="gridicon gridicon__ellipsis" height="24" width="24" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><g><circle cx="5" cy="12" r="2"/><circle cx="19" cy="12" r="2"/><circle cx="12" cy="12" r="2"/></g></svg> \ 2026 <div class="actnbr-popover tip tip-top-left actnbr-more"> \ 2027 <div class="tip-arrow"></div> \ 2028 <div class="tip-inner"> \ 2029 <ul> \ 2030 <li class="actnbr-sitename"><a href="' + fbd.siteURL + '">' + fbd.icon + ' ' + actionBarEscapeHtml( fbd.siteName ) + '</a></li> \ 2031 <li class="actnbr-folded-customize"><a href="'+ fbd.customizeLink +'">' + customizeIcon + '<span>' + fbd.i18n.customize + '<span></a></li> \ 2032 ' + fbHtmlLi + ' \ 2033 ' + signupHtml + ' \ 2034 ' + loginHtml + ' \ 2035 ' + themeHtml + ' \ 2036 ' + slkhtml + ' \ 2037 ' + reporthtml + ' \ 2038 ' + viewReaderHtml + ' \ 2039 ' + editFollowsHtml + ' \ 2040 ' + editSubsHtml + ' \ 2041 ' + foldhtml + ' \ 2042 </ul> \ 2043 </div> \ 2044 </div> \ 2045 </li> \ 2046 </ul>'; 2047 2048 fbdf = d.createElement( 'div' ); 2049 fbdf.id = 'actionbar'; 2050 fbdf.innerHTML = fhtml; 2051 b.appendChild( fbdf ); 2052 2053 $actionbar = $( '#actionbar' ).addClass( 'actnbr-' + fbd.themeSlug.replace( '/', '-' ) ); 2054 2055 // Add classes based on contents 2056 if ( fbd.canCustomizeSite ) { 2057 $actionbar.addClass( 'actnbr-has-customize' ); 2058 } 2059 2060 if ( fbd.canEditPost ) { 2061 $actionbar.addClass( 'actnbr-has-edit' ); 2062 } 2063 2064 if ( ! fbd.canCustomizeSite ) { 2065 $actionbar.addClass( 'actnbr-has-follow' ); 2066 } 2067 2068 if ( fbd.isFolded ) { 2069 $actionbar.addClass( 'actnbr-folded' ); 2070 } 2071 2072 // Show status message if available 2073 if ( fbd.statusMessage ) { 2074 showActionBarStatusMessage( fbd.statusMessage ); 2075 } 2076 2077 // *** Actions ***************** 2078 2079 // Follow Site 2080 $actionbar.on( 'click', '.actnbr-actn-follow', function(e) { 2081 e.preventDefault(); 2082 2083 if ( fbd.isLoggedIn ) { 2084 showActionBarStatusMessage( '<div class="actnbr-reader">' + fbd.i18n.followedText + '</div>' ); 2085 bumpStat( 'followed' ); 2086 var eventProps = { 2087 'follow_source': 'actionbar', 2088 'url': fbd.siteURL 2089 }; 2090 recordTracksEvent( 'wpcom_actionbar_site_followed', eventProps ); 2091 2092 request( 'ab_subscribe_to_blog' ); 2093 } else { 2094 showActionBarFollowForm(); 2095 } 2096 } ) 2097 2098 // UnFollow Site 2099 .on( 'click', '.actnbr-actn-following', function(e) { 2100 e.preventDefault(); 2101 $( '#actionbar .actnbr-actn-following' ).replaceWith( '<a class="actnbr-action actnbr-actn-follow" href="">' + followbtn + '<span>' + fbd.i18n.follow + '</span></a>' ); 2102 2103 bumpStat( 'unfollowed' ); 2104 var eventProps = { 2105 'follow_source': 'actionbar', 2106 'url': fbd.siteURL 2107 }; 2108 recordTracksEvent( 'wpcom_actionbar_site_unfollowed', eventProps ); 2109 2110 request( 'ab_unsubscribe_from_blog' ); 2111 } ) 2112 2113 // Show shortlink prompt 2114 .on( 'click', '.actnbr-shortlink a', function(e) { 2115 e.preventDefault(); 2116 window.prompt( "Shortlink: ", fbd.shortlink ); 2117 } ) 2118 2119 // Toggle more menu 2120 .on( 'click', '.actnbr-ellipsis', function(e) { 2121 if ( $( e.target ).closest( 'a' ).hasClass( 'actnbr-action' ) ) { 2122 return false;
2123 } 2124 2125 var popoverLi = $( '#actionbar .actnbr-ellipsis' ); 2126 popoverLi.toggleClass( 'actnbr-hidden' ); 2127 2128 setTimeout( function() { 2129 if ( ! popoverLi.hasClass( 'actnbr-hidden' ) ) { 2130 bumpStat( 'show_more_menu' ); 2131 2132 $( document ).on( 'click.actnbr-body-click', function() { 2133 popoverLi.addClass( 'actnbr-hidden' ); 2134 2135 $( document ).off( 'click.actnbr-body-click' ); 2136 } ); 2137 } 2138 }, 10 ); 2139 }) 2140 2141 // Fold/Unfold 2142 .on( 'click', '.actnbr-fold', function(e) { 2143 e.preventDefault(); 2144 2145 if ( $( '#actionbar' ).hasClass( 'actnbr-folded' ) ) { 2146 $( '.actnbr-fold a' ).html( fbd.i18n.foldBar ); 2147 $( '#actionbar' ).removeClass( 'actnbr-folded' ); 2148 2149 $.post( fbd.xhrURL, { 'action': 'unfold_actionbar' } ); 2150 } else { 2151 $( '.actnbr-fold a' ).html( fbd.i18n.unfoldBar ); 2152 $( '#actionbar' ).addClass( 'actnbr-folded' ); 2153 2154 $.post( fbd.xhrURL, { 'action': 'fold_actionbar' } ); 2155 } 2156 }) 2157 2158 // Record stats for clicks 2159 .on( 'click', '.actnbr-sitename a', createStatsBumperEventHandler( 'clicked_site_title' ) ) 2160 .on( 'click', '.actnbr-customize a', createStatsBumperEventHandler( 'customized' ) ) 2161 .on( 'click', '.actnbr-folded-customize a', createStatsBumperEventHandler( 'customized' ) ) 2162 .on( 'click', '.actnbr-theme a', createStatsBumperEventHandler( 'explored_theme' ) ) 2163 .on( 'click', '.actnbr-edit a', createStatsBumperEventHandler( 'edited' ) ) 2164 .on( 'click', '.actnbr-stats a', createStatsBumperEventHandler( 'clicked_stats' ) ) 2165 .on( 'click', '.flb-report a', createStatsBumperEventHandler( 'reported_content' ) ) 2166 .on( 'click', '.actnbr-follows a', createStatsBumperEventHandler( 'managed_following' ) ) 2167 .on( 'click', '.actnbr-shortlink a', function() { 2168 bumpStat( 'copied_shortlink' ); 2169 } ) 2170 .on( 'click', '.actnbr-reader a', createStatsBumperEventHandler( 'view_reader' ) ) 2171 .on( 'submit', '.actnbr-follow-bubble form', createStatsBumperEventHandler( 'submit_follow_form', function() { 2172 $( '#actionbar .actnbr-follow-bubble form button' ).attr( 'disabled', true ); 2173 } ) ) 2174 .on( 'click', '.actnbr-login-nudge a', createStatsBumperEventHandler( 'clicked_login_nudge' ) ) 2175 .on( 'click', '.actnbr-signup a', createStatsBumperEventHandler( 'clicked_signup_link' ) ) 2176 .on( 'click', '.actnbr-login a', createStatsBumperEventHandler( 'clicked_login_link' ) ) 2177 .on( 'click', '.actnbr-subs a', createStatsBumperEventHandler( 'clicked_manage_subs_link' ) ); 2178 2179 // Make Follow/Unfollow requests 2180 var request = function( action ) { 2181 $.post( fbd.xhrURL, { 2182 'action': action, 2183 '_wpnonce': fbd.nonce, 2184 'source': 'actionbar', 2185 'blog_id': fbd.siteID 2186 }); 2187 }; 2188 2189 // Show/Hide actionbar on scroll 2190 fb = $('#actionbar'); 2191 toggleactionbar = function() { 2192 var st = $(window).scrollTop(), 2193 topOffset = 0; 2194 2195 if ( $(window).scrollTop() < 0 ) { 2196 return; 2197 } 2198 2199 // Still 2200 if ( lastScrollTop == 0 || ( ( st == lastScrollTop ) && lastScrollDir == 'up' ) ) { 2201 fb.removeClass( 'actnbr-hidden' ); 2202 2203 // Moving 2204 } else { 2205 // Scrolling Up 2206 if ( st < lastScrollTop ){ 2207 fb.removeClass( 'actnbr-hidden' ); 2208 lastScrollDir = 'up'; 2209 2210 // Scrolling Down 2211 } else { 2212 // check if there are any popovers open, and only hide action bar if not 2213 if ( $( '#actionbar > ul > li:not(.actnbr-hidden) > .actnbr-popover' ).length === 0 ) { 2214 fb.addClass( 'actnbr-hidden' ); 2215 lastScrollDir = 'down'; 2216 2217 // Hide any menus 2218 $( '#actionbar li' ).addClass( 'actnbr-hidden' ); 2219 } 2220 } 2221 } 2222 2223 lastScrollTop = st; 2224 }; 2225 setInterval( toggleactionbar, 100 ); 2226 2227 var bumpStat = function( stat ) { 2228 return $.post( fbd.xhrURL, { 2229 'action': 'actionbar_stats', 2230 'stat': stat 2231 } ); 2232 }; 2233 2234 var recordTracksEvent = function( eventName, eventProps ) { 2235 eventProps = eventProps || {}; 2236 window._tkq = window._tkq || []; 2237 window._tkq.push( [ 'recordEvent', eventName, eventProps ] ); 2238 }; 2239 2240 /** 2241 * A factory method for creating an event handler function that will bump a specific stat and ONLY THEN re-dispatch 2242 * the event. This will ensure that the bumped stat is indeed recorded before navigating the page away, as otherwise 2243 * some browsers may very well decide to cancel the stat request in that case. 2244 * 2245 * @param {String} stat the name of the stat to bump 2246 * @param {Function} additionalEffect an additional function that should be called after the stat is bumped 2247 */ 2248 function createStatsBumperEventHandler( stat, additionalEffect ) { 2249 var completedEvents = {}; 2250 2251 return function eventHandler( event ) { 2252 if ( completedEvents[ event.timeStamp ] ) { 2253 delete completedEvents[ event.timeStamp ]; 2254 2255 // hack-around to submit forms, dispatching "submit" event is not enough for them 2256 if ( event.type === 'submit' ) { 2257 event.target.submit(); 2258 } 2259 2260 if ( typeof additionalEffect === 'function' ) { 2261 return additionalEffect( event ); 2262 } 2263 2264 return true; 2265 } 2266 2267 event.preventDefault(); 2268 event.stopPropagation(); 2269 2270 function dispatchOriginalEvent() { 2271 var newEvent; 2272 2273 // Retrieves the native event object created by the browser from the jQuery event object 2274 var originalEvent = event.originalEvent; 2275 2276 /** 2277 * Handles Internet Explorer that doesn't support Event nor CustomEvent constructors 2278 * 2279 * @see https://developer.mozilla.org/en-US/docs/Web/API/Event/Event 2280 * @see https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/CustomEvent 2281 * @see https://stackoverflow.com/questions/26596123/internet-explorer-9-10-11-event-constructor-doesnt-work/ 2282 */ 2283 if ( typeof window.CustomEvent !== 'function' ) { 2284 newEvent = document.createEvent( 'CustomEvent' ); 2285 newEvent.initCustomEvent( 2286 originalEvent.type, 2287 originalEvent.bubbles, 2288 originalEvent.cancelable, 2289 originalEvent.detail 2290 ); 2291 } else { 2292 newEvent = new originalEvent.constructor( originalEvent.type, originalEvent ); 2293 } 2294 2295 completedEvents[ newEvent.timeStamp ] = true; 2296 2297 originalEvent.target.dispatchEvent( newEvent ); 2298 } 2299 2300 bumpStat( stat ).then( dispatchOriginalEvent, dispatchOriginalEvent ); 2301 } 2302 } 2303 2304 function actionBarEscapeHtml(string) { 2305 return String(string).replace(/[&<>
2305"'\/]/g, function (s) { 2306 var entityMap = { 2307 "&": "&", 2308 "<": "<", 2309 ">": ">", 2310 '"': '"', 2311 "'": ''', 2312 "/": '/' 2313 }; 2314 return entityMap[s]; 2315 }); 2316 } 2317 2318 function showActionBarStatusMessage( message ) { 2319 $( '#actionbar .actnbr-actn-follow' ).replaceWith( '<a class="actnbr-action actnbr-actn-following" href="">' + followingbtn + '<span>' + fbd.i18n.following + '</span></a>' ); 2320 $( '#actionbar .actnbr-follow-bubble' ).html( ' \ 2321 <ul> \ 2322 <li class="actnbr-sitename"><a href="' + fbd.siteURL + '">' + fbd.icon + ' ' + actionBarEscapeHtml( fbd.siteName ) + '</a></li> \ 2323 <li class="actnbr-message">' + message + '</li> \ 2324 </ul> \ 2325 '); 2326 2327 var btn = $( '#actionbar .actnbr-btn' ); 2328 btn.removeClass( 'actnbr-hidden' ); 2329 2330 setTimeout( function() { 2331 if ( ! btn.hasClass( 'actnbr-hidden' ) ) { 2332 $( '#actionbar .actnbr-email-field' ).focus(); 2333 $( document ).on( 'click.actnbr-body-click', function(e) { 2334 if ( $( e.target ).closest( '.actnbr-popover' )[0] ) { 2335 return; 2336 } 2337 btn.addClass( 'actnbr-hidden' ); 2338 $( document ).off( 'click.actnbr-body-click' ); 2339 } ); 2340 } 2341 }, 10 ); 2342 } 2343 2344 function showActionBarFollowForm() { 2345 var btn = $( '#actionbar .actnbr-btn' ); 2346 btn.toggleClass( 'actnbr-hidden' ); 2347 2348 var form = $('<form>'); 2349 2350 if ( fbd.i18n.followers ) { 2351 form.append( $( '<div class="actnbr-follow-count">' ).html( fbd.i18n.followers ) ); 2352 } 2353 2354 form.append($('<div>').append($('<input>').attr({"type": "email", "name": "email", "placeholder": fbd.i18n.enterEmail, "class": "actnbr-email-field"}))); 2355 form.append($('<input type="hidden" name="action" value="subscribe"/>')); 2356 form.append($('<input type="hidden" name="blog_id">').attr('value', fbd.siteID)); 2357 form.append($('<input type="hidden" name="source">').attr('value', fbd.referer)); 2358 form.append($('<input type="hidden" name="sub-type" value="actionbar-follow"/>')); 2359 form.append($(fbd.subscribeNonce)); 2360 form.append($('<div class="actnbr-button-wrap">').append($('<button type="submit">').attr('value', fbd.i18n.subscribe).html(fbd.i18n.subscribe))); 2361 form.attr('method', 'post'); 2362 form.attr('action', 'https://subscribe.wordpress.com'); 2363 form.attr('accept-charset', 'utf-8'); 2364 2365 var html = $('<ul/>'); 2366 html.append($('<li class="actnbr-sitename">').append($('<a>').attr('href', fbd.siteURL).append($(fbd.icon)).append(' ' + actionBarEscapeHtml( fbd.siteName )))) 2367 html.append($('<li>').append(form)); 2368 html.append($('<li class="actnbr-login-nudge">').append($('<div>').html(fbd.i18n.alreadyUser))); 2369 2370 $( '#actionbar .actnbr-follow-bubble' ).empty().append(html); 2371 2372 setTimeout( function() { 2373 if ( ! btn.hasClass( 'actnbr-hidden' ) ) { 2374 bumpStat( 'show_follow_form' ); 2375 2376 $( '#actionbar .actnbr-email-field' ).focus(); 2377 2378 $( document ).on( 'click.actnbr-body-click', function( event ) { 2379 if ( $( event.target ).closest( '.actnbr-popover' )[ 0 ] ) { 2380 return; 2381 } 2382 2383 btn.addClass( 'actnbr-hidden' ); 2384 2385 $( document ).off( 'click.actnbr-body-click' ); 2386 } ); 2387 } 2388 }, 10 ); 2389 } 2390})(jQuery); 2391; 2392/* jshint sub: true, onevar: false, multistr: true, devel: true, smarttabs: true */ 2393/* global jetpackCarouselStrings, DocumentTouch */ 2394 2395// @start-hide-in-jetpack 2396if (typeof wpcom === 'undefined') { 2397 var wpcom = {}; 2398} 2399wpcom.carousel = (function(/*$*/) { 2400 var prebuilt_widths = jetpackCarouselStrings.widths; 2401 var pageviews_stats_args = jetpackCarouselStrings.stats_query_args; 2402 2403 var findFirstLargeEnoughWidth = function(original_w, original_h, dest_w, dest_h) { 2404 var inverse_ratio = original_h / original_w; 2405 2406 for ( var i = 0; i < prebuilt_widths.length; ++i ) { 2407 if ( prebuilt_widths[i] >= dest_w || prebuilt_widths[i] * inverse_ratio >= dest_h ) { 2408 return prebuilt_widths[i]; 2409 } 2410 } 2411 2412 return original_w; 2413 }; 2414 2415 var addWidthToImageURL = function(url, width) { 2416 width = parseInt(width, 10); 2417 // Give devices with a higher devicePixelRatio higher-res images (Retina display = 2, Android phones = 1.5, etc) 2418 if ('undefined' !== typeof window.devicePixelRatio && window.devicePixelRatio > 1) { 2419 width = Math.round( width * window.devicePixelRatio ); 2420 } 2421 url = addArgToURL(url, 'w', width); 2422 url = addArgToURL(url, 'h', ''); 2423 return url; 2424 }; 2425 2426 var addArgToURL = function(url, arg, value) { 2427 var re = new RegExp(arg+'=[^?&]+'); 2428 if ( url.match(re) ) { 2429 return url.replace(re, arg + '=' + value); 2430 } else { 2431 var divider = url.indexOf('?') !== -1 ? '&' : '?';
2432 return url + divider + arg + '=' + value; 2433 } 2434 }; 2435 2436 var stat = function ( names ) { 2437 if ( typeof names !== 'string' ) { 2438 names = names.join( ',' ); 2439 } 2440 2441 new Image().src = window.location.protocol + 2442 'https://pixel.wp.com/g.gif?v=wpcom-no-pv' + 2443 '&x_carousel=' + names + 2444 '&baba=' + Math.random(); 2445 }; 2446 2447 var pageview = function ( post_id ) { 2448 new Image().src = window.location.protocol + 2449 'https://pixel.wp.com/g.gif?host=' + encodeURIComponent( window.location.host ) + 2450 '&ref=' + encodeURIComponent( document.referrer ) + 2451 '&rand=' + Math.random() + 2452 '&' + pageviews_stats_args + 2453 '&post=' + encodeURIComponent( post_id ); 2454 }; 2455 2456 2457 return { 2458 findFirstLargeEnoughWidth: findFirstLargeEnoughWidth, 2459 addWidthToImageURL: addWidthToImageURL, 2460 stat: stat, 2461 pageview: pageview 2462 }; 2463 2464})(jQuery); 2465// @end-hide-in-jetpack 2466 2467jQuery(document).ready(function($) { 2468 2469 // gallery faded layer and container elements 2470 var overlay, comments, gallery, container, nextButton, previousButton, info, transitionBegin, 2471 caption, resizeTimeout, photo_info, close_hint, commentInterval, lastSelectedSlide, 2472 screenPadding = 110, originalOverflow = $('body').css('overflow'), originalHOverflow = $('html').css('overflow'), proportion = 85, 2473 last_known_location_hash = '', imageMeta, titleAndDescription, commentForm, leftColWrapper, scrollPos; 2474 2475 if ( window.innerWidth <= 760 ) { 2476 screenPadding = Math.round( ( window.innerWidth / 760 ) * 110 ); 2477 2478 if ( screenPadding < 40 && ( ( 'ontouchstart' in window ) || window.DocumentTouch && document instanceof DocumentTouch ) ) { 2479 screenPadding = 0; 2480 } 2481 } 2482 2483 // Adding a polyfill for browsers that do not have Date.now 2484 if ( 'undefined' === typeof Date.now ) { 2485 Date.now = function now() { 2486 return new Date().getTime(); 2487 }; 2488 } 2489 2490 var keyListener = function(e){ 2491 switch(e.which){ 2492 case 38: // up 2493 e.preventDefault(); 2494 container.scrollTop(container.scrollTop() - 100); 2495 break; 2496 case 40: // down 2497 e.preventDefault(); 2498 container.scrollTop(container.scrollTop() + 100); 2499 break; 2500 case 39: // right 2501 e.preventDefault(); 2502 gallery.jp_carousel('next'); 2503 break; 2504 case 37: // left 2505 case 8: // backspace 2506 e.preventDefault(); 2507 gallery.jp_carousel('previous'); 2508 break; 2509 case 27: // escape 2510 e.preventDefault(); 2511 container.jp_carousel('close'); 2512 break; 2513 default: 2514 // making jslint happy 2515 break; 2516 } 2517 }; 2518 2519 var resizeListener = function(/*e*/){ 2520 clearTimeout(resizeTimeout); 2521 resizeTimeout = setTimeout(function(){ 2522 gallery 2523 .jp_carousel('slides') 2524 .jp_carousel('fitSlide', true); 2525 gallery.jp_carousel('updateSlidePositions', true); 2526 gallery.jp_carousel('fitMeta', true); 2527 }, 200); 2528 }; 2529 2530 var prepareGallery = function( /*dataCarouselExtra*/ ){ 2531 if (!overlay) { 2532 overlay = $('<div></div>') 2533 .addClass('jp-carousel-overlay') 2534 .css({ 2535 'position' : 'fixed', 2536 'top' : 0, 2537 'right' : 0, 2538 'bottom' : 0, 2539 'left' : 0 2540 }); 2541 2542 var buttons = '<a class="jp-carousel-commentlink" href="#">' + jetpackCarouselStrings.comment + '</a>'; 2543 if ( 1 === Number( jetpackCarouselStrings.is_logged_in ) ) { 2544// @start-hide-in-jetpack 2545 if ( 1 === Number( jetpackCarouselStrings.is_public && 1 === Number( jetpackCarouselStrings.reblog_enabled ) ) ) { 2546 buttons += '<a class="jp-carousel-reblog" href="#">' + jetpackCarouselStrings.reblog + '</a>'; 2547 } 2548// @end-hide-in-jetpack 2549 } 2550 2551 buttons = $('<div class="jp-carousel-buttons">' + buttons + '</div>'); 2552 2553 caption = $('<h2 itemprop="caption description"></h2>'); 2554 photo_info = $('<div class="jp-carousel-photo-info"></div>').append(caption); 2555 2556 imageMeta = $('<div></div>') 2557 .addClass('jp-carousel-image-meta') 2558 .css({ 2559 'float' : 'right', 2560 'margin-top' : '20px', 2561 'width' : '250px' 2562 }); 2563 2564 imageMeta 2565 .append( buttons ) 2566 .append( '<ul class=\'jp-carousel-image-exif\' style=\'display:none;\'></ul>' ) 2567 .append( '<a class=\'jp-carousel-image-download\' style=\'display:none;\'></a>' ) 2568 .append( '<div class=\'jp-carousel-image-map\' style=\'display:none;\'></div>' ); 2569 2570 titleAndDescription = $('<div></div>') 2571 .addClass('jp-carousel-titleanddesc') 2572 .css({ 2573 'width' : '100%', 2574 'margin-top' : imageMeta.css('margin-top') 2575 }); 2576 2577 var commentFormMarkup = '<div id="jp-carousel-comment-form-container">'; 2578 2579 if ( jetpackCarouselStrings.local_comments_commenting_as && jetpackCarouselStrings.local_comments_commenting_as.length ) { 2580 // Comments not enabled, fallback to local comments 2581 2582 if ( 1 !== Number( jetpackCarouselStrings.is_logged_in ) && 1 === Number( jetpackCarouselStrings.comment_registration ) ) { 2583 commentFormMarkup += '<div id="jp-carousel-comment-form-commenting-as">' + jetpackCarouselStrings.local_comments_commenting_as + '</div>'; 2584 } else { 2585 commentFormMarkup += '<form id="jp-carousel-comment-form">'; 2586 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>'; 2587 commentFormMarkup += '<div id="jp-carousel-comment-form-submit-and-info-wrapper">'; 2588 commentFormMarkup += '<div id="jp-carousel-comment-form-commenting-as">' + jetpackCarouselStrings.local_comments_commenting_as + '</div>'; 2589 commentFormMarkup += '<input type="submit" name="submit" class="jp-carousel-comment-form-button" id="jp-carousel-comment-form-button-submit" value="'+jetpackCarouselStrings.post_comment+'" />'; 2590 commentFormMarkup += '<span id="jp-carousel-comment-form-spinner"> </span>'; 2591 commentFormMarkup += '<div id="jp-carousel-comment-post-results"></div>'; 2592 commentFormMarkup += '</div>'; 2593 commentFormMarkup += '</form>'; 2594 } 2595 } 2596 commentFormMarkup += '</div>'; 2597 2598 commentForm = $(commentFormMarkup) 2599 .css({ 2600 'width' : '100%', 2601 'margin-top' : '20px', 2602 'color' : '#999' 2603 }); 2604 2605 comments = $('<div></div>') 2606 .addClass('jp-carousel-comments') 2607 .css({ 2608 'width' : '100%', 2609 'bottom' : '10px', 2610 'margin-top' : '20px' 2611 }); 2612 2613 var commentsLoading = $('<div id="jp-carousel-comments-loading"><span>'+jetpackCarouselStrings.loading_comments+'</span></div>') 2614 .css({ 2615 'width' : '100%', 2616 'bottom' : '10px', 2617 'margin-top' : '20px' 2618 }); 2619
2620 var leftWidth = ( $(window).width() - ( screenPadding * 2 ) ) - (imageMeta.width() + 40); 2621 leftWidth += 'px'; 2622 2623 leftColWrapper = $('<div></div>') 2624 .addClass('jp-carousel-left-column-wrapper') 2625 .css({ 2626 'width' : Math.floor( leftWidth ) 2627 }) 2628 .append(titleAndDescription) 2629 .append(commentForm) 2630 .append(comments) 2631 .append(commentsLoading); 2632 2633 var fadeaway = $('<div></div>') 2634 .addClass('jp-carousel-fadeaway'); 2635 2636 info = $('<div></div>') 2637 .addClass('jp-carousel-info') 2638 .css({ 2639 'top' : Math.floor( ($(window).height() / 100) * proportion ), 2640 'left' : screenPadding, 2641 'right' : screenPadding 2642 }) 2643 .append(photo_info) 2644 .append(imageMeta); 2645 2646 if ( window.innerWidth <= 760 ) { 2647 photo_info.remove().insertAfter( titleAndDescription ); 2648 info.prepend( leftColWrapper ); 2649 } 2650 else { 2651 info.append( leftColWrapper ); 2652 } 2653 2654 var targetBottomPos = ( $(window).height() - parseInt( info.css('top'), 10 ) ) + 'px'; 2655 2656 nextButton = $('<div><span></span></div>') 2657 .addClass('jp-carousel-next-button') 2658 .css({ 2659 'right' : '15px' 2660 }) 2661 .hide(); 2662 2663 previousButton = $('<div><span></span></div>') 2664 .addClass('jp-carousel-previous-button') 2665 .css({ 2666 'left' : 0 2667 }) 2668 .hide(); 2669 2670 nextButton.add( previousButton ).css( { 2671 'position' : 'fixed', 2672 'top' : '40px', 2673 'bottom' : targetBottomPos, 2674 'width' : screenPadding 2675 } ); 2676 2677 gallery = $('<div></div>') 2678 .addClass('jp-carousel') 2679 .css({ 2680 'position' : 'absolute', 2681 'top' : 0, 2682 'bottom' : targetBottomPos, 2683 'left' : 0, 2684 'right' : 0 2685 }); 2686 2687 close_hint = $('<div class="jp-carousel-close-hint"><span>×</span></div>') 2688 .css({ 2689 position : 'fixed' 2690 }); 2691
2692 container = $('<div></div>') 2693 .addClass('jp-carousel-wrap') 2694 .addClass( 'jp-carousel-transitions' ); 2695 if ( 'white' === jetpackCarouselStrings.background_color ) { 2696 container.addClass('jp-carousel-light'); 2697 } 2698 2699 container.attr('itemscope', ''); 2700 2701 container.attr('itemtype', 'https://schema.org/ImageGallery'); 2702 2703 container.css({ 2704 'position' : 'fixed', 2705 'top' : 0, 2706 'right' : 0, 2707 'bottom' : 0, 2708 'left' : 0, 2709 'z-index' : 2147483647, 2710 'overflow-x' : 'hidden', 2711 'overflow-y' : 'auto', 2712 'direction' : 'ltr' 2713 }) 2714 .hide() 2715 .append(overlay) 2716 .append(gallery) 2717 .append(fadeaway) 2718 .append(info) 2719 .append(nextButton) 2720 .append(previousButton) 2721 .append(close_hint) 2722 .appendTo($('body')) 2723 .click(function(e){ 2724 var target = $(e.target), wrap = target.parents('div.jp-carousel-wrap'), data = wrap.data('carousel-extra'), 2725 slide = wrap.find('div.selected'), attachment_id = slide.data('attachment-id'); 2726 data = data || []; 2727 2728 if ( target.is(gallery) || target.parents().add(target).is(close_hint) ) { 2729 container.jp_carousel('close'); 2730// @start-hide-in-jetpack 2731 } else if ( target.hasClass('jp-carousel-reblog') ) { 2732 e.preventDefault(); 2733 e.stopPropagation(); 2734 if ( !target.hasClass('reblogged') ) { 2735 target.jp_carousel('show_reblog_box'); 2736 wpcom.carousel.stat('reblog_show_box'); 2737 } 2738 } else if ( target.parents('#carousel-reblog-box').length ) { 2739 if ( target.is('a.cancel') ) { 2740 e.preventDefault(); 2741 e.stopPropagation(); 2742 target.jp_carousel('hide_reblog_box'); 2743 wpcom.carousel.stat('reblog_cancel'); 2744 } else if ( target.is( 'input[type="submit"]' ) ) { 2745 e.preventDefault(); 2746 e.stopPropagation(); 2747 2748 var note = $('#carousel-reblog-box textarea').val(); 2749 if ( jetpackCarouselStrings.reblog_add_thoughts === note ) { 2750 note = ''; 2751 } 2752 2753 $('#carousel-reblog-submit').val( jetpackCarouselStrings.reblogging ); 2754 $('#carousel-reblog-submit').prop('disabled', true); 2755 $( '#carousel-reblog-box div.submit span.canceltext' ).spin( 'small' ); 2756 2757 $.post( jetpackCarouselStrings.ajaxurl, { 2758 'action': 'post_reblog', 2759 'reblog_source': 'carousel', 2760 'original_blog_id': $('#carousel-reblog-box input#carousel-reblog-blog-id').val(), 2761 'original_post_id': $('.jp-carousel div.selected').data('attachment-id'), 2762 'blog_id': $('#carousel-reblog-box select').val(), 2763 'blog_url': $('#carousel-reblog-box input#carousel-reblog-blog-url').val(), 2764 'blog_title': $('#carousel-reblog-box input#carousel-reblog-blog-title').val(), 2765 'post_url': $('#carousel-reblog-box input#carousel-reblog-post-url').val(), 2766 'post_title': slide.data( 'caption' ) || $('#carousel-reblog-box input#carousel-reblog-post-title').val(), 2767 'note': note, 2768 '_wpnonce': $('#carousel-reblog-box #_wpnonce').val() 2769 }, 2770 function(/*result*/) { 2771 $('#carousel-reblog-box').css({ 'height': $('#carousel-reblog-box').height() + 'px' }).slideUp('fast'); 2772 $('a.jp-carousel-reblog').html( jetpackCarouselStrings.reblogged ).removeClass( 'reblog' ).addClass( 'reblogged' ); 2773 $( '#carousel-reblog-box div.submit span.canceltext' ).spin( false ); 2774 $('#carousel-reblog-submit').val( jetpackCarouselStrings.post_reblog ); 2775 $('div.jp-carousel-info').children().not('#carousel-reblog-box').fadeIn('fast'); 2776 slide.data('reblogged', 1); 2777 $('div.gallery').find('img[data-attachment-id="' + slide.data('attachment-id') + '"]').data('reblogged', 1); 2778 2779 2780 }, 'json' ); 2781 wpcom.carousel.stat('reblog_submit'); 2782 } 2783 } else if ( target.hasClass( 'jp-carousel-image-download' ) ) { 2784 wpcom.carousel.stat( 'download_original_click' ); 2785// @end-hide-in-jetpack 2786 } else if ( target.hasClass('jp-carousel-commentlink') ) { 2787 e.preventDefault(); 2788 e.stopPropagation(); 2789 $(window).unbind('keydown', keyListener); 2790 container.animate({scrollTop: parseInt(info.position()['top'], 10)}, 'fast'); 2791 $('#jp-carousel-comment-form-submit-and-info-wrapper').slideDown('fast'); 2792 $('#jp-carousel-comment-form-comment-field').focus(); 2793 } else if ( target.hasClass('jp-carousel-comment-login') ) { 2794 var url = jetpackCarouselStrings.login_url + '%23jp-carousel-' + attachment_id; 2795 2796 window.location.href = url; 2797 } else if ( target.parents('#jp-carousel-comment-form-container').length ) { 2798 var textarea = $('#jp-carousel-comment-form-comment-field') 2799 .blur(function(){ 2800 $(window).bind('keydown', keyListener); 2801 }) 2802 .focus(function(){ 2803 $(window).unbind('keydown', keyListener); 2804 }); 2805 2806 var emailField = $('#jp-carousel-comment-form-email-field') 2807 .blur(function(){ 2808 $(window).bind('keydown', keyListener); 2809 }) 2810 .focus(function(){ 2811 $(window).unbind('keydown', keyListener); 2812 }); 2813 2814 var authorField = $('#jp-carousel-comment-form-author-field') 2815 .blur(function(){ 2816 $(window).bind('keydown', keyListener); 2817 }) 2818 .focus(function(){ 2819 $(window).unbind('keydown', keyListener); 2820 }); 2821 2822 var urlField = $('#jp-carousel-comment-form-url-field') 2823 .blur(function(){ 2824 $(window).bind('keydown', keyListener); 2825 }) 2826 .focus(function(){ 2827 $(window).unbind('keydown', keyListener); 2828 }); 2829 2830 if ( textarea && textarea.attr('id') === target.attr('id')) { 2831 // For first page load 2832 $(window).unbind('keydown', keyListener); 2833 $('#jp-carousel-comment-form-submit-and-info-wrapper').slideDown('fast'); 2834 } else if ( target.is( 'input[type="submit"]' ) ) { 2835 e.preventDefault(); 2836 e.stopPropagation(); 2837 2838 $('#jp-carousel-comment-form-spinner').spin('small', 'white'); 2839 2840 var ajaxData = { 2841 action: 'post_attachment_comment', 2842 nonce: jetpackCarouselStrings.nonce, 2843 blog_id: data['blog_id'], 2844 id: attachment_id, 2845 comment: textarea.val() 2846 }; 2847 2848 if ( ! ajaxData['comment'].length ) { 2849 gallery.jp_carousel('postCommentError', {'field': 'jp-carousel-comment-form-comment-field', 'error': jetpackCarouselStrings.no_comment_text}); 2850 return; 2851 } 2852 2853 if ( 1 !== Number( jetpackCarouselStrings.is_logged_in ) ) { 2854 ajaxData['email'] = emailField.val(); 2855 ajaxData['author'] = authorField.val(); 2856 ajaxData['url'] = urlField.val(); 2857 2858 if ( 1 === Number( jetpackCarouselStrings.require_name_email ) ) { 2859 if ( ! ajaxData['email'].length || ! ajaxData['email'].match('@') ) { 2860 gallery.jp_carousel('postCommentError', {'field': 'jp-carousel-comment-form-email-field', 'error': jetpackCarouselStrings.no_comment_email}); 2861 return; 2862 } else if ( ! ajaxData['author'].length ) { 2863 gallery.jp_carousel('postCommentError', {'field': 'jp-carousel-comment-form-author-field', 'error': jetpackCarouselStrings.no_comment_author}); 2864 return; 2865 } 2866 } 2867 } 2868 2869 $.ajax({ 2870 type: 'POST', 2871 url: jetpackCarouselStrings.ajaxurl, 2872 data: ajaxData, 2873 dataType: 'json', 2874 success: function(response/*, status, xhr*/) { 2875 if ( 'approved' === response.comment_status ) {
2876 $('#jp-carousel-comment-post-results').slideUp('fast').html('<span class="jp-carousel-comment-post-success">' + jetpackCarouselStrings.comment_approved + '</span>').slideDown('fast'); 2877 } else if ( 'unapproved' === response.comment_status ) { 2878 $('#jp-carousel-comment-post-results').slideUp('fast').html('<span class="jp-carousel-comment-post-success">' + jetpackCarouselStrings.comment_unapproved + '</span>').slideDown('fast'); 2879 } else { 2880 // 'deleted', 'spam', false 2881 $('#jp-carousel-comment-post-results').slideUp('fast').html('<span class="jp-carousel-comment-post-error">' + jetpackCarouselStrings.comment_post_error + '</span>').slideDown('fast'); 2882 } 2883 gallery.jp_carousel('clearCommentTextAreaValue'); 2884 gallery.jp_carousel('getComments', {attachment_id: attachment_id, offset: 0, clear: true}); 2885 $('#jp-carousel-comment-form-button-submit').val(jetpackCarouselStrings.post_comment); 2886 $('#jp-carousel-comment-form-spinner').spin(false); 2887 }, 2888 error: function(/*xhr, status, error*/) { 2889 // TODO: Add error handling and display here 2890 gallery.jp_carousel('postCommentError', {'field': 'jp-carousel-comment-form-comment-field', 'error': jetpackCarouselStrings.comment_post_error}); 2891 return; 2892 } 2893 }); 2894 } 2895 } else if ( ! target.parents( '.jp-carousel-info' ).length ) { 2896 container.jp_carousel('next'); 2897 } 2898 }) 2899 .bind('jp_carousel.afterOpen', function(){ 2900 $(window).bind('keydown', keyListener); 2901 $(window).bind('resize', resizeListener); 2902 gallery.opened = true; 2903 2904 resizeListener(); 2905 }) 2906 .bind('jp_carousel.beforeClose', function(){ 2907 var scroll = $(window).scrollTop(); 2908 2909 $(window).unbind('keydown', keyListener); 2910 $(window).unbind('resize', resizeListener); 2911 $(window).scrollTop(scroll); 2912 $( '.jp-carousel-previous-button' ).hide(); 2913 $( '.jp-carousel-next-button' ).hide(); 2914 gallery.jp_carousel( 'hide_reblog_box' ); // @hide-in-jetpack 2915 }) 2916 .bind('jp_carousel.afterClose', function(){ 2917 if ( window.location.hash && history.back ) { 2918 history.back(); 2919 } 2920 last_known_location_hash = ''; 2921 gallery.opened = false; 2922 }) 2923 .on( 'transitionend.jp-carousel ', '.jp-carousel-slide', function ( e ) { 2924 // If the movement transitions take more than twice the allotted time, disable them. 2925 // There is some wiggle room in the 2x, since some of that time is taken up in 2926 // JavaScript, setting up the transition and calling the events. 2927 if ( 'transform' === e.originalEvent.propertyName ) { 2928 var transitionMultiplier = ( ( Date.now() - transitionBegin ) / 1000 ) / e.originalEvent.elapsedTime; 2929 2930 container.off( 'transitionend.jp-carousel' ); 2931 2932 if ( transitionMultiplier >= 2 ) { 2933 $( '.jp-carousel-transitions' ).removeClass( 'jp-carousel-transitions' ); 2934 } 2935 } 2936 } ); 2937 2938 $( '.jp-carousel-wrap' ).touchwipe( { 2939 wipeLeft : function ( e ) { 2940 e.preventDefault(); 2941 gallery.jp_carousel( 'next' ); 2942 }, 2943 wipeRight : function ( e ) { 2944 e.preventDefault(); 2945 gallery.jp_carousel( 'previous' ); 2946 }, 2947 preventDefaultEvents : false 2948 } ); 2949 2950 nextButton.add(previousButton).click(function(e){ 2951 e.preventDefault(); 2952 e.stopPropagation(); 2953 if ( nextButton.is(this) ) { 2954 gallery.jp_carousel('next'); 2955 } else { 2956 gallery.jp_carousel('previous'); 2957 } 2958 }); 2959 } 2960 }; 2961 2962 var processSingleImageGallery = function() { 2963 // process links that contain img tag with attribute data-attachment-id 2964 $( 'a img[data-attachment-id]' ).each(function() { 2965 var container = $( this ).parent(); 2966 2967 // skip if image was already added to gallery by shortcode 2968 if( container.parent( '.gallery-icon' ).length ) { 2969 return; 2970 } 2971 2972 // skip if the container is not a link 2973 if ( 'undefined' === typeof( $( container ).attr( 'href' ) ) ) { 2974 return; 2975 } 2976 2977 var valid = false; 2978 2979 // if link points to 'Media File' (ignoring GET parameters) and flag is set allow it 2980 if ( $( container ).attr( 'href' ).split( '?' )[0] === $( this ).attr( 'data-orig-file' ).split( '?' )[0] && 2981 1 === Number( jetpackCarouselStrings.single_image_gallery_media_file ) 2982 ) { 2983 valid = true; 2984 } 2985 2986 // if link points to 'Attachment Page' allow it
2987 if( $( container ).attr( 'href' ) === $( this ).attr( 'data-permalink' ) ) { 2988 valid = true; 2989 } 2990 2991 // links to 'Custom URL' or 'Media File' when flag not set are not valid 2992 if( ! valid ) { 2993 return; 2994 } 2995 2996 // make this node a gallery recognizable by event listener above 2997 $( container ).addClass( 'single-image-gallery' ) ; 2998 // blog_id is needed to allow posting comments to correct blog 2999 $( container ).data( 'carousel-extra', { blog_id: Number( jetpackCarouselStrings.blog_id ) } ); 3000 }); 3001 }; 3002 3003 var methods = { 3004 testForData: function(gallery) { 3005 gallery = $( gallery ); // make sure we have it as a jQuery object. 3006 return !( ! gallery.length || ! gallery.data( 'carousel-extra' ) ); 3007 }, 3008 3009 testIfOpened: function() { 3010 return !!( 'undefined' !== typeof(gallery) && 'undefined' !== typeof(gallery.opened) && gallery.opened ); 3011 }, 3012 3013 openOrSelectSlide: function( index ) { 3014 // The `open` method triggers an asynchronous effect, so we will get an 3015 // error if we try to use `open` then `selectSlideAtIndex` immediately 3016 // after it. We can only use `selectSlideAtIndex` if the carousel is 3017 // already open. 3018 if ( ! $( this ).jp_carousel( 'testIfOpened' ) ) { 3019 // The `open` method selects the correct slide during the 3020 // initialization. 3021 $( this ).jp_carousel( 'open', { start_index: index } ); 3022 } else { 3023 gallery.jp_carousel( 'selectSlideAtIndex', index ); 3024 } 3025 }, 3026 3027 open: function(options) { 3028 var settings = { 3029 'items_selector' : '.gallery-item [data-attachment-id], .tiled-gallery-item [data-attachment-id], img[data-attachment-id]', 3030 'start_index': 0 3031 }, 3032 data = $(this).data('carousel-extra'); 3033 3034 if ( !data ) { 3035 return; // don't run if the default gallery functions weren't used 3036 } 3037 3038 prepareGallery( data ); 3039 3040 if ( gallery.jp_carousel( 'testIfOpened' ) ) { 3041 return; // don't open if already opened 3042 } 3043 3044 // make sure to stop the page from scrolling behind the carousel overlay, so we don't trigger 3045 // infiniscroll for it when enabled (Reader, theme infiniscroll, etc). 3046 originalOverflow = $('body').css('overflow'); 3047 $('body').css('overflow', 'hidden'); 3048 // prevent html from overflowing on some of the new themes. 3049 originalHOverflow = $('html').css('overflow'); 3050 $('html').css('overflow', 'hidden'); 3051 scrollPos = $( window ).scrollTop(); 3052 3053 container.data('carousel-extra', data); 3054// @start-hide-in-jetpack 3055 wpcom.carousel.stat( ['open', 'view_image'] ); 3056// @end-hide-in-jetpack 3057 3058 return this.each(function() { 3059 // If options exist, lets merge them 3060 // with our default settings 3061 var $this = $(this); 3062 3063 if ( options ) { 3064 $.extend( settings, options ); 3065 } 3066 if ( -1 === settings.start_index ) { 3067 settings.start_index = 0; //-1 returned if can't find index, so start from beginning 3068 } 3069 3070 container.trigger('jp_carousel.beforeOpen').fadeIn('fast',function(){ 3071 container.trigger('jp_carousel.afterOpen'); 3072 gallery 3073 .jp_carousel('initSlides', $this.find(settings.items_selector), settings.start_index) 3074 .jp_carousel('selectSlideAtIndex', settings.start_index); 3075 }); 3076 gallery.html(''); 3077 }); 3078 }, 3079 3080 selectSlideAtIndex : function(index){ 3081 var slides = this.jp_carousel('slides'), selected = slides.eq(index); 3082 3083 if ( 0 === selected.length ) { 3084 selected = slides.eq(0); 3085 } 3086 3087 gallery.jp_carousel('selectSlide', selected, false); 3088 return this; 3089 }, 3090 3091 close : function(){ 3092 // make sure to let the page scroll again 3093 $('body').css('overflow', originalOverflow); 3094 $('html').css('overflow', originalHOverflow); 3095 this.jp_carousel( 'clearCommentTextAreaValue' ); 3096 return container 3097 .trigger('jp_carousel.beforeClose') 3098 .fadeOut('fast', function(){ 3099 container.trigger('jp_carousel.afterClose'); 3100 $( window ).scrollTop( scrollPos ); 3101 }); 3102 3103 }, 3104 3105 next : function() { 3106 this.jp_carousel( 'previousOrNext', 'nextSlide' ); 3107 gallery.jp_carousel( 'hide_reblog_box' ); // @hide-in-jetpack 3108 }, 3109 3110 previous : function() { 3111 this.jp_carousel( 'previousOrNext', 'prevSlide' ); 3112 gallery.jp_carousel( 'hide_reblog_box' ); // @hide-in-jetpack 3113 }, 3114 3115 previousOrNext : function ( slideSelectionMethodName ) { 3116 if ( ! this.jp_carousel( 'hasMultipleImages' ) ) { 3117 return false;
3118 } 3119 3120 var slide = gallery.jp_carousel( slideSelectionMethodName ); 3121 3122 if ( slide ) { 3123 container.animate( { scrollTop: 0 }, 'fast' ); 3124 this.jp_carousel( 'clearCommentTextAreaValue' ); 3125 this.jp_carousel( 'selectSlide', slide ); 3126 wpcom.carousel.stat( ['previous', 'view_image'] ); // @hide-in-jetpack 3127 } 3128 }, 3129 3130 // @start-hide-in-jetpack 3131 resetButtons : function(current) { 3132 if ( current.data( 'reblogged' ) ) { 3133 $('.jp-carousel-buttons a.jp-carousel-reblog').addClass( 'reblogged' ).text( jetpackCarouselStrings.reblogged ); 3134 } else { 3135 $('.jp-carousel-buttons a.jp-carousel-reblog').removeClass( 'reblogged' ).text( jetpackCarouselStrings.reblog ); 3136 } 3137 // Must also take care of reblog/reblogged here 3138 }, 3139 // @end-hide-in-jetpack 3140 3141 3142 selectedSlide : function(){ 3143 return this.find('.selected'); 3144 }, 3145 3146 setSlidePosition : function(x) { 3147 transitionBegin = Date.now(); 3148 3149 return this.css({ 3150 '-webkit-transform':'translate3d(' + x + 'px,0,0)', 3151 '-moz-transform':'translate3d(' + x + 'px,0,0)', 3152 '-ms-transform':'translate(' + x + 'px,0)', 3153 '-o-transform':'translate(' + x + 'px,0)', 3154 'transform':'translate3d(' + x + 'px,0,0)' 3155 }); 3156 }, 3157 3158 updateSlidePositions : function(animate) { 3159 var current = this.jp_carousel( 'selectedSlide' ), 3160 galleryWidth = gallery.width(), 3161 currentWidth = current.width(), 3162 previous = gallery.jp_carousel( 'prevSlide' ), 3163 next = gallery.jp_carousel( 'nextSlide' ), 3164 previousPrevious = previous.prev(), 3165 nextNext = next.next(), 3166 left = Math.floor( ( galleryWidth - currentWidth ) * 0.5 ); 3167 3168 current.jp_carousel( 'setSlidePosition', left ).show(); 3169 3170 // minimum width 3171 gallery.jp_carousel( 'fitInfo', animate ); 3172 3173 // prep the slides 3174 var direction = lastSelectedSlide.is( current.prevAll() ) ? 1 : -1; 3175 3176 // Since we preload the `previousPrevious` and `nextNext` slides, we need 3177 // to make sure they technically visible in the DOM, but invisible to the 3178 // user. To hide them from the user, we position them outside the edges 3179 // of the window. 3180 // 3181 // This section of code only applies when there are more than three 3182 // slides. Otherwise, the `previousPrevious` and `nextNext` slides will 3183 // overlap with the `previous` and `next` slides which must be visible 3184 // regardless. 3185 if ( 1 === direction ) { 3186 if ( ! nextNext.is( previous ) ) { 3187 nextNext.jp_carousel( 'setSlidePosition', galleryWidth + next.width() ).show(); 3188 } 3189 3190 if ( ! previousPrevious.is( next ) ) { 3191 previousPrevious.jp_carousel( 'setSlidePosition', -previousPrevious.width() - currentWidth ).show(); 3192 } 3193 } else { 3194 if ( ! nextNext.is( previous ) ) { 3195 nextNext.jp_carousel( 'setSlidePosition', galleryWidth + currentWidth ).show(); 3196 } 3197 } 3198 3199 previous.jp_carousel( 'setSlidePosition', Math.floor( -previous.width() + ( screenPadding * 0.75 ) ) ).show(); 3200 next.jp_carousel( 'setSlidePosition', Math.ceil( galleryWidth - ( screenPadding * 0.75 ) ) ).show(); 3201 }, 3202 3203 selectSlide : function(slide, animate){ 3204 lastSelectedSlide = this.find( '.selected' ).removeClass( 'selected' ); 3205 3206 var slides = gallery.jp_carousel( 'slides' ).css({ 'position': 'fixed' }), 3207 current = $( slide ).addClass( 'selected' ).css({ 'position': 'relative' }), 3208 attachmentId = current.data( 'attachment-id' ), 3209 previous = gallery.jp_carousel( 'prevSlide' ), 3210 next = gallery.jp_carousel( 'nextSlide' ), 3211 previousPrevious = previous.prev(), 3212 nextNext = next.next(), 3213 animated, 3214 captionHtml; 3215 3216 // center the main image 3217 gallery.jp_carousel( 'loadFullImage', current ); 3218 3219 caption.hide(); 3220 3221 if ( next.length === 0 && slides.length <= 2 ) { 3222 $( '.jp-carousel-next-button' ).hide(); 3223 } else { 3224 $( '.jp-carousel-next-button' ).show(); 3225 } 3226 3227 if ( previous.length === 0 && slides.length <= 2 ) { 3228 $( '.jp-carousel-previous-button' ).hide(); 3229 } else { 3230 $( '.jp-carousel-previous-button' ).show(); 3231 } 3232 3233 animated = current 3234 .add( previous ) 3235 .add( previousPrevious ) 3236 .add( next ) 3237 .add( nextNext ) 3238 .jp_carousel( 'loadSlide' ); 3239 3240 // slide the whole view to the x we want 3241 slides.not( animated ).hide(); 3242 3243 gallery.jp_carousel( 'updateSlidePositions', animate ); 3244 3245 gallery.jp_carousel( 'resetButtons', current ); // @hide-in-jetpack 3246 container.trigger( 'jp_carousel.selectSlide', [current] ); 3247 3248 gallery.jp_carousel( 'getTitleDesc', { 3249 title: current.data( 'title' ), 3250 desc: current.data( 'desc' ) 3251 }); 3252 3253 var imageMeta = current.data( 'image-meta' ); 3254 gallery.jp_carousel( 'updateExif', imageMeta ); 3255 gallery.jp_carousel( 'updateFullSizeLink', current ); 3256 gallery.jp_carousel( 'updateMap', imageMeta ); 3257 gallery.jp_carousel( 'testCommentsOpened', current.data( 'comments-opened' ) ); 3258 gallery.jp_carousel( 'getComments', { 3259 'attachment_id': attachmentId, 3260 'offset': 0, 3261 'clear': true 3262 });
3263 $( '#jp-carousel-comment-post-results' ).slideUp(); 3264 3265 // $('<div />').text(sometext).html() is a trick to go to HTML to plain 3266 // text (including HTML entities decode, etc) 3267 if ( current.data( 'caption' ) ) { 3268 captionHtml = $( '<div />' ).text( current.data( 'caption' ) ).html(); 3269 3270 if ( captionHtml === $( '<div />' ).text( current.data( 'title' ) ).html() ) { 3271 $( '.jp-carousel-titleanddesc-title' ).fadeOut( 'fast' ).empty(); 3272 } 3273 3274 if ( captionHtml === $( '<div />' ).text( current.data( 'desc' ) ).html() ) { 3275 $( '.jp-carousel-titleanddesc-desc' ).fadeOut( 'fast' ).empty(); 3276 } 3277 3278 caption.html( current.data( 'caption' ) ).fadeIn( 'slow' ); 3279 } else { 3280 caption.fadeOut( 'fast' ).empty(); 3281 } 3282 3283 // Record pageview in WP Stats, for each new image loaded full-screen. 3284 if ( jetpackCarouselStrings.stats ) { 3285 new Image().src = document.location.protocol + 3286 'https://pixel.wp.com/g.gif?' + 3287 jetpackCarouselStrings.stats + 3288 '&post=' + encodeURIComponent( attachmentId ) + 3289 '&rand=' + Math.random(); 3290 } 3291 3292 wpcom.carousel.pageview( attachmentId ); // @hide-in-jetpack 3293 3294 // Load the images for the next and previous slides. 3295 $( next ).add( previous ).each( function() { 3296 gallery.jp_carousel( 'loadFullImage', $( this ) ); 3297 }); 3298 3299 window.location.hash = last_known_location_hash = '#jp-carousel-' + attachmentId; 3300 }, 3301 3302 slides : function(){ 3303 return this.find('.jp-carousel-slide'); 3304 }, 3305 3306 slideDimensions : function(){ 3307 return { 3308 width: $(window).width() - (screenPadding * 2), 3309 height: Math.floor( $(window).height() / 100 * proportion - 60 ) 3310 }; 3311 }, 3312 3313 loadSlide : function() { 3314 return this.each(function(){ 3315 var slide = $(this); 3316 slide.find('img') 3317 .one('load', function(){ 3318 // set the width/height of the image if it's too big 3319 slide 3320 .jp_carousel('fitSlide',false); 3321 }); 3322 }); 3323 }, 3324 3325 bestFit : function(){ 3326 var max = gallery.jp_carousel('slideDimensions'), 3327 orig = this.jp_carousel('originalDimensions'), 3328 orig_ratio = orig.width / orig.height, 3329 w_ratio = 1, 3330 h_ratio = 1, 3331 width, height; 3332 3333 if ( orig.width > max.width ) { 3334 w_ratio = max.width / orig.width; 3335 } 3336 if ( orig.height > max.height ) { 3337 h_ratio = max.height / orig.height; 3338 } 3339 3340 if ( w_ratio < h_ratio ) { 3341 width = max.width; 3342 height = Math.floor( width / orig_ratio ); 3343 } else if ( h_ratio < w_ratio ) { 3344 height = max.height; 3345 width = Math.floor( height * orig_ratio ); 3346 } else { 3347 width = orig.width; 3348 height = orig.height; 3349 } 3350 3351 return { 3352 width: width, 3353 height: height 3354 }; 3355 }, 3356 3357 fitInfo : function(/*animated*/){ 3358 var current = this.jp_carousel('selectedSlide'), 3359 size = current.jp_carousel('bestFit'); 3360 3361 photo_info.css({ 3362 'left' : Math.floor( (info.width() - size.width) * 0.5 ), 3363 'width' : Math.floor( size.width ) 3364 }); 3365 3366 return this; 3367 }, 3368 3369 fitMeta : function(animated){ 3370 var newInfoTop = { top: Math.floor( $(window).height() / 100 * proportion + 5 ) + 'px' }; 3371 var newLeftWidth = { width: ( info.width() - (imageMeta.width() + 80) ) + 'px' }; 3372 3373 if (animated) { 3374 info.animate(newInfoTop); 3375 leftColWrapper.animate(newLeftWidth); 3376 } else { 3377 info.animate(newInfoTop); 3378 leftColWrapper.css(newLeftWidth); 3379 } 3380 }, 3381 3382 fitSlide : function(/*animated*/){ 3383 return this.each(function(){ 3384 var $this = $(this), 3385 dimensions = $this.jp_carousel('bestFit'), 3386 method = 'css', 3387 max = gallery.jp_carousel('slideDimensions'); 3388 3389 dimensions.left = 0; 3390 dimensions.top = Math.floor( (max.height - dimensions.height) * 0.5 ) + 40; 3391 $this[method](dimensions); 3392 }); 3393 }, 3394 3395 texturize : function(text) { 3396 text = '' + text; // make sure we get a string. Title "1" came in as int 1, for example, which did not support .replace(). 3397 text = text.replace(/'/g, '’').replace(/'/g, '’').replace(/[\u2019]/g, '’'); 3398 text = text.replace(/"/g, '”').replace(/"/g, '”').replace(/"/g, '”').replace(/[\u201D]/g, '”'); 3399 text = text.replace(/([\w]+)=&#[\d]+;(.+?)&#[\d]+;/g, '$1="$2"'); // untexturize allowed HTML tags params double-quotes 3400 return $.trim(text); 3401 }, 3402 3403 initSlides : function(items, start_index){ 3404 if ( items.length < 2 ) { 3405 $( '.jp-carousel-next-button, .jp-carousel-previous-button' ).hide(); 3406 } else { 3407 $( '.jp-carousel-next-button, .jp-carousel-previous-button' ).show(); 3408 } 3409 3410 // Calculate the new src. 3411 items.each(function(/*i*/){ 3412 var src_item = $(this), 3413 orig_size = src_item.data('orig-size') || '', 3414 max = gallery.jp_carousel('slideDimensions'), 3415 parts = orig_size.split(','), 3416 medium_file = src_item.data('medium-file') || '', 3417 large_file = src_item.data('large-file') || '', 3418 src; 3419 orig_size = {width: parseInt(parts[0], 10), height: parseInt(parts[1], 10)}; 3420 3421// @start-hide-in-jetpack 3422 if ( 'undefined' !== typeof wpcom ) { 3423 src = src_item.attr('src') || src_item.attr('original') || src_item.data('original') || src_item.data('lazy-src'); 3424 if (src.indexOf('imgpress') !== -1) { 3425 src = src_item.data('orig-file'); 3426 } 3427 src = wpcom.carousel.addWidthToImageURL( src, wpcom.carousel.findFirstLargeEnoughWidth( orig_size.width, orig_size.height, max.width, max.height ) ); 3428 } else { 3429 3430// @end-hide-in-jetpack 3431 src = src_item.data('orig-file'); 3432 3433 src = gallery.jp_carousel('selectBestImageSize', { 3434 orig_file : src, 3435 orig_width : orig_size.width, 3436 orig_height : orig_size.height, 3437 max_width : max.width, 3438 max_height : max.height, 3439 medium_file : medium_file, 3440 large_file : large_file 3441 }); 3442// @start-hide-in-jetpack 3443 } // end else of if ( 'undefined' != typeof wpcom ) 3444// @end-hide-in-jetpack 3445 3446 // Set the final src 3447 $(this).data( 'gallery-src', src ); 3448 }); 3449 3450 // If the start_index is not 0 then preload the clicked image first. 3451 if ( 0 !== start_index ) { 3452 $('<img/>')[0].src = $(items[start_index]).data('gallery-src'); 3453 } 3454 3455 var useInPageThumbnails = items.first().closest( '.tiled-gallery.type-rectangular' ).length > 0; 3456 3457 // create the 'slide' 3458 items.each(function(i){ 3459 var src_item = $(this), 3460 reblogged = src_item.data( 'reblogged' ) || 0, // @hide-in-jetpack 3461 attachment_id = src_item.data('attachment-id') || 0, 3462 comments_opened = src_item.data('comments-opened') || 0, 3463 image_meta = src_item.data('image-meta') || {}, 3464 orig_size = src_item.data('orig-size') || '',
3465 thumb_size = { width : src_item[0].naturalWidth, height : src_item[0].naturalHeight }, 3466 title = src_item.data('image-title') || '', 3467 description = src_item.data('image-description') || '', 3468 caption = src_item.parents('.gallery-item').find('.gallery-caption').html() || '', 3469 src = src_item.data('gallery-src') || '', 3470 medium_file = src_item.data('medium-file') || '', 3471 large_file = src_item.data('large-file') || '', 3472 orig_file = src_item.data('orig-file') || ''; 3473 3474 var tiledCaption = src_item.parents('div.tiled-gallery-item').find('div.tiled-gallery-caption').html(); 3475 if ( tiledCaption ) { 3476 caption = tiledCaption; 3477 } 3478 3479 if ( attachment_id && orig_size.length ) { 3480 title = gallery.jp_carousel('texturize', title); 3481 description = gallery.jp_carousel('texturize', description); 3482 caption = gallery.jp_carousel('texturize', caption); 3483 3484 // Initially, the image is a 1x1 transparent gif. The preview is shown as a background image on the slide itself. 3485 var image = $( '<img/>' ) 3486 .attr( 'src', 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7' ) 3487 .css( 'width', '100%' ) 3488 .css( 'height', '100%' ); 3489 3490 var slide = $('<div class="jp-carousel-slide" itemprop="associatedMedia" itemscope itemtype="https://schema.org/ImageObject"></div>') 3491 .hide() 3492 .css({ 3493 //'position' : 'fixed', 3494 'left' : i < start_index ? -1000 : gallery.width() 3495 }) 3496 .append( image ) 3497 .appendTo(gallery) 3498 .data('src', src ) 3499 .data('title', title) 3500 .data('desc', description) 3501 .data('caption', caption) 3502 .data('attachment-id', attachment_id) 3503 .data('permalink', src_item.parents('a').attr('href')) 3504 .data('orig-size', orig_size) 3505 .data('comments-opened', comments_opened) 3506 .data('image-meta', image_meta) 3507 .data('medium-file', medium_file) 3508 .data('large-file', large_file) 3509 .data('orig-file', orig_file) 3510 .data('thumb-size', thumb_size) 3511 .data( 'reblogged', reblogged ) // @hide-in-jetpack 3512 ; 3513 3514 if ( useInPageThumbnails ) { 3515 // Use the image already loaded in the gallery as a preview. 3516 slide 3517 .data( 'preview-image', src_item.attr( 'src' ) ) 3518 .css( { 3519 'background-image' : 'url("' + src_item.attr( 'src' ) + '")', 3520 'background-size' : '100% 100%', 3521 'background-position' : 'center center' 3522 } ); 3523 } 3524 3525 slide.jp_carousel( 'fitSlide', false ); 3526 } 3527 }); 3528 return this; 3529 }, 3530 3531 selectBestImageSize: function(args) { 3532 if ( 'object' !== typeof args ) { 3533 args = {}; 3534 } 3535 3536 if ( 'undefined' === typeof args.orig_file ) { 3537 return ''; 3538 } 3539 3540 if ( 'undefined' === typeof args.orig_width || 'undefined' === typeof args.max_width ) { 3541 return args.orig_file; 3542 } 3543 3544 if ( 'undefined' === typeof args.medium_file || 'undefined' === typeof args.large_file ) { 3545 return args.orig_file; 3546 } 3547 3548 // Check if the image is being served by Photon (using a regular expression on the hostname). 3549 3550 var imageLinkParser = document.createElement( 'a' ); 3551 imageLinkParser.href = args.large_file; 3552 3553 var isPhotonUrl = ( imageLinkParser.hostname.match( /^i[\d]{1}.wp.com$/i ) != null ); 3554 3555 var medium_size_parts = gallery.jp_carousel( 'getImageSizeParts', args.medium_file, args.orig_width, isPhotonUrl ); 3556 var large_size_parts = gallery.jp_carousel( 'getImageSizeParts', args.large_file, args.orig_width, isPhotonUrl ); 3557 3558 var large_width = parseInt( large_size_parts[0], 10 ), 3559 large_height = parseInt( large_size_parts[1], 10 ), 3560 medium_width = parseInt( medium_size_parts[0], 10 ), 3561 medium_height = parseInt( medium_size_parts[1], 10 ); 3562 3563 // Assign max width and height. 3564 args.orig_max_width = args.max_width; 3565 args.orig_max_height = args.max_height; 3566 3567 // Give devices with a higher devicePixelRatio higher-res images (Retina display = 2, Android phones = 1.5, etc) 3568 if ( 'undefined' !== typeof window.devicePixelRatio && window.devicePixelRatio > 1 ) { 3569 args.max_width = args.max_width * window.devicePixelRatio; 3570 args.max_height = args.max_height * window.devicePixelRatio; 3571 } 3572 3573 if ( large_width >= args.max_width || large_height >= args.max_height ) { 3574 return args.large_file; 3575 } 3576 3577 if ( medium_width >= args.max_width || medium_height >= args.max_height ) { 3578 return args.medium_file; 3579 } 3580 3581 if ( isPhotonUrl ) { 3582 // args.orig_file doesn't point to a Photon url, so in this case we use args.large_file 3583 // to return the photon url of the original image. 3584 var largeFileIndex = args.large_file.lastIndexOf( '?' ); 3585 var origPhotonUrl = args.large_file; 3586 if ( -1 !== largeFileIndex ) { 3587 origPhotonUrl = args.large_file.substring( 0, largeFileIndex ); 3588 // If we have a really large image load a smaller version 3589 // that is closer to the viewable size 3590 if ( args.orig_width > args.max_width || args.orig_height > args.max_height ) { 3591 origPhotonUrl += '?fit=' + args.orig_max_width + '%2C' + args.orig_max_height; 3592 } 3593 } 3594 return origPhotonUrl; 3595 } 3596 3597 return args.orig_file; 3598 }, 3599 3600 getImageSizeParts: function( file, orig_width, isPhotonUrl ) { 3601 var size = isPhotonUrl ? 3602 file.replace( /.*=([\d]+%2C[\d]+).*$/, '$1' ) : 3603 file.replace( /.*-([\d]+x[\d]+)\..+$/, '$1' ); 3604 3605 var size_parts = ( size !== file ) ? 3606 ( isPhotonUrl ? size.split( '%2C' ) : size.split( 'x' ) ) : 3607 [ orig_width, 0 ]; 3608 3609 // If one of the dimensions is set to 9999, then the actual value of that dimension can't be retrieved from the url. 3610 // In that case, we set the value to 0. 3611 if ( '9999' === size_parts[0] ) { 3612 size_parts[0] = '0'; 3613 } 3614 3615 if ( '9999' === size_parts[1] ) { 3616 size_parts[1] = '0'; 3617 } 3618 3619 return size_parts; 3620 }, 3621 3622// @start-hide-in-jetpack 3623 show_reblog_box: function() { 3624 $('#carousel-reblog-box textarea').val(jetpackCarouselStrings.reblog_add_thoughts); 3625 //t.addClass('selected'); 3626 $('#carousel-reblog-box p.response').remove(); 3627 $('#carousel-reblog-box div.submit, #carousel-reblog-box div.submit span.canceltext').show(); 3628 $('#carousel-reblog-box div.submit input[type=submit]').prop('disabled', false); 3629 3630 var current = $('.jp-carousel div.selected'); 3631 $('#carousel-reblog-box input#carousel-reblog-post-url').val( current.data('permalink') ); 3632 $('#carousel-reblog-box input#carousel-reblog-post-title').val( $('div.jp-carousel-info').children('h2').text() ); 3633 3634 $('div.jp-carousel-info').append( $('#carousel-reblog-box') ).children().fadeOut('fast'); 3635 $('#carousel-reblog-box').fadeIn('fast'); 3636 }, 3637 3638 hide_reblog_box: function () { 3639 $( 'div.jp-carousel-info' ).children().not( '#carousel-reblog-box' ).fadeIn( 'fast' ); 3640 $( '#carousel-reblog-box' ).fadeOut( 'fast' ); 3641 }, 3642// @end-hide-in-jetpack 3643 3644 originalDimensions: function() { 3645 var splitted = $(this).data('orig-size').split(','); 3646 return {width: parseInt(splitted[0], 10), height: parseInt(splitted[1], 10)}; 3647 }, 3648 3649 format: function( args ) { 3650 if ( 'object' !== typeof args ) { 3651 args = {}; 3652 } 3653 if ( ! args.text || 'undefined' === typeof args.text ) { 3654 return; 3655 } 3656 if ( ! args.replacements || 'undefined' === typeof args.replacements ) { 3657 return args.text; 3658 } 3659 return args.text.replace(/{(\d+)}/g, function( match, number ) { 3660 return typeof args.replacements[number] !== 'undefined' ? args.replacements[number] : match; 3661 }); 3662 }, 3663 3664 /** 3665 * Returns a number in a fraction format that represents the shutter speed. 3666 * @param Number speed 3667 * @return String 3668 */ 3669 shutterSpeed: function( speed ) { 3670 var denominator; 3671 3672 // round to one decimal if value >
3672 1s by multiplying it by 10, rounding, then dividing by 10 again 3673 if ( speed >= 1 ) { 3674 return Math.round( speed * 10 ) / 10 + 's'; 3675 } 3676 3677 // If the speed is less than one, we find the denominator by inverting 3678 // the number. Since cameras usually use rational numbers as shutter 3679 // speeds, we should get a nice round number. Or close to one in cases 3680 // like 1/30. So we round it. 3681 denominator = Math.round( 1 / speed ); 3682 3683 return '1/' + denominator + 's'; 3684 }, 3685 3686 parseTitleDesc: function( value ) { 3687 if ( !value.match(' ') && value.match('_') ) { 3688 return ''; 3689 } 3690 // Prefix list originally based on http://commons.wikimedia.org/wiki/MediaWiki:Filename-prefix-blacklist 3691 $([ 3692 'CIMG', // Casio 3693 'DSC_', // Nikon 3694 'DSCF', // Fuji 3695 'DSCN', // Nikon 3696 'DUW', // some mobile phones 3697 'GEDC', // GE 3698 'IMG', // generic 3699 'JD', // Jenoptik 3700 'MGP', // Pentax 3701 'PICT', // misc. 3702 'Imagen', // misc. 3703 'Foto', // misc. 3704 'DSC', // misc. 3705 'Scan', // Scanners 3706 'SANY', // Sanyo 3707 'SAM', // Samsung 3708 'Screen Shot [0-9]+' // Mac screenshots 3709 ]) 3710 .each(function(key, val){ 3711 var regex = new RegExp('^' + val); 3712 if ( regex.test(value) ) { 3713 value = ''; 3714 return; 3715 } 3716 }); 3717 return value; 3718 }, 3719 3720 getTitleDesc: function( data ) { 3721 var title ='', desc = '', markup = '', target; 3722 3723 target = $( 'div.jp-carousel-titleanddesc', 'div.jp-carousel-wrap' ); 3724 target.hide(); 3725 3726 title = gallery.jp_carousel('parseTitleDesc', data.title) || ''; 3727 desc = gallery.jp_carousel('parseTitleDesc', data.desc) || ''; 3728 3729 if ( title.length || desc.length ) { 3730 // Convert from HTML to plain text (including HTML entities decode, etc) 3731 if ( $('<div />').html( title ).text() === $('<div />').html( desc ).text() ) { 3732 title = ''; 3733 } 3734 3735 markup = ( title.length ) ? '<div class="jp-carousel-titleanddesc-title">' + title + '</div>' : ''; 3736 markup += ( desc.length ) ? '<div class="jp-carousel-titleanddesc-desc">' + desc + '</div>' : ''; 3737 3738 target.html( markup ).fadeIn('slow'); 3739 } 3740 3741 $( 'div#jp-carousel-comment-form-container' ).css('margin-top', '20px'); 3742 $( 'div#jp-carousel-comments-loading' ).css('margin-top', '20px'); 3743 }, 3744 3745 // updateExif updates the contents of the exif UL (.jp-carousel-image-exif) 3746 updateExif: function( meta ) { 3747 if ( !meta || 1 !== Number( jetpackCarouselStrings.display_exif ) ) { 3748 return false; 3749 } 3750 3751 var $ul = $( '<ul class=\'jp-carousel-image-exif\'></ul>' ); 3752 3753 $.each( meta, function( key, val ) { 3754 if ( 0 === parseFloat(val) || !val.length || -1 === $.inArray( key, $.makeArray( jetpackCarouselStrings.meta_data ) ) ) { 3755 return; 3756 } 3757 3758 switch( key ) { 3759 case 'focal_length': 3760 val = val + 'mm'; 3761 break; 3762 case 'shutter_speed': 3763 val = gallery.jp_carousel('shutterSpeed', val); 3764 break; 3765 case 'aperture': 3766 val = 'f/' + val; 3767 break; 3768 } 3769 3770 $ul.append( '<li><h5>' + jetpackCarouselStrings[key] + '</h5>' + val + '</li>' ); 3771 }); 3772 3773 // Update (replace) the content of the ul 3774 $( 'div.jp-carousel-image-meta ul.jp-carousel-image-exif' ).replaceWith( $ul ); 3775 }, 3776 3777 // updateFullSizeLink updates the contents of the jp-carousel-image-download link 3778 updateFullSizeLink: function(current) { 3779 if(!current || !current.data) { 3780 return false; 3781 } 3782 var original, 3783 origSize = current.data('orig-size').split(',' ), 3784 imageLinkParser = document.createElement( 'a' ); 3785 3786 imageLinkParser.href = current.data( 'src' ).replace( /\?.+$/, '' ); 3787 3788 // Is this a Photon URL? 3789 if ( imageLinkParser.hostname.match( /^i[\d]{1}.wp.com$/i ) !== null ) { 3790 original = imageLinkParser.href; 3791 } else { 3792 original = current.data('orig-file').replace(/\?.+$/, ''); 3793 } 3794 3795 var permalink = $( '<a>'+gallery.jp_carousel('format', {'text': jetpackCarouselStrings.download_original, 'replacements': origSize})+'</a>' ) 3796 .addClass( 'jp-carousel-image-download' ) 3797 .attr( 'href', original ) 3798 .attr( 'target', '_blank' ); 3799
3800 // Update (replace) the content of the anchor 3801 $( 'div.jp-carousel-image-meta a.jp-carousel-image-download' ).replaceWith( permalink ); 3802 }, 3803 3804 updateMap: function( meta ) { 3805 if ( !meta.latitude || !meta.longitude || 1 !== Number( jetpackCarouselStrings.display_geo ) ) { 3806 return; 3807 } 3808 3809 var latitude = meta.latitude, 3810 longitude = meta.longitude, 3811 $metabox = $( 'div.jp-carousel-image-meta', 'div.jp-carousel-wrap' ), 3812 $mapbox = $( '<div></div>' ), 3813 style = '&scale=2&style=feature:all|element:all|invert_lightness:true|hue:0x0077FF|saturation:-50|lightness:-5|gamma:0.91'; 3814 3815 $mapbox 3816 .addClass( 'jp-carousel-image-map' ) 3817 .html( '<img width="154" height="154" src="https://maps.googleapis.com/maps/api/staticmap?\ 3818 center=' + latitude + ',' + longitude + '&\ 3819 zoom=8&\ 3820 size=154x154&\ 3821 sensor=false&\ 3822 markers=size:medium%7Ccolor:blue%7C' + latitude + ',' + longitude + style +'" class="gmap-main" />\ 3823 \ 3824 <div class="gmap-topright"><div class="imgclip"><img width="175" height="154" src="https://maps.googleapis.com/maps/api/staticmap?\ 3825 center=' + latitude + ',' + longitude + '&\ 3826 zoom=3&\ 3827 size=175x154&\ 3828 sensor=false&\ 3829 markers=size:small%7Ccolor:blue%7C' + latitude + ',' + longitude + style + '"c /></div></div>\ 3830 \ 3831 ' ) 3832 .prependTo( $metabox ); 3833 }, 3834 3835 testCommentsOpened: function( opened ) { 3836 if ( 1 === parseInt( opened, 10 ) ) { 3837// @start-hide-in-jetpack 3838 if ( 1 === Number( jetpackCarouselStrings.is_logged_in ) ) { 3839 $('.jp-carousel-commentlink').fadeIn('fast'); 3840 } else { 3841// @end-hide-in-jetpack 3842 $('.jp-carousel-buttons').fadeIn('fast'); 3843// @start-hide-in-jetpack 3844 } 3845// @end-hide-in-jetpack 3846 commentForm.fadeIn('fast'); 3847 } else { 3848// @start-hide-in-jetpack 3849 if ( 1 === Number( jetpackCarouselStrings.is_logged_in ) ) { 3850 $('.jp-carousel-commentlink').fadeOut('fast'); 3851 } else { 3852// @end-hide-in-jetpack 3853 $('.jp-carousel-buttons').fadeOut('fast'); 3854// @start-hide-in-jetpack 3855 } 3856// @end-hide-in-jetpack 3857 commentForm.fadeOut('fast'); 3858 } 3859 }, 3860 3861 getComments: function( args ) { 3862 clearInterval( commentInterval ); 3863 3864 if ( 'object' !== typeof args ) { 3865 return; 3866 } 3867 3868 if ( 'undefined' === typeof args.attachment_id || ! args.attachment_id ) { 3869 return; 3870 } 3871 3872 if ( ! args.offset || 'undefined' === typeof args.offset || args.offset < 1 ) { 3873 args.offset = 0; 3874 } 3875 3876 var comments = $('.jp-carousel-comments'), 3877 commentsLoading = $('#jp-carousel-comments-loading').show(); 3878 3879 if ( args.clear ) { 3880 comments.hide().empty(); 3881 } 3882 3883 $.ajax({ 3884 type: 'GET', 3885 url: jetpackCarouselStrings.ajaxurl, 3886 dataType: 'json', 3887 data: { 3888 action: 'get_attachment_comments', 3889 nonce: jetpackCarouselStrings.nonce, 3890 id: args.attachment_id, 3891 offset: args.offset 3892 }, 3893 success: function(data/*, status, xhr*/) { 3894 if ( args.clear ) { 3895 comments.fadeOut('fast').empty(); 3896 } 3897 3898 $( data ).each(function(){ 3899 var comment = $('<div></div>') 3900 .addClass('jp-carousel-comment') 3901 .attr('id', 'jp-carousel-comment-' + this['id']) 3902 .html( 3903 '<div class="comment-gravatar">' + 3904 this['gravatar_markup'] + 3905 '</div>' + 3906 '<div class="comment-author">' + 3907 this['author_markup'] + 3908 '</div>' + 3909 '<div class="comment-date">' + 3910 this['date_gmt'] + 3911 '</div>' + 3912 '<div class="comment-content">' + 3913 this['content'] + 3914 '</div>' 3915 ); 3916 comments.append(comment); 3917 3918 // Set the interval to check for a new page of comments. 3919 clearInterval( commentInterval ); 3920 commentInterval = setInterval( function() { 3921 if ( ( $('.jp-carousel-overlay').height() - 150 ) < $('.jp-carousel-wrap').scrollTop() + $(window).height() ) { 3922 gallery.jp_carousel('getComments',{ attachment_id: args.attachment_id, offset: args.offset + 10, clear: false }); 3923 clearInterval( commentInterval ); 3924 } 3925 }, 300 ); 3926 }); 3927 3928 // Verify (late) that the user didn't repeatldy click the arrows really fast, in which case the requested 3929 // attachment id might no longer match the current attachment id by the time we get the data back or a now 3930 // registered infiniscroll event kicks in, so we don't ever display comments for the wrong image by mistake. 3931 var current = $('.jp-carousel div.selected'); 3932 if ( current && current.data && current.data('attachment-id') != args.attachment_id ) { // jshint ignore:line 3933 comments.fadeOut('fast'); 3934 comments.empty(); 3935 return; 3936 } 3937 3938 // Increase the height of the background, semi-transparent overlay to match the new length of the comments list. 3939 $('.jp-carousel-overlay').height( $(window).height() + titleAndDescription.height() + commentForm.height() + ( (comments.height() > 0) ? comments.height() : imageMeta.height() ) + 200 ); 3940 3941 comments.show(); 3942 commentsLoading.hide(); 3943 }, 3944 error: function(xhr, status, error) { 3945 // TODO: proper error handling 3946 console.log( 'Comment get fail...', xhr, status, error ); 3947 comments.fadeIn('fast'); 3948 commentsLoading.fadeOut('fast'); 3949 } 3950 }); 3951 }, 3952 3953 postCommentError: function(args) { 3954 if ( 'object' !== typeof args ) { 3955 args = {}; 3956 } 3957 if ( ! args.field || 'undefined' === typeof args.field || ! args.error || 'undefined' === typeof args.error ) { 3958 return; 3959 }
3960 $('#jp-carousel-comment-post-results').slideUp('fast').html('<span class="jp-carousel-comment-post-error">'+args.error+'</span>').slideDown('fast'); 3961 $('#jp-carousel-comment-form-spinner').spin(false); 3962 }, 3963 3964 setCommentIframeSrc: function(attachment_id) { 3965 var iframe = $('#jp-carousel-comment-iframe'); 3966 // Set the proper irame src for the current attachment id 3967 if (iframe && iframe.length) { 3968 iframe.attr('src', iframe.attr('src').replace(/(postid=)\d+/, '$1'+attachment_id) ); 3969 iframe.attr('src', iframe.attr('src').replace(/(%23.+)?$/, '%23jp-carousel-'+attachment_id) ); 3970 } 3971 }, 3972 3973 clearCommentTextAreaValue: function() { 3974 var commentTextArea = $('#jp-carousel-comment-form-comment-field'); 3975 if ( commentTextArea ) { 3976 commentTextArea.val(''); 3977 } 3978 }, 3979 3980 nextSlide : function () { 3981 var slides = this.jp_carousel( 'slides' ); 3982 var selected = this.jp_carousel( 'selectedSlide' ); 3983 3984 if ( selected.length === 0 || ( slides.length > 2 && selected.is( slides.last() ) ) ) { 3985 return slides.first(); 3986 } 3987 3988 return selected.next(); 3989 }, 3990 3991 prevSlide : function () { 3992 var slides = this.jp_carousel( 'slides' ); 3993 var selected = this.jp_carousel( 'selectedSlide' ); 3994 3995 if ( selected.length === 0 || ( slides.length > 2 && selected.is( slides.first() ) ) ) { 3996 return slides.last(); 3997 } 3998 3999 return selected.prev(); 4000 }, 4001 4002 loadFullImage : function ( slide ) { 4003 var image = slide.find( 'img:first' ); 4004 4005 if ( ! image.data( 'loaded' ) ) { 4006 // If the width of the slide is smaller than the width of the "thumbnail" we're already using, 4007 // don't load the full image. 4008 4009 image.on( 'load.jetpack', function () { 4010 image.off( 'load.jetpack' ); 4011 $( this ).closest( '.jp-carousel-slide' ).css( 'background-image', '' ); 4012 } ); 4013 4014 if ( ! slide.data( 'preview-image' ) || ( slide.data( 'thumb-size' ) && slide.width() > slide.data( 'thumb-size' ).width ) ) { 4015 image.attr( 'src', image.closest( '.jp-carousel-slide' ).data( 'src' ) ).attr('itemprop', 'image'); 4016 } else { 4017 image.attr( 'src', slide.data( 'preview-image' ) ).attr('itemprop', 'image'); 4018 } 4019 4020 image.data( 'loaded', 1 ); 4021 } 4022 }, 4023 4024 hasMultipleImages : function () { 4025 return gallery.jp_carousel('slides').length > 1; 4026 } 4027 }; 4028 4029 $.fn.jp_carousel = function(method){ 4030 // ask for the HTML of the gallery 4031 // Method calling logic 4032 if ( methods[method] ) { 4033 return methods[ method ].apply( this, Array.prototype.slice.call( arguments, 1 )); 4034 } else if ( typeof method === 'object' || ! method ) { 4035 return methods.open.apply( this, arguments ); 4036 } else { 4037 $.error( 'Method ' + method + ' does not exist on jQuery.jp_carousel' ); 4038 } 4039 4040 }; 4041 4042 // register the event listener for starting the gallery 4043 $(document.body).on('click.jp-carousel', 'div.gallery, div.tiled-gallery, ul.wp-block-gallery, div.wp-block-jetpack-tiled-gallery, a.single-image-gallery', function( e ) { 4044 if ( ! $(this).jp_carousel( 'testForData', e.currentTarget ) ) { 4045 return; 4046 } 4047 4048 // Do not open the modal if we are looking at a gallery caption from before WP5, which may contain a link. 4049 if ( $(e.target).parent().hasClass('gallery-caption') ) { 4050 return; 4051 } 4052 4053 // Do not open the modal if we are looking at a caption of a gallery block, which may contain a link. 4054 if ( $(e.target).parent().is('figcaption') ) { 4055 return; 4056 } 4057 4058 e.preventDefault(); 4059 4060 // Stopping propagation in case there are parent elements 4061 // with .gallery or .tiled-gallery class 4062 e.stopPropagation(); 4063 $(this).jp_carousel('open', { start_index: $(this).find('.gallery-item, .tiled-gallery-item, .blocks-gallery-item, .tiled-gallery__item').index($(e.target).parents('.gallery-item, .tiled-gallery-item, .blocks-gallery-item, .tiled-gallery__item'))}); 4064 }); 4065 4066 // handle lightbox (single image gallery) for images linking to 'Attachment Page' 4067 if ( 1 === Number( jetpackCarouselStrings.single_image_gallery ) ) { 4068 processSingleImageGallery(); 4069 $( document.body ).on( 'post-load', function() { 4070 processSingleImageGallery(); 4071 } ); 4072 } 4073 4074 // Makes carousel work on page load and when back button leads to same URL with carousel hash (ie: no actual document.ready trigger)
4075 $( window ).on( 'hashchange.jp-carousel', function () { 4076 4077 var hashRegExp = /jp-carousel-(\d+)/, 4078 matches, attachmentId, galleries, selectedThumbnail; 4079 4080 if ( ! window.location.hash || ! hashRegExp.test( window.location.hash ) ) { 4081 if ( gallery && gallery.opened ) { 4082 container.jp_carousel( 'close' ); 4083 } 4084 4085 return; 4086 } 4087 4088 if ( ( window.location.hash === last_known_location_hash ) && gallery.opened ) { 4089 return; 4090 } 4091 4092 if ( window.location.hash && gallery && !gallery.opened && history.back) { 4093 history.back(); 4094 return; 4095 } 4096 4097 last_known_location_hash = window.location.hash; 4098 matches = window.location.hash.match( hashRegExp ); 4099 attachmentId = parseInt( matches[1], 10 ); 4100 galleries = $( 'div.gallery, div.tiled-gallery, a.single-image-gallery, ul.wp-block-gallery, div.wp-block-jetpack-tiled-gallery' ); 4101 4102 // Find the first thumbnail that matches the attachment ID in the location 4103 // hash, then open the gallery that contains it. 4104 galleries.each( function( _, galleryEl ) { 4105 $( galleryEl ).find('img').each( function( imageIndex, imageEl ) { 4106 if ( $( imageEl ).data( 'attachment-id' ) === parseInt( attachmentId, 10 ) ) { 4107 selectedThumbnail = { index: imageIndex, gallery: galleryEl }; 4108 return false; 4109 } 4110 }); 4111 4112 if ( selectedThumbnail ) { 4113 $( selectedThumbnail.gallery ) 4114 .jp_carousel( 'openOrSelectSlide', selectedThumbnail.index ); 4115 return false; 4116 } 4117 }); 4118 }); 4119 4120 if ( window.location.hash ) { 4121 $( window ).trigger( 'hashchange' ); 4122 } 4123}); 4124 4125/** 4126 * jQuery Plugin to obtain touch gestures from iPhone, iPod Touch and iPad, should also work with Android mobile phones (not tested yet!) 4127 * Common usage: wipe images (left and right to show the previous or next image) 4128 * 4129 * @author Andreas Waltl, netCU Internetagentur (http://www.netcu.de) 4130 * Version 1.1.1, modified to pass the touchmove event to the callbacks. 4131 */ 4132(function($) { 4133$.fn.touchwipe = function(settings) { 4134 var config = { 4135 min_move_x: 20, 4136 min_move_y: 20, 4137 wipeLeft: function(/*e*/) { }, 4138 wipeRight: function(/*e*/) { }, 4139 wipeUp: function(/*e*/) { }, 4140 wipeDown: function(/*e*/) { }, 4141 preventDefaultEvents: true 4142 }; 4143 4144 if (settings) { 4145 $.extend(config, settings); 4146 } 4147 4148 this.each(function() { 4149 var startX; 4150 var startY; 4151 var isMoving = false; 4152 4153 function cancelTouch() { 4154 this.removeEventListener('touchmove', onTouchMove); 4155 startX = null; 4156 isMoving = false; 4157 } 4158 4159 function onTouchMove(e) { 4160 if(config.preventDefaultEvents) { 4161 e.preventDefault(); 4162 } 4163 if(isMoving) { 4164 var x = e.touches[0].pageX; 4165 var y = e.touches[0].pageY; 4166 var dx = startX - x; 4167 var dy = startY - y; 4168 if(Math.abs(dx) >= config.min_move_x) { 4169 cancelTouch(); 4170 if(dx > 0) { 4171 config.wipeLeft(e); 4172 } else { 4173 config.wipeRight(e); 4174 } 4175 } 4176 else if(Math.abs(dy) >= config.min_move_y) { 4177 cancelTouch(); 4178 if(dy > 0) { 4179 config.wipeDown(e); 4180 } else { 4181 config.wipeUp(e); 4182 } 4183 } 4184 } 4185 } 4186 4187 function onTouchStart(e) 4188 { 4189 if (e.touches.length === 1) { 4190 startX = e.touches[0].pageX; 4191 startY = e.touches[0].pageY; 4192 isMoving = true; 4193 this.addEventListener('touchmove', onTouchMove, false); 4194 } 4195 } 4196 if ('ontouchstart' in document.documentElement) { 4197 this.addEventListener('touchstart', onTouchStart, false); 4198 } 4199 }); 4200 4201 return this; 4202}; 4203})(jQuery); 4204; 4205/* SWFObject v2.2 <http://code.google.com/p/swfobject/> 4206 is released under the MIT License <http://www.opensource.org/licenses/mit-license.php> 4207*/ 4208var 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)}}
4208else{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}}}}();; 4209/*! 4210 * VideoPress JavaScript Loader 1.09 4211 * 4212 * Copyright 2011 Automattic Inc. 4213 * Licensed under GNU General Public License (GPL) Version 2 or later 4214 * http://www.gnu.org/licenses/gpl-2.0.html 4215 */ 4216 4217// jQuery.type() was introduced in 1.4.3, WP 3.0 has 1.4.2 4218// To maintain backwards compatibility, insert our own version if it doesn't exist 4219if ( typeof jQuery.type != 'function' ) { 4220 jQuery.extend({ 4221 class2type: {}, 4222 4223 type: function( obj ) { 4224 return obj == null ? 4225 String( obj ) : 4226 jQuery.class2type[ toString.call(obj) ] || "object"; 4227 } 4228 }); 4229 4230 jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) { 4231 jQuery.class2type[ "[object " + name + "]" ] = name.toLowerCase(); 4232 }); 4233 4234} 4235 4236jQuery.extend({VideoPress: { 4237 error:{ 4238 messages:{ 4239 age:"You are of insufficient age to view this video.", 4240 error:"Unable to download and play video", 4241 flash:"Error loading Flash on your system", 4242 freedom:'You do not have sufficient <a href="http://www.gnu.org/philosophy/free-sw.html">Freedom levels</a> to view this video.', 4243 incompatible:'VideoPress requires either HTML5 video or <a href="http://www.adobe.com/go/getflashplayer">
4243Adobe Flash Player 10</a> or above for playback.', 4244 incapable:"Your device is incapable of playing the requested video.", 4245 network:"A network error prevented video download and playback" 4246 } 4247 }, 4248 support:{ 4249 flash: function() { 4250 if ( typeof swfobject !== "undefined" && swfobject.hasFlashPlayerVersion( jQuery.VideoPress.video.flash.min_version ) ) { 4251 return true; 4252 } else { 4253 return false; 4254 } 4255 }, 4256 html5Video: function(sourcetype) { 4257 var v = document.createElement("video"); 4258 if ( !!v.canPlayType ) { 4259 if ( jQuery.type(sourcetype)==="string" ) { 4260 return !!v.canPlayType(sourcetype).replace(/no/,""); 4261 } 4262 return true; 4263 } else { 4264 return false; 4265 } 4266 } 4267 }, 4268 data:[], 4269 analytics:{ 4270 wpcom:{ 4271 base_uri:"https://pixel.wp.com/v.gif?", 4272 params:function(guid, filetype) { 4273 var data = jQuery.VideoPress.data[guid]; 4274 if ( !jQuery.isPlainObject(data) ) { 4275 return; 4276 } 4277 4278 var params = {blog:data.blog,post:data.post,page_url:top.document.URL}; 4279 if ( filetype==="mp4" && data.mp4 && data.mp4.size ) { 4280 params.video_fmt = "fmt_" + data.mp4.size; 4281 } else { 4282 params.video_fmt = "fmt_std"; 4283 } 4284 return params; 4285 }, 4286 send:function(params) { 4287 var beacon = new Image(); 4288 beacon.src = jQuery.VideoPress.analytics.wpcom.base_uri + jQuery.param(params); 4289 beacon=null; 4290 } 4291 }, 4292 ga:{ 4293 is_active:function(){ 4294 if ( (typeof _gaq !== "undefined") && jQuery.type( _gaq )==="array" ) { 4295 return true; 4296 } else { 4297 return false; 4298 } 4299 } 4300 }, 4301 /*comscore:{ 4302 is_active()function(){ 4303 if ( typeof COMSCORE !== "undefined" ) 4304 return true; 4305 } 4306 }*/ 4307 impression:function(guid) { 4308 var params = jQuery.VideoPress.analytics.wpcom.params( guid, "mp4" ); 4309 if ( !jQuery.isPlainObject( params ) ) { 4310 return; 4311 } 4312 params.video_impression = 1; 4313 jQuery.VideoPress.analytics.wpcom.send( params ); 4314 }, 4315 played:function(guid, filetype) { 4316 var params = jQuery.VideoPress.analytics.wpcom.params( guid, filetype ); 4317 if ( !jQuery.isPlainObject( params ) ) { 4318 return; 4319 } 4320 params.video_play = 1; 4321 jQuery.VideoPress.analytics.wpcom.send( params ); 4322 4323 if ( jQuery.VideoPress.analytics.ga.is_active() ) { 4324 /* Google Analytics tracks unique events per visit. 4325 * Unique video value omitted since two videos on the same page that are both played would only be recorded as one play event. 4326 */ 4327 _gaq.push( ["_trackEvent", "Videos", "Play" ] ); 4328 } 4329 }, 4330 watched:function( guid, filetype, current_time, initial_time ) { 4331 if ( jQuery.VideoPress.data[guid].playback === undefined ) { 4332 var start = 0; 4333 if ( initial_time !== undefined && jQuery.type(initial_time)==="number" && initial_time > 0 ) { 4334 if ( current_time > initial_time ) { 4335 start = current_time - initial_time; 4336 } 4337 } 4338 jQuery.VideoPress.data[guid].playback = { last_observed:current_time, time_elapsed:start }; 4339 } 4340 var time_watched = current_time - jQuery.VideoPress.data[guid].playback.last_observed; 4341 if ( time_watched > 0 ) { 4342 jQuery.VideoPress.data[guid].playback.time_elapsed += time_watched; 4343 jQuery.VideoPress.data[guid].playback.last_observed = current_time; 4344 if ( jQuery.VideoPress.data[guid].playback.time_elapsed > 15 ) { 4345 var params = jQuery.VideoPress.analytics.wpcom.params( guid, filetype ); 4346 if ( !jQuery.isPlainObject( params ) ) { 4347 return; 4348 } 4349 params.t = 15; 4350 jQuery.VideoPress.analytics.wpcom.send( params ); 4351 jQuery.VideoPress.data[guid].playback.time_elapsed -= 15; 4352 } else if ( current_time === jQuery.VideoPress.data[guid].duration ) { 4353 jQuery.VideoPress.analytics.wpcom.send( params ); 4354 jQuery.VideoPress.data[guid].playback.time_elapsed = 0; 4355 delete jQuery.VideoPress.data[guid].playback; 4356 } 4357 } 4358 } 4359 }, 4360 requirements:{ 4361 isSufficientAge: function( container_el, min_age ) { 4362 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() ) ); 4363 var allowed_age = new Date( Date.now() - (1000*60*60*24*365*min_age) ); 4364 if ( birthday > allowed_age ) { 4365 container_el.html( '<p class="error" style="color:#fff;font-weight:bold">' + jQuery.VideoPress.error.messages.age + "</p>"); 4366 } else { 4367 jQuery.VideoPress.video.play(container_el); 4368 } 4369 }, 4370 allowedDomain: function (allowed_domains) { 4371 if ( jQuery.type(allowed_domains)==="array" ) { 4372 if ( jQuery.inArray( top.document.location.hostname, allowed_domains )===-1 ) { 4373 return false;
4374 } 4375 } 4376 return true; 4377 } 4378 }, 4379 video:{ 4380 flash:{ 4381 // Protocol and domain for player_uri and expressinstall set in video.play() 4382 player_uri: ( 'https:' == location.protocol ? 'https://v0.wordpress.com' : 'http://s0.videopress.com' ) + "/player.swf?v=1.04", 4383 min_version:"10.0.0", 4384 params:{wmode:"direct",quality:"autohigh",seamlesstabbing:"true",allowfullscreen:"true",allowscriptaccess:"always",overstretch:"true"}, 4385 expressinstall: ( 'https:' == location.protocol ? 'https://v0.wordpress.com' : 'http://s0.videopress.com' ) + "/playerProductInstall.swf", 4386 embedCallback: function(event) { 4387 if ( event.success===false ) { 4388 jQuery("#" + event.id).html("<p>" + jQuery.VideoPress.error.messages.flash + "</p>"); 4389 } 4390 } 4391 }, 4392 types:{mp4:'video/mp4; codecs="avc1.64001E, mp4a.40.2"',ogv:'video/ogg; codecs="theora, vorbis"'}, 4393 canPlay:function () { 4394 if ( jQuery.VideoPress.support.flash() ) { 4395 jQuery.VideoPress.video.playerSupport = "flash"; 4396 } else if ( jQuery.VideoPress.support.html5Video() ) { 4397 if ( jQuery.VideoPress.support.html5Video( jQuery.VideoPress.video.types.mp4 ) ) { 4398 jQuery.VideoPress.video.playerSupport = "mp4"; 4399 } else if ( jQuery.VideoPress.support.html5Video( jQuery.VideoPress.video.types.ogv ) ) { 4400 jQuery.VideoPress.video.playerSupport = "ogv"; 4401 } else { 4402 jQuery.VideoPress.video.playerSupport = "html5"; 4403 } 4404 } else { 4405 jQuery.VideoPress.video.playerSupport = ""; 4406 } 4407 }, 4408 prepare: function ( guid, config, count ) { 4409 var video = jQuery.VideoPress.data[guid][count]; 4410 if ( config.container === undefined || jQuery.type(video)!=="object" ) { 4411 return; 4412 } 4413 4414 var width = 0; 4415 if ( config.width !== undefined ) { 4416 width = config.width; 4417 } else { 4418 config.container.width(); 4419 } 4420 4421 4422 var height = 0; 4423 if ( config.height !== undefined ) { 4424 height = config.height; 4425 } else { 4426 config.container.height(); 4427 } 4428 4429 var div_id = "#v-" + guid + '-' + count; 4430 4431 var parent_width = jQuery( div_id ).parent().width(); 4432 var diffw = 0; 4433 var diffh = 0; 4434 var ratio = 0; 4435 if ( width > parent_width ) { 4436 diffw = width - parent_width + 11; 4437 ratio = ( width * 1.0 ) / ( height * 1.0 ); 4438 diffh = diffw / ratio; 4439 4440 width -= diffw; 4441 height -= Math.round( diffh ); 4442 } 4443 4444 if ( width < 60 || height < 60 ) { 4445 width = 400; 4446 height = 300; 4447 } 4448 4449 jQuery.VideoPress.data[guid][count].dimensions = {}; 4450 4451 if( 0 == ratio ) { 4452 jQuery.VideoPress.data[guid][count].dimensions.width = width; 4453 jQuery.VideoPress.data[guid][count].dimensions.height = height; 4454 } 4455 else { 4456 jQuery.VideoPress.data[guid][count].dimensions.width = width - 7; 4457 jQuery.VideoPress.data[guid][count].dimensions.height = height - Math.round( 7 / ratio ); 4458 4459 jQuery( div_id ).width( width ); 4460 jQuery( div_id ).height( height + 50 ); 4461 4462 jQuery( div_id + "-placeholder" ).width( jQuery.VideoPress.data[guid][count].dimensions.width ); 4463 jQuery( div_id + "-placeholder" ).height( jQuery.VideoPress.data[guid][count].dimensions.height ); 4464 4465 jQuery( div_id + "-placeholder img.videopress-poster" ).width( jQuery.VideoPress.data[guid][count].dimensions.width ); 4466 jQuery( div_id + "-placeholder img.videopress-poster" ).height( jQuery.VideoPress.data[guid][count].dimensions.height ); 4467 } 4468 4469 config.container.data( "guid", guid ); 4470 config.container.data( "count", count ); 4471 if ( jQuery.VideoPress.video.playerSupport === undefined ) { 4472 jQuery.VideoPress.video.canPlay(); 4473 } 4474 4475 if ( config.freedom===true && jQuery.type(video.ogv)==="string" ) { 4476 jQuery.VideoPress.video.insert( config.container, guid, count, video, "ogv", jQuery.VideoPress.data[guid][count].dimensions.width, jQuery.VideoPress.data[guid].dimensions.height ); 4477 config.container.data( "player", "ogv" ); 4478 } else if ( jQuery.VideoPress.video.playerSupport === "flash" ) { 4479 config.container.data( "player", "flash" ); 4480 config.container.append( '<div id="v-' + guid + "-" + count + '-video">' ); 4481 } else if ( jQuery.inArray( jQuery.VideoPress.video.playerSupport, ["html5","mp4","ogv"] ) && ( jQuery.type(video.mp4.uri)==="str
4481ing" || jQuery.type(video.ogv.uri)==="string" ) ) { 4482 var load_type = "html5"; 4483 if ( jQuery.VideoPress.video.playerSupport==="mp4" && video.mp4!==undefined && jQuery.type(video.mp4.uri)==="string" ) { 4484 load_type = "mp4"; 4485 } else if ( jQuery.VideoPress.video.playerSupport==="ogv" && video.ogv!==undefined && jQuery.type(video.ogv.uri)==="string" ) { 4486 load_type = "ogv"; 4487 } 4488 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 ); 4489 config.container.data( "player", load_type ); 4490 load_type=null; 4491 } else { 4492 config.container.html('<p class="videopress-error">' + jQuery.VideoPress.error.messages.incompatible + '</p>'); 4493 return false; 4494 } 4495 return true; 4496 }, 4497 insert: function( container_el, guid, count, video_data, video_type, width, height ) { 4498 var video_id = "v-" + guid + "-" + count + "-video"; 4499 var video_el = jQuery("<video />"); 4500 video_el.attr( "id", video_id ); 4501 video_el.attr( "width", width ); 4502 video_el.attr( "height", height ); 4503 video_el.attr( "poster", video_data.poster ); 4504 if ( video_type==="ogv" ) { 4505 video_el.attr( "preload", "metadata" ); 4506 } else { 4507 video_el.attr( "preload", "none" ); 4508 } 4509 video_el.attr( "controls", "true" ); 4510 video_el.attr( "x-webkit-airplay", "allow" ); 4511 if ( video_type==="mp4" && video_data.mp4!==undefined && jQuery.type(video_data.mp4.uri)==="string" ) { 4512 video_el.attr( "src", video_data.mp4.uri ); 4513 } else if ( video_type==="ogv" && video_data.ogv!==undefined && jQuery.type(video_data.ogv.uri)==="string" ) { 4514 video_el.attr( "src", video_data.ogv.uri ); 4515 } else { 4516 // Purposely omit source type attribute since the browser does not seem to support specifics such as canPlayType 4517 if ( video_data.mp4!==undefined && jQuery.type(video_data.mp4.uri)==="string" ) { 4518 video_el.append( '<source src="' - video_data.mp4.uri + '" />' ); 4519 } 4520 if ( video_data.ogv!==undefined && jQuery.type(video_data.ogv.uri)==="string" ) { 4521 video_el.append( '<source src="' + video_data.ogv.uri + '" />' ); 4522 } 4523 } 4524 4525 if ( video_data.tracks !== undefined ) { 4526 video_el.append( video_data.tracks ); 4527 } 4528 video_el.append( '<p class="videopress-error">' + jQuery.VideoPress.error.messages.incompatible + "</p>" ); 4529 video_el.hide(); 4530 container_el.append( video_el ); 4531 video_el=null; 4532 video_id=null; 4533 }, 4534 play: function( container_el ) { 4535 var player = container_el.data( "player" ); 4536 if ( player===undefined ) { 4537 player="flash"; 4538 } 4539 4540 var guid = container_el.data( "guid" ); 4541 var count = container_el.data( "count" ); 4542 4543 if ( player === "flash" ) { 4544 jQuery( "#" + container_el.attr("id") + "-placeholder", container_el ).remove(); 4545 4546 var player_uri = jQuery.VideoPress.video.flash.player_uri; 4547 var expressinstall = jQuery.VideoPress.video.flash.expressinstall; 4548 4549 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 ); 4550 } else if ( jQuery.inArray( player, ["html5", "mp4", "ogv"] ) ) { 4551 var video_el = jQuery("video", container_el); 4552 if ( video_el ) { 4553 jQuery( "#" + container_el.attr("id") + "-placeholder", container_el ).remove(); 4554 if ( player==="html5" ) { 4555 player = "mp4"; 4556 } 4557 jQuery.VideoPress.video.playHTML5( video_el, guid, player ); 4558 } 4559 } else { 4560 jQuery( "#" + container_el.attr("id") + "-placeholder", container_el ).remove(); 4561 container_el.append( '<p class="videopress-error">Unable to play video. No suitable player.</p>' ); 4562 } 4563 4564 var play_event = new CustomEvent( 'videopress_play_video', { 'detail': { 'video_id': guid } } ); 4565 window.dispatchEvent( play_event ); 4566 }, 4567 playHTML5: function( video_el, guid, filetype ) { 4568 video_el.show(); 4569 video_el[0].load(); 4570 4571 /* It seems load() sometimes does not work, but play() will trigger load. 4572 * Tried attaching play() to a data event but data might not load 4573 * So we trigger play() even if there is not enough data loaded to begin playback 4574 */ 4575 video_el[0].play(); 4576 jQuery.VideoPress.analytics.played(guid, filetype); 4577 video_el.bind( "error stalled", function(e) { 4578 var message = jQuery.VideoPress.error.messages.error; 4579 try { 4580 // provide a more detailed error message if a failure reason is communicated 4581 switch (e.target.error.code) { 4582 case e.target.error.MEDIA_ERR_NETWORK: 4583 message = jQuery.VideoPress.error.messages.network; 4584 break; 4585 case e.target.error.MEDIA_ERR_DECODE: 4586 case e.target.error.MEDIA_ERR_SRC_NOT_SUPPORTED: 4587 message = jQuery.VideoPress.error.messages.incapable + " " + filetype.toUpperCase() + "."; 4588 break; 4589 default: 4590 break; 4591 } 4592 } catch( err ){} 4593 // provide an opportunity to silence an error with an empty string 4594 if ( message.length > 0 ) { 4595 video_el.html( '<p class="videopress-error">' + message + "</p>" ); 4596 } 4597 message=null; 4598 } ); 4599 video_el.bind( "durationchange", {guid:guid}, function( event ) { 4600 var duration = jQuery(event.target).attr("duration"); 4601 if ( jQuery.type(duration)==="number" ) { 4602 jQuery.VideoPress.data[event.data.guid].duration = duration; 4603 } 4604 duration=null; 4605 } ); 4606 4607 /* Only record stats after video data has loaded 4608 * 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. 4609 */ 4610 video_el.one( "loadeddata", {guid:guid, filetype:filetype}, function( event ){ 4611 var filetype = event.data.filetype; 4612 var loaded_file = jQuery(event.target).attr("currentSrc"); 4613 if ( jQuery.type(loaded_file)==="string" && loaded_file.length > 3 ) { 4614 var ext = loaded_file.substr( loaded_file.lastIndexOf(".") + 1 ).toLowerCase(); 4615 if ( jQuery.inArray( ext, ["mp4","ogv"] ) ) { 4616 filetype = ext; 4617 } 4618 ext=null; 4619 } 4620 video_el.bind( "play", {guid:event.data.guid,filetype:filetype}, function( event ) { 4621 jQuery.VideoPress.analytics.played(event.data.guid, event.data.filetype); 4622 } ); 4623 video_el.bind( "timeupdate", {guid:event.data.guid,filetype:filetype}, function( event ) { 4624 var target = jQuery(event.target); 4625 jQuery.VideoPress.analytics.watched( event.data.guid, event.data.filetype, target.attr("currentTime"), target.attr("initialTime") ); 4626 target=null; 4627 } ); 4628 video_el.bind( "ended", {guid:event.data.guid,filetype:filetype}, function( event ) { 4629 jQuery.VideoPress.analytics.watched( event.data.guid, event.data.filetype, jQuery.VideoPress.data[guid].duration, jQuery(event.target).attr("initialTime") ); 4630 } ); 4631 } ); 4632 } 4633 } 4634}}); 4635;
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.