/* Detect-zoom
* -----------
* Cross Browser Zoom and Pixel Ratio Detector
* Version 1.0.4 | Apr 1 2013
* dual-licensed under the WTFPL and MIT license
* Maintained by https://github/tombigel
* Original developer https://github.com/yonran
*/
//AMD and CommonJS initialization copied from https://github.com/zohararad/audio5js
(function (root, ns, factory) {
"use strict";
if (typeof (module) !== 'undefined' && module.exports) { // CommonJS
module.exports = factory(ns, root);
} else if (typeof (define) === 'function' && define.amd) { // AMD
define("factory", function () {
return factory(ns, root);
});
} else {
root[ns] = factory(ns, root);
}
}(window, 'detectZoom', function () {
/**
* Use devicePixelRatio if supported by the browser
* @return {Number}
* @private
*/
var devicePixelRatio = function () {
return window.devicePixelRatio || 1;
};
/**
* Fallback function to set default values
* @return {Object}
* @private
*/
var fallback = function () {
return {
zoom: 1,
devicePxPerCssPx: 1
};
};
/**
* IE 8 and 9: no trick needed!
* TODO: Test on IE10 and Windows 8 RT
* @return {Object}
* @private
**/
var ie8 = function () {
var zoom = Math.round((screen.deviceXDPI / screen.logicalXDPI) * 100) / 100;
return {
zoom: zoom,
devicePxPerCssPx: zoom * devicePixelRatio()
};
};
/**
* For IE10 we need to change our technique again...
* thanks https://github.com/stefanvanburen
* @return {Object}
* @private
*/
var ie10 = function () {
var zoom = Math.round((document.documentElement.offsetHeight / window.innerHeight) * 100) / 100;
return {
zoom: zoom,
devicePxPerCssPx: zoom * devicePixelRatio()
};
};
/**
* Mobile WebKit
* the trick: window.innerWIdth is in CSS pixels, while
* screen.width and screen.height are in system pixels.
* And there are no scrollbars to mess up the measurement.
* @return {Object}
* @private
*/
var webkitMobile = function () {
var deviceWidth = (Math.abs(window.orientation) == 90) ? screen.height : screen.width;
var zoom = deviceWidth / window.innerWidth;
return {
zoom: zoom,
devicePxPerCssPx: zoom * devicePixelRatio()
};
};
/**
* Desktop Webkit
* the trick: an element's clientHeight is in CSS pixels, while you can
* set its line-height in system pixels using font-size and
* -webkit-text-size-adjust:none.
* device-pixel-ratio: http://www.webkit.org/blog/55/high-dpi-web-sites/
*
* Previous trick (used before http://trac.webkit.org/changeset/100847):
* documentElement.scrollWidth is in CSS pixels, while
* document.width was in system pixels. Note that this is the
* layout width of the document, which is slightly different from viewport
* because document width does not include scrollbars and might be wider
* due to big elements.
* @return {Object}
* @private
*/
var webkit = function () {
var important = function (str) {
return str.replace(/;/g, " !important;");
};
var div = document.createElement('div');
div.innerHTML = "1
2
3
4
5
6
7
8
9
0";
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;'));
// The container exists so that the div will be laid out in its own flow
// while not impacting the layout, viewport size, or display of the
// webpage as a whole.
// Add !important and relevant CSS rule resets
// so that other rules cannot affect the results.
var container = document.createElement('div');
container.setAttribute('style', important('width:0; height:0; overflow:hidden; visibility:hidden; position: absolute;'));
container.appendChild(div);
document.body.appendChild(container);
var zoom = 1000 / div.clientHeight;
zoom = Math.round(zoom * 100) / 100;
document.body.removeChild(container);
return{
zoom: zoom,
devicePxPerCssPx: zoom * devicePixelRatio()
};
};
/**
* no real trick; device-pixel-ratio is the ratio of device dpi / css dpi.
* (Note that this is a different interpretation than Webkit's device
* pixel ratio, which is the ratio device dpi / system dpi).
*
* Also, for Mozilla, there is no difference between the zoom factor and the device ratio.
*
* @return {Object}
* @private
*/
var firefox4 = function () {
var zoom = mediaQueryBinarySearch('min--moz-device-pixel-ratio', '', 0, 10, 20, 0.0001);
zoom = Math.round(zoom * 100) / 100;
return {
zoom: zoom,
devicePxPerCssPx: zoom
};
};
/**
* Firefox 18.x
* Mozilla added support for devicePixelRatio to Firefox 18,
* but it is affected by the zoom level, so, like in older
* Firefox we can't tell if we are in zoom mode or in a device
* with a different pixel ratio
* @return {Object}
* @private
*/
var firefox18 = function () {
return {
zoom: firefox4().zoom,
devicePxPerCssPx: devicePixelRatio()
};
};
/**
* works starting Opera 11.11
* the trick: outerWidth is the viewport width including scrollbars in
* system px, while innerWidth is the viewport width including scrollbars
* in CSS px
* @return {Object}
* @private
*/
var opera11 = function () {
var zoom = window.top.outerWidth / window.top.innerWidth;
zoom = Math.round(zoom * 100) / 100;
return {
zoom: zoom,
devicePxPerCssPx: zoom * devicePixelRatio()
};
};
/**
* Use a binary search through media queries to find zoom level in Firefox
* @param property
* @param unit
* @param a
* @param b
* @param maxIter
* @param epsilon
* @return {Number}
*/
var mediaQueryBinarySearch = function (property, unit, a, b, maxIter, epsilon) {
var matchMedia;
var head, style, div;
if (window.matchMedia) {
matchMedia = window.matchMedia;
} else {
head = document.getElementsByTagName('head')[0];
style = document.createElement('style');
head.appendChild(style);
div = document.createElement('div');
div.className = 'mediaQueryBinarySearch';
div.style.display = 'none';
document.body.appendChild(div);
matchMedia = function (query) {
style.sheet.insertRule('@media ' + query + '{.mediaQueryBinarySearch ' + '{text-decoration: underline} }', 0);
var matched = getComputedStyle(div, null).textDecoration == 'underline';
style.sheet.deleteRule(0);
return {matches: matched};
};
}
var ratio = binarySearch(a, b, maxIter);
if (div) {
head.removeChild(style);
document.body.removeChild(div);
}
return ratio;
function binarySearch(a, b, maxIter) {
var mid = (a + b) / 2;
if (maxIter <= 0 || b - a < epsilon) {
return mid;
}
var query = "(" + property + ":" + mid + unit + ")";
if (matchMedia(query).matches) {
return binarySearch(mid, b, maxIter - 1);
} else {
return binarySearch(a, mid, maxIter - 1);
}
}
};
/**
* Generate detection function
* @private
*/
var detectFunction = (function () {
var func = fallback;
//IE8+
if (!isNaN(screen.logicalXDPI) && !isNaN(screen.systemXDPI)) {
func = ie8;
}
// IE10+ / Touch
else if (window.navigator.msMaxTouchPoints) {
func = ie10;
}
//Mobile Webkit
else if ('orientation' in window && typeof document.body.style.webkitMarquee === 'string') {
func = webkitMobile;
}
//WebKit
else if (typeof document.body.style.webkitMarquee === 'string') {
func = webkit;
}
//Opera
else if (navigator.userAgent.indexOf('Opera') >= 0) {
func = opera11;
}
//Last one is Firefox
//FF 18.x
else if (window.devicePixelRatio) {
func = firefox18;
}
//FF 4.0 - 17.x
else if (firefox4().zoom > 0.001) {
func = firefox4;
}
return func;
}());
return ({
/**
* Ratios.zoom shorthand
* @return {Number} Zoom level
*/
zoom: function () {
return detectFunction().zoom;
},
/**
* Ratios.devicePxPerCssPx shorthand
* @return {Number} devicePxPerCssPx level
*/
device: function () {
return detectFunction().devicePxPerCssPx;
}
});
}));
var wpcom_img_zoomer = {
clientHintSupport: {
gravatar: false,
files: false,
photon: false,
mshots: false,
staticAssets: false,
latex: false,
imgpress: false,
},
useHints: false,
zoomed: false,
timer: null,
interval: 1000, // zoom polling interval in millisecond
// Should we apply width/height attributes to control the image size?
imgNeedsSizeAtts: function( img ) {
// Do not overwrite existing width/height attributes.
if ( img.getAttribute('width') !== null || img.getAttribute('height') !== null )
return false;
// Do not apply the attributes if the image is already constrained by a parent element.
if ( img.width < img.naturalWidth || img.height < img.naturalHeight )
return false;
return true;
},
hintsFor: function( service ) {
if ( this.useHints === false ) {
return false;
}
if ( this.hints() === false ) {
return false;
}
if ( typeof this.clientHintSupport[service] === "undefined" ) {
return false;
}
if ( this.clientHintSupport[service] === true ) {
return true;
}
return false;
},
hints: function() {
try {
var chrome = window.navigator.userAgent.match(/\sChrome\/([0-9]+)\.[.0-9]+\s/)
if (chrome !== null) {
var version = parseInt(chrome[1], 10)
if (isNaN(version) === false && version >= 46) {
return true
}
}
} catch (e) {
return false
}
return false
},
init: function() {
var t = this;
try{
t.zoomImages();
t.timer = setInterval( function() { t.zoomImages(); }, t.interval );
}
catch(e){
}
},
stop: function() {
if ( this.timer )
clearInterval( this.timer );
},
getScale: function() {
var scale = detectZoom.device();
// Round up to 1.5 or the next integer below the cap.
if ( scale <= 1.0 ) scale = 1.0;
else if ( scale <= 1.5 ) scale = 1.5;
else if ( scale <= 2.0 ) scale = 2.0;
else if ( scale <= 3.0 ) scale = 3.0;
else if ( scale <= 4.0 ) scale = 4.0;
else scale = 5.0;
return scale;
},
shouldZoom: function( scale ) {
var t = this;
// Do not operate on hidden frames.
if ( "innerWidth" in window && !window.innerWidth )
return false;
// Don't do anything until scale > 1
if ( scale == 1.0 && t.zoomed == false )
return false;
return true;
},
zoomImages: function() {
var t = this;
var scale = t.getScale();
if ( ! t.shouldZoom( scale ) ){
return;
}
t.zoomed = true;
// Loop through all the elements on the page.
var imgs = document.getElementsByTagName("img");
for ( var i = 0; i < imgs.length; i++ ) {
// Wait for original images to load
if ( "complete" in imgs[i] && ! imgs[i].complete )
continue;
// Skip images that have srcset attributes.
if ( imgs[i].hasAttribute('srcset') ) {
continue;
}
// Skip images that don't need processing.
var imgScale = imgs[i].getAttribute("scale");
if ( imgScale == scale || imgScale == "0" )
continue;
// Skip images that have already failed at this scale
var scaleFail = imgs[i].getAttribute("scale-fail");
if ( scaleFail && scaleFail <= scale )
continue;
// Skip images that have no dimensions yet.
if ( ! ( imgs[i].width && imgs[i].height ) )
continue;
// Skip images from Lazy Load plugins
if ( ! imgScale && imgs[i].getAttribute("data-lazy-src") && (imgs[i].getAttribute("data-lazy-src") !== imgs[i].getAttribute("src")))
continue;
if ( t.scaleImage( imgs[i], scale ) ) {
// Mark the img as having been processed at this scale.
imgs[i].setAttribute("scale", scale);
}
else {
// Set the flag to skip this image.
imgs[i].setAttribute("scale", "0");
}
}
},
scaleImage: function( img, scale ) {
var t = this;
var newSrc = img.src;
var isFiles = false;
var isLatex = false;
var isPhoton = false;
// Skip slideshow images
if ( img.parentNode.className.match(/slideshow-slide/) )
return false;
// Skip CoBlocks Lightbox images
if ( img.parentNode.className.match(/coblocks-lightbox__image/) )
return false;
// Scale gravatars that have ?s= or ?size=
if ( img.src.match( /^https?:\/\/([^\/]*\.)?gravatar\.com\/.+[?&](s|size)=/ ) ) {
if ( this.hintsFor( "gravatar" ) === true ) {
return false;
}
newSrc = img.src.replace( /([?&](s|size)=)(\d+)/, function( $0, $1, $2, $3 ) {
// Stash the original size
var originalAtt = "originals",
originalSize = img.getAttribute(originalAtt);
if ( originalSize === null ) {
originalSize = $3;
img.setAttribute(originalAtt, originalSize);
if ( t.imgNeedsSizeAtts( img ) ) {
// Fix width and height attributes to rendered dimensions.
img.width = img.width;
img.height = img.height;
}
}
// Get the width/height of the image in CSS pixels
var size = img.clientWidth;
// Convert CSS pixels to device pixels
var targetSize = Math.ceil(img.clientWidth * scale);
// Don't go smaller than the original size
targetSize = Math.max( targetSize, originalSize );
// Don't go larger than the service supports
targetSize = Math.min( targetSize, 512 );
return $1 + targetSize;
});
}
// Scale mshots that have width
else if ( img.src.match(/^https?:\/\/([^\/]+\.)*(wordpress|wp)\.com\/mshots\/.+[?&]w=\d+/) ) {
if ( this.hintsFor( "mshots" ) === true ) {
return false;
}
newSrc = img.src.replace( /([?&]w=)(\d+)/, function($0, $1, $2) {
// Stash the original size
var originalAtt = 'originalw', originalSize = img.getAttribute(originalAtt);
if ( originalSize === null ) {
originalSize = $2;
img.setAttribute(originalAtt, originalSize);
if ( t.imgNeedsSizeAtts( img ) ) {
// Fix width and height attributes to rendered dimensions.
img.width = img.width;
img.height = img.height;
}
}
// Get the width of the image in CSS pixels
var size = img.clientWidth;
// Convert CSS pixels to device pixels
var targetSize = Math.ceil(size * scale);
// Don't go smaller than the original size
targetSize = Math.max( targetSize, originalSize );
// Don't go bigger unless the current one is actually lacking
if ( scale > img.getAttribute("scale") && targetSize <= img.naturalWidth )
targetSize = $2;
if ( $2 != targetSize )
return $1 + targetSize;
return $0;
});
// Update height attribute to match width
newSrc = newSrc.replace( /([?&]h=)(\d+)/, function($0, $1, $2) {
if ( newSrc == img.src ) {
return $0;
}
// Stash the original size
var originalAtt = 'originalh', originalSize = img.getAttribute(originalAtt);
if ( originalSize === null ) {
originalSize = $2;
img.setAttribute(originalAtt, originalSize);
}
// Get the height of the image in CSS pixels
var size = img.clientHeight;
// Convert CSS pixels to device pixels
var targetSize = Math.ceil(size * scale);
// Don't go smaller than the original size
targetSize = Math.max( targetSize, originalSize );
// Don't go bigger unless the current one is actually lacking
if ( scale > img.getAttribute("scale") && targetSize <= img.naturalHeight )
targetSize = $2;
if ( $2 != targetSize )
return $1 + targetSize;
return $0;
});
}
// Scale simple imgpress queries (s0.wp.com) that only specify w/h/fit
else if ( img.src.match(/^https?:\/\/([^\/.]+\.)*(wp|wordpress)\.com\/imgpress\?(.+)/) ) {
if ( this.hintsFor( "imgpress" ) === true ) {
return false;
}
var imgpressSafeFunctions = ["zoom", "url", "h", "w", "fit", "filter", "brightness", "contrast", "colorize", "smooth", "unsharpmask"];
// Search the query string for unsupported functions.
var qs = RegExp.$3.split('&');
for ( var q in qs ) {
q = qs[q].split('=')[0];
if ( imgpressSafeFunctions.indexOf(q) == -1 ) {
return false;
}
}
// Fix width and height attributes to rendered dimensions.
img.width = img.width;
img.height = img.height;
// Compute new src
if ( scale == 1 )
newSrc = img.src.replace(/\?(zoom=[^&]+&)?/, '?');
else
newSrc = img.src.replace(/\?(zoom=[^&]+&)?/, '?zoom=' + scale + '&');
}
// Scale files.wordpress.com, LaTeX, or Photon images (i#.wp.com)
else if (
( isFiles = img.src.match(/^https?:\/\/([^\/]+)\.files\.wordpress\.com\/.+[?&][wh]=/) ) ||
( isLatex = img.src.match(/^https?:\/\/([^\/.]+\.)*(wp|wordpress)\.com\/latex\.php\?(latex|zoom)=(.+)/) ) ||
( isPhoton = img.src.match(/^https?:\/\/i[\d]{1}\.wp\.com\/(.+)/) )
) {
if ( false !== isFiles && this.hintsFor( "files" ) === true ) {
return false
}
if ( false !== isLatex && this.hintsFor( "latex" ) === true ) {
return false
}
if ( false !== isPhoton && this.hintsFor( "photon" ) === true ) {
return false
}
// Fix width and height attributes to rendered dimensions.
img.width = img.width;
img.height = img.height;
// Compute new src
if ( scale == 1 ) {
newSrc = img.src.replace(/\?(zoom=[^&]+&)?/, '?');
} else {
newSrc = img.src;
var url_var = newSrc.match( /([?&]w=)(\d+)/ );
if ( url_var !== null && url_var[2] ) {
newSrc = newSrc.replace( url_var[0], url_var[1] + img.width );
}
url_var = newSrc.match( /([?&]h=)(\d+)/ );
if ( url_var !== null && url_var[2] ) {
newSrc = newSrc.replace( url_var[0], url_var[1] + img.height );
}
var zoom_arg = '&zoom=2';
if ( !newSrc.match( /\?/ ) ) {
zoom_arg = '?zoom=2';
}
img.setAttribute( 'srcset', newSrc + zoom_arg + ' ' + scale + 'x' );
}
}
// Scale static assets that have a name matching *-1x.png or *@1x.png
else if ( img.src.match(/^https?:\/\/[^\/]+\/.*[-@]([12])x\.(gif|jpeg|jpg|png)(\?|$)/) ) {
if ( this.hintsFor( "staticAssets" ) === true ) {
return false;
}
// Fix width and height attributes to rendered dimensions.
img.width = img.width;
img.height = img.height;
var currentSize = RegExp.$1, newSize = currentSize;
if ( scale <= 1 )
newSize = 1;
else
newSize = 2;
if ( currentSize != newSize )
newSrc = img.src.replace(/([-@])[12]x\.(gif|jpeg|jpg|png)(\?|$)/, '$1'+newSize+'x.$2$3');
}
else {
return false;
}
// Don't set img.src unless it has changed. This avoids unnecessary reloads.
if ( newSrc != img.src ) {
// Store the original img.src
var prevSrc, origSrc = img.getAttribute("src-orig");
if ( !origSrc ) {
origSrc = img.src;
img.setAttribute("src-orig", origSrc);
}
// In case of error, revert img.src
prevSrc = img.src;
img.onerror = function(){
img.src = prevSrc;
if ( img.getAttribute("scale-fail") < scale )
img.setAttribute("scale-fail", scale);
img.onerror = null;
};
// Finally load the new image
img.src = newSrc;
}
return true;
}
};
wpcom_img_zoomer.init();
;
/* globals infiniteScroll, _wpmejsSettings, ga, _gaq, WPCOM_sharing_counts, MediaElementPlayer */
( function () {
// Open closure.
// Local vars.
var Scroller, ajaxurl, stats, type, text, totop, loading_text;
// IE requires special handling
var isIE = -1 != navigator.userAgent.search( 'MSIE' );
if ( isIE ) {
var IEVersion = navigator.userAgent.match( /MSIE\s?(\d+)\.?\d*;/ );
IEVersion = parseInt( IEVersion[ 1 ] );
}
// HTTP ajaxurl when site is HTTPS causes Access-Control-Allow-Origin failure in Desktop and iOS Safari
if ( 'https:' == document.location.protocol ) {
infiniteScroll.settings.ajaxurl = infiniteScroll.settings.ajaxurl.replace(
'http://',
'https://'
);
}
/**
* Loads new posts when users scroll near the bottom of the page.
*/
Scroller = function ( settings ) {
var self = this;
// Initialize our variables
this.id = settings.id;
this.body = document.body;
this.window = window;
this.element = document.getElementById( settings.id );
this.wrapperClass = settings.wrapper_class;
this.ready = true;
this.disabled = false;
this.page = 1;
this.offset = settings.offset;
this.currentday = settings.currentday;
this.order = settings.order;
this.throttle = false;
this.click_handle = settings.click_handle;
this.google_analytics = settings.google_analytics;
this.history = settings.history;
this.origURL = window.location.href;
// Handle element
this.handle = document.createElement( 'div' );
this.handle.setAttribute( 'id', 'infinite-handle' );
this.handle.innerHTML = '';
// Footer settings
this.footer = {
el: document.getElementById( 'infinite-footer' ),
wrap: settings.footer,
};
// Bind methods used as callbacks
this.checkViewportOnLoadBound = self.checkViewportOnLoad.bind( this );
// Core's native MediaElement.js implementation needs special handling
this.wpMediaelement = null;
// We have two type of infinite scroll
// cases 'scroll' and 'click'
if ( type == 'scroll' ) {
// Bind refresh to the scroll event
// Throttle to check for such case every 300ms
// On event the case becomes a fact
this.window.addEventListener( 'scroll', function () {
self.throttle = true;
} );
// Go back top method
self.gotop();
setInterval( function () {
if ( self.throttle ) {
// Once the case is the case, the action occurs and the fact is no more
self.throttle = false;
// Reveal or hide footer
self.thefooter();
// Fire the refresh
self.refresh();
self.determineURL(); // determine the url
}
}, 250 );
// Ensure that enough posts are loaded to fill the initial viewport, to compensate for short posts and large displays.
self.ensureFilledViewport();
this.body.addEventListener( 'is.post-load', self.checkViewportOnLoadBound );
} else if ( type == 'click' ) {
if ( this.click_handle ) {
this.element.appendChild( this.handle );
}
this.handle.addEventListener( 'click', function () {
// Handle the handle
if ( self.click_handle ) {
self.handle.parentNode.removeChild( self.handle );
}
// Fire the refresh
self.refresh();
} );
}
// Initialize any Core audio or video players loaded via IS
this.body.addEventListener( 'is.post-load', self.initializeMejs );
};
/**
* Normalize the access to the document scrollTop value.
*/
Scroller.prototype.getScrollTop = function () {
return window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0;
};
/**
* Polyfill jQuery.extend.
*/
Scroller.prototype.extend = function ( out ) {
out = out || {};
for ( var i = 1; i < arguments.length; i++ ) {
if ( ! arguments[ i ] ) {
continue;
}
for ( var key in arguments[ i ] ) {
if ( arguments[ i ].hasOwnProperty( key ) ) {
out[ key ] = arguments[ i ][ key ];
}
}
}
return out;
};
/**
* Check whether we should fetch any additional posts.
*/
Scroller.prototype.check = function () {
var wrapperMeasurements = this.measure( this.element, [ this.wrapperClass ] );
// Fetch more posts when we're less than 2 screens away from the bottom.
return wrapperMeasurements.bottom < 2 * this.window.innerHeight;
};
/**
* Renders the results from a successful response.
*/
Scroller.prototype.render = function ( response ) {
var childrenToAppend = Array.prototype.slice.call( response.fragment.childNodes );
this.body.classList.add( 'infinity-success' );
// Render the retrieved nodes.
while ( childrenToAppend.length > 0 ) {
var currentNode = childrenToAppend.shift();
this.element.appendChild( currentNode );
}
this.trigger( this.body, 'is.post-load', {
jqueryEventName: 'post-load',
data: response,
} );
this.ready = true;
};
/**
* Returns the object used to query for new posts.
*/
Scroller.prototype.query = function () {
return {
page: this.page + this.offset, // Load the next page.
currentday: this.currentday,
order: this.order,
scripts: window.infiniteScroll.settings.scripts,
styles: window.infiniteScroll.settings.styles,
query_args: window.infiniteScroll.settings.query_args,
query_before: window.infiniteScroll.settings.query_before,
last_post_date: window.infiniteScroll.settings.last_post_date,
};
};
Scroller.prototype.animate = function ( cb, duration ) {
var start = performance.now();
requestAnimationFrame( function animate( time ) {
var timeFraction = Math.min( 1, ( time - start ) / duration );
cb( timeFraction );
if ( timeFraction < 1 ) {
requestAnimationFrame( animate );
}
} );
};
/**
* Scroll back to top.
*/
Scroller.prototype.gotop = function () {
var blog = document.getElementById( 'infinity-blog-title' );
var self = this;
if ( ! blog ) {
return;
}
blog.setAttribute( 'title', totop );
blog.addEventListener( 'click', function ( e ) {
var sourceScroll = self.window.pageYOffset;
e.preventDefault();
self.animate( function ( progress ) {
var currentScroll = sourceScroll - sourceScroll * progress;
document.documentElement.scrollTop = document.body.scrollTop = currentScroll;
}, 200 );
} );
};
/**
* The infinite footer.
*/
Scroller.prototype.thefooter = function () {
var self = this,
pageWrapper,
footerContainer,
width,
sourceBottom,
targetBottom,
footerEnabled = this.footer && this.footer.el;
if ( ! footerEnabled ) {
return;
}
// Check if we have an id for the page wrapper
if ( 'string' === typeof this.footer.wrap ) {
try {
pageWrapper = document.getElementById( this.footer.wrap );
width = pageWrapper.getBoundingClientRect();
width = width.width;
} catch ( err ) {
width = 0;
}
// Make the footer match the width of the page
if ( width > 479 ) {
footerContainer = this.footer.el.querySelector( '.container' );
if ( footerContainer ) {
footerContainer.style.width = width + 'px';
}
}
}
// Reveal footer
sourceBottom = parseInt( self.footer.el.style.bottom || -50, 10 );
targetBottom = this.window.pageYOffset >= 350 ? 0 : -50;
if ( sourceBottom !== targetBottom ) {
self.animate( function ( progress ) {
var currentBottom = sourceBottom + ( targetBottom - sourceBottom ) * progress;
self.footer.el.style.bottom = currentBottom + 'px';
if ( 1 === progress ) {
sourceBottom = targetBottom;
}
}, 200 );
}
};
/**
* Recursively convert a JS object into URL encoded data.
*/
Scroller.prototype.urlEncodeJSON = function ( obj, prefix ) {
var params = [],
encodedKey,
newPrefix;
for ( var key in obj ) {
encodedKey = encodeURIComponent( key );
newPrefix = prefix ? prefix + '[' + encodedKey + ']' : encodedKey;
if ( 'object' === typeof obj[ key ] ) {
if ( ! Array.isArray( obj[ key ] ) || obj[ key ].length > 0 ) {
params.push( this.urlEncodeJSON( obj[ key ], newPrefix ) );
} else {
// Explicitly expose empty arrays with no values
params.push( newPrefix + '[]=' );
}
} else {
params.push( newPrefix + '=' + encodeURIComponent( obj[ key ] ) );
}
}
return params.join( '&' );
};
/**
* Controls the flow of the refresh. Don't mess.
*/
Scroller.prototype.refresh = function () {
var self = this,
query,
xhr,
loader,
customized;
// If we're disabled, ready, or don't pass the check, bail.
if ( this.disabled || ! this.ready || ! this.check() ) {
return;
}
// Let's get going -- set ready to false to prevent
// multiple refreshes from occurring at once.
this.ready = false;
// Create a loader element to show it's working.
if ( this.click_handle ) {
if ( ! loader ) {
document.getElementById( 'infinite-aria' ).textContent = loading_text;
loader = document.createElement( 'div' );
loader.classList.add( 'infinite-loader' );
loader.setAttribute( 'role', 'progress' );
loader.innerHTML =
'
' + jQuery.VideoPress.error.messages.age + "
"); } else { jQuery.VideoPress.video.play(container_el); } }, allowedDomain: function (allowed_domains) { if ( jQuery.type(allowed_domains)==="array" ) { if ( jQuery.inArray( top.document.location.hostname, allowed_domains )===-1 ) { return false; } } return true; } }, video:{ flash:{ // Protocol and domain for player_uri and expressinstall set in video.play() player_uri: ( 'https:' == location.protocol ? 'https://v0.wordpress.com' : 'http://s0.videopress.com' ) + "/player.swf?v=1.04", min_version:"10.0.0", params:{wmode:"direct",quality:"autohigh",seamlesstabbing:"true",allowfullscreen:"true",allowscriptaccess:"always",overstretch:"true"}, expressinstall: ( 'https:' == location.protocol ? 'https://v0.wordpress.com' : 'http://s0.videopress.com' ) + "/playerProductInstall.swf", embedCallback: function(event) { if ( event.success===false ) { jQuery("#" + event.id).html("" + jQuery.VideoPress.error.messages.flash + "
"); } } }, types:{mp4:'video/mp4; codecs="avc1.64001E, mp4a.40.2"',ogv:'video/ogg; codecs="theora, vorbis"'}, canPlay:function () { if ( jQuery.VideoPress.support.flash() ) { jQuery.VideoPress.video.playerSupport = "flash"; } else if ( jQuery.VideoPress.support.html5Video() ) { if ( jQuery.VideoPress.support.html5Video( jQuery.VideoPress.video.types.mp4 ) ) { jQuery.VideoPress.video.playerSupport = "mp4"; } else if ( jQuery.VideoPress.support.html5Video( jQuery.VideoPress.video.types.ogv ) ) { jQuery.VideoPress.video.playerSupport = "ogv"; } else { jQuery.VideoPress.video.playerSupport = "html5"; } } else { jQuery.VideoPress.video.playerSupport = ""; } }, prepare: function ( guid, config, count ) { var video = jQuery.VideoPress.data[guid][count]; if ( config.container === undefined || jQuery.type(video)!=="object" ) { return; } var width = 0; if ( config.width !== undefined ) { width = config.width; } else { config.container.width(); } var height = 0; if ( config.height !== undefined ) { height = config.height; } else { config.container.height(); } var div_id = "#v-" + guid + '-' + count; var parent_width = jQuery( div_id ).parent().width(); var diffw = 0; var diffh = 0; var ratio = 0; if ( width > parent_width ) { diffw = width - parent_width + 11; ratio = ( width * 1.0 ) / ( height * 1.0 ); diffh = diffw / ratio; width -= diffw; height -= Math.round( diffh ); } if ( width < 60 || height < 60 ) { width = 400; height = 300; } jQuery.VideoPress.data[guid][count].dimensions = {}; if( 0 == ratio ) { jQuery.VideoPress.data[guid][count].dimensions.width = width; jQuery.VideoPress.data[guid][count].dimensions.height = height; } else { jQuery.VideoPress.data[guid][count].dimensions.width = width - 7; jQuery.VideoPress.data[guid][count].dimensions.height = height - Math.round( 7 / ratio ); jQuery( div_id ).width( width ); jQuery( div_id ).height( height + 50 ); jQuery( div_id + "-placeholder" ).width( jQuery.VideoPress.data[guid][count].dimensions.width ); jQuery( div_id + "-placeholder" ).height( jQuery.VideoPress.data[guid][count].dimensions.height ); jQuery( div_id + "-placeholder img.videopress-poster" ).width( jQuery.VideoPress.data[guid][count].dimensions.width ); jQuery( div_id + "-placeholder img.videopress-poster" ).height( jQuery.VideoPress.data[guid][count].dimensions.height ); } config.container.data( "guid", guid ); config.container.data( "count", count ); if ( jQuery.VideoPress.video.playerSupport === undefined ) { jQuery.VideoPress.video.canPlay(); } if ( config.freedom===true && jQuery.type(video.ogv)==="string" ) { jQuery.VideoPress.video.insert( config.container, guid, count, video, "ogv", jQuery.VideoPress.data[guid][count].dimensions.width, jQuery.VideoPress.data[guid].dimensions.height ); config.container.data( "player", "ogv" ); } else if ( jQuery.VideoPress.video.playerSupport === "flash" ) { config.container.data( "player", "flash" ); config.container.append( '' + jQuery.VideoPress.error.messages.incompatible + '
'); return false; } return true; }, insert: function( container_el, guid, count, video_data, video_type, width, height ) { var video_id = "v-" + guid + "-" + count + "-video"; var video_el = jQuery(""); video_el.attr( "id", video_id ); video_el.attr( "width", width ); video_el.attr( "height", height ); video_el.attr( "poster", video_data.poster ); if ( video_type==="ogv" ) { video_el.attr( "preload", "metadata" ); } else { video_el.attr( "preload", "none" ); } video_el.attr( "controls", "true" ); video_el.attr( "x-webkit-airplay", "allow" ); if ( video_type==="mp4" && video_data.mp4!==undefined && jQuery.type(video_data.mp4.uri)==="string" ) { video_el.attr( "src", video_data.mp4.uri ); } else if ( video_type==="ogv" && video_data.ogv!==undefined && jQuery.type(video_data.ogv.uri)==="string" ) { video_el.attr( "src", video_data.ogv.uri ); } else { // Purposely omit source type attribute since the browser does not seem to support specifics such as canPlayType if ( video_data.mp4!==undefined && jQuery.type(video_data.mp4.uri)==="string" ) { video_el.append( '' + jQuery.VideoPress.error.messages.incompatible + "
" ); video_el.hide(); container_el.append( video_el ); video_el=null; video_id=null; }, play: function( container_el ) { var player = container_el.data( "player" ); if ( player===undefined ) { player="flash"; } var guid = container_el.data( "guid" ); var count = container_el.data( "count" ); if ( player === "flash" ) { jQuery( "#" + container_el.attr("id") + "-placeholder", container_el ).remove(); var player_uri = jQuery.VideoPress.video.flash.player_uri; var expressinstall = jQuery.VideoPress.video.flash.expressinstall; swfobject.embedSWF( player_uri, "v-" + guid + "-" + count + "-video", jQuery.VideoPress.data[guid][count].dimensions.width, jQuery.VideoPress.data[guid][count].dimensions.height, jQuery.VideoPress.video.flash.min_version, expressinstall, {guid:guid,autoPlay:"true",isDynamicSeeking:"true",hd:jQuery.VideoPress.data[guid][count].hd}, jQuery.VideoPress.video.flash.params, null, jQuery.VideoPress.video.flash.embedCallback ); } else if ( jQuery.inArray( player, ["html5", "mp4", "ogv"] ) ) { var video_el = jQuery("video", container_el); if ( video_el ) { jQuery( "#" + container_el.attr("id") + "-placeholder", container_el ).remove(); if ( player==="html5" ) { player = "mp4"; } jQuery.VideoPress.video.playHTML5( video_el, guid, player ); } } else { jQuery( "#" + container_el.attr("id") + "-placeholder", container_el ).remove(); container_el.append( 'Unable to play video. No suitable player.
' ); } var play_event = new CustomEvent( 'videopress_play_video', { 'detail': { 'video_id': guid } } ); window.dispatchEvent( play_event ); }, playHTML5: function( video_el, guid, filetype ) { video_el.show(); video_el[0].load(); /* It seems load() sometimes does not work, but play() will trigger load. * Tried attaching play() to a data event but data might not load * So we trigger play() even if there is not enough data loaded to begin playback */ video_el[0].play(); jQuery.VideoPress.analytics.played(guid, filetype); video_el.bind( "error stalled", function(e) { var message = jQuery.VideoPress.error.messages.error; try { // provide a more detailed error message if a failure reason is communicated switch (e.target.error.code) { case e.target.error.MEDIA_ERR_NETWORK: message = jQuery.VideoPress.error.messages.network; break; case e.target.error.MEDIA_ERR_DECODE: case e.target.error.MEDIA_ERR_SRC_NOT_SUPPORTED: message = jQuery.VideoPress.error.messages.incapable + " " + filetype.toUpperCase() + "."; break; default: break; } } catch( err ){} // provide an opportunity to silence an error with an empty string if ( message.length > 0 ) { video_el.html( '' + message + "
" ); } message=null; } ); video_el.bind( "durationchange", {guid:guid}, function( event ) { var duration = jQuery(event.target).attr("duration"); if ( jQuery.type(duration)==="number" ) { jQuery.VideoPress.data[event.data.guid].duration = duration; } duration=null; } ); /* Only record stats after video data has loaded * If html5 video seems to work but we could not match on a specific codec descriptor then there may be multiple source elements. Browser chooses a source at runtime in source order. We check the loaded video filetype instead of assuming MP4. */ video_el.one( "loadeddata", {guid:guid, filetype:filetype}, function( event ){ var filetype = event.data.filetype; var loaded_file = jQuery(event.target).attr("currentSrc"); if ( jQuery.type(loaded_file)==="string" && loaded_file.length > 3 ) { var ext = loaded_file.substr( loaded_file.lastIndexOf(".") + 1 ).toLowerCase(); if ( jQuery.inArray( ext, ["mp4","ogv"] ) ) { filetype = ext; } ext=null; } video_el.bind( "play", {guid:event.data.guid,filetype:filetype}, function( event ) { jQuery.VideoPress.analytics.played(event.data.guid, event.data.filetype); } ); video_el.bind( "timeupdate", {guid:event.data.guid,filetype:filetype}, function( event ) { var target = jQuery(event.target); jQuery.VideoPress.analytics.watched( event.data.guid, event.data.filetype, target.attr("currentTime"), target.attr("initialTime") ); target=null; } ); video_el.bind( "ended", {guid:event.data.guid,filetype:filetype}, function( event ) { jQuery.VideoPress.analytics.watched( event.data.guid, event.data.filetype, jQuery.VideoPress.data[guid].duration, jQuery(event.target).attr("initialTime") ); } ); } ); } } }}); ; /* global jetpackCarouselStrings, DocumentTouch */ // @start-hide-in-jetpack if (typeof wpcom === 'undefined') { var wpcom = {}; } wpcom.carousel = (function (/*$*/) { var prebuilt_widths = jetpackCarouselStrings.widths; var pageviews_stats_args = jetpackCarouselStrings.stats_query_args; var findFirstLargeEnoughWidth = function (original_w, original_h, dest_w, dest_h) { var inverse_ratio = original_h / original_w; for ( var i = 0; i < prebuilt_widths.length; ++i ) { if ( prebuilt_widths[i] >= dest_w || prebuilt_widths[i] * inverse_ratio >= dest_h ) { return prebuilt_widths[i]; } } return original_w; }; var removeResizeFromImageURL = function ( url ) { return removeArgFromURL( url, 'resize' ); }; var removeArgFromURL = function ( url, arg ) { var re = new RegExp( '[\\?&]' + arg + '(=[^?&]+)?' ); if ( url.match( re ) ) { return url.replace( re, '' ); } return url; }; var addWidthToImageURL = function (url, width) { width = parseInt(width, 10); // Give devices with a higher devicePixelRatio higher-res images (Retina display = 2, Android phones = 1.5, etc) if ('undefined' !== typeof window.devicePixelRatio && window.devicePixelRatio > 1) { width = Math.round( width * window.devicePixelRatio ); } url = addArgToURL(url, 'w', width); url = addArgToURL(url, 'h', ''); return url; }; var addArgToURL = function (url, arg, value) { var re = new RegExp(arg+'=[^?&]+'); if ( url.match(re) ) { return url.replace(re, arg + '=' + value); } else { var divider = url.indexOf('?') !== -1 ? '&' : '?'; return url + divider + arg + '=' + value; } }; var stat = function ( names ) { if ( typeof names !== 'string' ) { names = names.join( ',' ); } new Image().src = window.location.protocol + '//pixel.wp.com/g.gif?v=wpcom-no-pv' + '&x_carousel=' + names + '&baba=' + Math.random(); }; var pageview = function ( post_id ) { new Image().src = window.location.protocol + '//pixel.wp.com/g.gif?host=' + encodeURIComponent( window.location.host ) + '&ref=' + encodeURIComponent( document.referrer ) + '&rand=' + Math.random() + '&' + pageviews_stats_args + '&post=' + encodeURIComponent( post_id ); }; return { findFirstLargeEnoughWidth: findFirstLargeEnoughWidth, removeResizeFromImageURL: removeResizeFromImageURL, addWidthToImageURL: addWidthToImageURL, stat: stat, pageview: pageview }; })(jQuery); // @end-hide-in-jetpack jQuery( document ).ready( function ( $ ) { // gallery faded layer and container elements var overlay, gallery, container, info, transitionBegin, caption, resizeTimeout, photo_info, commentInterval, lastSelectedSlide, screenPadding, originalOverflow = $( 'body' ).css( 'overflow' ), originalHOverflow = $( 'html' ).css( 'overflow' ), proportion = 85, last_known_location_hash = '', imageMeta, titleAndDescription, commentForm, leftColWrapper, scrollPos; var keyListener = function ( e ) { switch ( e.which ) { case 38: // up e.preventDefault(); container.scrollTop( container.scrollTop() - 100 ); break; case 40: // down e.preventDefault(); container.scrollTop( container.scrollTop() + 100 ); break; case 39: // right e.preventDefault(); gallery.jp_carousel( 'next' ); break; case 37: // left case 8: // backspace e.preventDefault(); gallery.jp_carousel( 'previous' ); break; case 27: // escape e.preventDefault(); container.jp_carousel( 'close' ); break; default: // making jslint happy break; } }; var calculatePadding = function() { var baseScreenPadding = 110; screenPadding = baseScreenPadding; if ( window.innerWidth <= 760 ) { screenPadding = Math.round( ( window.innerWidth / 760 ) * baseScreenPadding ); var isTouch = 'ontouchstart' in window || ( window.DocumentTouch && document instanceof DocumentTouch ); if ( screenPadding < 40 && isTouch ) { screenPadding = 0; } } } var resizeListener = function (/*e*/) { // Don't animate if user prefers reduced motion. var shouldAnimate = window.matchMedia && ! window.matchMedia( '(prefers-reduced-motion: reduce)' ).matches; clearTimeout( resizeTimeout ); resizeTimeout = setTimeout( function () { calculatePadding(); gallery.jp_carousel( 'slides' ).jp_carousel( 'fitSlide', shouldAnimate ); gallery.jp_carousel( 'updateSlidePositions', shouldAnimate ); gallery.jp_carousel( 'fitMeta', shouldAnimate ); }, 200 ); }; var prepareGallery = function (/*dataCarouselExtra*/) { if ( ! overlay ) { container = $( '.jp-carousel-wrap' ); overlay = container.find( '.jp-carousel-overlay' ); gallery = container.find( '.jp-carousel' ); caption = container.find( '.jp-carousel-caption' ); photo_info = container.find( '.jp-carousel-photo-info' ); info = container.find( '.jp-carousel-info' ); commentForm = container.find( '.jp-carousel-comment-form-container' ); commentsLoading = container.find( '.jp-carousel-comments-loading' ); imageMeta = container.find( '.jp-carousel-image-meta' ); leftColWrapper = container.find( '.jp-carousel-left-column-wrapper' ); titleAndDescription = container.find( '.jp-carousel-titleanddesc' ); buttons = container.find( '.jp-carousel-buttons' ); var nextButton = container.find( '.jp-carousel-next-button' ); var previousButton = container.find( '.jp-carousel-previous-button' ); calculatePadding(); gallery.jp_carousel( 'fitMeta', false ); container.click( function ( e ) { var target = $( e.target ), wrap = target.parents( 'div.jp-carousel-wrap' ), data = wrap.data( 'carousel-extra' ), slide = wrap.find( 'div.selected' ), attachment_id = slide.data( 'attachment-id' ); data = data || []; if ( target.is( gallery ) || target.parents().add( target ).is( container.find( '.jp-carousel-close-hint' ) ) ) { if ( ! window.matchMedia( '(max-device-width: 760px)' ).matches ) { container.jp_carousel( 'close' ); } else { if ( target.parents().add( target ).is( container.find( '.jp-carousel-close-hint' ) ) ) { container.jp_carousel( 'close' ); } if ( e.pageX <= 70 ) { container.jp_carousel( 'previous' ); } if ( $( window ).width() - e.pageX <= 70 ) { container.jp_carousel( 'next' ); } } // @start-hide-in-jetpack } else if ( target.hasClass('jp-carousel-reblog') ) { e.preventDefault(); e.stopPropagation(); if ( !target.hasClass('reblogged') ) { target.jp_carousel('show_reblog_box'); wpcom.carousel.stat('reblog_show_box'); } } else if ( target.parents('#carousel-reblog-box').length ) { if ( target.is('a.cancel') ) { e.preventDefault(); e.stopPropagation(); target.jp_carousel('hide_reblog_box'); wpcom.carousel.stat('reblog_cancel'); } else if ( target.is( 'input[type="submit"]' ) ) { e.preventDefault(); e.stopPropagation(); var note = $('#carousel-reblog-box textarea').val(); if ( jetpackCarouselStrings.reblog_add_thoughts === note ) { note = ''; } $('#carousel-reblog-submit').val( jetpackCarouselStrings.reblogging ); $('#carousel-reblog-submit').prop('disabled', true); $( '#carousel-reblog-box div.submit span.canceltext' ).show(); $.post( jetpackCarouselStrings.ajaxurl, { 'action': 'post_reblog', 'reblog_source': 'carousel', 'original_blog_id': $('#carousel-reblog-box input#carousel-reblog-blog-id').val(), 'original_post_id': $('.jp-carousel div.selected').data('attachment-id'), 'blog_id': $('#carousel-reblog-box select').val(), 'blog_url': $('#carousel-reblog-box input#carousel-reblog-blog-url').val(), 'blog_title': $('#carousel-reblog-box input#carousel-reblog-blog-title').val(), 'post_url': $('#carousel-reblog-box input#carousel-reblog-post-url').val(), 'post_title': slide.data( 'caption' ) || $('#carousel-reblog-box input#carousel-reblog-post-title').val(), 'note': note, '_wpnonce': $('#carousel-reblog-box #_wpnonce').val() }, function (/*result*/) { $('#carousel-reblog-box').css({ 'height': $('#carousel-reblog-box').height() + 'px' }).slideUp('fast'); $('a.jp-carousel-reblog').html( jetpackCarouselStrings.reblogged ).removeClass( 'reblog' ).addClass( 'reblogged' ); $( '#carousel-reblog-box div.submit span.canceltext' ).hide(); $('#carousel-reblog-submit').val( jetpackCarouselStrings.post_reblog ); $('div.jp-carousel-info').children().not('#carousel-reblog-box').fadeIn('fast'); slide.data('reblogged', 1); $('div.gallery').find('img[data-attachment-id="' + slide.data('attachment-id') + '"]').data('reblogged', 1); }, 'json' ); wpcom.carousel.stat('reblog_submit'); } } else if ( target.hasClass( 'jp-carousel-image-download' ) ) { wpcom.carousel.stat( 'download_original_click' ); // @end-hide-in-jetpack } else if ( target.hasClass( 'jp-carousel-commentlink' ) ) { e.preventDefault(); e.stopPropagation(); $( window ).unbind( 'keydown', keyListener ); container.animate( { scrollTop: parseInt( info.position()[ 'top' ], 10 ) }, 'fast' ); $( '#jp-carousel-comment-form-submit-and-info-wrapper' ).slideDown( 'fast' ); $( '#jp-carousel-comment-form-comment-field' ).focus(); } else if ( target.hasClass( 'jp-carousel-comment-login' ) ) { var url = jetpackCarouselStrings.login_url + '%23jp-carousel-' + attachment_id; window.location.href = url; } else if ( target.parents( '#jp-carousel-comment-form-container' ).length ) { var textarea = $( '#jp-carousel-comment-form-comment-field' ) .blur( function () { $( window ).bind( 'keydown', keyListener ); } ) .focus( function () { $( window ).unbind( 'keydown', keyListener ); } ); var emailField = $( '#jp-carousel-comment-form-email-field' ) .blur( function () { $( window ).bind( 'keydown', keyListener ); } ) .focus( function () { $( window ).unbind( 'keydown', keyListener ); } ); var authorField = $( '#jp-carousel-comment-form-author-field' ) .blur( function () { $( window ).bind( 'keydown', keyListener ); } ) .focus( function () { $( window ).unbind( 'keydown', keyListener ); } ); var urlField = $( '#jp-carousel-comment-form-url-field' ) .blur( function () { $( window ).bind( 'keydown', keyListener ); } ) .focus( function () { $( window ).unbind( 'keydown', keyListener ); } ); if ( textarea && textarea.attr( 'id' ) === target.attr( 'id' ) ) { // For first page load $( window ).unbind( 'keydown', keyListener ); $( '#jp-carousel-comment-form-submit-and-info-wrapper' ).slideDown( 'fast' ); } else if ( target.is( 'input[type="submit"]' ) ) { e.preventDefault(); e.stopPropagation(); $( '#jp-carousel-comment-form-spinner' ).show(); var ajaxData = { action: 'post_attachment_comment', nonce: jetpackCarouselStrings.nonce, blog_id: data[ 'blog_id' ], id: attachment_id, comment: textarea.val(), }; if ( ! ajaxData[ 'comment' ].length ) { gallery.jp_carousel( 'postCommentError', { field: 'jp-carousel-comment-form-comment-field', error: jetpackCarouselStrings.no_comment_text, } ); return; } if ( 1 !== Number( jetpackCarouselStrings.is_logged_in ) ) { ajaxData[ 'email' ] = emailField.val(); ajaxData[ 'author' ] = authorField.val(); ajaxData[ 'url' ] = urlField.val(); if ( 1 === Number( jetpackCarouselStrings.require_name_email ) ) { if ( ! ajaxData[ 'email' ].length || ! ajaxData[ 'email' ].match( '@' ) ) { gallery.jp_carousel( 'postCommentError', { field: 'jp-carousel-comment-form-email-field', error: jetpackCarouselStrings.no_comment_email, } ); return; } else if ( ! ajaxData[ 'author' ].length ) { gallery.jp_carousel( 'postCommentError', { field: 'jp-carousel-comment-form-author-field', error: jetpackCarouselStrings.no_comment_author, } ); return; } } } $.ajax( { type: 'POST', url: jetpackCarouselStrings.ajaxurl, data: ajaxData, dataType: 'json', success: function ( response /*, status, xhr*/ ) { if ( 'approved' === response.comment_status ) { $( '#jp-carousel-comment-post-results' ) .slideUp( 'fast' ) .html( '' + jetpackCarouselStrings.comment_approved + '' ) .slideDown( 'fast' ); } else if ( 'unapproved' === response.comment_status ) { $( '#jp-carousel-comment-post-results' ) .slideUp( 'fast' ) .html( '' + jetpackCarouselStrings.comment_unapproved + '' ) .slideDown( 'fast' ); } else { // 'deleted', 'spam', false $( '#jp-carousel-comment-post-results' ) .slideUp( 'fast' ) .html( '' + jetpackCarouselStrings.comment_post_error + '' ) .slideDown( 'fast' ); } gallery.jp_carousel( 'clearCommentTextAreaValue' ); gallery.jp_carousel( 'getComments', { attachment_id: attachment_id, offset: 0, clear: true, } ); $( '#jp-carousel-comment-form-button-submit' ).val( jetpackCarouselStrings.post_comment ); $( '#jp-carousel-comment-form-spinner' ).hide(); }, error: function (/*xhr, status, error*/) { // TODO: Add error handling and display here gallery.jp_carousel( 'postCommentError', { field: 'jp-carousel-comment-form-comment-field', error: jetpackCarouselStrings.comment_post_error, } ); return; }, } ); } } else if ( ! target.parents( '.jp-carousel-info' ).length ) { if ( window.matchMedia( '(max-device-width: 760px)' ).matches ) { if ( e.pageX <= 70 ) { container.jp_carousel( 'previous' ); } if ( $( window ).width() - e.pageX <= 70 ) { container.jp_carousel( 'next' ); } } else { container.jp_carousel( 'next' ); } } } ) .bind( 'jp_carousel.afterOpen', function () { $( window ).bind( 'keydown', keyListener ); $( window ).bind( 'resize', resizeListener ); gallery.opened = true; resizeListener(); } ) .bind( 'jp_carousel.beforeClose', function () { var scroll = $( window ).scrollTop(); $( window ).unbind( 'keydown', keyListener ); $( window ).unbind( 'resize', resizeListener ); $( window ).scrollTop( scroll ); $( '.jp-carousel-previous-button' ).hide(); $( '.jp-carousel-next-button' ).hide(); // Set height to original value // Fix some themes where closing carousel brings view back to top $( 'html' ).css( 'height', '' ); gallery.jp_carousel( 'hide_reblog_box' ); // @hide-in-jetpack } ) .bind( 'jp_carousel.afterClose', function () { if ( window.location.hash && history.back ) { history.back(); } last_known_location_hash = ''; gallery.opened = false; } ) .on( 'transitionend.jp-carousel ', '.jp-carousel-slide', function ( e ) { // If the movement transitions take more than twice the allotted time, disable them. // There is some wiggle room in the 2x, since some of that time is taken up in // JavaScript, setting up the transition and calling the events. if ( 'transform' === e.originalEvent.propertyName ) { var transitionMultiplier = ( Date.now() - transitionBegin ) / 1000 / e.originalEvent.elapsedTime; container.off( 'transitionend.jp-carousel' ); if ( transitionMultiplier >= 2 ) { $( '.jp-carousel-transitions' ).removeClass( 'jp-carousel-transitions' ); } } } ); container.touchwipe( { wipeLeft: function ( e ) { e.preventDefault(); gallery.jp_carousel( 'next' ); }, wipeRight: function ( e ) { e.preventDefault(); gallery.jp_carousel( 'previous' ); }, preventDefaultEvents: false, } ); nextButton.add( previousButton ).click( function ( e ) { e.preventDefault(); e.stopPropagation(); if ( nextButton.is( this ) ) { gallery.jp_carousel( 'next' ); } else { gallery.jp_carousel( 'previous' ); } } ); } }; var processSingleImageGallery = function () { // process links that contain img tag with attribute data-attachment-id $( 'a img[data-attachment-id]' ).each( function () { var container = $( this ).parent(); // skip if image was already added to gallery by shortcode if ( container.parent( '.gallery-icon' ).length ) { return; } // skip if the container is not a link if ( 'undefined' === typeof $( container ).attr( 'href' ) ) { return; } var valid = false; // if link points to 'Media File' (ignoring GET parameters) and flag is set allow it if ( $( container ).attr( 'href' ).split( '?' )[ 0 ] === $( this ).attr( 'data-orig-file' ).split( '?' )[ 0 ] && 1 === Number( jetpackCarouselStrings.single_image_gallery_media_file ) ) { valid = true; } // if link points to 'Attachment Page' allow it if ( $( container ).attr( 'href' ) === $( this ).attr( 'data-permalink' ) ) { valid = true; } // links to 'Custom URL' or 'Media File' when flag not set are not valid if ( ! valid ) { return; } // make this node a gallery recognizable by event listener above $( container ).addClass( 'single-image-gallery' ); // blog_id is needed to allow posting comments to correct blog $( container ).data( 'carousel-extra', { blog_id: Number( jetpackCarouselStrings.blog_id ), } ); } ); }; var methods = { testForData: function ( gallery ) { gallery = $( gallery ); return ! ( ! gallery.length || ! gallery.data( 'carousel-extra' ) ); }, testIfOpened: function () { return !! ( 'undefined' !== typeof gallery && 'undefined' !== typeof gallery.opened && gallery.opened ); }, openOrSelectSlide: function ( index ) { // The `open` method triggers an asynchronous effect, so we will get an // error if we try to use `open` then `selectSlideAtIndex` immediately // after it. We can only use `selectSlideAtIndex` if the carousel is // already open. if ( ! $( this ).jp_carousel( 'testIfOpened' ) ) { // The `open` method selects the correct slide during the // initialization. $( this ).jp_carousel( 'open', { start_index: index } ); } else { gallery.jp_carousel( 'selectSlideAtIndex', index ); } }, open: function ( options ) { var settings = { items_selector: '.gallery-item [data-attachment-id], .tiled-gallery-item [data-attachment-id], img[data-attachment-id]', start_index: 0, }, data = $( this ).data( 'carousel-extra' ); if ( ! data ) { return; // don't run if the default gallery functions weren't used } prepareGallery( data ); if ( gallery.jp_carousel( 'testIfOpened' ) ) { return; // don't open if already opened } // make sure to stop the page from scrolling behind the carousel overlay, so we don't trigger // infiniscroll for it when enabled (Reader, theme infiniscroll, etc). originalOverflow = $( 'body' ).css( 'overflow' ); $( 'body' ).css( 'overflow', 'hidden' ); // prevent html from overflowing on some of the new themes. originalHOverflow = $( 'html' ).css( 'overflow' ); $( 'html' ).css( 'overflow', 'hidden' ); scrollPos = $( window ).scrollTop(); container.data( 'carousel-extra', data ); // @start-hide-in-jetpack wpcom.carousel.stat( ['open', 'view_image'] ); // @end-hide-in-jetpack return this.each( function () { // If options exist, lets merge them // with our default settings var $this = $( this ); if ( options ) { $.extend( settings, options ); } if ( -1 === settings.start_index ) { settings.start_index = 0; //-1 returned if can't find index, so start from beginning } container.trigger( 'jp_carousel.beforeOpen' ).fadeIn( 'fast', function () { container.trigger( 'jp_carousel.afterOpen' ); gallery .jp_carousel( 'initSlides', $this.find( settings.items_selector ), settings.start_index ) .jp_carousel( 'selectSlideAtIndex', settings.start_index ); } ); gallery.html( '' ); } ); }, selectSlideAtIndex: function ( index ) { var slides = this.jp_carousel( 'slides' ), selected = slides.eq( index ); if ( 0 === selected.length ) { selected = slides.eq( 0 ); } gallery.jp_carousel( 'selectSlide', selected, false ); return this; }, close: function () { // make sure to let the page scroll again $( 'body' ).css( 'overflow', originalOverflow ); $( 'html' ).css( 'overflow', originalHOverflow ); this.jp_carousel( 'clearCommentTextAreaValue' ); return container.trigger( 'jp_carousel.beforeClose' ).fadeOut( 'fast', function () { container.trigger( 'jp_carousel.afterClose' ); $( window ).scrollTop( scrollPos ); } ); }, next: function () { this.jp_carousel( 'previousOrNext', 'nextSlide' ); gallery.jp_carousel( 'hide_reblog_box' ); // @hide-in-jetpack }, previous: function () { this.jp_carousel( 'previousOrNext', 'prevSlide' ); gallery.jp_carousel( 'hide_reblog_box' ); // @hide-in-jetpack }, previousOrNext: function ( slideSelectionMethodName ) { if ( ! this.jp_carousel( 'hasMultipleImages' ) ) { return false; } var slide = gallery.jp_carousel( slideSelectionMethodName ); if ( slide ) { container.animate( { scrollTop: 0 }, 'fast' ); this.jp_carousel( 'clearCommentTextAreaValue' ); this.jp_carousel( 'selectSlide', slide ); wpcom.carousel.stat( ['previous', 'view_image'] ); // @hide-in-jetpack } }, // @start-hide-in-jetpack resetButtons : function (current) { if ( current.data( 'reblogged' ) ) { $('.jp-carousel-buttons a.jp-carousel-reblog').addClass( 'reblogged' ).text( jetpackCarouselStrings.reblogged ); } else { $('.jp-carousel-buttons a.jp-carousel-reblog').removeClass( 'reblogged' ).text( jetpackCarouselStrings.reblog ); } // Must also take care of reblog/reblogged here }, // @end-hide-in-jetpack selectedSlide: function () { return this.find( '.selected' ); }, setSlidePosition: function ( x ) { transitionBegin = Date.now(); return this.css( { '-webkit-transform': 'translate3d(' + x + 'px,0,0)', '-moz-transform': 'translate3d(' + x + 'px,0,0)', '-ms-transform': 'translate(' + x + 'px,0)', '-o-transform': 'translate(' + x + 'px,0)', transform: 'translate3d(' + x + 'px,0,0)', } ); }, updateSlidePositions: function ( animate ) { var current = this.jp_carousel( 'selectedSlide' ), galleryWidth = gallery.width(), currentWidth = current.width(), previous = gallery.jp_carousel( 'prevSlide' ), next = gallery.jp_carousel( 'nextSlide' ), previousPrevious = previous.prev(), nextNext = next.next(), left = Math.floor( ( galleryWidth - currentWidth ) * 0.5 ); current.jp_carousel( 'setSlidePosition', left ).show(); // minimum width gallery.jp_carousel( 'fitInfo', animate ); // prep the slides var direction = lastSelectedSlide.is( current.prevAll() ) ? 1 : -1; // Since we preload the `previousPrevious` and `nextNext` slides, we need // to make sure they technically visible in the DOM, but invisible to the // user. To hide them from the user, we position them outside the edges // of the window. // // This section of code only applies when there are more than three // slides. Otherwise, the `previousPrevious` and `nextNext` slides will // overlap with the `previous` and `next` slides which must be visible // regardless. if ( 1 === direction ) { if ( ! nextNext.is( previous ) ) { nextNext.jp_carousel( 'setSlidePosition', galleryWidth + next.width() ).show(); } if ( ! previousPrevious.is( next ) ) { previousPrevious .jp_carousel( 'setSlidePosition', -previousPrevious.width() - currentWidth ) .show(); } } else { if ( ! nextNext.is( previous ) ) { nextNext.jp_carousel( 'setSlidePosition', galleryWidth + currentWidth ).show(); } } previous .jp_carousel( 'setSlidePosition', Math.floor( -previous.width() + screenPadding * 0.75 ) ) .show(); next .jp_carousel( 'setSlidePosition', Math.ceil( galleryWidth - screenPadding * 0.75 ) ) .show(); }, selectSlide: function ( slide, animate ) { lastSelectedSlide = this.find( '.selected' ).removeClass( 'selected' ); var slides = gallery.jp_carousel( 'slides' ).css( { position: 'fixed' } ), current = $( slide ).addClass( 'selected' ).css( { position: 'relative' } ), attachmentId = current.data( 'attachment-id' ), previous = gallery.jp_carousel( 'prevSlide' ), next = gallery.jp_carousel( 'nextSlide' ), previousPrevious = previous.prev(), nextNext = next.next(), animated, captionHtml; // center the main image gallery.jp_carousel( 'loadFullImage', current ); caption.hide(); if ( next.length === 0 && slides.length <= 2 ) { $( '.jp-carousel-next-button' ).hide(); } else { $( '.jp-carousel-next-button' ).show(); } if ( previous.length === 0 && slides.length <= 2 ) { $( '.jp-carousel-previous-button' ).hide(); } else { $( '.jp-carousel-previous-button' ).show(); } animated = current .add( previous ) .add( previousPrevious ) .add( next ) .add( nextNext ) .jp_carousel( 'loadSlide' ); // slide the whole view to the x we want slides.not( animated ).hide(); gallery.jp_carousel( 'updateSlidePositions', animate ); gallery.jp_carousel( 'resetButtons', current ); // @hide-in-jetpack container.trigger( 'jp_carousel.selectSlide', [ current ] ); gallery.jp_carousel( 'getTitleDesc', { title: current.data( 'title' ), desc: current.data( 'desc' ), } ); var imageMeta = current.data( 'image-meta' ); gallery.jp_carousel( 'updateExif', imageMeta ); gallery.jp_carousel( 'updateFullSizeLink', current ); if ( 1 === +jetpackCarouselStrings.display_comments ) { gallery.jp_carousel( 'testCommentsOpened', current.data( 'comments-opened' ) ); gallery.jp_carousel( 'getComments', { attachment_id: attachmentId, offset: 0, clear: true, } ); $( '#jp-carousel-comment-post-results' ).slideUp(); } // $('').text(sometext).html() is a trick to go to HTML to plain // text (including HTML entities decode, etc) if ( current.data( 'caption' ) ) { captionHtml = $( '' ).text( current.data( 'caption' ) ).html(); if ( captionHtml === $( '' ).text( current.data( 'title' ) ).html() ) { $( '.jp-carousel-titleanddesc-title' ).fadeOut( 'fast' ).empty(); } if ( captionHtml === $( '' ).text( current.data( 'desc' ) ).html() ) { $( '.jp-carousel-titleanddesc-desc' ).fadeOut( 'fast' ).empty(); } caption.html( current.data( 'caption' ) ).fadeIn( 'slow' ); } else { caption.fadeOut( 'fast' ).empty(); } // Record pageview in WP Stats, for each new image loaded full-screen. if ( jetpackCarouselStrings.stats ) { new Image().src = document.location.protocol + '//pixel.wp.com/g.gif?' + jetpackCarouselStrings.stats + '&post=' + encodeURIComponent( attachmentId ) + '&rand=' + Math.random(); } wpcom.carousel.pageview( attachmentId ); // @hide-in-jetpack // Load the images for the next and previous slides. $( next ) .add( previous ) .each( function () { gallery.jp_carousel( 'loadFullImage', $( this ) ); } ); window.location.hash = last_known_location_hash = '#jp-carousel-' + attachmentId; }, slides: function () { return this.find( '.jp-carousel-slide' ); }, slideDimensions: function () { return { width: $( window ).width() - screenPadding * 2, height: Math.floor( ( $( window ).height() / 100 ) * proportion - 60 ), }; }, loadSlide: function () { return this.each( function () { var slide = $( this ); slide.find( 'img' ).one( 'load', function () { // set the width/height of the image if it's too big slide.jp_carousel( 'fitSlide', false ); } ); } ); }, bestFit: function () { var max = gallery.jp_carousel( 'slideDimensions' ), orig = this.jp_carousel( 'originalDimensions' ), orig_ratio = orig.width / orig.height, w_ratio = 1, h_ratio = 1, width, height; if ( orig.width > max.width ) { w_ratio = max.width / orig.width; } if ( orig.height > max.height ) { h_ratio = max.height / orig.height; } if ( w_ratio < h_ratio ) { width = max.width; height = Math.floor( width / orig_ratio ); } else if ( h_ratio < w_ratio ) { height = max.height; width = Math.floor( height * orig_ratio ); } else { width = orig.width; height = orig.height; } return { width: width, height: height, }; }, fitInfo: function (/*animated*/) { var current = this.jp_carousel( 'selectedSlide' ); var size = current.jp_carousel( 'bestFit' ); photo_info.css( { left: Math.floor( ( info.width() - size.width ) * 0.5 ), width: Math.floor( size.width ), } ); return this; }, fitMeta: function ( animated ) { var newInfoPos = { left: screenPadding + 'px', right: screenPadding + 'px' }; if ( animated ) { info.animate( newInfoPos ); } else { info.css( newInfoPos ); } }, fitSlide: function (/*animated*/) { return this.each( function () { var $this = $( this ), dimensions = $this.jp_carousel( 'bestFit' ), method = 'css', max = gallery.jp_carousel( 'slideDimensions' ); dimensions.left = 0; dimensions.top = Math.floor( ( max.height - dimensions.height ) * 0.5 ) + 40; $this[ method ]( dimensions ); } ); }, texturize: function ( text ) { text = '' + text; // make sure we get a string. Title "1" came in as int 1, for example, which did not support .replace(). text = text .replace( /'/g, '’' ) .replace( /'/g, '’' ) .replace( /[\u2019]/g, '’' ); text = text .replace( /"/g, '”' ) .replace( /"/g, '”' ) .replace( /"/g, '”' ) .replace( /[\u201D]/g, '”' ); text = text.replace( /([\w]+)=[\d]+;(.+?)[\d]+;/g, '$1="$2"' ); // untexturize allowed HTML tags params double-quotes return $.trim( text ); }, initSlides: function ( items, start_index ) { if ( items.length < 2 ) { $( '.jp-carousel-next-button, .jp-carousel-previous-button' ).hide(); } else { $( '.jp-carousel-next-button, .jp-carousel-previous-button' ).show(); } // Calculate the new src. items.each( function (/*i*/) { var src_item = $( this ), orig_size = src_item.data( 'orig-size' ) || '', max = gallery.jp_carousel( 'slideDimensions' ), parts = orig_size.split( ',' ), medium_file = src_item.data( 'medium-file' ) || '', large_file = src_item.data( 'large-file' ) || '', src; orig_size = { width: parseInt( parts[ 0 ], 10 ), height: parseInt( parts[ 1 ], 10 ) }; // @start-hide-in-jetpack if ( 'undefined' !== typeof wpcom ) { src = src_item.attr('src') || src_item.attr('original') || src_item.data('original') || src_item.data('lazy-src'); if (src.indexOf('imgpress') !== -1) { src = src_item.data('orig-file'); } // Square/Circle galleries use a resize param that needs to be removed. src = wpcom.carousel.removeResizeFromImageURL( src ); src = wpcom.carousel.addWidthToImageURL( src, wpcom.carousel.findFirstLargeEnoughWidth( orig_size.width, orig_size.height, max.width, max.height ) ); } else { // @end-hide-in-jetpack src = src_item.data( 'orig-file' ); src = gallery.jp_carousel( 'selectBestImageSize', { orig_file: src, orig_width: orig_size.width, orig_height: orig_size.height, max_width: max.width, max_height: max.height, medium_file: medium_file, large_file: large_file, } ); // @start-hide-in-jetpack } // end else of if ( 'undefined' != typeof wpcom ) // @end-hide-in-jetpack // Set the final src $( this ).data( 'gallery-src', src ); } ); // If the start_index is not 0 then preload the clicked image first. if ( 0 !== start_index ) { $( '