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 // Skip CoBlocks Lightbox images 458 if ( img.parentNode.className.match(/coblocks-lightbox__image/) ) 459 return false; 460 461 // Scale gravatars that have ?s= or ?size= 462 if ( img.src.match( /^https?:\/\/([^\/]*\.)?gravatar\.com\/.+[?&](s|size)=/ ) ) { 463 if ( this.hintsFor( "gravatar" ) === true ) { 464 return false;
465 } 466 newSrc = img.src.replace( /([?&](s|size)=)(\d+)/, function( $0, $1, $2, $3 ) { 467 // Stash the original size 468 var originalAtt = "originals", 469 originalSize = img.getAttribute(originalAtt); 470 if ( originalSize === null ) { 471 originalSize = $3; 472 img.setAttribute(originalAtt, originalSize); 473 if ( t.imgNeedsSizeAtts( img ) ) { 474 // Fix width and height attributes to rendered dimensions. 475 img.width = img.width; 476 img.height = img.height; 477 } 478 } 479 // Get the width/height of the image in CSS pixels 480 var size = img.clientWidth; 481 // Convert CSS pixels to device pixels 482 var targetSize = Math.ceil(img.clientWidth * scale); 483 // Don't go smaller than the original size 484 targetSize = Math.max( targetSize, originalSize ); 485 // Don't go larger than the service supports 486 targetSize = Math.min( targetSize, 512 ); 487 return $1 + targetSize; 488 }); 489 } 490 491 // Scale mshots that have width 492 else if ( img.src.match(/^https?:\/\/([^\/]+\.)*(wordpress|wp)\.com\/mshots\/.+[?&]w=\d+/) ) { 493 if ( this.hintsFor( "mshots" ) === true ) { 494 return false; 495 } 496 newSrc = img.src.replace( /([?&]w=)(\d+)/, function($0, $1, $2) { 497 // Stash the original size 498 var originalAtt = 'originalw', originalSize = img.getAttribute(originalAtt); 499 if ( originalSize === null ) { 500 originalSize = $2; 501 img.setAttribute(originalAtt, originalSize); 502 if ( t.imgNeedsSizeAtts( img ) ) { 503 // Fix width and height attributes to rendered dimensions. 504 img.width = img.width; 505 img.height = img.height; 506 } 507 } 508 // Get the width of the image in CSS pixels 509 var size = img.clientWidth; 510 // Convert CSS pixels to device pixels 511 var targetSize = Math.ceil(size * scale); 512 // Don't go smaller than the original size 513 targetSize = Math.max( targetSize, originalSize ); 514 // Don't go bigger unless the current one is actually lacking 515 if ( scale > img.getAttribute("scale") && targetSize <= img.naturalWidth ) 516 targetSize = $2; 517 if ( $2 != targetSize ) 518 return $1 + targetSize; 519 return $0; 520 }); 521 522 // Update height attribute to match width 523 newSrc = newSrc.replace( /([?&]h=)(\d+)/, function($0, $1, $2) { 524 if ( newSrc == img.src ) { 525 return $0; 526 } 527 // Stash the original size 528 var originalAtt = 'originalh', originalSize = img.getAttribute(originalAtt); 529 if ( originalSize === null ) { 530 originalSize = $2; 531 img.setAttribute(originalAtt, originalSize); 532 } 533 // Get the height of the image in CSS pixels 534 var size = img.clientHeight; 535 // Convert CSS pixels to device pixels 536 var targetSize = Math.ceil(size * scale); 537 // Don't go smaller than the original size 538 targetSize = Math.max( targetSize, originalSize ); 539 // Don't go bigger unless the current one is actually lacking 540 if ( scale > img.getAttribute("scale") && targetSize <= img.naturalHeight ) 541 targetSize = $2; 542 if ( $2 != targetSize ) 543 return $1 + targetSize; 544 return $0; 545 }); 546 } 547 548 // Scale simple imgpress queries (s0.wp.com) that only specify w/h/fit 549 else if ( img.src.match(/^https?:\/\/([^\/.]+\.)*(wp|wordpress)\.com\/imgpress\?(.+)/) ) { 550 if ( this.hintsFor( "imgpress" ) === true ) { 551 return false; 552 } 553 var imgpressSafeFunctions = ["zoom", "url", "h", "w", "fit", "filter", "brightness", "contrast", "colorize", "smooth", "unsharpmask"]; 554 // Search the query string for unsupported functions. 555 var qs = RegExp.$3.split('&'); 556 for ( var q in qs ) { 557 q = qs[q].split('=')[0]; 558 if ( imgpressSafeFunctions.indexOf(q) == -1 ) { 559 return false; 560 } 561 } 562 // Fix width and height attributes to rendered dimensions. 563 img.width = img.width; 564 img.height = img.height; 565 // Compute new src 566 if ( scale == 1 ) 567 newSrc = img.src.replace(/\?(zoom=[^&]+&)?/, '?'); 568 else 569 newSrc = img.src.replace(/\?(zoom=[^&]+&)?/, '?zoom=' + scale + '&'); 570 } 571 572 // Scale files.wordpress.com, LaTeX, or Photon images (i#.wp.com) 573 else if ( 574 ( isFiles = img.src.match(/^https?:\/\/([^\/]+)\.files\.wordpress\.com\/.+[?&][wh]=/) ) || 575 ( isLatex = img.src.match(/^https?:\/\/([^\/.]+\.)*(wp|wordpress)\.com\/latex\.php\?(latex|zoom)=(.+)/) ) || 576 ( isPhoton = img.src.match(/^https?:\/\/i[\d]{1}\.wp\.com\/(.+)/) ) 577 ) { 578 if ( false !== isFiles && this.hintsFor( "files" ) === true ) { 579 return false 580 } 581 if ( false !== isLatex && this.hintsFor( "latex" ) === true ) { 582 return false 583 } 584 if ( false !== isPhoton && this.hintsFor( "photon" ) === true ) { 585 return false 586 } 587 // Fix width and height attributes to rendered dimensions. 588 img.width = img.width;
589 img.height = img.height; 590 // Compute new src 591 if ( scale == 1 ) { 592 newSrc = img.src.replace(/\?(zoom=[^&]+&)?/, '?'); 593 } else { 594 newSrc = img.src; 595 596 var url_var = newSrc.match( /([?&]w=)(\d+)/ ); 597 if ( url_var !== null && url_var[2] ) { 598 newSrc = newSrc.replace( url_var[0], url_var[1] + img.width ); 599 } 600 601 url_var = newSrc.match( /([?&]h=)(\d+)/ ); 602 if ( url_var !== null && url_var[2] ) { 603 newSrc = newSrc.replace( url_var[0], url_var[1] + img.height ); 604 } 605 606 var zoom_arg = '&zoom=2'; 607 if ( !newSrc.match( /\?/ ) ) { 608 zoom_arg = '?zoom=2'; 609 } 610 img.setAttribute( 'srcset', newSrc + zoom_arg + ' ' + scale + 'x' ); 611 } 612 } 613 614 // Scale static assets that have a name matching *-1x.png or *@1x.png 615 else if ( img.src.match(/^https?:\/\/[^\/]+\/.*[-@]([12])x\.(gif|jpeg|jpg|png)(\?|$)/) ) { 616 if ( this.hintsFor( "staticAssets" ) === true ) { 617 return false; 618 } 619 // Fix width and height attributes to rendered dimensions. 620 img.width = img.width; 621 img.height = img.height; 622 var currentSize = RegExp.$1, newSize = currentSize; 623 if ( scale <= 1 ) 624 newSize = 1; 625 else 626 newSize = 2; 627 if ( currentSize != newSize ) 628 newSrc = img.src.replace(/([-@])[12]x\.(gif|jpeg|jpg|png)(\?|$)/, '$1'+newSize+'x.$2$3'); 629 } 630 631 else { 632 return false; 633 } 634 635 // Don't set img.src unless it has changed. This avoids unnecessary reloads. 636 if ( newSrc != img.src ) { 637 // Store the original img.src 638 var prevSrc, origSrc = img.getAttribute("src-orig"); 639 if ( !origSrc ) { 640 origSrc = img.src; 641 img.setAttribute("src-orig", origSrc); 642 } 643 // In case of error, revert img.src 644 prevSrc = img.src; 645 img.onerror = function(){ 646 img.src = prevSrc; 647 if ( img.getAttribute("scale-fail") < scale ) 648 img.setAttribute("scale-fail", scale); 649 img.onerror = null; 650 }; 651 // Finally load the new image 652 img.src = newSrc; 653 } 654 655 return true; 656 } 657}; 658 659wpcom_img_zoomer.init(); 660; 661!function(e){var t={};function n(o){if(t[o])return t[o].exports;var c=t[o]={i:o,l:!1,exports:{}};return e[o].call(c.exports,c,c.exports,n),c.l=!0,c.exports}n.m=e,n.c=t,n.d=function(e,t,o){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:o})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var o=Object.create(null);if(n.r(o),Object.defineProperty(o,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var c in e)n.d(o,c,function(t){return e[t]}.bind(null,c));return o},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=287)}({287:function(e,t){!function(){"use strict";var e=document.getElementsByClassName("has-lightbox");Array.from(e).forEach((function(e,t){e.className+=" lightbox-"+t+" ",function(e){var t=document.createElement("div");t.setAttribute("class","coblocks-lightbox");var n=document.createElement("div");n.setAttribute("class","coblocks-lightbox__background");var o=document.createElement("div");o.setAttribute("class","coblocks-lightbox__heading");var c=document.createElement("button");c.setAttribute("class","coblocks-lightbox__close");var r=document.createElement("span");r.setAttribute("class","coblocks-lightbox__count");var a=document.createElement("div");a.setAttribute("class","coblocks-lightbox__image");var i=document.createElement("img"),l=document.createElement("figcaption");l.setAttribute("class","coblocks-lightbox__caption");var s=document.createElement("button");s.setAttribute("class","coblocks-lightbox__arrow coblocks-lightbox__arrow--left");var u=document.createElement("button");u.setAttribute("class","coblocks-lightbox__arrow coblocks-lightbox__arrow--right");var d=document.createElement("div");d.setAttribute("class","arrow-right");var b=document.createElement("div");b.setAttribute("class","arrow-left");var m,f=document.querySelectorAll(".has-lightbox.lightbox-".concat(e," > :not(.carousel-nav) figure img, figure.has-lightbox.lightbox-").concat(e," > img")),g=document.querySelectorAll(".has-lightbox.lightbox-".concat(e," > :not(.carousel-nav) figure figcaption"));o.append(r,c),a.append(i,l),s.append(b),u.append(d),t.append(n,o,a,s,u),f.length>0&&(document.getElementsByTagName("BODY")[0].append(t),1===f.length&&(u.remove(),s.remove()));g.length>0&&Array.from(g).forEach((function(e,t){e.addEventListener("click",(function(){p(t)}))}));Array.from(f).forEach((function(e,t){e.closest("figure").addEventListener("click",(function(){p(t)}))})),s.addEventListener("click",(function(){p(m=0===m?f.length-1:m-1)})),u.addEventListener("click",(function(){p(m=m===f.length-1?0:m+1)})),n.addEventListener("click",(function(){t.style.display="none"})),c.addEventListener("click",(function(){t.style.display="none"}));var v={preloaded:!1,setPreloadImages:function(){v.preloaded||(v.preloaded=!0,Array.from(f).forEach((function(e,t){v["img-".concat(t)]=new window.Image,v["img-".concat(t)].src=e.attributes.src.value,v["img-".concat(t)]["data-caption"]=f[t]&&f[t].nextElementSibling?function(e){for(var t=e.nextElementSibling;t;){if(t.matches("figcaption"))return t.innerHTML;t=t.nextElementSibling}return""}(f[t]):""})),document.onkeydown=function(e){if(void 0!==t&&"none"!==t)switch((e=e||window.event).keyCode){case 27:c.click();break;
661case 37:case 65:s.click();break;case 39:case 68:u.click()}})}};function p(e){v.setPreloadImages(),m=e,t.style.display="flex",n.style.backgroundImage="url(".concat(v["img-".concat(m)].src,")"),i.src=v["img-".concat(m)].src,l.innerHTML=v["img-".concat(m)]["data-caption"],r.textContent="".concat(m+1," / ").concat(f.length)}}(t)}))}()}});; 662( function( $ ) { 663 var cookieValue = document.cookie.replace( /(?:(?:^|.*;\s*)eucookielaw\s*\=\s*([^;]*).*$)|^.*$/, '$1' ), 664 overlay = $( '#eu-cookie-law' ), 665 container = $( '.widget_eu_cookie_law_widget' ), 666 initialScrollPosition, 667 scrollFunction; 668 669 if ( overlay.hasClass( 'ads-active' ) ) { 670 var adsCookieValue = document.cookie.replace( /(?:(?:^|.*;\s*)personalized-ads-consent\s*\=\s*([^;]*).*$)|^.*$/, '$1' ); 671 if ( '' !== cookieValue && '' !== adsCookieValue ) { 672 overlay.remove(); 673 } 674 } else if ( '' !== cookieValue ) { 675 overlay.remove(); 676 } 677 678 $( '.widget_eu_cookie_law_widget' ).appendTo( 'body' ).fadeIn(); 679 680 overlay.find( 'form' ).on( 'submit', accept ); 681 682 if ( overlay.hasClass( 'hide-on-scroll' ) ) { 683 initialScrollPosition = $( window ).scrollTop(); 684 scrollFunction = function() { 685 if ( Math.abs( $( window ).scrollTop() - initialScrollPosition ) > 50 ) { 686 accept(); 687 } 688 }; 689 $( window ).on( 'scroll', scrollFunction ); 690 } else if ( overlay.hasClass( 'hide-on-time' ) ) { 691 setTimeout( accept, overlay.data( 'hide-timeout' ) * 1000 ); 692 } 693 694 var accepted = false; 695 function accept( event ) { 696 if ( accepted ) { 697 return; 698 } 699 accepted = true; 700 701 if ( event && event.preventDefault ) { 702 event.preventDefault(); 703 } 704 705 if ( overlay.hasClass( 'hide-on-scroll' ) ) { 706 $( window ).off( 'scroll', scrollFunction ); 707 } 708 709 var expireTime = new Date(); 710 expireTime.setTime( expireTime.getTime() + ( overlay.data( 'consent-expiration' ) * 24 * 60 * 60 * 1000 ) ); 711 712 document.cookie = 'eucookielaw=' + expireTime.getTime() + ';path=/;expires=' + expireTime.toGMTString(); 713 if ( overlay.hasClass( 'ads-active' ) && overlay.hasClass( 'hide-on-button' ) ) { 714 document.cookie = 'personalized-ads-consent=' + expireTime.getTime() + ';path=/;expires=' + expireTime.toGMTString(); 715 } 716 717 overlay.fadeOut( 400, function() { 718 overlay.remove(); 719 container.remove(); 720 } ); 721 } 722} )( jQuery ); 723; 724(function() { 725 726 /** 727 * Debounce 728 * 729 * @param {Function} func 730 * @param {number} wait 731 * @param {boolean} immediate 732 */ 733 function debounce(func, wait, immediate) { 734 'use strict'; 735 736 var timeout; 737 wait = (typeof wait !== 'undefined') ? wait : 20; 738 immediate = (typeof immediate !== 'undefined') ? immediate : true; 739 740 return function() { 741 742 var context = this, args = arguments; 743 var later = function() { 744 timeout = null; 745 746 if (!immediate) { 747 func.apply(context, args); 748 } 749 }; 750 751 var callNow = immediate && !timeout; 752 753 clearTimeout(timeout); 754 timeout = setTimeout(later, wait); 755 756 if (callNow) { 757 func.apply(context, args); 758 } 759 }; 760 } 761 762 /** 763 * Get page header height and use it for top-margin on 764 * site-content when above mobile breakpoint 765 */ 766 function pageHeaderHeight() { 767 var body = document.body; 768 769 if ( document.documentElement.clientWidth < 560 ) { 770 document.getElementById( "primary" ).style.marginTop = 0; 771 body.classList.remove( 'wp-sticky-header' ); 772 } else { 773 var header = document.getElementById( 'masthead' ); 774 var content = document.getElementById( 'primary' ); 775 776 content.style.marginTop = header.offsetHeight + "px"; 777 778 if ( document.documentElement.clientHeight / 5 - header.offsetHeight >= 0 ) { 779 body.classList.add( 'wp-sticky-header' ); 780 } else { 781 body.classList.remove( 'wp-sticky-header' ); 782 } 783 } 784 }; 785 786 /** 787 * Run our function every time the window resizes 788 */ 789 var isResizing = false; 790 window.addEventListener( 'resize', 791 debounce( function() { 792 if ( isResizing ) { 793 return; 794 } 795 796 isResizing = true; 797 setTimeout( function() { 798 pageHeaderHeight(); 799 isResizing = false; 800 }, 150 ); 801 } ) 802 ); 803 804 /** 805 * Run our page header height function 806 */ 807 pageHeaderHeight(); 808})(); 809; 810/* globals JSON */ 811( function () { 812 var eventName = 'wpcom_masterbar_click'; 813 814 var linksTracksEvents = { 815 // top level items 816 'wp-admin-bar-blog' : 'my_sites', 817 'wp-admin-bar-newdash' : 'reader',
818 'wp-admin-bar-ab-new-post' : 'write_button', 819 'wp-admin-bar-my-account' : 'my_account', 820 'wp-admin-bar-notes' : 'notifications', 821 // my sites - top items 822 'wp-admin-bar-switch-site' : 'my_sites_switch_site', 823 'wp-admin-bar-blog-info' : 'my_sites_site_info', 824 'wp-admin-bar-site-view' : 'my_sites_view_site', 825 'wp-admin-bar-blog-stats' : 'my_sites_site_stats', 826 'wp-admin-bar-plan' : 'my_sites_plan', 827 'wp-admin-bar-plan-badge' : 'my_sites_plan_badge', 828 // my sites - manage 829 'wp-admin-bar-edit-page' : 'my_sites_manage_site_pages', 830 'wp-admin-bar-new-page-badge' : 'my_sites_manage_add_page', 831 'wp-admin-bar-edit-post' : 'my_sites_manage_blog_posts', 832 'wp-admin-bar-new-post-badge' : 'my_sites_manage_add_post', 833 'wp-admin-bar-edit-attachment' : 'my_sites_manage_media', 834 'wp-admin-bar-new-attachment-badge' : 'my_sites_manage_add_media', 835 'wp-admin-bar-comments' : 'my_sites_manage_comments', 836 'wp-admin-bar-edit-jetpack-testimonial' : 'my_sites_manage_testimonials', 837 'wp-admin-bar-new-jetpack-testimonial' : 'my_sites_manage_add_testimonial', 838 'wp-admin-bar-edit-jetpack-portfolio' : 'my_sites_manage_portfolio', 839 'wp-admin-bar-new-jetpack-portfolio' : 'my_sites_manage_add_portfolio', 840 // my sites - personalize 841 'wp-admin-bar-themes' : 'my_sites_personalize_themes', 842 'wp-admin-bar-cmz' : 'my_sites_personalize_themes_customize', 843 // my sites - configure 844 'wp-admin-bar-sharing' : 'my_sites_configure_sharing', 845 'wp-admin-bar-people' : 'my_sites_configure_people', 846 'wp-admin-bar-people-add' : 'my_sites_configure_people_add_button', 847 'wp-admin-bar-plugins' : 'my_sites_configure_plugins', 848 'wp-admin-bar-domains' : 'my_sites_configure_domains', 849 'wp-admin-bar-domains-add' : 'my_sites_configure_add_domain', 850 'wp-admin-bar-blog-settings' : 'my_sites_configure_settings', 851 'wp-admin-bar-legacy-dashboard' : 'my_sites_configure_wp_admin', 852 // reader 853 'wp-admin-bar-followed-sites' : 'reader_followed_sites', 854 'wp-admin-bar-reader-followed-sites-manage': 'reader_manage_followed_sites', 855 'wp-admin-bar-discover-discover' : 'reader_discover', 856 'wp-admin-bar-discover-search' : 'reader_search', 857 'wp-admin-bar-my-activity-my-likes' : 'reader_my_likes', 858 // account 859 'wp-admin-bar-user-info' : 'my_account_user_name', 860 // account - profile 861 'wp-admin-bar-my-profile' : 'my_account_profile_my_profile', 862 'wp-admin-bar-account-settings' : 'my_account_profile_account_settings', 863 'wp-admin-bar-billing' : 'my_account_profile_manage_purchases', 864 'wp-admin-bar-security' : 'my_account_profile_security', 865 'wp-admin-bar-notifications' : 'my_account_profile_notifications', 866 // account - special 867 'wp-admin-bar-get-apps' : 'my_account_special_get_apps', 868 'wp-admin-bar-next-steps' : 'my_account_special_next_steps', 869 'wp-admin-bar-help' : 'my_account_special_help', 870 }; 871 872 var notesTracksEvents = { 873 openSite: function ( data ) { 874 return { 875 clicked: 'masterbar_notifications_panel_site', 876 site_id: data.siteId 877 }; 878 }, 879 openPost: function ( data ) { 880 return { 881 clicked: 'masterbar_notifications_panel_post', 882 site_id: data.siteId, 883 post_id: data.postId 884 }; 885 }, 886 openComment: function ( data ) { 887 return { 888 clicked: 'masterbar_notifications_panel_comment', 889 site_id: data.siteId, 890 post_id: data.postId, 891 comment_id: data.commentId 892 }; 893 } 894 }; 895 896 // Element.prototype.matches as a standalone function, with old browser fallback 897 function matches( node, selector ) { 898 if ( ! node ) { 899 return undefined; 900 } 901 902 if ( ! Element.prototype.matches && ! Element.prototype.msMatchesSelector ) { 903 throw new Error( 'Unsupported browser' ); 904 } 905 906 return Element.prototype.matches ? node.matches( selector ) : node.msMatchesSelector( selector ); 907 } 908 909 // Element.prototype.closest as a standalone function, with old browser fallback 910 function closest( node, selector ) { 911 if ( ! node ) { 912 return undefined; 913 } 914 915 if ( Element.prototype.closest ) { 916 return node.closest( selector ); 917 } 918 919 do { 920 if ( matches( node, selector ) ) { 921 return node; 922 } 923 924 node = node.parentElement || node.parentNode; 925 } while ( node !== null && node.nodeType === 1 ); 926 927 return null; 928 } 929 930 function recordTracksEvent( eventProps ) { 931 eventProps = eventProps || {}; 932 window._tkq = window._tkq || []; 933 window._tkq.push( [ 'recordEvent', eventName, eventProps ] ); 934 } 935 936 function parseJson( s, defaultValue ) { 937 try { 938 return JSON.parse( s ); 939 } catch ( e ) { 940 return defaultValue; 941 } 942 } 943 944 function createTrackableLinkEventHandler( link ) { 945 return function () { 946 var parent = closest( link, 'li' ); 947 948 if ( ! parent ) { 949 return; 950 } 951 952 var trackingId = link.getAttribute( 'ID' ) || parent.getAttribute( 'ID' ); 953 954 if ( ! linksTracksEvents.hasOwnProperty( trackingId ) ) { 955 return; 956 } 957 958 var eventProps = { 'clicked': linksTracksEvents[ trackingId ] }; 959 recordTracksEvent( eventProps ); 960 } 961 } 962
963 function init() { 964 var trackableLinkSelector = '.mb-trackable .ab-item:not(div),' + 965 '#wp-admin-bar-notes .ab-item,' + 966 '#wp-admin-bar-user-info .ab-item,' + 967 '.mb-trackable .ab-secondary'; 968 969 var trackableLinks = document.querySelectorAll( trackableLinkSelector ); 970 971 for ( var i = 0; i < trackableLinks.length; i++ ) { 972 var link = trackableLinks[ i ]; 973 var handler = createTrackableLinkEventHandler( link ); 974 975 link.addEventListener( 'click', handler ); 976 link.addEventListener( 'touchstart', handler ); 977 } 978 } 979 980 if ( document.readyState === 'loading' ) { 981 document.addEventListener( 'DOMContentLoaded', init ); 982 } else { 983 init(); 984 } 985 986 // listen for postMessage events from the notifications iframe 987 window.addEventListener( 'message', function ( event ) { 988 if ( event.origin !== 'https://widgets.wp.com' ) { 989 return; 990 } 991 992 var data = ( typeof event.data === 'string' ) ? parseJson( event.data, {} ) : event.data; 993 if ( data.type !== 'notesIframeMessage' ) { 994 return; 995 } 996 997 var eventData = notesTracksEvents[ data.action ]; 998 if ( ! eventData ) { 999 return; 1000 } 1001 1002 recordTracksEvent( eventData( data ) ); 1003 }, false ); 1004 1005} )(); 1006; 1007/* global jetpackCarouselStrings, DocumentTouch */ 1008 1009// @start-hide-in-jetpack 1010if (typeof wpcom === 'undefined') { 1011 var wpcom = {}; 1012} 1013wpcom.carousel = (function (/*$*/) { 1014 var prebuilt_widths = jetpackCarouselStrings.widths; 1015 var pageviews_stats_args = jetpackCarouselStrings.stats_query_args; 1016 1017 var findFirstLargeEnoughWidth = function (original_w, original_h, dest_w, dest_h) { 1018 var inverse_ratio = original_h / original_w; 1019 1020 for ( var i = 0; i < prebuilt_widths.length; ++i ) { 1021 if ( prebuilt_widths[i] >= dest_w || prebuilt_widths[i] * inverse_ratio >= dest_h ) { 1022 return prebuilt_widths[i]; 1023 } 1024 } 1025 1026 return original_w; 1027 }; 1028 1029 var removeResizeFromImageURL = function ( url ) { 1030 return removeArgFromURL( url, 'resize' ); 1031 }; 1032 1033 var removeArgFromURL = function ( url, arg ) { 1034 var re = new RegExp( '[\\?&]' + arg + '(=[^?&]+)?' ); 1035 if ( url.match( re ) ) { 1036 return url.replace( re, '' ); 1037 } 1038 return url; 1039 }; 1040 1041 var addWidthToImageURL = function (url, width) { 1042 width = parseInt(width, 10); 1043 // Give devices with a higher devicePixelRatio higher-res images (Retina display = 2, Android phones = 1.5, etc) 1044 if ('undefined' !== typeof window.devicePixelRatio && window.devicePixelRatio > 1) { 1045 width = Math.round( width * window.devicePixelRatio ); 1046 } 1047 url = addArgToURL(url, 'w', width); 1048 url = addArgToURL(url, 'h', ''); 1049 return url; 1050 }; 1051 1052 var addArgToURL = function (url, arg, value) { 1053 var re = new RegExp(arg+'=[^?&]+'); 1054 if ( url.match(re) ) { 1055 return url.replace(re, arg + '=' + value); 1056 } else { 1057 var divider = url.indexOf('?') !== -1 ? '&' : '?'; 1058 return url + divider + arg + '=' + value; 1059 } 1060 }; 1061 1062 var stat = function ( names ) { 1063 if ( typeof names !== 'string' ) { 1064 names = names.join( ',' ); 1065 } 1066 1067 new Image().src = window.location.protocol + 1068 '//pixel.wp.com/g.gif?v=wpcom-no-pv' + 1069 '&x_carousel=' + names + 1070 '&baba=' + Math.random(); 1071 }; 1072 1073 var pageview = function ( post_id ) { 1074 new Image().src = window.location.protocol + 1075 '//pixel.wp.com/g.gif?host=' + encodeURIComponent( window.location.host ) + 1076 '&ref=' + encodeURIComponent( document.referrer ) + 1077 '&rand=' + Math.random() + 1078 '&' + pageviews_stats_args + 1079 '&post=' + encodeURIComponent( post_id ); 1080 }; 1081 1082 1083 return { 1084 findFirstLargeEnoughWidth: findFirstLargeEnoughWidth, 1085 removeResizeFromImageURL: removeResizeFromImageURL, 1086 addWidthToImageURL: addWidthToImageURL, 1087 stat: stat, 1088 pageview: pageview 1089 }; 1090 1091})(jQuery); 1092// @end-hide-in-jetpack 1093jQuery( document ).ready( function ( $ ) { 1094 // gallery faded layer and container elements 1095 var overlay, 1096 comments, 1097 gallery, 1098 container, 1099 nextButton, 1100 previousButton, 1101 info, 1102 transitionBegin, 1103 caption, 1104 resizeTimeout, 1105 photo_info, 1106 close_hint, 1107 commentInterval, 1108 lastSelectedSlide, 1109 screenPadding = 110, 1110 originalOverflow = $( 'body' ).css( 'overflow' ), 1111 originalHOverflow = $( 'html' ).css( 'overflow' ), 1112 proportion = 85, 1113 last_known_location_hash = '', 1114 imageMeta, 1115 titleAndDescription, 1116 commentForm, 1117 leftColWrapper, 1118 scrollPos; 1119 1120 if ( window.innerWidth <= 760 ) { 1121 screenPadding = Math.round( ( window.innerWidth / 760 ) * 110 ); 1122 1123 if ( 1124 screenPadding < 40 && 1125 ( 'ontouchstart' in window || ( window.DocumentTouch && document instanceof DocumentTouch ) ) 1126 ) { 1127 screenPadding = 0; 1128 } 1129 } 1130 1131 // Adding a polyfill for browsers that do not have Date.now 1132 if ( 'undefined' === typeof Date.now ) { 1133 Date.now = function now() { 1134 return new Date().getTime(); 1135 }; 1136 } 1137 1138 var keyListener = function ( e ) { 1139 switch ( e.which ) { 1140 case 38: // up 1141 e.preventDefault(); 1142 container.scrollTop( container.scrollTop() - 100 ); 1143 break; 1144 case 40: // down 1145 e.preventDefault(); 1146 container.scrollTop( container.scrollTop() + 100 ); 1147 break; 1148 case 39: // right 1149 e.preventDefault(); 1150 gallery.jp_carousel( 'next' ); 1151 break; 1152 case 37: // left 1153 case 8: // backspace 1154 e.preventDefault(); 1155 gallery.jp_carousel( 'previous' ); 1156 break; 1157 case 27: // escape 1158 e.preventDefault(); 1159 container.jp_carousel( 'close' ); 1160 break; 1161 default: 1162 // making jslint happy 1163 break; 1164 } 1165 }; 1166 1167 var resizeListener = function (/*e*/) { 1168 clearTimeout( resizeTimeout ); 1169 resizeTimeout = setTimeout( function () { 1170 gallery.jp_carousel( 'slides' ).jp_carousel( 'fitSlide', true ); 1171 gallery.jp_carousel( 'updateSlidePositions', true ); 1172 gallery.jp_carousel( 'fitMeta', true ); 1173 }, 200 ); 1174 }; 1175 1176 var prepareGallery = function (/*dataCarouselExtra*/) { 1177 if ( ! overlay ) {
1178 overlay = $( '<div></div>' ) 1179 .addClass( 'jp-carousel-overlay' ) 1180 .css( { 1181 position: 'fixed', 1182 top: 0, 1183 right: 0, 1184 bottom: 0, 1185 left: 0, 1186 } ); 1187 1188 var displayComments = 1 === +jetpackCarouselStrings.display_comments; 1189 var buttons = displayComments 1190 ? '<a class="jp-carousel-commentlink" href="#">' + jetpackCarouselStrings.comment + '</a>' 1191 : ''; 1192 if ( 1 === Number( jetpackCarouselStrings.is_logged_in ) ) { 1193// @start-hide-in-jetpack 1194 if ( 1 === Number( jetpackCarouselStrings.is_public && 1 === Number( jetpackCarouselStrings.reblog_enabled ) ) ) { 1195 buttons += '<a class="jp-carousel-reblog" href="#">' + jetpackCarouselStrings.reblog + '</a>'; 1196 } 1197// @end-hide-in-jetpack 1198 } 1199 1200 buttons = $( '<div class="jp-carousel-buttons">' + buttons + '</div>' ); 1201 1202 caption = $( '<h2 itemprop="caption description"></h2>' ); 1203 photo_info = $( '<div class="jp-carousel-photo-info"></div>' ).append( caption ); 1204 1205 imageMeta = $( '<div></div>' ).addClass( 'jp-carousel-image-meta' ).css( { 1206 float: 'right', 1207 'margin-top': '20px', 1208 width: '250px', 1209 } ); 1210 1211 if ( 0 < buttons.children().length ) { 1212 imageMeta.append( buttons ); 1213 } 1214 1215 imageMeta 1216 .append( "<ul class='jp-carousel-image-exif' style='display:none;'></ul>" ) 1217 .append( "<a class='jp-carousel-image-download' style='display:none;'></a>" ) 1218 .append( "<div class='jp-carousel-image-map' style='display:none;'></div>" ); 1219 1220 titleAndDescription = $( '<div></div>' ) 1221 .addClass( 'jp-carousel-titleanddesc' ) 1222 .css( { 1223 width: '100%', 1224 'margin-top': imageMeta.css( 'margin-top' ), 1225 } ); 1226 1227 var leftWidth = $( window ).width() - screenPadding * 2 - ( imageMeta.width() + 40 ); 1228 leftWidth += 'px'; 1229 1230 leftColWrapper = $( '<div></div>' ) 1231 .addClass( 'jp-carousel-left-column-wrapper' ) 1232 .css( { 1233 width: Math.floor( leftWidth ), 1234 } ) 1235 .append( titleAndDescription ); 1236 1237 if ( displayComments ) { 1238 var commentFormMarkup = '<div id="jp-carousel-comment-form-container">'; 1239 1240 if ( 1241 jetpackCarouselStrings.local_comments_commenting_as && 1242 jetpackCarouselStrings.local_comments_commenting_as.length 1243 ) { 1244 // Comments not enabled, fallback to local comments 1245 1246 if ( 1247 1 !== Number( jetpackCarouselStrings.is_logged_in ) && 1248 1 === Number( jetpackCarouselStrings.comment_registration ) 1249 ) { 1250 commentFormMarkup += 1251 '<div id="jp-carousel-comment-form-commenting-as">' + 1252 jetpackCarouselStrings.local_comments_commenting_as + 1253 '</div>'; 1254 } else { 1255 commentFormMarkup += '<form id="jp-carousel-comment-form">'; 1256 commentFormMarkup += 1257 '<textarea name="comment" class="jp-carousel-comment-form-field jp-carousel-comment-form-textarea" id="jp-carousel-comment-form-comment-field" placeholder="' + 1258 jetpackCarouselStrings.write_comment + 1259 '"></textarea>'; 1260 commentFormMarkup += '<div id="jp-carousel-comment-form-submit-and-info-wrapper">'; 1261 commentFormMarkup += 1262 '<div id="jp-carousel-comment-form-commenting-as">' + 1263 jetpackCarouselStrings.local_comments_commenting_as + 1264 '</div>'; 1265 commentFormMarkup += 1266 '<input type="submit" name="submit" class="jp-carousel-comment-form-button" id="jp-carousel-comment-form-button-submit" value="' + 1267 jetpackCarouselStrings.post_comment + 1268 '" />'; 1269 commentFormMarkup += '<span id="jp-carousel-comment-form-spinner"> </span>'; 1270 commentFormMarkup += '<div id="jp-carousel-comment-post-results"></div>'; 1271 commentFormMarkup += '</div>'; 1272 commentFormMarkup += '</form>'; 1273 } 1274 } 1275 commentFormMarkup += '</div>'; 1276 1277 commentForm = $( commentFormMarkup ).css( { 1278 width: '100%', 1279 'margin-top': '20px', 1280 color: '#999', 1281 } ); 1282 1283 comments = $( '<div></div>' ).addClass( 'jp-carousel-comments' ).css( { 1284 width: '100%', 1285 bottom: '10px', 1286 'margin-top': '20px', 1287 } ); 1288 1289 var commentsLoading = $( 1290 '<div id="jp-carousel-comments-loading"><span>' + 1291 jetpackCarouselStrings.loading_comments + 1292 '</span></div>' 1293 ).css( { 1294 width: '100%', 1295 bottom: '10px', 1296 'margin-top': '20px', 1297 } ); 1298 1299 leftColWrapper.append( commentForm ).append( comments ).append( commentsLoading ); 1300 } 1301 1302 var fadeaway = $( '<div></div>' ).addClass( 'jp-carousel-fadeaway' ); 1303 1304 info = $( '<div></div>' ) 1305 .addClass( 'jp-carousel-info' ) 1306 .css( { 1307 top: Math.floor( ( $( window ).height() / 100 ) * proportion ), 1308 left: screenPadding, 1309 right: screenPadding, 1310 } ) 1311 .append( photo_info ) 1312 .append( imageMeta ); 1313 1314 if ( window.innerWidth <= 760 ) { 1315 photo_info.remove().insertAfter( titleAndDescription ); 1316 info.prepend( leftColWrapper ); 1317 } else { 1318 info.append( leftColWrapper ); 1319 } 1320 1321 var targetBottomPos = $( window ).height() - parseInt( info.css( 'to
1321p' ), 10 ) + 'px'; 1322 1323 nextButton = $( '<div><span></span></div>' ) 1324 .addClass( 'jp-carousel-next-button' ) 1325 .css( { 1326 right: '15px', 1327 } ) 1328 .hide(); 1329 1330 previousButton = $( '<div><span></span></div>' ) 1331 .addClass( 'jp-carousel-previous-button' ) 1332 .css( { 1333 left: 0, 1334 } ) 1335 .hide(); 1336 1337 nextButton.add( previousButton ).css( { 1338 position: 'fixed', 1339 top: '40px', 1340 bottom: targetBottomPos, 1341 width: screenPadding, 1342 } ); 1343 1344 gallery = $( '<div></div>' ).addClass( 'jp-carousel' ).css( { 1345 position: 'absolute', 1346 top: 0, 1347 bottom: targetBottomPos, 1348 left: 0, 1349 right: 0, 1350 } ); 1351 1352 close_hint = $( '<div class="jp-carousel-close-hint"><span>×</span></div>' ).css( { 1353 position: 'fixed', 1354 } ); 1355 1356 container = $( '<div></div>' ) 1357 .addClass( 'jp-carousel-wrap' ) 1358 .addClass( 'jp-carousel-transitions' ); 1359 if ( 'white' === jetpackCarouselStrings.background_color ) { 1360 container.addClass( 'jp-carousel-light' ); 1361 } 1362 1363 container.attr( 'itemscope', '' ); 1364 1365 container.attr( 'itemtype', 'https://schema.org/ImageGallery' ); 1366 1367 container 1368 .css( { 1369 position: 'fixed', 1370 top: 0, 1371 right: 0, 1372 bottom: 0, 1373 left: 0, 1374 'z-index': 2147483647, 1375 'overflow-x': 'hidden', 1376 'overflow-y': 'auto', 1377 direction: 'ltr', 1378 } ) 1379 .hide() 1380 .append( overlay ) 1381 .append( gallery ) 1382 .append( fadeaway ) 1383 .append( info ) 1384 .append( nextButton ) 1385 .append( previousButton ) 1386 .append( close_hint ) 1387 .appendTo( $( 'body' ) ) 1388 .click( function ( e ) { 1389 var target = $( e.target ), 1390 wrap = target.parents( 'div.jp-carousel-wrap' ), 1391 data = wrap.data( 'carousel-extra' ), 1392 slide = wrap.find( 'div.selected' ), 1393 attachment_id = slide.data( 'attachment-id' ); 1394 data = data || []; 1395 1396 if ( target.is( gallery ) || target.parents().add( target ).is( close_hint ) ) { 1397 container.jp_carousel( 'close' ); 1398// @start-hide-in-jetpack 1399 } else if ( target.hasClass('jp-carousel-reblog') ) { 1400 e.preventDefault(); 1401 e.stopPropagation(); 1402 if ( !target.hasClass('reblogged') ) { 1403 target.jp_carousel('show_reblog_box'); 1404 wpcom.carousel.stat('reblog_show_box'); 1405 } 1406 } else if ( target.parents('#carousel-reblog-box').length ) { 1407 if ( target.is('a.cancel') ) { 1408 e.preventDefault(); 1409 e.stopPropagation(); 1410 target.jp_carousel('hide_reblog_box'); 1411 wpcom.carousel.stat('reblog_cancel'); 1412 } else if ( target.is( 'input[type="submit"]' ) ) { 1413 e.preventDefault(); 1414 e.stopPropagation(); 1415 1416 var note = $('#carousel-reblog-box textarea').val(); 1417 if ( jetpackCarouselStrings.reblog_add_thoughts === note ) { 1418 note = ''; 1419 } 1420 1421 $('#carousel-reblog-submit').val( jetpackCarouselStrings.reblogging ); 1422 $('#carousel-reblog-submit').prop('disabled', true); 1423 $( '#carousel-reblog-box div.submit span.canceltext' ).show(); 1424 1425 $.post( jetpackCarouselStrings.ajaxurl, { 1426 'action': 'post_reblog', 1427 'reblog_source': 'carousel', 1428 'original_blog_id': $('#carousel-reblog-box input#carousel-reblog-blog-id').val(), 1429 'original_post_id': $('.jp-carousel div.selected').data('attachment-id'), 1430 'blog_id': $('#carousel-reblog-box select').val(), 1431 'blog_url': $('#carousel-reblog-box input#carousel-reblog-blog-url').val(), 1432 'blog_title': $('#carousel-reblog-box input#carousel-reblog-blog-title').val(), 1433 'post_url': $('#carousel-reblog-box input#carousel-reblog-post-url').val(), 1434 'post_title': slide.data( 'caption' ) || $('#carousel-reblog-box input#carousel-reblog-post-title').val(), 1435 'note': note, 1436 '_wpnonce': $('#carousel-reblog-box #_wpnonce').val() 1437 }, 1438 function (/*result*/) { 1439 $('#carousel-reblog-box').css({ 'height': $('#carousel-reblog-box').height() + 'px' }).slideUp('fast'); 1440 $('a.jp-carousel-reblog').html( jetpackCarouselStrings.reblogged ).removeClass( 'reblog' ).addClass( 'reblogged' ); 1441 $( '#carousel-reblog-box div.submit span.canceltext' ).hide(); 1442 $('#carousel-reblog-submit').val( jetpackCarouselStrings.post_reblog ); 1443 $('div.jp-carousel-info').children().not('#carousel-reblog-box').fadeIn('fast'); 1444 slide.data('reblogged', 1); 1445 $('div.gallery').find('img[data-attachment-id="' + slide.data('attachment-id') + '"]').data('reblogged', 1); 1446 1447 1448 }, 'json' ); 1449 wpcom.carousel.stat('reblog_submit'); 1450 } 1451 } else if ( target.hasClass( 'jp-carousel-image-download' ) ) { 1452 wpcom.carousel.stat( 'download_original_click' ); 1453// @end-hide-in-jetpack 1454 } else if ( target.hasClass( 'jp-carousel-commentlink' ) ) { 1455 e.preventDefault(); 1456 e.stopPropagation(); 1457 $( window ).unbind( 'keydown', keyListener ); 1458 container.animate( { scrollTop: parseInt( info.position()[ 'top' ], 10 ) }, 'fast' ); 1459 $( '#jp-carousel-comment-form-submit-and-info-wrapper' ).slideDown( 'fast' ); 1460 $( '#jp-carousel-comment-form-comment-field' ).focus(); 1461 } else if ( target.hasClass( 'jp-carousel-comment-login' ) ) { 1462 var url = jetpackCarouselStrings.login_url + '%23jp-carousel-' + attachment_id; 1463 1464 window.location.href = url; 1465 } else if ( target.parents( '#jp-carousel-comment-form-container' ).length ) { 1466 var textarea = $( '#jp-carousel-comment-form-comment-field' ) 1467 .blur( function () { 1468 $( window ).bind( 'keydown', keyListener ); 1469 } ) 1470 .focus( function () { 1471 $( window ).unbind( 'keydown', keyListener ); 1472 } ); 1473 1474 var emailField = $( '#jp-carousel-comment-form-email-field' ) 1475 .blur( function () { 1476 $( window ).bind( 'keydown', keyListener ); 1477 } ) 1478 .focus( function () { 1479 $( window ).unbind( 'keydown', keyListener ); 1480 } ); 1481 1482 var authorField = $( '#jp-carousel-comment-form-author-field' ) 1483 .blur( function () { 1484 $( window ).bind( 'keydown', keyListener ); 1485 } ) 1486 .focus( function () { 1487 $( window ).unbind( 'keydown', keyListener ); 1488 } ); 1489 1490 var urlField = $( '#jp-carousel-comment-form-url-field' ) 1491 .blur( function () { 1492 $( window ).bind( 'keydown', keyListener ); 1493 } ) 1494 .focus( function () { 1495 $( window ).unbind( 'keydown', keyListener ); 1496 } ); 1497 1498 if ( textarea && textarea.attr( 'id' ) === target.attr( 'id' ) ) { 1499 // For first page load 1500 $( window ).unbind( 'keydown', keyListener ); 1501 $( '#jp-carousel-comment-form-submit-and-info-wrapper' ).slideDown( 'fast' ); 1502 } else if ( target.is( 'input[type="submit"]' ) ) { 1503 e.preventDefault(); 1504 e.stopPropagation(); 1505 1506 $( '#jp-carousel-comment-form-spinner' ).show(); 1507 1508 var ajaxData = { 1509 action: 'post_attachment_comment', 1510 nonce: jetpackCarouselStrings.nonce, 1511 blog_id: data[ 'blog_id' ], 1512 id: attachment_id, 1513 comment: textarea.val(), 1514 }; 1515 1516 if ( ! ajaxData[ 'comment' ].length ) { 1517 gallery.jp_carousel( 'postCommentError', { 1518 field: 'jp-carousel-comment-form-comment-field', 1519 error: jetpackCarouselStrings.no_comment_text, 1520 } ); 1521 return; 1522 } 1523 1524 if ( 1 !== Number( jetpackCarouselStrings.is_logged_in ) ) { 1525 ajaxData[ 'email' ] = emailField.val(); 1526 ajaxData[ 'author' ] = authorField.val(); 1527 ajaxData[ 'url' ] = urlField.val(); 1528 1529 if ( 1 === Number( jetpackCarouselStrings.require_name_email ) ) { 1530 if ( ! ajaxData[ 'email' ].length || ! ajaxData[ 'email' ].match( '@' ) ) { 1531 gallery.jp_carousel( 'postCommentError', { 1532 field: 'jp-carousel-comment-form-email-field', 1533 error: jetpackCarouselStrings.no_comment_email, 1534 } ); 1535 return; 1536 } else if ( ! ajaxData[ 'author' ].length ) { 1537 gallery.jp_carousel( 'postCommentError', { 1538 field: 'jp-carousel-comment-form-author-field', 1539 error: jetpackCarouselStrings.no_comment_author, 1540 } ); 1541 return; 1542 } 1543 } 1544 } 1545 1546 $.ajax( { 1547 type: 'POST', 1548 url: jetpackCarouselStrings.ajaxurl, 1549 data: ajaxData, 1550 dataType: 'json', 1551 success: function ( response /*, status, xhr*/ ) { 1552 if ( 'approved' === response.comment_status ) { 1553 $( '#jp-carousel-comment-post-results' ) 1554 .slideUp( 'fast' ) 1555 .html( 1556 '<span class="jp-carousel-comment-post-success">' + 1557 jetpackCarouselStrings.comment_approved + 1558 '</span>' 1559 ) 1560 .slideDown( 'fast' ); 1561 } else if ( 'unapproved' === response.comment_status ) { 1562 $( '#jp-carousel-comment-post-results' ) 1563 .slideUp( 'fast' ) 1564 .html( 1565 '<span class="jp-carousel-comment-post-success">' + 1566 jetpackCarouselStrings.comment_unapproved + 1567 '</span>' 1568 ) 1569 .slideDown( 'fast' ); 1570 } else { 1571 // 'deleted', 'spam', false 1572 $( '#jp-carousel-comment-post-results' ) 1573 .slideUp( 'fast' ) 1574 .html( 1575 '<span class="jp-carousel-comment-post-error">' + 1576 jetpackCarouselStrings.comment_post_error + 1577 '</span>' 1578 ) 1579 .slideDown( 'fast' ); 1580 } 1581 gallery.jp_carousel( 'clearCommentTextAreaValue' ); 1582 gallery.jp_carousel( 'getComments', { 1583 attachment_id: attachment_id, 1584 offset: 0, 1585 clear: true, 1586 } ); 1587 $( '#jp-carousel-comment-form-button-submit' ).val( 1588 jetpackCarouselStrings.post_comment 1589 ); 1590 $( '#jp-carousel-comment-form-spinner' ).hide(); 1591 }, 1592 error: function (/*xhr, status, error*/) { 1593 // TODO: Add error handling and display here 1594 gallery.jp_carousel( 'postCommentError', { 1595 field: 'jp-carousel-comment-form-comment-field', 1596 error: jetpackCarouselStrings.comment_post_error, 1597 } ); 1598 return; 1599 }, 1600 } ); 1601 } 1602 } else if ( ! target.parents( '.jp-carousel-info' ).length ) { 1603 container.jp_carousel( 'next' ); 1604 } 1605 } ) 1606 .bind( 'jp_carousel.afterOpen', function () { 1607 $( window ).bind( 'keydown', keyListener ); 1608 $( window ).bind( 'resize', resizeListener ); 1609 gallery.opened = true; 1610 1611 resizeListener(); 1612 } ) 1613 .bind( 'jp_carousel.beforeClose', function () { 1614 var scroll = $( window ).scrollTop(); 1615 1616 $( window ).unbind( 'keydown', keyListener ); 1617 $( window ).unbind( 'resize', resizeListener ); 1618 $( window ).scrollTop( scroll ); 1619 $( '.jp-carousel-previous-button' ).hide(); 1620 $( '.jp-carousel-next-button' ).hide(); 1621 // Set height to original value 1622 // Fix some themes where closing carousel brings view back to top 1623 $( 'html' ).css( 'height', '' ); 1624 gallery.jp_carousel( 'hide_reblog_box' ); // @hide-in-jetpack 1625 } ) 1626 .bind( 'jp_carousel.afterClose', function () { 1627 if ( window.location.hash && history.back ) { 1628 history.back(); 1629 } 1630 last_known_location_hash = ''; 1631 gallery.opened = false;
1632 } ) 1633 .on( 'transitionend.jp-carousel ', '.jp-carousel-slide', function ( e ) { 1634 // If the movement transitions take more than twice the allotted time, disable them. 1635 // There is some wiggle room in the 2x, since some of that time is taken up in 1636 // JavaScript, setting up the transition and calling the events. 1637 if ( 'transform' === e.originalEvent.propertyName ) { 1638 var transitionMultiplier = 1639 ( Date.now() - transitionBegin ) / 1000 / e.originalEvent.elapsedTime; 1640 1641 container.off( 'transitionend.jp-carousel' ); 1642 1643 if ( transitionMultiplier >= 2 ) { 1644 $( '.jp-carousel-transitions' ).removeClass( 'jp-carousel-transitions' ); 1645 } 1646 } 1647 } ); 1648 1649 $( '.jp-carousel-wrap' ).touchwipe( { 1650 wipeLeft: function ( e ) { 1651 e.preventDefault(); 1652 gallery.jp_carousel( 'next' ); 1653 }, 1654 wipeRight: function ( e ) { 1655 e.preventDefault(); 1656 gallery.jp_carousel( 'previous' ); 1657 }, 1658 preventDefaultEvents: false, 1659 } ); 1660 1661 nextButton.add( previousButton ).click( function ( e ) { 1662 e.preventDefault(); 1663 e.stopPropagation(); 1664 if ( nextButton.is( this ) ) { 1665 gallery.jp_carousel( 'next' ); 1666 } else { 1667 gallery.jp_carousel( 'previous' ); 1668 } 1669 } ); 1670 } 1671 }; 1672 1673 var processSingleImageGallery = function () { 1674 // process links that contain img tag with attribute data-attachment-id 1675 $( 'a img[data-attachment-id]' ).each( function () { 1676 var container = $( this ).parent(); 1677 1678 // skip if image was already added to gallery by shortcode 1679 if ( container.parent( '.gallery-icon' ).length ) { 1680 return; 1681 } 1682 1683 // skip if the container is not a link 1684 if ( 'undefined' === typeof $( container ).attr( 'href' ) ) { 1685 return; 1686 } 1687 1688 var valid = false; 1689 1690 // if link points to 'Media File' (ignoring GET parameters) and flag is set allow it 1691 if ( 1692 $( container ).attr( 'href' ).split( '?' )[ 0 ] === 1693 $( this ).attr( 'data-orig-file' ).split( '?' )[ 0 ] && 1694 1 === Number( jetpackCarouselStrings.single_image_gallery_media_file ) 1695 ) { 1696 valid = true; 1697 } 1698 1699 // if link points to 'Attachment Page' allow it 1700 if ( $( container ).attr( 'href' ) === $( this ).attr( 'data-permalink' ) ) { 1701 valid = true; 1702 } 1703 1704 // links to 'Custom URL' or 'Media File' when flag not set are not valid 1705 if ( ! valid ) { 1706 return; 1707 } 1708 1709 // make this node a gallery recognizable by event listener above 1710 $( container ).addClass( 'single-image-gallery' ); 1711 // blog_id is needed to allow posting comments to correct blog 1712 $( container ).data( 'carousel-extra', { 1713 blog_id: Number( jetpackCarouselStrings.blog_id ), 1714 } ); 1715 } ); 1716 }; 1717 1718 var methods = { 1719 testForData: function ( gallery ) { 1720 gallery = $( gallery ); // make sure we have it as a jQuery object. 1721 return ! ( ! gallery.length || ! gallery.data( 'carousel-extra' ) ); 1722 }, 1723 1724 testIfOpened: function () { 1725 return !! ( 1726 'undefined' !== typeof gallery && 1727 'undefined' !== typeof gallery.opened && 1728 gallery.opened 1729 ); 1730 }, 1731 1732 openOrSelectSlide: function ( index ) { 1733 // The `open` method triggers an asynchronous effect, so we will get an 1734 // error if we try to use `open` then `selectSlideAtIndex` immediately 1735 // after it. We can only use `selectSlideAtIndex` if the carousel is 1736 // already open. 1737 if ( ! $( this ).jp_carousel( 'testIfOpened' ) ) { 1738 // The `open` method selects the correct slide during the 1739 // initialization. 1740 $( this ).jp_carousel( 'open', { start_index: index } ); 1741 } else { 1742 gallery.jp_carousel( 'selectSlideAtIndex', index ); 1743 } 1744 }, 1745 1746 open: function ( options ) { 1747 var settings = { 1748 items_selector: 1749 '.gallery-item [data-attachment-id], .tiled-gallery-item [data-attachment-id], img[data-attachment-id]', 1750 start_index: 0, 1751 }, 1752 data = $( this ).data( 'carousel-extra' ); 1753 1754 if ( ! data ) { 1755 return; // don't run if the default gallery functions weren't used 1756 } 1757 1758 prepareGallery( data ); 1759 1760 if ( gallery.jp_carousel( 'testIfOpened' ) ) { 1761 return; // don't open if already opened 1762 } 1763 1764 // make sure to stop the page from scrolling behind the carousel overlay, so we don't trigger 1765 // infiniscroll for it when enabled (Reader, theme infiniscroll, etc). 1766 originalOverflow = $( 'body' ).css( 'overflow' ); 1767 $( 'body' ).css( 'overflow', 'hidden' ); 1768 // prevent html from overflowing on some of the new themes. 1769 originalHOverflow = $( 'html' ).css( 'overflow' ); 1770 $( 'html' ).css( 'overflow', 'hidden' ); 1771 scrollPos = $( window ).scrollTop(); 1772 1773 container.data( 'carousel-extra', data ); 1774// @start-hide-in-jetpack 1775 wpcom.carousel.stat( ['open', 'view_image'] ); 1776// @end-hide-in-jetpack 1777 1778 return this.each( function () { 1779 // If options exist, lets merge them 1780 // with our default settings 1781 var $this = $( this ); 1782 1783 if ( options ) { 1784 $.extend( settings, options ); 1785 } 1786 if ( -1 === settings.start_index ) { 1787 settings.start_index = 0; //-1 returned if can't find index, so start from beginning 1788 } 1789 1790 container.trigger( 'jp_carousel.beforeOpen' ).fadeIn( 'fast', function () { 1791 container.trigger( 'jp_carousel.afterOpen' ); 1792 gallery 1793 .jp_carousel( 1794 'initSlides', 1795 $this.find( settings.items_selector ), 1796 settings.start_index 1797 ) 1798 .jp_carousel( 'selectSlideAtIndex', settings.start_index ); 1799 } ); 1800 gallery.html( '' ); 1801 } ); 1802 }, 1803 1804 selectSlideAtIndex: function ( index ) { 1805 var slides = this.jp_carousel( 'slides' ), 1806 selected = slides.eq( index ); 1807 1808 if ( 0 === selected.length ) { 1809 selected = slides.eq( 0 ); 1810 } 1811 1812 gallery.jp_carousel( 'selectSlide', selected, false ); 1813 return this; 1814 }, 1815 1816 close: function () { 1817 // make sure to let the page scroll again 1818 $( 'body' ).css( 'overflow', originalOverflow ); 1819 $( 'html' ).css( 'overflow', originalHOverflow ); 1820 this.jp_carousel( 'clearCommentTextAreaValue' ); 1821 return container.trigger( 'jp_carousel.beforeClose' ).fadeOut( 'fast', function () { 1822 container.trigger( 'jp_carousel.afterClose' ); 1823 $( window ).scrollTop( scrollPos ); 1824 } ); 1825 }, 1826 1827 next: function () { 1828 this.jp_carousel( 'previousOrNext', 'nextSlide' ); 1829 gallery.jp_carousel( 'hide_reblog_box' ); // @hide-in-jetpack 1830 }, 1831 1832 previous: function () { 1833 this.jp_carousel( 'previousOrNext', 'prevSlide' ); 1834 gallery.jp_carousel( 'hide_reblog_box' ); // @hide-in-jetpack 1835 }, 1836 1837 previousOrNext: function ( slideSelectionMethodName ) { 1838 if ( ! this.jp_carousel( 'hasMultipleImages' ) ) { 1839 return false;
1840 } 1841 1842 var slide = gallery.jp_carousel( slideSelectionMethodName ); 1843 1844 if ( slide ) { 1845 container.animate( { scrollTop: 0 }, 'fast' ); 1846 this.jp_carousel( 'clearCommentTextAreaValue' ); 1847 this.jp_carousel( 'selectSlide', slide ); 1848 wpcom.carousel.stat( ['previous', 'view_image'] ); // @hide-in-jetpack 1849 } 1850 }, 1851 1852 // @start-hide-in-jetpack 1853 resetButtons : function (current) { 1854 if ( current.data( 'reblogged' ) ) { 1855 $('.jp-carousel-buttons a.jp-carousel-reblog').addClass( 'reblogged' ).text( jetpackCarouselStrings.reblogged ); 1856 } else { 1857 $('.jp-carousel-buttons a.jp-carousel-reblog').removeClass( 'reblogged' ).text( jetpackCarouselStrings.reblog ); 1858 } 1859 // Must also take care of reblog/reblogged here 1860 }, 1861 // @end-hide-in-jetpack 1862 selectedSlide: function () { 1863 return this.find( '.selected' ); 1864 }, 1865 1866 setSlidePosition: function ( x ) { 1867 transitionBegin = Date.now(); 1868 1869 return this.css( { 1870 '-webkit-transform': 'translate3d(' + x + 'px,0,0)', 1871 '-moz-transform': 'translate3d(' + x + 'px,0,0)', 1872 '-ms-transform': 'translate(' + x + 'px,0)', 1873 '-o-transform': 'translate(' + x + 'px,0)', 1874 transform: 'translate3d(' + x + 'px,0,0)', 1875 } ); 1876 }, 1877 1878 updateSlidePositions: function ( animate ) { 1879 var current = this.jp_carousel( 'selectedSlide' ), 1880 galleryWidth = gallery.width(), 1881 currentWidth = current.width(), 1882 previous = gallery.jp_carousel( 'prevSlide' ), 1883 next = gallery.jp_carousel( 'nextSlide' ), 1884 previousPrevious = previous.prev(), 1885 nextNext = next.next(), 1886 left = Math.floor( ( galleryWidth - currentWidth ) * 0.5 ); 1887 1888 current.jp_carousel( 'setSlidePosition', left ).show(); 1889 1890 // minimum width 1891 gallery.jp_carousel( 'fitInfo', animate ); 1892 1893 // prep the slides 1894 var direction = lastSelectedSlide.is( current.prevAll() ) ? 1 : -1; 1895 1896 // Since we preload the `previousPrevious` and `nextNext` slides, we need 1897 // to make sure they technically visible in the DOM, but invisible to the 1898 // user. To hide them from the user, we position them outside the edges 1899 // of the window. 1900 // 1901 // This section of code only applies when there are more than three 1902 // slides. Otherwise, the `previousPrevious` and `nextNext` slides will 1903 // overlap with the `previous` and `next` slides which must be visible 1904 // regardless. 1905 if ( 1 === direction ) { 1906 if ( ! nextNext.is( previous ) ) { 1907 nextNext.jp_carousel( 'setSlidePosition', galleryWidth + next.width() ).show(); 1908 } 1909 1910 if ( ! previousPrevious.is( next ) ) { 1911 previousPrevious 1912 .jp_carousel( 'setSlidePosition', -previousPrevious.width() - currentWidth ) 1913 .show(); 1914 } 1915 } else { 1916 if ( ! nextNext.is( previous ) ) { 1917 nextNext.jp_carousel( 'setSlidePosition', galleryWidth + currentWidth ).show(); 1918 } 1919 } 1920 1921 previous 1922 .jp_carousel( 'setSlidePosition', Math.floor( -previous.width() + screenPadding * 0.75 ) ) 1923 .show(); 1924 next 1925 .jp_carousel( 'setSlidePosition', Math.ceil( galleryWidth - screenPadding * 0.75 ) ) 1926 .show(); 1927 }, 1928 1929 selectSlide: function ( slide, animate ) { 1930 lastSelectedSlide = this.find( '.selected' ).removeClass( 'selected' ); 1931 1932 var slides = gallery.jp_carousel( 'slides' ).css( { position: 'fixed' } ), 1933 current = $( slide ).addClass( 'selected' ).css( { position: 'relative' } ), 1934 attachmentId = current.data( 'attachment-id' ), 1935 previous = gallery.jp_carousel( 'prevSlide' ), 1936 next = gallery.jp_carousel( 'nextSlide' ), 1937 previousPrevious = previous.prev(), 1938 nextNext = next.next(), 1939 animated, 1940 captionHtml; 1941 1942 // center the main image 1943 gallery.jp_carousel( 'loadFullImage', current ); 1944 1945 caption.hide(); 1946 1947 if ( next.length === 0 && slides.length <= 2 ) { 1948 $( '.jp-carousel-next-button' ).hide(); 1949 } else { 1950 $( '.jp-carousel-next-button' ).show(); 1951 } 1952 1953 if ( previous.length === 0 && slides.length <= 2 ) { 1954 $( '.jp-carousel-previous-button' ).hide(); 1955 } else { 1956 $( '.jp-carousel-previous-button' ).show(); 1957 } 1958 1959 animated = current 1960 .add( previous ) 1961 .add( previousPrevious ) 1962 .add( next ) 1963 .add( nextNext ) 1964 .jp_carousel( 'loadSlide' ); 1965 1966 // slide the whole view to the x we want 1967 slides.not( animated ).hide(); 1968 1969 gallery.jp_carousel( 'updateSlidePositions', animate ); 1970 gallery.jp_carousel( 'resetButtons', current ); // @hide-in-jetpack 1971 1972 container.trigger( 'jp_carousel.selectSlide', [ current ] ); 1973 1974 gallery.jp_carousel( 'getTitleDesc', { 1975 title: current.data( 'title' ), 1976 desc: current.data( 'desc' ), 1977 } ); 1978 1979 var imageMeta = current.data( 'image-meta' ); 1980 gallery.jp_carousel( 'updateExif', imageMeta ); 1981 gallery.jp_carousel( 'updateFullSizeLink', current ); 1982 gallery.jp_carousel( 'updateMap', imageMeta ); 1983 1984 if ( 1 === +jetpackCarouselStrings.display_comments ) { 1985 gallery.jp_carousel( 'testCommentsOpened', current.data( 'comments-opened' ) ); 1986 gallery.jp_carousel( 'getComments', { 1987 attachment_id: attachmentId, 1988 offset: 0, 1989 clear: true, 1990 } );
1991 $( '#jp-carousel-comment-post-results' ).slideUp(); 1992 } 1993 1994 // $('<div />').text(sometext).html() is a trick to go to HTML to plain 1995 // text (including HTML entities decode, etc) 1996 if ( current.data( 'caption' ) ) { 1997 captionHtml = $( '<div />' ).text( current.data( 'caption' ) ).html(); 1998 1999 if ( captionHtml === $( '<div />' ).text( current.data( 'title' ) ).html() ) { 2000 $( '.jp-carousel-titleanddesc-title' ).fadeOut( 'fast' ).empty(); 2001 } 2002 2003 if ( captionHtml === $( '<div />' ).text( current.data( 'desc' ) ).html() ) { 2004 $( '.jp-carousel-titleanddesc-desc' ).fadeOut( 'fast' ).empty(); 2005 } 2006 2007 caption.html( current.data( 'caption' ) ).fadeIn( 'slow' ); 2008 } else { 2009 caption.fadeOut( 'fast' ).empty(); 2010 } 2011 2012 // Record pageview in WP Stats, for each new image loaded full-screen. 2013 if ( jetpackCarouselStrings.stats ) { 2014 new Image().src = 2015 document.location.protocol + 2016 '//pixel.wp.com/g.gif?' + 2017 jetpackCarouselStrings.stats + 2018 '&post=' + 2019 encodeURIComponent( attachmentId ) + 2020 '&rand=' + 2021 Math.random(); 2022 } 2023 2024 wpcom.carousel.pageview( attachmentId ); // @hide-in-jetpack 2025 // Load the images for the next and previous slides. 2026 $( next ) 2027 .add( previous ) 2028 .each( function () { 2029 gallery.jp_carousel( 'loadFullImage', $( this ) ); 2030 } ); 2031 2032 window.location.hash = last_known_location_hash = '#jp-carousel-' + attachmentId; 2033 }, 2034 2035 slides: function () { 2036 return this.find( '.jp-carousel-slide' ); 2037 }, 2038 2039 slideDimensions: function () { 2040 return { 2041 width: $( window ).width() - screenPadding * 2, 2042 height: Math.floor( ( $( window ).height() / 100 ) * proportion - 60 ), 2043 }; 2044 }, 2045 2046 loadSlide: function () { 2047 return this.each( function () { 2048 var slide = $( this ); 2049 slide.find( 'img' ).one( 'load', function () { 2050 // set the width/height of the image if it's too big 2051 slide.jp_carousel( 'fitSlide', false ); 2052 } ); 2053 } ); 2054 }, 2055 2056 bestFit: function () { 2057 var max = gallery.jp_carousel( 'slideDimensions' ), 2058 orig = this.jp_carousel( 'originalDimensions' ), 2059 orig_ratio = orig.width / orig.height, 2060 w_ratio = 1, 2061 h_ratio = 1, 2062 width, 2063 height; 2064 2065 if ( orig.width > max.width ) { 2066 w_ratio = max.width / orig.width; 2067 } 2068 if ( orig.height > max.height ) { 2069 h_ratio = max.height / orig.height; 2070 } 2071 2072 if ( w_ratio < h_ratio ) { 2073 width = max.width; 2074 height = Math.floor( width / orig_ratio ); 2075 } else if ( h_ratio < w_ratio ) { 2076 height = max.height; 2077 width = Math.floor( height * orig_ratio ); 2078 } else { 2079 width = orig.width; 2080 height = orig.height; 2081 } 2082 2083 return { 2084 width: width, 2085 height: height, 2086 }; 2087 }, 2088 2089 fitInfo: function (/*animated*/) { 2090 var current = this.jp_carousel( 'selectedSlide' ), 2091 size = current.jp_carousel( 'bestFit' ); 2092 2093 photo_info.css( { 2094 left: Math.floor( ( info.width() - size.width ) * 0.5 ), 2095 width: Math.floor( size.width ), 2096 } ); 2097 2098 return this; 2099 }, 2100 2101 fitMeta: function ( animated ) { 2102 var newInfoTop = { 2103 top: Math.floor( ( $( window ).height() / 100 ) * proportion + 5 ) + 'px', 2104 }; 2105 var newLeftWidth = { width: info.width() - ( imageMeta.width() + 80 ) + 'px' }; 2106 2107 if ( animated ) { 2108 info.animate( newInfoTop ); 2109 leftColWrapper.animate( newLeftWidth ); 2110 } else { 2111 info.animate( newInfoTop ); 2112 leftColWrapper.css( newLeftWidth ); 2113 } 2114 }, 2115 2116 fitSlide: function (/*animated*/) { 2117 return this.each( function () { 2118 var $this = $( this ), 2119 dimensions = $this.jp_carousel( 'bestFit' ), 2120 method = 'css', 2121 max = gallery.jp_carousel( 'slideDimensions' ); 2122 2123 dimensions.left = 0; 2124 dimensions.top = Math.floor( ( max.height - dimensions.height ) * 0.5 ) + 40; 2125 $this[ method ]( dimensions ); 2126 } ); 2127 }, 2128 2129 texturize: function ( text ) { 2130 text = '' + text; // make sure we get a string. Title "1" came in as int 1, for example, which did not support .replace(). 2131 text = text 2132 .replace( /'/g, '’' ) 2133 .replace( /'/g, '’' ) 2134 .replace( /[\u2019]/g, '’' ); 2135 text = text 2136 .replace( /"/g, '”' ) 2137 .replace( /"/g, '”' ) 2138 .replace( /"/g, '”' ) 2139 .replace( /[\u201D]/g, '”' ); 2140 text = text.replace( /([\w]+)=&#[\d]+;(.+?)&#[\d]+;/g, '$1="$2"' ); // untexturize allowed HTML tags params double-quotes 2141 return $.trim( text ); 2142 }, 2143 2144 initSlides: function ( items, start_index ) { 2145 if ( items.length < 2 ) { 2146 $( '.jp-carousel-next-button, .jp-carousel-previous-button' ).hide(); 2147 } else { 2148 $( '.jp-carousel-next-button, .jp-carousel-previous-button' ).show(); 2149 } 2150 2151 // Calculate the new src. 2152 items.each( function (/*i*/) { 2153 var src_item = $( this ), 2154 orig_size = src_item.data( 'orig-size' ) || '', 2155 max = gallery.jp_carousel( 'slideDimensions' ), 2156 parts = orig_size.split( ',' ), 2157 medium_file = src_item.data( 'medium-file' ) || '', 2158 large_file = src_item.data( 'large-file' ) || '', 2159 src; 2160 orig_size = { width: parseInt( parts[ 0 ], 10 ), height: parseInt( parts[ 1 ], 10 ) }; 2161 2162// @start-hide-in-jetpack 2163 if ( 'undefined' !== typeof wpcom ) { 2164 src = src_item.attr('src') || src_item.attr('original') || src_item.data('original') || src_item.data('lazy-src'); 2165 if (src.indexOf('imgpress') !== -1) { 2166 src = src_item.data('orig-file'); 2167 } 2168 // Square/Circle galleries use a resize param that needs to be removed. 2169 src = wpcom.carousel.removeResizeFromImageURL( src ); 2170 src = wpcom.carousel.addWidthToImageURL( src, wpcom.carousel.findFirstLargeEnoughWidth( orig_size.width, orig_size.height, max.width, max.height ) ); 2171 } else { 2172 2173// @end-hide-in-jetpack 2174 src = src_item.data( 'orig-file' ); 2175 2176 src = gallery.jp_carousel( 'selectBestImageSize', { 2177 orig_file: src, 2178 orig_width: orig_size.width, 2179 orig_height: orig_size.height, 2180 max_width: max.width, 2181 max_height: max.height, 2182 medium_file: medium_file, 2183 large_file: large_file, 2184 } ); 2185// @start-hide-in-jetpack 2186 } // end else of if ( 'undefined' != typeof wpcom ) 2187// @end-hide-in-jetpack 2188 2189 // Set the final src 2190 $( this ).data( 'gallery-src', src ); 2191 } ); 2192 2193 // If the start_index is not 0 then preload the clicked image first. 2194 if ( 0 !== start_index ) { 2195 $( '<img/>' )[ 0 ].src = $( items[ start_index ] ).data( 'gallery-src' ); 2196 } 2197 2198 var useInPageThumbnails = 2199 items.first().closest( '.tiled-gallery.type-rectangular' ).length > 0; 2200 2201 // create the 'slide' 2202 items.each( function ( i ) { 2203 var src_item = $( this ), 2204 reblogged = src_item.data( 'reblogged' ) || 0, // @hide-in-jetpack 2205 attachment_id = src_item.data( 'attachment-id' ) || 0, 2206 comments_opened = src_item.data( 'comments-opened' ) || 0, 2207 image_meta = src_item.data( 'image-meta' ) || {}, 2208 orig_size = src_item.data( 'orig-size' ) || '',
2209 thumb_size = { width: src_item[ 0 ].naturalWidth, height: src_item[ 0 ].naturalHeight }, 2210 title = src_item.data( 'image-title' ) || '', 2211 description = src_item.data( 'image-description' ) || '', 2212 caption = src_item.parents( '.gallery-item' ).find( '.gallery-caption' ).html() || '', 2213 src = src_item.data( 'gallery-src' ) || '', 2214 medium_file = src_item.data( 'medium-file' ) || '', 2215 large_file = src_item.data( 'large-file' ) || '', 2216 orig_file = src_item.data( 'orig-file' ) || ''; 2217 2218 var tiledCaption = src_item 2219 .parents( 'div.tiled-gallery-item' ) 2220 .find( 'div.tiled-gallery-caption' ) 2221 .html(); 2222 if ( tiledCaption ) { 2223 caption = tiledCaption; 2224 } 2225 2226 if ( attachment_id && orig_size.length ) { 2227 title = gallery.jp_carousel( 'texturize', title ); 2228 description = gallery.jp_carousel( 'texturize', description ); 2229 caption = gallery.jp_carousel( 'texturize', caption ); 2230 2231 // Initially, the image is a 1x1 transparent gif. The preview is shown as a background image on the slide itself. 2232 var image = $( '<img/>' ) 2233 .attr( 2234 'src', 2235 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7' 2236 ) 2237 .css( 'width', '100%' ) 2238 .css( 'height', '100%' ); 2239 2240 var slide = $( 2241 '<div class="jp-carousel-slide" itemprop="associatedMedia" itemscope itemtype="https://schema.org/ImageObject"></div>' 2242 ) 2243 .hide() 2244 .css( { 2245 //'position' : 'fixed', 2246 left: i < start_index ? -1000 : gallery.width(), 2247 } ) 2248 .append( image ) 2249 .appendTo( gallery ) 2250 .data( 'src', src ) 2251 .data( 'title', title ) 2252 .data( 'desc', description ) 2253 .data( 'caption', caption ) 2254 .data( 'attachment-id', attachment_id ) 2255 .data( 'permalink', src_item.parents( 'a' ).attr( 'href' ) ) 2256 .data( 'orig-size', orig_size ) 2257 .data( 'comments-opened', comments_opened ) 2258 .data( 'image-meta', image_meta ) 2259 .data( 'medium-file', medium_file ) 2260 .data( 'large-file', large_file ) 2261 .data( 'orig-file', orig_file ) 2262 .data( 'reblogged', reblogged ) // @hide-in-jetpack 2263 .data( 'thumb-size', thumb_size ); 2264 if ( useInPageThumbnails ) { 2265 // Use the image already loaded in the gallery as a preview. 2266 slide.data( 'preview-image', src_item.attr( 'src' ) ).css( { 2267 'background-image': 'url("' + src_item.attr( 'src' ) + '")', 2268 'background-size': '100% 100%', 2269 'background-position': 'center center', 2270 } ); 2271 } 2272 2273 slide.jp_carousel( 'fitSlide', false ); 2274 } 2275 } ); 2276 return this; 2277 }, 2278 2279 selectBestImageSize: function ( args ) { 2280 if ( 'object' !== typeof args ) { 2281 args = {}; 2282 } 2283 2284 if ( 'undefined' === typeof args.orig_file ) { 2285 return ''; 2286 } 2287 2288 if ( 'undefined' === typeof args.orig_width || 'undefined' === typeof args.max_width ) { 2289 return args.orig_file; 2290 } 2291 2292 if ( 'undefined' === typeof args.medium_file || 'undefined' === typeof args.large_file ) { 2293 return args.orig_file; 2294 } 2295 2296 // Check if the image is being served by Photon (using a regular expression on the hostname). 2297 2298 var imageLinkParser = document.createElement( 'a' ); 2299 imageLinkParser.href = args.large_file; 2300 2301 var isPhotonUrl = /^i[0-2].wp.com$/i.test( imageLinkParser.hostname ); 2302 2303 var medium_size_parts = gallery.jp_carousel( 2304 'getImageSizeParts', 2305 args.medium_file, 2306 args.orig_width, 2307 isPhotonUrl 2308 ); 2309 var large_size_parts = gallery.jp_carousel( 2310 'getImageSizeParts', 2311 args.large_file, 2312 args.orig_width, 2313 isPhotonUrl 2314 ); 2315 2316 var large_width = parseInt( large_size_parts[ 0 ], 10 ), 2317 large_height = parseInt( large_size_parts[ 1 ], 10 ), 2318 medium_width = parseInt( medium_size_parts[ 0 ], 10 ), 2319 medium_height = parseInt( medium_size_parts[ 1 ], 10 ); 2320 2321 // Assign max width and height. 2322 args.orig_max_width = args.max_width; 2323 args.orig_max_height = args.max_height; 2324 2325 // Give devices with a higher devicePixelRatio higher-res images (Retina display = 2, Android phones = 1.5, etc) 2326 if ( 'undefined' !== typeof window.devicePixelRatio && window.devicePixelRatio > 1 ) { 2327 args.max_width = args.max_width * window.devicePixelRatio; 2328 args.max_height = args.max_height * window.devicePixelRatio; 2329 } 2330 2331 if ( large_width >= args.max_width || large_height >= args.max_height ) { 2332 return args.large_file; 2333 } 2334 2335 if ( medium_width >= args.max_width || medium_height >= args.max_height ) { 2336 return args.medium_file; 2337 } 2338 2339 if ( isPhotonUrl ) { 2340 // args.orig_file doesn't point to a Photon url, so in this case we use args.large_file 2341 // to return the photon url of the original image. 2342 var largeFileIndex = args.large_file.lastIndexOf( '?' ); 2343 var origPhotonUrl = args.large_file; 2344 if ( -1 !== largeFileIndex ) { 2345 origPhotonUrl = args.large_file.substring( 0, largeFileIndex ); 2346 // If we have a really large image load a smaller version 2347 // that is closer to the viewable size 2348 if ( args.orig_width > args.max_width || args.orig_height > args.max_height ) { 2349 origPhotonUrl += '?fit=' + args.orig_max_width + '%2C' + args.orig_max_height; 2350 } 2351 } 2352 return origPhotonUrl; 2353 } 2354 2355 return args.orig_file; 2356 }, 2357 2358 getImageSizeParts: function ( file, orig_width, isPhotonUrl ) { 2359 var size = isPhotonUrl 2360 ? file.replace( /.*=([\d]+%2C[\d]+).*$/, '$1' ) 2361 : file.replace( /.*-([\d]+x[\d]+)\..+$/, '$1' ); 2362 2363 var size_parts = 2364 size !== file 2365 ? isPhotonUrl 2366 ? size.split( '%2C' ) 2367 : size.split( 'x' ) 2368 : [ orig_width, 0 ]; 2369 2370 // If one of the dimensions is set to 9999, then the actual value of that dimension can't be retrieved from the url. 2371 // In that case, we set the value to 0. 2372 if ( '9999' === size_parts[ 0 ] ) { 2373 size_parts[ 0 ] = '0'; 2374 } 2375 2376 if ( '9999' === size_parts[ 1 ] ) { 2377 size_parts[ 1 ] = '0'; 2378 } 2379 2380 return size_parts; 2381 }, 2382 2383// @start-hide-in-jetpack 2384 show_reblog_box: function () { 2385 $('#carousel-reblog-box textarea').val(jetpackCarouselStrings.reblog_add_thoughts); 2386 //t.addClass('selected'); 2387 $('#carousel-reblog-box p.response').remove(); 2388 $('#carousel-reblog-box div.submit, #carousel-reblog-box div.submit span.canceltext').show(); 2389 $('#carousel-reblog-box div.submit input[type=submit]').prop('disabled', false); 2390 2391 var current = $('.jp-carousel div.selected'); 2392 $('#carousel-reblog-box input#carousel-reblog-post-url').val( current.data('permalink') ); 2393 $('#carousel-reblog-box input#carousel-reblog-post-title').val( $('div.jp-carousel-info').children('h2').text() ); 2394 2395 $('div.jp-carousel-info').append( $('#carousel-reblog-box') ).children().fadeOut('fast'); 2396 $('#carousel-reblog-box').fadeIn('fast'); 2397 }, 2398 2399 hide_reblog_box: function () { 2400 $( 'div.jp-carousel-info' ).children().not( '#carousel-reblog-box' ).fadeIn( 'fast' ); 2401 $( '#carousel-reblog-box' ).fadeOut( 'fast' ); 2402 }, 2403// @end-hide-in-jetpack 2404 originalDimensions: function () { 2405 var splitted = $( this ).data( 'orig-size' ).split( ',' ); 2406 return { width: parseInt( splitted[ 0 ], 10 ), height: parseInt( splitted[ 1 ], 10 ) }; 2407 }, 2408 2409 format: function ( args ) { 2410 if ( 'object' !== typeof args ) { 2411 args = {}; 2412 } 2413 if ( ! args.text || 'undefined' === typeof args.text ) { 2414 return; 2415 } 2416 if ( ! args.replacements || 'undefined' === typeof args.replacements ) { 2417 return args.text; 2418 } 2419 return args.text.replace( /{(\d+)}/g, function ( match, number ) { 2420 return typeof args.replacements[ number ] !== 'undefined' 2421 ? args.replacements[ number ] 2422 : match; 2423 } ); 2424 }, 2425 2426 /** 2427 * Returns a number in a fraction format that represents the shutter speed. 2428 * @param Number speed 2429 * @return String 2430 */ 2431 shutterSpeed: function ( speed ) { 2432 var denominator; 2433 2434 // round to one decimal if value >
2434 1s by multiplying it by 10, rounding, then dividing by 10 again 2435 if ( speed >= 1 ) { 2436 return Math.round( speed * 10 ) / 10 + 's'; 2437 } 2438 2439 // If the speed is less than one, we find the denominator by inverting 2440 // the number. Since cameras usually use rational numbers as shutter 2441 // speeds, we should get a nice round number. Or close to one in cases 2442 // like 1/30. So we round it. 2443 denominator = Math.round( 1 / speed ); 2444 2445 return '1/' + denominator + 's'; 2446 }, 2447 2448 parseTitleDesc: function ( value ) { 2449 if ( ! value.match( ' ' ) && value.match( '_' ) ) { 2450 return ''; 2451 } 2452 2453 return value; 2454 }, 2455 2456 getTitleDesc: function ( data ) { 2457 var title = '', 2458 desc = '', 2459 markup = '', 2460 target; 2461 2462 target = $( 'div.jp-carousel-titleanddesc', 'div.jp-carousel-wrap' ); 2463 target.hide(); 2464 2465 title = gallery.jp_carousel( 'parseTitleDesc', data.title ) || ''; 2466 desc = gallery.jp_carousel( 'parseTitleDesc', data.desc ) || ''; 2467 2468 if ( title.length || desc.length ) { 2469 // Convert from HTML to plain text (including HTML entities decode, etc) 2470 if ( $( '<div />' ).html( title ).text() === $( '<div />' ).html( desc ).text() ) { 2471 title = ''; 2472 } 2473 2474 markup = title.length 2475 ? '<div class="jp-carousel-titleanddesc-title">' + title + '</div>' 2476 : ''; 2477 markup += desc.length 2478 ? '<div class="jp-carousel-titleanddesc-desc">' + desc + '</div>' 2479 : ''; 2480 2481 target.html( markup ).fadeIn( 'slow' ); 2482 } 2483 2484 $( 'div#jp-carousel-comment-form-container' ).css( 'margin-top', '20px' ); 2485 $( 'div#jp-carousel-comments-loading' ).css( 'margin-top', '20px' ); 2486 }, 2487 2488 // updateExif updates the contents of the exif UL (.jp-carousel-image-exif) 2489 updateExif: function ( meta ) { 2490 if ( ! meta || 1 !== Number( jetpackCarouselStrings.display_exif ) ) { 2491 return false; 2492 } 2493 2494 var $ul = $( "<ul class='jp-carousel-image-exif'></ul>" ); 2495 2496 $.each( meta, function ( key, val ) { 2497 if ( 2498 0 === parseFloat( val ) || 2499 ! val.length || 2500 -1 === $.inArray( key, $.makeArray( jetpackCarouselStrings.meta_data ) ) 2501 ) { 2502 return; 2503 } 2504 2505 switch ( key ) { 2506 case 'focal_length': 2507 val = val + 'mm'; 2508 break; 2509 case 'shutter_speed': 2510 val = gallery.jp_carousel( 'shutterSpeed', val ); 2511 break; 2512 case 'aperture': 2513 val = 'f/' + val; 2514 break; 2515 } 2516 2517 $ul.append( '<li><h5>' + jetpackCarouselStrings[ key ] + '</h5>' + val + '</li>' ); 2518 } ); 2519 2520 // Update (replace) the content of the ul 2521 $( 'div.jp-carousel-image-meta ul.jp-carousel-image-exif' ).replaceWith( $ul ); 2522 }, 2523 2524 // updateFullSizeLink updates the contents of the jp-carousel-image-download link 2525 updateFullSizeLink: function ( current ) { 2526 if ( ! current || ! current.data ) { 2527 return false; 2528 } 2529 var original, 2530 origSize = current.data( 'orig-size' ).split( ',' ), 2531 imageLinkParser = document.createElement( 'a' ); 2532 2533 imageLinkParser.href = current.data( 'src' ).replace( /\?.+$/, '' ); 2534 2535 // Is this a Photon URL? 2536 if ( imageLinkParser.hostname.match( /^i[\d]{1}.wp.com$/i ) !== null ) { 2537 original = imageLinkParser.href; 2538 } else { 2539 original = current.data( 'orig-file' ).replace( /\?.+$/, '' ); 2540 } 2541 2542 var permalink = $( 2543 '<a>' + 2544 gallery.jp_carousel( 'format', { 2545 text: jetpackCarouselStrings.download_original, 2546 replacements: origSize, 2547 } ) + 2548 '</a>' 2549 ) 2550 .addClass( 'jp-carousel-image-download' ) 2551 .attr( 'href', original ) 2552 .attr( 'target', '_blank' ); 2553 2554 // Update (replace) the content of the anchor 2555 $( 'div.jp-carousel-image-meta a.jp-carousel-image-download' ).replaceWith( permalink ); 2556 }, 2557 2558 updateMap: function ( meta ) { 2559 if ( 2560 ! meta.latitude || 2561 ! meta.longitude || 2562 1 !== Number( jetpackCarouselStrings.display_geo ) 2563 ) { 2564 return; 2565 } 2566 2567 var latitude = meta.latitude, 2568 longitude = meta.longitude, 2569 $metabox = $( 'div.jp-carousel-image-meta', 'div.jp-carousel-wrap' ), 2570 $mapbox = $( '<div></div>' ), 2571 style = 2572 '&scale=2&style=feature:all|element:all|invert_lightness:true|hue:0x0077FF|saturation:-50|lightness:-5|gamma:0.91'; 2573 2574 $mapbox 2575 .addClass( 'jp-carousel-image-map' ) 2576 .html( 2577 '<img width="154" height="154" src="https://maps.googleapis.com/ma
2577ps/api/staticmap?\ 2578 center=' + 2579 latitude + 2580 ',' + 2581 longitude + 2582 '&\ 2583 zoom=8&\ 2584 size=154x154&\ 2585 sensor=false&\ 2586 markers=size:medium%7Ccolor:blue%7C' + 2587 latitude + 2588 ',' + 2589 longitude + 2590 style + 2591 '" class="gmap-main" />\ 2592 \ 2593 <div class="gmap-topright"><div class="imgclip"><img width="175" height="154" src="https://maps.googleapis.com/maps/api/staticmap?\ 2594 center=' + 2595 latitude + 2596 ',' + 2597 longitude + 2598 '&\ 2599 zoom=3&\ 2600 size=175x154&\ 2601 sensor=false&\ 2602 markers=size:small%7Ccolor:blue%7C' + 2603 latitude + 2604 ',' + 2605 longitude + 2606 style + 2607 '"c /></div></div>\ 2608 \ 2609 ' 2610 ) 2611 .prependTo( $metabox ); 2612 }, 2613 2614 testCommentsOpened: function ( opened ) { 2615 if ( 1 === parseInt( opened, 10 ) ) { 2616// @start-hide-in-jetpack 2617 if ( 1 === Number( jetpackCarouselStrings.is_logged_in ) ) { 2618 $('.jp-carousel-commentlink').fadeIn('fast'); 2619 } else { 2620// @end-hide-in-jetpack 2621 $( '.jp-carousel-buttons' ).fadeIn( 'fast' ); 2622// @start-hide-in-jetpack 2623 } 2624// @end-hide-in-jetpack 2625 commentForm.fadeIn( 'fast' ); 2626 } else { 2627// @start-hide-in-jetpack 2628 if ( 1 === Number( jetpackCarouselStrings.is_logged_in ) ) { 2629 $('.jp-carousel-commentlink').fadeOut('fast'); 2630 } else { 2631// @end-hide-in-jetpack 2632 $( '.jp-carousel-buttons' ).fadeOut( 'fast' ); 2633// @start-hide-in-jetpack 2634 } 2635// @end-hide-in-jetpack 2636 commentForm.fadeOut( 'fast' ); 2637 } 2638 }, 2639 2640 getComments: function ( args ) { 2641 clearInterval( commentInterval ); 2642 2643 if ( 'object' !== typeof args ) { 2644 return; 2645 } 2646 2647 if ( 'undefined' === typeof args.attachment_id || ! args.attachment_id ) { 2648 return; 2649 } 2650 2651 if ( ! args.offset || 'undefined' === typeof args.offset || args.offset < 1 ) { 2652 args.offset = 0; 2653 } 2654 2655 var comments = $( '.jp-carousel-comments' ), 2656 commentsLoading = $( '#jp-carousel-comments-loading' ).show(); 2657 2658 if ( args.clear ) { 2659 comments.hide().empty(); 2660 } 2661 2662 $.ajax( { 2663 type: 'GET', 2664 url: jetpackCarouselStrings.ajaxurl, 2665 dataType: 'json', 2666 data: { 2667 action: 'get_attachment_comments', 2668 nonce: jetpackCarouselStrings.nonce, 2669 id: args.attachment_id, 2670 offset: args.offset, 2671 }, 2672 success: function ( data /*, status, xhr*/ ) { 2673 if ( args.clear ) { 2674 comments.fadeOut( 'fast' ).empty(); 2675 } 2676 2677 $( data ).each( function () { 2678 var comment = $( '<div></div>' ) 2679 .addClass( 'jp-carousel-comment' ) 2680 .attr( 'id', 'jp-carousel-comment-' + this[ 'id' ] ) 2681 .html( 2682 '<div class="comment-gravatar">' + 2683 this[ 'gravatar_markup' ] + 2684 '</div>' + 2685 '<div class="comment-author">' + 2686 this[ 'author_markup' ] + 2687 '</div>' + 2688 '<div class="comment-date">' + 2689 this[ 'date_gmt' ] + 2690 '</div>' + 2691 '<div class="comment-content">' + 2692 this[ 'content' ] + 2693 '</div>' 2694 ); 2695 comments.append( comment ); 2696 2697 // Set the interval to check for a new page of comments. 2698 clearInterval( commentInterval ); 2699 commentInterval = setInterval( function () { 2700 if ( 2701 $( '.jp-carousel-overlay' ).height() - 150 < 2702 $( '.jp-carousel-wrap' ).scrollTop() + $( window ).height() 2703 ) { 2704 gallery.jp_carousel( 'getComments', { 2705 attachment_id: args.attachment_id, 2706 offset: args.offset + 10, 2707 clear: false, 2708 } ); 2709 clearInterval( commentInterval ); 2710 } 2711 }, 300 ); 2712 } ); 2713 2714 // Verify (late) that the user didn't repeatldy click the arrows really fast, in which case the requested 2715 // attachment id might no longer match the current attachment id by the time we get the data back or a now 2716 // registered infiniscroll event kicks in, so we don't ever display comments for the wrong image by mistake. 2717 var current = $( '.jp-carousel div.selected' ); 2718 if ( current && current.data && current.data( 'attachment-id' ) != args.attachment_id ) { 2719 comments.fadeOut( 'fast' ); 2720 comments.empty(); 2721 return; 2722 } 2723 2724 // Increase the height of the background, semi-transparent overlay to match the new length of the comments list. 2725 $( '.jp-carousel-overlay' ).height( 2726 $( window ).height() + 2727 titleAndDescription.height() + 2728 commentForm.height() + 2729 ( comments.height() > 0 ? comments.height() : imageMeta.height() ) + 2730 200 2731 ); 2732 2733 comments.show(); 2734 commentsLoading.hide(); 2735 }, 2736 error: function ( xhr, status, error ) { 2737 // TODO: proper error handling 2738 console.log( 'Comment get fail...', xhr, status, error ); 2739 comments.fadeIn( 'fast' ); 2740 commentsLoading.fadeOut( 'fast' ); 2741 }, 2742 } ); 2743 }, 2744 2745 postCommentError: function ( args ) { 2746 if ( 'object' !== typeof args ) { 2747 args = {}; 2748 } 2749 if ( 2750 ! args.field || 2751 'undefined' === typeof args.field || 2752 ! args.error || 2753 'undefined' === typeof args.error 2754 ) { 2755 return; 2756 } 2757 $( '#jp-carousel-comment-post-results' ) 2758 .slideUp( 'fast' ) 2759 .html( '<span class="jp-carousel-comment-post-error">' + args.error + '</span>' ) 2760 .slideDown( 'fast' ); 2761 $( '#jp-carousel-comment-form-spinner' ).hide(); 2762 }, 2763 2764 setCommentIframeSrc: function ( attachment_id ) { 2765 var iframe = $( '#jp-carousel-comment-iframe' ); 2766 // Set the proper irame src for the current attachment id 2767 if ( iframe && iframe.length ) { 2768 iframe.attr( 'src', iframe.attr( 'src' ).replace( /(postid=)\d+/, '$1' + attachment_id ) ); 2769 iframe.attr( 2770 'src', 2771 iframe.attr( 'src' ).replace( /(%23.+)?$/, '%23jp-carousel-' + attachment_id ) 2772 ); 2773 } 2774 }, 2775 2776 clearCommentTextAreaValue: function () { 2777 var commentTextArea = $( '#jp-carousel-comment-form-comment-field' ); 2778 if ( commentTextArea ) { 2779 commentTextArea.val( '' ); 2780 } 2781 }, 2782 2783 nextSlide: function () { 2784 var slides = this.jp_carousel( 'slides' ); 2785 var selected = this.jp_carousel( 'selectedSlide' ); 2786 2787 if ( selected.length === 0 || ( slides.length > 2 && selected.is( slides.last() ) ) ) { 2788 return slides.first(); 2789 } 2790 2791 return selected.next(); 2792 }, 2793 2794 prevSlide: function () { 2795 var slides = this.jp_carousel( 'slides' ); 2796 var selected = this.jp_carousel( 'selectedSlide' ); 2797 2798 if ( selected.length === 0 || ( slides.length > 2 && selected.is( slides.first() ) ) ) { 2799 return slides.last(); 2800 } 2801 2802 return selected.prev(); 2803 }, 2804 2805 loadFullImage: function ( slide ) {
2806 var image = slide.find( 'img:first' ); 2807 2808 if ( ! image.data( 'loaded' ) ) { 2809 // If the width of the slide is smaller than the width of the "thumbnail" we're already using, 2810 // don't load the full image. 2811 2812 image.on( 'load.jetpack', function () { 2813 image.off( 'load.jetpack' ); 2814 $( this ).closest( '.jp-carousel-slide' ).css( 'background-image', '' ); 2815 } ); 2816 2817 if ( 2818 ! slide.data( 'preview-image' ) || 2819 ( slide.data( 'thumb-size' ) && slide.width() > slide.data( 'thumb-size' ).width ) 2820 ) { 2821 image 2822 .attr( 'src', image.closest( '.jp-carousel-slide' ).data( 'src' ) ) 2823 .attr( 'itemprop', 'image' ); 2824 } else { 2825 image.attr( 'src', slide.data( 'preview-image' ) ).attr( 'itemprop', 'image' ); 2826 } 2827 2828 image.data( 'loaded', 1 ); 2829 } 2830 }, 2831 2832 hasMultipleImages: function () { 2833 return gallery.jp_carousel( 'slides' ).length > 1; 2834 }, 2835 }; 2836 2837 $.fn.jp_carousel = function ( method ) { 2838 // ask for the HTML of the gallery 2839 // Method calling logic 2840 if ( methods[ method ] ) { 2841 return methods[ method ].apply( this, Array.prototype.slice.call( arguments, 1 ) ); 2842 } else if ( typeof method === 'object' || ! method ) { 2843 return methods.open.apply( this, arguments ); 2844 } else { 2845 $.error( 'Method ' + method + ' does not exist on jQuery.jp_carousel' ); 2846 } 2847 }; 2848 2849 // register the event listener for starting the gallery 2850 $( document.body ).on( 2851 'click.jp-carousel', 2852 'div.gallery, div.tiled-gallery, ul.wp-block-gallery, ul.blocks-gallery-grid, div.wp-block-jetpack-tiled-gallery, a.single-image-gallery', 2853 function ( e ) { 2854 if ( ! $( this ).jp_carousel( 'testForData', e.currentTarget ) ) { 2855 return; 2856 } 2857 2858 // Do not open the modal if we are looking at a gallery caption from before WP5, which may contain a link. 2859 if ( $( e.target ).parent().hasClass( 'gallery-caption' ) ) { 2860 return; 2861 } 2862 2863 // Do not open the modal if we are looking at a caption of a gallery block, which may contain a link. 2864 if ( $( e.target ).parent().is( 'figcaption' ) ) { 2865 return; 2866 } 2867 2868 // Set height to auto 2869 // Fix some themes where closing carousel brings view back to top 2870 $( 'html' ).css( 'height', 'auto' ); 2871 2872 e.preventDefault(); 2873 2874 // Stopping propagation in case there are parent elements 2875 // with .gallery or .tiled-gallery class 2876 e.stopPropagation(); 2877 $( this ).jp_carousel( 'open', { 2878 start_index: $( this ) 2879 .find( '.gallery-item, .tiled-gallery-item, .blocks-gallery-item, .tiled-gallery__item' ) 2880 .index( 2881 $( e.target ).parents( 2882 '.gallery-item, .tiled-gallery-item, .blocks-gallery-item, .tiled-gallery__item' 2883 ) 2884 ), 2885 } ); 2886 } 2887 ); 2888 2889 // handle lightbox (single image gallery) for images linking to 'Attachment Page' 2890 if ( 1 === Number( jetpackCarouselStrings.single_image_gallery ) ) { 2891 processSingleImageGallery(); 2892 $( document.body ).on( 'post-load', function () { 2893 processSingleImageGallery(); 2894 } ); 2895 } 2896 2897 // Makes carousel work on page load and when back button leads to same URL with carousel hash (ie: no actual document.ready trigger) 2898 $( window ).on( 'hashchange.jp-carousel', function () { 2899 var hashRegExp = /jp-carousel-(\d+)/, 2900 matches, 2901 attachmentId, 2902 galleries, 2903 selectedThumbnail; 2904 2905 if ( ! window.location.hash || ! hashRegExp.test( window.location.hash ) ) { 2906 if ( gallery && gallery.opened ) { 2907 container.jp_carousel( 'close' ); 2908 } 2909 2910 return; 2911 } 2912 2913 if ( window.location.hash === last_known_location_hash && gallery.opened ) { 2914 return; 2915 } 2916 2917 if ( window.location.hash && gallery && ! gallery.opened && history.back ) { 2918 history.back(); 2919 return; 2920 } 2921 2922 last_known_location_hash = window.location.hash; 2923 matches = window.location.hash.match( hashRegExp ); 2924 attachmentId = parseInt( matches[ 1 ], 10 ); 2925 galleries = $( 2926 'div.gallery, div.tiled-gallery, a.single-image-gallery, ul.wp-block-gallery, div.wp-block-jetpack-tiled-gallery' 2927 ); 2928 2929 // Find the first thumbnail that matches the attachment ID in the location 2930 // hash, then open the gallery that contains it. 2931 galleries.each( function ( _, galleryEl ) { 2932 $( galleryEl )
2933 .find( 'img' ) 2934 .each( function ( imageIndex, imageEl ) { 2935 if ( $( imageEl ).data( 'attachment-id' ) === parseInt( attachmentId, 10 ) ) { 2936 selectedThumbnail = { index: imageIndex, gallery: galleryEl }; 2937 return false; 2938 } 2939 } ); 2940 2941 if ( selectedThumbnail ) { 2942 $( selectedThumbnail.gallery ).jp_carousel( 'openOrSelectSlide', selectedThumbnail.index ); 2943 return false; 2944 } 2945 } ); 2946 } ); 2947 2948 if ( window.location.hash ) { 2949 $( window ).trigger( 'hashchange' ); 2950 } 2951} ); 2952 2953/** 2954 * jQuery Plugin to obtain touch gestures from iPhone, iPod Touch and iPad, should also work with Android mobile phones (not tested yet!) 2955 * Common usage: wipe images (left and right to show the previous or next image) 2956 * 2957 * @author Andreas Waltl, netCU Internetagentur (http://www.netcu.de) 2958 * Version 1.1.1, modified to pass the touchmove event to the callbacks. 2959 */ 2960( function ( $ ) { 2961 $.fn.touchwipe = function ( settings ) { 2962 var config = { 2963 min_move_x: 20, 2964 min_move_y: 20, 2965 wipeLeft: function (/*e*/) {}, 2966 wipeRight: function (/*e*/) {}, 2967 wipeUp: function (/*e*/) {}, 2968 wipeDown: function (/*e*/) {}, 2969 preventDefaultEvents: true, 2970 }; 2971 2972 if ( settings ) { 2973 $.extend( config, settings ); 2974 } 2975 2976 this.each( function () { 2977 var startX; 2978 var startY; 2979 var isMoving = false; 2980 2981 function cancelTouch() { 2982 this.removeEventListener( 'touchmove', onTouchMove ); 2983 startX = null; 2984 isMoving = false; 2985 } 2986 2987 function onTouchMove( e ) { 2988 if ( config.preventDefaultEvents ) { 2989 e.preventDefault(); 2990 } 2991 if ( isMoving ) { 2992 var x = e.touches[ 0 ].pageX; 2993 var y = e.touches[ 0 ].pageY; 2994 var dx = startX - x; 2995 var dy = startY - y; 2996 if ( Math.abs( dx ) >= config.min_move_x ) { 2997 cancelTouch(); 2998 if ( dx > 0 ) { 2999 config.wipeLeft( e ); 3000 } else { 3001 config.wipeRight( e ); 3002 } 3003 } else if ( Math.abs( dy ) >= config.min_move_y ) { 3004 cancelTouch(); 3005 if ( dy > 0 ) { 3006 config.wipeDown( e ); 3007 } else { 3008 config.wipeUp( e ); 3009 } 3010 } 3011 } 3012 } 3013 3014 function onTouchStart( e ) { 3015 if ( e.touches.length === 1 ) { 3016 startX = e.touches[ 0 ].pageX; 3017 startY = e.touches[ 0 ].pageY; 3018 isMoving = true; 3019 this.addEventListener( 'touchmove', onTouchMove, false ); 3020 } 3021 } 3022 if ( 'ontouchstart' in document.documentElement ) { 3023 this.addEventListener( 'touchstart', onTouchStart, false ); 3024 } 3025 } ); 3026 3027 return this; 3028 }; 3029} )( jQuery ); 3030;
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.