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