/* 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; // 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(); ; /* global pm, wpcom_reblog */ var jetpackLikesWidgetQueue = []; var jetpackLikesWidgetBatch = []; var jetpackLikesMasterReady = false; function JetpackLikespostMessage( message, target ) { if ( 'string' === typeof message ){ try { message = JSON.parse( message ); } catch(e) { return; } } pm( { target: target, type: 'likesMessage', data: message, origin: '*' } ); } function JetpackLikesBatchHandler() { var requests = []; jQuery( 'div.jetpack-likes-widget-unloaded' ).each( function() { if ( jetpackLikesWidgetBatch.indexOf( this.id ) > -1 ) { return; } jetpackLikesWidgetBatch.push( this.id ); var regex = /like-(post|comment)-wrapper-(\d+)-(\d+)-(\w+)/, match = regex.exec( this.id ), info; if ( ! match || match.length !== 5 ) { return; } info = { blog_id: match[2], width: this.width }; if ( 'post' === match[1] ) { info.post_id = match[3]; } else if ( 'comment' === match[1] ) { info.comment_id = match[3]; } info.obj_id = match[4]; requests.push( info ); }); if ( requests.length > 0 ) { JetpackLikespostMessage( { event: 'initialBatch', requests: requests }, window.frames['likes-master'] ); } } function JetpackLikesMessageListener( event, message ) { var allowedOrigin, $container, $list, offset, rowLength, height, scrollbarWidth; if ( 'undefined' === typeof event.event ) { return; } // We only allow messages from one origin allowedOrigin = window.location.protocol + '//widgets.wp.com'; if ( allowedOrigin !== message.origin ) { return; } if ( 'masterReady' === event.event ) { jQuery( document ).ready( function() { jetpackLikesMasterReady = true; var stylesData = { event: 'injectStyles' }, $sdTextColor = jQuery( '.sd-text-color' ), $sdLinkColor = jQuery( '.sd-link-color' ); if ( jQuery( 'iframe.admin-bar-likes-widget' ).length > 0 ) { JetpackLikespostMessage( { event: 'adminBarEnabled' }, window.frames[ 'likes-master' ] ); stylesData.adminBarStyles = { background: jQuery( '#wpadminbar .quicklinks li#wp-admin-bar-wpl-like > a' ).css( 'background' ), isRtl: ( 'rtl' === jQuery( '#wpadminbar' ).css( 'direction' ) ) }; } if ( ! window.addEventListener ) { jQuery( '#wp-admin-bar-admin-bar-likes-widget' ).hide(); } stylesData.textStyles = { color: $sdTextColor.css( 'color' ), fontFamily: $sdTextColor.css( 'font-family' ), fontSize: $sdTextColor.css( 'font-size' ), direction: $sdTextColor.css( 'direction' ), fontWeight: $sdTextColor.css( 'font-weight' ), fontStyle: $sdTextColor.css( 'font-style' ), textDecoration: $sdTextColor.css('text-decoration') }; stylesData.linkStyles = { color: $sdLinkColor.css('color'), fontFamily: $sdLinkColor.css('font-family'), fontSize: $sdLinkColor.css('font-size'), textDecoration: $sdLinkColor.css('text-decoration'), fontWeight: $sdLinkColor.css( 'font-weight' ), fontStyle: $sdLinkColor.css( 'font-style' ) }; JetpackLikespostMessage( stylesData, window.frames[ 'likes-master' ] ); JetpackLikesBatchHandler(); jQuery( document ).on( 'inview', 'div.jetpack-likes-widget-unloaded', function() { jetpackLikesWidgetQueue.push( this.id ); }); }); } if ( 'showLikeWidget' === event.event ) { jQuery( '#' + event.id + ' .post-likes-widget-placeholder' ).fadeOut( 'fast', function() { jQuery( '#' + event.id + ' .post-likes-widget' ).fadeIn( 'fast', function() { JetpackLikespostMessage( { event: 'likeWidgetDisplayed', blog_id: event.blog_id, post_id: event.post_id, obj_id: event.obj_id }, window.frames['likes-master'] ); }); }); } if ( 'clickReblogFlair' === event.event ) { wpcom_reblog.toggle_reblog_box_flair( event.obj_id ); } if ( 'showOtherGravatars' === event.event ) { $container = jQuery( '#likes-other-gravatars' ); $list = $container.find( 'ul' ); $container.hide(); $list.html( '' ); $container.find( '.likes-text span' ).text( event.total ); jQuery.each( event.likers, function( i, liker ) { var element = jQuery( '
  • ' ); element.addClass( liker.css_class ); element.find( 'a' ). attr({ href: liker.profile_URL, rel: 'nofollow', target: '_parent' }). addClass( 'wpl-liker' ); element.find( 'img' ). attr({ src: liker.avatar_URL, alt: liker.name }). css({ width: '30px', height: '30px', paddingRight: '3px' }); $list.append( element ); } ); offset = jQuery( '[name=\'' + event.parent + '\']' ).offset(); $container.css( 'left', offset.left + event.position.left - 10 + 'px' ); $container.css( 'top', offset.top + event.position.top - 33 + 'px' ); rowLength = Math.floor( event.width / 37 ); height = ( Math.ceil( event.likers.length / rowLength ) * 37 ) + 13; if ( height > 204 ) { height = 204; } $container.css( 'height', height + 'px' ); $container.css( 'width', rowLength * 37 - 7 + 'px' ); $list.css( 'width', rowLength * 37 + 'px' ); $container.fadeIn( 'slow' ); scrollbarWidth = $list[0].offsetWidth - $list[0].clientWidth; if ( scrollbarWidth > 0 ) { $container.width( $container.width() + scrollbarWidth ); $list.width( $list.width() + scrollbarWidth ); } } } pm.bind( 'likesMessage', JetpackLikesMessageListener ); jQuery( document ).click( function( e ) { var $container = jQuery( '#likes-other-gravatars' ); if ( $container.has( e.target ).length === 0 ) { $container.fadeOut( 'slow' ); } }); function JetpackLikesWidgetQueueHandler() { var $wrapper, wrapperID, found; if ( ! jetpackLikesMasterReady ) { setTimeout( JetpackLikesWidgetQueueHandler, 500 ); return; } if ( jetpackLikesWidgetQueue.length > 0 ) { // We may have a widget that needs creating now found = false; while( jetpackLikesWidgetQueue.length > 0 ) { // Grab the first member of the queue that isn't already loading. wrapperID = jetpackLikesWidgetQueue.splice( 0, 1 )[0]; if ( jQuery( '#' + wrapperID ).hasClass( 'jetpack-likes-widget-unloaded' ) ) { found = true; break; } } if ( ! found ) { setTimeout( JetpackLikesWidgetQueueHandler, 500 ); return; } } else if ( jQuery( 'div.jetpack-likes-widget-unloaded' ).length > 0 ) { // Grab any unloaded widgets for a batch request JetpackLikesBatchHandler(); // Get the next unloaded widget wrapperID = jQuery( 'div.jetpack-likes-widget-unloaded' ).first()[0].id; if ( ! wrapperID ) { // Everything is currently loaded setTimeout( JetpackLikesWidgetQueueHandler, 500 ); return; } } if ( 'undefined' === typeof wrapperID ) { setTimeout( JetpackLikesWidgetQueueHandler, 500 ); return; } $wrapper = jQuery( '#' + wrapperID ); $wrapper.find( 'iframe' ).remove(); if ( $wrapper.hasClass( 'slim-likes-widget' ) ) { $wrapper.find( '.post-likes-widget-placeholder' ).after( '' ); } else { $wrapper.find( '.post-likes-widget-placeholder' ).after( '' ); } $wrapper.removeClass( 'jetpack-likes-widget-unloaded' ).addClass( 'jetpack-likes-widget-loading' ); $wrapper.find( 'iframe' ).load( function( e ) { var $iframe = jQuery( e.target ); $wrapper.removeClass( 'jetpack-likes-widget-loading' ).addClass( 'jetpack-likes-widget-loaded' ); JetpackLikespostMessage( { event: 'loadLikeWidget', name: $iframe.attr( 'name' ), width: $iframe.width() }, window.frames[ 'likes-master' ] ); if ( $wrapper.hasClass( 'slim-likes-widget' ) ) { $wrapper.find( 'iframe' ).Jetpack( 'resizeable' ); } }); setTimeout( JetpackLikesWidgetQueueHandler, 250 ); } JetpackLikesWidgetQueueHandler(); ; // WARNING: This file is distributed verbatim in Jetpack. There should be nothing WordPress.com specific in this file. @hide-in-jetpack (function($){ // Open closure // Local vars var Scroller, ajaxurl, stats, type, text, totop; // IE requires special handling var isIE = ( -1 != navigator.userAgent.search( 'MSIE' ) ); if ( isIE ) { var IEVersion = navigator.userAgent.match(/MSIE\s?(\d+)\.?\d*;/); var 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 = $( '#' + 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.handle = '
    '; this.click_handle = settings.click_handle; this.google_analytics = settings.google_analytics; this.history = settings.history; this.origURL = window.location.href; this.pageCache = {}; // Footer settings this.footer = $( '#infinite-footer' ); this.footer.wrap = settings.footer; // 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.bind( 'scroll.infinity', function() { this.throttle = true; }); // Go back top method self.gotop(); setInterval( function() { if ( this.throttle ) { // Once the case is the case, the action occurs and the fact is no more this.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.bind( 'post-load', { self: self }, self.checkViewportOnLoad ); } else if ( type == 'click' ) { if ( this.click_handle ) { this.element.append( this.handle ); } this.body.delegate( '#infinite-handle', 'click.infinity', function() { // Handle the handle if ( self.click_handle ) { $( '#infinite-handle' ).remove(); } // Fire the refresh self.refresh(); }); } // Initialize any Core audio or video players loaded via IS this.body.bind( 'post-load', { self: self }, self.initializeMejs ); }; /** * Check whether we should fetch any additional posts. */ Scroller.prototype.check = function() { var container = this.element.offset(); // If the container can't be found, stop otherwise errors result if ( 'object' !== typeof container ) { return false; } var bottom = this.window.scrollTop() + this.window.height(), threshold = container.top + this.element.outerHeight(false) - (this.window.height() * 2); return bottom > threshold; }; /** * Renders the results from a successful response. */ Scroller.prototype.render = function( response ) { this.body.addClass( 'infinity-success' ); // Check if we can wrap the html this.element.append( response.html ); this.body.trigger( 'post-load', response ); this.ready = true; }; /** * Returns the object used to query for new posts. */ Scroller.prototype.query = function() { return { page : this.page, currentday : this.currentday, order : this.order, scripts : window.infiniteScroll.settings.scripts, styles : window.infiniteScroll.settings.styles, query_args : window.infiniteScroll.settings.query_args, last_post_date : window.infiniteScroll.settings.last_post_date }; }; /** * Scroll back to top. */ Scroller.prototype.gotop = function() { var blog = $( '#infinity-blog-title' ); blog.attr( 'title', totop ); // Scroll to top on blog title blog.bind( 'click', function( e ) { $( 'html, body' ).animate( { scrollTop: 0 }, 'fast' ); e.preventDefault(); }); }; /** * The infinite footer. */ Scroller.prototype.thefooter = function() { var self = this, width; // Check if we have an id for the page wrapper if ( $.type( this.footer.wrap ) === "string" ) { width = $( 'body #' + this.footer.wrap ).outerWidth( false ); // Make the footer match the width of the page if ( width > 479 ) this.footer.find( '.container' ).css( 'width', width ); } // Reveal footer if ( this.window.scrollTop() >= 350 ) self.footer.animate( { 'bottom': 0 }, 'fast' ); else if ( this.window.scrollTop() < 350 ) self.footer.animate( { 'bottom': '-50px' }, 'fast' ); }; /** * Controls the flow of the refresh. Don't mess. */ Scroller.prototype.refresh = function() { var self = this, query, jqxhr, load, loader, color, 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 ) { loader = ''; this.element.append( loader ); loader = this.element.find( '.infinite-loader' ); color = loader.css( 'color' ); try { loader.spin( 'medium-left', color ); } catch ( error ) { } } // Generate our query vars. query = $.extend({ action: 'infinite_scroll' }, this.query() ); // Inject Customizer state. if ( 'undefined' !== typeof wp && wp.customize && wp.customize.settings.theme ) { customized = {}; query.wp_customize = 'on'; query.theme = wp.customize.settings.theme.stylesheet; wp.customize.each( function( setting ) { if ( setting._dirty ) { customized[ setting.id ] = setting(); } } ); query.customized = JSON.stringify( customized ); query.nonce = wp.customize.settings.nonce.preview; } // Fire the ajax request. jqxhr = $.post( infiniteScroll.settings.ajaxurl, query ); // Allow refreshes to occur again if an error is triggered. jqxhr.fail( function() { if ( self.click_handle ) { loader.hide(); } self.ready = true; }); // Success handler jqxhr.done( function( response ) { // On success, let's hide the loader circle. if ( self.click_handle ) { loader.hide(); } // Check for and parse our response. if ( ! response || ! response.type ) { return; } // If we've succeeded... if ( response.type == 'success' ) { // If additional scripts are required by the incoming set of posts, parse them if ( response.scripts ) { $( response.scripts ).each( function() { var elementToAppendTo = this.footer ? 'body' : 'head'; // Add script handle to list of those already parsed window.infiniteScroll.settings.scripts.push( this.handle ); // Output extra data, if present if ( this.extra_data ) { var data = document.createElement('script'), dataContent = document.createTextNode( "//" ); data.type = 'text/javascript'; data.appendChild( dataContent ); document.getElementsByTagName( elementToAppendTo )[0].appendChild(data); } // Build script tag and append to DOM in requested location var script = document.createElement('script'); script.type = 'text/javascript'; script.src = this.src; script.id = this.handle; // If MediaElement.js is loaded in by this set of posts, don't initialize the players a second time as it breaks them all if ( 'wp-mediaelement' === this.handle ) { self.body.unbind( 'post-load', self.initializeMejs ); } if ( 'wp-mediaelement' === this.handle && 'undefined' === typeof mejs ) { self.wpMediaelement = {}; self.wpMediaelement.tag = script; self.wpMediaelement.element = elementToAppendTo; setTimeout( self.maybeLoadMejs.bind( self ), 250 ); } else { document.getElementsByTagName( elementToAppendTo )[0].appendChild(script); } } ); } // If additional stylesheets are required by the incoming set of posts, parse them if ( response.styles ) { $( response.styles ).each( function() { // Add stylesheet handle to list of those already parsed window.infiniteScroll.settings.styles.push( this.handle ); // Build link tag var style = document.createElement('link'); style.rel = 'stylesheet'; style.href = this.src; style.id = this.handle + '-css'; // Destroy link tag if a conditional statement is present and either the browser isn't IE, or the conditional doesn't evaluate true if ( this.conditional && ( ! isIE || ! eval( this.conditional.replace( /%ver/g, IEVersion ) ) ) ) var style = false; // Append link tag if necessary if ( style ) document.getElementsByTagName('head')[0].appendChild(style); } ); } // stash the response in the page cache self.pageCache[self.page] = response; // Increment the page number self.page++; // Record pageview in WP Stats, if available. if ( stats ) new Image().src = document.location.protocol + '//pixel.wp.com/g.gif?' + stats + '&post=0&baba=' + Math.random(); // Add new posts to the postflair object if ( 'object' == typeof response.postflair && 'object' == typeof WPCOM_sharing_counts ) WPCOM_sharing_counts = $.extend( WPCOM_sharing_counts, response.postflair ); // Render the results self.render.apply( self, arguments ); // If 'click' type and there are still posts to fetch, add back the handle if ( type == 'click' ) { if ( response.lastbatch ) { if ( self.click_handle ) { $( '#infinite-handle' ).remove(); // Update body classes self.body.addClass( 'infinity-end' ).removeClass( 'infinity-success' ); } else { self.body.trigger( 'infinite-scroll-posts-end' ); } } else { if ( self.click_handle ) { self.element.append( self.handle ); } else { self.body.trigger( 'infinite-scroll-posts-more' ); } } } else if ( response.lastbatch ) { self.disabled = true; self.body.addClass( 'infinity-end' ).removeClass( 'infinity-success' ); } // Update currentday to the latest value returned from the server if ( response.currentday ) { self.currentday = response.currentday; } // Fire Google Analytics pageview if ( self.google_analytics ) { var ga_url = self.history.path.replace( /%d/, self.page ); if ( 'object' === typeof _gaq ) { _gaq.push( [ '_trackPageview', ga_url ] ); } if ( 'function' === typeof ga ) { ga( 'send', 'pageview', ga_url ); } } } }); return jqxhr; }; /** * Core's native media player uses MediaElement.js * The library's size is sufficient that it may not be loaded in time for Core's helper to invoke it, so we need to delay until `mejs` exists. */ Scroller.prototype.maybeLoadMejs = function() { if ( null === this.wpMediaelement ) { return; } if ( 'undefined' === typeof mejs ) { setTimeout( this.maybeLoadMejs, 250 ); } else { document.getElementsByTagName( this.wpMediaelement.element )[0].appendChild( this.wpMediaelement.tag ); this.wpMediaelement = null; // Ensure any subsequent IS loads initialize the players this.body.bind( 'post-load', { self: this }, this.initializeMejs ); } } /** * Initialize the MediaElement.js player for any posts not previously initialized */ Scroller.prototype.initializeMejs = function( ev, response ) { // Are there media players in the incoming set of posts? if ( ! response.html || -1 === response.html.indexOf( 'wp-audio-shortcode' ) && -1 === response.html.indexOf( 'wp-video-shortcode' ) ) { return; } // Don't bother if mejs isn't loaded for some reason if ( 'undefined' === typeof mejs ) { return; } // Adapted from wp-includes/js/mediaelement/wp-mediaelement.js // Modified to not initialize already-initialized players, as Mejs doesn't handle that well $(function () { var settings = {}; if ( typeof _wpmejsSettings !== 'undefined' ) { settings.pluginPath = _wpmejsSettings.pluginPath; } settings.success = function (mejs) { var autoplay = mejs.attributes.autoplay && 'false' !== mejs.attributes.autoplay; if ( 'flash' === mejs.pluginType && autoplay ) { mejs.addEventListener( 'canplay', function () { mejs.play(); }, false ); } }; $('.wp-audio-shortcode, .wp-video-shortcode').not( '.mejs-container' ).mediaelementplayer( settings ); }); } /** * Trigger IS to load additional posts if the initial posts don't fill the window. * On large displays, or when posts are very short, the viewport may not be filled with posts, so we overcome this by loading additional posts when IS initializes. */ Scroller.prototype.ensureFilledViewport = function() { var self = this, windowHeight = self.window.height(), postsHeight = self.element.height(), aveSetHeight = 0, wrapperQty = 0; // Account for situations where postsHeight is 0 because child list elements are floated if ( postsHeight === 0 ) { $( self.element.selector + ' > li' ).each( function() { postsHeight += $( this ).height(); } ); if ( postsHeight === 0 ) { self.body.unbind( 'post-load', self.checkViewportOnLoad ); return; } } // Calculate average height of a set of posts to prevent more posts than needed from being loaded. $( '.' + self.wrapperClass ).each( function() { aveSetHeight += $( this ).height(); wrapperQty++; } ); if ( wrapperQty > 0 ) aveSetHeight = aveSetHeight / wrapperQty; else aveSetHeight = 0; // Load more posts if space permits, otherwise stop checking for a full viewport if ( postsHeight < windowHeight && ( postsHeight + aveSetHeight < windowHeight ) ) { self.ready = true; self.refresh(); } else { self.body.unbind( 'post-load', self.checkViewportOnLoad ); } } /** * Event handler for ensureFilledViewport(), tied to the post-load trigger. * Necessary to ensure that the variable `this` contains the scroller when used in ensureFilledViewport(). Since this function is tied to an event, `this` becomes the DOM element the event is tied to. */ Scroller.prototype.checkViewportOnLoad = function( ev ) { ev.data.self.ensureFilledViewport(); } /** * Identify archive page that corresponds to majority of posts shown in the current browser window. */ Scroller.prototype.determineURL = function () { var self = this, windowTop = $( window ).scrollTop(), windowBottom = windowTop + $( window ).height(), windowSize = windowBottom - windowTop, setsInView = [], setsHidden = [], pageNum = false; // Find out which sets are in view $( '.' + self.wrapperClass ).each( function() { var id = $( this ).attr( 'id' ), setTop = $( this ).offset().top, setHeight = $( this ).outerHeight( false ), setBottom = 0, setPageNum = $( this ).data( 'page-num' ); // Account for containers that have no height because their children are floated elements. if ( 0 === setHeight ) { $( '> *', this ).each( function() { setHeight += $( this ).outerHeight( false ); } ); } // Determine position of bottom of set by adding its height to the scroll position of its top. setBottom = setTop + setHeight; // Populate setsInView object. While this logic could all be combined into a single conditional statement, this is easier to understand. if ( setTop < windowTop && setBottom > windowBottom ) { // top of set is above window, bottom is below setsInView.push({'id': id, 'top': setTop, 'bottom': setBottom, 'pageNum': setPageNum }); } else if( setTop > windowTop && setTop < windowBottom ) { // top of set is between top (gt) and bottom (lt) setsInView.push({'id': id, 'top': setTop, 'bottom': setBottom, 'pageNum': setPageNum }); } else if( setBottom > windowTop && setBottom < windowBottom ) { // bottom of set is between top (gt) and bottom (lt) setsInView.push({'id': id, 'top': setTop, 'bottom': setBottom, 'pageNum': setPageNum }); } else { setsHidden.push({'id': id, 'top': setTop, 'bottom': setBottom, 'pageNum': setPageNum }); } } ); $.each(setsHidden, function() { var $set = $('#' + this.id); if( $set.hasClass( 'is--replaced' ) ) { return; } self.pageCache[ this.pageNum].html = $set.html(); $set.css('min-height', ( this.bottom - this.top ) + 'px' ) .addClass('is--replaced') .empty(); }); $.each(setsInView, function() { var $set = $('#' + this.id); if( $set.hasClass('is--replaced') ) { $set.css('min-height', '').removeClass('is--replaced'); if( this.pageNum in self.pageCache ) { $set.html( self.pageCache[this.pageNum].html ); self.body.trigger( 'post-load', self.pageCache[this.pageNum] ); } } }); // Parse number of sets found in view in an attempt to update the URL to match the set that comprises the majority of the window. if ( 0 == setsInView.length ) { pageNum = -1; } else if ( 1 == setsInView.length ) { var setData = setsInView.pop(); // If the first set of IS posts is in the same view as the posts loaded in the template by WordPress, determine how much of the view is comprised of IS-loaded posts if ( ( ( windowBottom - setData.top ) / windowSize ) < 0.5 ) pageNum = -1; else pageNum = setData.pageNum; } else { var majorityPercentageInView = 0; // Identify the IS set that comprises the majority of the current window and set the URL to it. $.each( setsInView, function( i, setData ) { var topInView = 0, bottomInView = 0, percentOfView = 0; // Figure percentage of view the current set represents if ( setData.top > windowTop && setData.top < windowBottom ) topInView = ( windowBottom - setData.top ) / windowSize; if ( setData.bottom > windowTop && setData.bottom < windowBottom ) bottomInView = ( setData.bottom - windowTop ) / windowSize; // Figure out largest percentage of view for current set if ( topInView >= bottomInView ) percentOfView = topInView; else if ( bottomInView >= topInView ) percentOfView = bottomInView; // Does current set's percentage of view supplant the largest previously-found set? if ( percentOfView > majorityPercentageInView ) { pageNum = setData.pageNum; majorityPercentageInView = percentOfView; } } ); } // If a page number could be determined, update the URL // -1 indicates that the original requested URL should be used. if ( 'number' == typeof pageNum ) { if ( pageNum != -1 ) pageNum++; self.updateURL( pageNum ); } } /** * Update address bar to reflect archive page URL for a given page number. * Checks if URL is different to prevent pollution of browser history. */ Scroller.prototype.updateURL = function( page ) { // IE only supports pushState() in v10 and above, so don't bother if those conditions aren't met. if ( ! window.history.pushState ) { return; } var self = this, offset = self.offset > 0 ? self.offset - 1 : 0, pageSlug = -1 == page ? self.origURL : window.location.protocol + '//' + self.history.host + self.history.path.replace( /%d/, page + offset ) + self.history.parameters; if ( window.location.href != pageSlug ) { history.pushState( null, null, pageSlug ); } } /** * Pause scrolling. */ Scroller.prototype.pause = function() { this.disabled = true; }; /** * Resume scrolling. */ Scroller.prototype.resume = function() { this.disabled = false; }; /** * Ready, set, go! */ $( document ).ready( function() { // Check for our variables if ( 'object' != typeof infiniteScroll ) return; // Set ajaxurl (for brevity) ajaxurl = infiniteScroll.settings.ajaxurl; // Set stats, used for tracking stats stats = infiniteScroll.settings.stats; // Define what type of infinity we have, grab text for click-handle type = infiniteScroll.settings.type; text = infiniteScroll.settings.text; totop = infiniteScroll.settings.totop; // Initialize the scroller (with the ID of the element from the theme) infiniteScroll.scroller = new Scroller( infiniteScroll.settings ); /** * Monitor user scroll activity to update URL to correspond to archive page for current set of IS posts */ if( type == 'click' ) { var timer = null; $( window ).bind( 'scroll', function() { // run the real scroll handler once every 250 ms. if ( timer ) { return; } timer = setTimeout( function() { infiniteScroll.scroller.determineURL(); timer = null; } , 250 ); }); } // Integrate with Selective Refresh in the Customizer. if ( 'undefined' !== typeof wp && wp.customize && wp.customize.selectiveRefresh ) { /** * Handle rendering of selective refresh partials. * * Make sure that when a partial is rendered, the Jetpack post-load event * will be triggered so that any dynamic elements will be re-constructed, * such as ME.js elements, Photon replacements, social sharing, and more. * Note that this is applying here not strictly to posts being loaded. * If a widget contains a ME.js element and it is previewed via selective * refresh, the post-load would get triggered allowing any dynamic elements * therein to also be re-constructed. * * @param {wp.customize.selectiveRefresh.Placement} placement */ wp.customize.selectiveRefresh.bind( 'partial-content-rendered', function( placement ) { var content; if ( 'string' === typeof placement.addedContent ) { content = placement.addedContent; } else if ( placement.container ) { content = $( placement.container ).html(); } if ( content ) { $( document.body ).trigger( 'post-load', { html: content } ); } } ); /* * Add partials for posts added via infinite scroll. * * This is unnecessary when MutationObserver is supported by the browser * since then this will be handled by Selective Refresh in core. */ if ( 'undefined' === typeof MutationObserver ) { $( document.body ).on( 'post-load', function( e, response ) { var rootElement = null; if ( response.html && -1 !== response.html.indexOf( 'data-customize-partial' ) ) { if ( infiniteScroll.settings.id ) { rootElement = $( '#' + infiniteScroll.settings.id ); } wp.customize.selectiveRefresh.addPartials( rootElement ); } } ); } } }); })(jQuery); // Close closure ; /* jshint ignore:start */ !function(d,s,id){ var js,fjs=d.getElementsByTagName(s)[0],p=/^http:/.test(d.location)?'http':'https'; if(!d.getElementById(id)){ js=d.createElement(s); js.id=id;js.src=p+"://platform.twitter.com/widgets.js"; fjs.parentNode.insertBefore(js,fjs); } }(document,"script","twitter-wjs"); /* jshint ignore:end */ ; /*** * Warning: This file is remotely enqueued in Jetpack's Masterbar module. * Changing it will also affect Jetpack sites. */ jQuery( document ).ready( function( $, wpcom ) { var masterbar, menupops = $( 'li#wp-admin-bar-blog.menupop, li#wp-admin-bar-newdash.menupop, li#wp-admin-bar-my-account.menupop' ), newmenu = $( '#wp-admin-bar-new-post-types' ); // Unbind hoverIntent, we want clickable menus. menupops .unbind( 'mouseenter mouseleave' ) .removeProp( 'hoverIntent_t' ) .removeProp( 'hoverIntent_s' ) .on( 'mouseover', function(e) { var li = $(e.target).closest( 'li.menupop' ); menupops.not(li).removeClass( 'ab-hover' ); li.toggleClass( 'ab-hover' ); } ) .on( 'click touchstart', function(e) { var $target = $( e.target ); if ( masterbar.focusSubMenus( $target ) ) { return; } e.preventDefault(); masterbar.toggleMenu( $target ); } ); masterbar = { focusSubMenus: function( $target ) { // Handle selection of menu items if ( ! $target.closest( 'ul' ).hasClass( 'ab-top-menu' ) ) { $target .closest( 'li' ); return true; } return false; }, toggleMenu: function( $target ) { var $li = $target.closest( 'li.menupop' ), $html = $( 'html' ); $( 'body' ).off( 'click.ab-menu' ); $( '#wpadminbar li.menupop' ).not($li).removeClass( 'ab-active wpnt-stayopen wpnt-show' ); if ( $li.hasClass( 'ab-active' ) ) { $li.removeClass( 'ab-active' ); $html.removeClass( 'ab-menu-open' ); } else { $li.addClass( 'ab-active' ); $html.addClass( 'ab-menu-open' ); $( 'body' ).on( 'click.ab-menu', function( e ) { if ( ! $( e.target ).parents( '#wpadminbar' ).length ) { e.preventDefault(); masterbar.toggleMenu( $li ); $( 'body' ).off( 'click.ab-menu' ); } } ); } } }; } );; /*globals JSON */ ( function( $ ) { var eventName = 'wpcom_masterbar_click'; var linksTracksEvents = { //top level items 'wp-admin-bar-blog' : 'my_sites', 'wp-admin-bar-newdash' : 'reader', 'wp-admin-bar-ab-new-post' : 'write_button', 'wp-admin-bar-my-account' : 'my_account', 'wp-admin-bar-notes' : 'notifications', //my sites - top items 'wp-admin-bar-switch-site' : 'my_sites_switch_site', 'wp-admin-bar-blog-info' : 'my_sites_site_info', 'wp-admin-bar-site-view' : 'my_sites_view_site', 'wp-admin-bar-blog-stats' : 'my_sites_site_stats', 'wp-admin-bar-plan' : 'my_sites_plan', 'wp-admin-bar-plan-badge' : 'my_sites_plan_badge', //my sites - manage 'wp-admin-bar-edit-page' : 'my_sites_manage_site_pages', 'wp-admin-bar-new-page-badge' : 'my_sites_manage_add_page', 'wp-admin-bar-edit-post' : 'my_sites_manage_blog_posts', 'wp-admin-bar-new-post-badge' : 'my_sites_manage_add_post', 'wp-admin-bar-edit-attachment' : 'my_sites_manage_media', 'wp-admin-bar-new-attachment-badge' : 'my_sites_manage_add_media', 'wp-admin-bar-comments' : 'my_sites_manage_comments', 'wp-admin-bar-edit-jetpack-testimonial' : 'my_sites_manage_testimonials', 'wp-admin-bar-new-jetpack-testimonial' : 'my_sites_manage_add_testimonial', 'wp-admin-bar-edit-jetpack-portfolio' : 'my_sites_manage_portfolio', 'wp-admin-bar-new-jetpack-portfolio' : 'my_sites_manage_add_portfolio', //my sites - personalize 'wp-admin-bar-themes' : 'my_sites_personalize_themes', 'wp-admin-bar-cmz' : 'my_sites_personalize_themes_customize', //my sites - configure 'wp-admin-bar-sharing' : 'my_sites_configure_sharing', 'wp-admin-bar-people' : 'my_sites_configure_people', 'wp-admin-bar-people-add' : 'my_sites_configure_people_add_button', 'wp-admin-bar-plugins' : 'my_sites_configure_plugins', 'wp-admin-bar-domains' : 'my_sites_configure_domains', 'wp-admin-bar-domains-add' : 'my_sites_configure_add_domain', 'wp-admin-bar-blog-settings' : 'my_sites_configure_settings', 'wp-admin-bar-legacy-dashboard' : 'my_sites_configure_wp_admin', //reader 'wp-admin-bar-followed-sites' : 'reader_followed_sites', 'wp-admin-bar-reader-followed-sites-manage': 'reader_manage_followed_sites', 'wp-admin-bar-discover-discover' : 'reader_discover', 'wp-admin-bar-discover-search' : 'reader_search', 'wp-admin-bar-my-activity-my-likes' : 'reader_my_likes', //account 'wp-admin-bar-user-info' : 'my_account_user_name', // account - profile 'wp-admin-bar-my-profile' : 'my_account_profile_my_profile', 'wp-admin-bar-account-settings' : 'my_account_profile_account_settings', 'wp-admin-bar-billing' : 'my_account_profile_manage_purchases', 'wp-admin-bar-security' : 'my_account_profile_security', 'wp-admin-bar-notifications' : 'my_account_profile_notifications', //account - special 'wp-admin-bar-get-apps' : 'my_account_special_get_apps', 'wp-admin-bar-next-steps' : 'my_account_special_next_steps', 'wp-admin-bar-help' : 'my_account_special_help', }; var notesTracksEvents = { openSite: function( data ) { return { clicked: 'masterbar_notifications_panel_site', site_id: data.siteId }; }, openPost: function( data ) { return { clicked: 'masterbar_notifications_panel_post', site_id: data.siteId, post_id: data.postId }; }, openComment: function( data ) { return { clicked: 'masterbar_notifications_panel_comment', site_id: data.siteId, post_id: data.postId, comment_id: data.commentId }; } }; function recordTracksEvent( eventProps ) { eventProps = eventProps || {}; window._tkq = window._tkq || []; window._tkq.push( [ 'recordEvent', eventName, eventProps ] ); } function parseJson( s, defaultValue ) { try { return JSON.parse( s ); } catch ( e ) { return defaultValue; } } $( document ).ready( function() { var trackableLinks = '.mb-trackable .ab-item:not(div),' + '#wp-admin-bar-notes .ab-item,' + '#wp-admin-bar-user-info .ab-item,' + '.mb-trackable .ab-secondary'; $( trackableLinks ).on( 'click touchstart', function( e ) { var $target = $( e.target ), $parent = $target.closest( 'li' ); if ( ! $parent ) { return; } var trackingId = $target.attr( 'ID' ) || $parent.attr( 'ID' ); if ( ! linksTracksEvents.hasOwnProperty( trackingId ) ) { return; } var eventProps = { 'clicked': linksTracksEvents[ trackingId ] }; recordTracksEvent( eventProps ); } ); } ); // listen for postMessage events from the notifications iframe $( window ).on( 'message', function( e ) { var event = ! e.data && e.originalEvent.data ? e.originalEvent : event; if ( event.origin !== 'https://widgets.wp.com' ) { return; } var data = ( 'string' === typeof event.data ) ? parseJson( event.data, {} ) : event.data; if ( 'notesIframeMessage' !== data.type ) { return; } var eventData = notesTracksEvents[ data.action ]; if ( ! eventData ) { return; } recordTracksEvent( eventData( data ) ); } ); } )( jQuery ); ; var wpcom = window.wpcom || {}; wpcom.actionbar = {}; wpcom.actionbar.data = actionbardata; // This might be better in another file, but is here for now (function($){ var fbd = wpcom.actionbar.data, d = document, docHeight = $( d ).height(), b = d.getElementsByTagName( 'body' )[0], lastScrollTop = 0, lastScrollDir, fb, fhtml, fbhtml, fbHtmlLi, followingbtn, followbtn, fbdf, action, slkhtml = '', foldhtml = '', reporthtml = '', customizeIcon, editIcon, statsIcon, themeHtml = '', signupHtml = '', loginHtml = '', viewReaderHtml = '', editSubsHtml = '', editFollowsHtml = '', toggleactionbar, $actionbar; // Don't show actionbar when iframed if ( window != window.top ) { return; } fhtml = ''; fbdf = d.createElement( 'div' ); fbdf.id = 'actionbar'; fbdf.innerHTML = fhtml; b.appendChild( fbdf ); $actionbar = $( '#actionbar' ).addClass( 'actnbr-' + fbd.themeSlug.replace( '/', '-' ) ); // Add classes based on contents if ( fbd.canCustomizeSite ) { $actionbar.addClass( 'actnbr-has-customize' ); } if ( fbd.canEditPost ) { $actionbar.addClass( 'actnbr-has-edit' ); } if ( ! fbd.canCustomizeSite ) { $actionbar.addClass( 'actnbr-has-follow' ); } if ( fbd.isFolded ) { $actionbar.addClass( 'actnbr-folded' ); } // Show status message if available if ( fbd.statusMessage ) { showActionBarStatusMessage( fbd.statusMessage ); } // *** Actions ***************** // Follow Site $actionbar.on( 'click', '.actnbr-actn-follow', function(e) { e.preventDefault(); if ( fbd.isLoggedIn ) { showActionBarStatusMessage( '
    ' + fbd.i18n.followedText + '
    ' ); bumpStat( 'followed' ); request( 'ab_subscribe_to_blog' ); } else { showActionBarFollowForm(); } } ) // UnFollow Site .on( 'click', '.actnbr-actn-following', function(e) { e.preventDefault(); $( '#actionbar .actnbr-actn-following' ).replaceWith( '' + followbtn + '' + fbd.i18n.follow + '' ); bumpStat( 'unfollowed' ); request( 'ab_unsubscribe_from_blog' ); } ) // Show shortlink prompt .on( 'click', '.actnbr-shortlink a', function(e) { e.preventDefault(); window.prompt( "Shortlink: ", fbd.shortlink ); } ) // Toggle more menu .on( 'click', '.actnbr-ellipsis', function(e) { if ( $( e.target ).closest( 'a' ).hasClass( 'actnbr-action' ) ) { return false; } var popoverLi = $( '#actionbar .actnbr-ellipsis' ); popoverLi.toggleClass( 'actnbr-hidden' ); setTimeout( function() { if ( ! popoverLi.hasClass( 'actnbr-hidden' ) ) { $( document ).on( 'click.actnbr-body-click', function(e) { popoverLi.addClass( 'actnbr-hidden' ); $( document ).off( 'click.actnbr-body-click' ); } ); } }, 10 ); }) // Fold/Unfold .on( 'click', '.actnbr-fold', function(e) { e.preventDefault(); if ( $( '#actionbar' ).hasClass( 'actnbr-folded' ) ) { $( '.actnbr-fold a' ).html( fbd.i18n.foldBar ); $( '#actionbar' ).removeClass( 'actnbr-folded' ); $.post( fbd.xhrURL, { 'action': 'unfold_actionbar' } ); } else { $( '.actnbr-fold a' ).html( fbd.i18n.unfoldBar ); $( '#actionbar' ).addClass( 'actnbr-folded' ); $.post( fbd.xhrURL, { 'action': 'fold_actionbar' } ); } }) // Record stats for clicks .on( 'click', '.actnbr-sitename a', function(e) { bumpStat( 'clicked_site_title' ); }) .on( 'click', '.actnbr-customize a', function(e) { bumpStat( 'customized' ); }) .on( 'click', '.actnbr-folded-customize a', function(e) { bumpStat( 'customized' ); }) .on( 'click', '.actnbr-theme a', function(e) { bumpStat( 'explored_theme' ); }) .on( 'click', '.actnbr-edit a', function(e) { bumpStat( 'edited' ); }) .on( 'click', '.actnbr-stats a', function(e) { bumpStat( 'clicked_stats' ); }) .on( 'click', '.flb-report a', function(e) { bumpStat( 'reported_content' ); }) .on( 'click', '.actnbr-follows a', function(e) { bumpStat( 'managed_following' ); }) .on( 'click', '.actnbr-shortlink a', function(e) { bumpStat( 'copied_shortlink' ); }) .on( 'click', '.actnbr-reader a', function(e) { bumpStat( 'view_reader' ); }) .on( 'submit', '.actnbr-follow-bubble form', function ( e ) { $( '#actionbar .actnbr-follow-bubble form button' ).attr( 'disabled', true ); }); // Make Follow/Unfollow requests var request = function( action ) { $.post( fbd.xhrURL, { 'action': action, '_wpnonce': fbd.nonce, 'source': 'actionbar', 'blog_id': fbd.siteID }); }; // Show/Hide actionbar on scroll fb = $('#actionbar'); toggleactionbar = function() { var st = $(window).scrollTop(), topOffset = 0; if ( $(window).scrollTop() < 0 ) { return; } // Still if ( lastScrollTop == 0 || ( ( st == lastScrollTop ) && lastScrollDir == 'up' ) ) { fb.removeClass( 'actnbr-hidden' ); // Moving } else { // Scrolling Up if ( st < lastScrollTop ){ fb.removeClass( 'actnbr-hidden' ); lastScrollDir = 'up'; // Scrolling Down } else { // check if there are any popovers open, and only hide action bar if not if ( $( '#actionbar > ul > li:not(.actnbr-hidden) > .actnbr-popover' ).length === 0 ) { fb.addClass( 'actnbr-hidden' ) lastScrollDir = 'down'; // Hide any menus $( '#actionbar li' ).addClass( 'actnbr-hidden' ); } } } lastScrollTop = st; } setInterval( toggleactionbar, 100 ); // Bump stats var bumpStat = function( stat ) { $.post( fbd.xhrURL, { 'action': 'actionbar_stats', 'stat': stat }); } function actionBarEscapeHtml(string) { return String(string).replace(/[&<>"'\/]/g, function (s) { var entityMap = { "&": "&", "<": "<", ">": ">", '"': '"', "'": ''', "/": '/' }; return entityMap[s]; }); }; function showActionBarStatusMessage( message ) { $( '#actionbar .actnbr-actn-follow' ).replaceWith( '' + followingbtn + '' + fbd.i18n.following + '' ); $( '#actionbar .actnbr-follow-bubble' ).html( ' \ \ '); var btn = $( '#actionbar .actnbr-btn' ); btn.removeClass( 'actnbr-hidden' ); setTimeout( function() { if ( ! btn.hasClass( 'actnbr-hidden' ) ) { $( '#actionbar .actnbr-email-field' ).focus(); $( document ).on( 'click.actnbr-body-click', function(e) { if ( $( e.target ).closest( '.actnbr-popover' )[0] ) { return; } btn.addClass( 'actnbr-hidden' ); $( document ).off( 'click.actnbr-body-click' ); } ); } }, 10 ); } function showActionBarFollowForm() { var btn = $( '#actionbar .actnbr-btn' ); btn.toggleClass( 'actnbr-hidden' ); var form = $('
    '); if ( fbd.i18n.followers ) form.append($('
    ').html(fbd.i18n.followers)); form.append($('
    ').append($('').attr({"type": "email", "name": "email", "placeholder": fbd.i18n.enterEmail, "class": "actnbr-email-field"}))); form.append($('')); form.append($('').attr('value', fbd.siteID)); form.append($('').attr('value', fbd.referer)); form.append($('')); form.append($(fbd.subscribeNonce)); form.append($('
    ').append($('