| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720 |
- /* global wpcom, jetpackCarouselStrings, DocumentTouch */
- ( function () {
- 'use strict';
- var swiper;
- /////////////////////////////////////
- // Utility functions
- /////////////////////////////////////
- var util = ( function () {
- var noop = function () {};
- function texturize( text ) {
- // Ensure we get a string.
- text = text + '';
- text = text.replace( /'/g, '’' ).replace( /'/g, '’' );
- text = text
- .replace( /"/g, '”' )
- .replace( /"/g, '”' )
- .replace( /"/g, '”' )
- .replace( /[\u201D]/g, '”' );
- // Untexturize allowed HTML tags params double-quotes.
- text = text.replace( /([\w]+)=&#[\d]+;(.+?)&#[\d]+;/g, '$1="$2"' );
- return text.trim();
- }
- function applyReplacements( text, replacements ) {
- if ( ! text ) {
- return;
- }
- if ( ! replacements ) {
- return text;
- }
- return text.replace( /{(\d+)}/g, function ( match, number ) {
- return typeof replacements[ number ] !== 'undefined' ? replacements[ number ] : match;
- } );
- }
- function getBackgroundImage( imgEl ) {
- var canvas = document.createElement( 'canvas' ),
- context = canvas.getContext && canvas.getContext( '2d' );
- if ( ! imgEl ) {
- return;
- }
- context.filter = 'blur(20px) ';
- context.drawImage( imgEl, 0, 0 );
- var url = canvas.toDataURL( 'image/png' );
- canvas = null;
- return url;
- }
- return {
- noop: noop,
- texturize: texturize,
- applyReplacements: applyReplacements,
- getBackgroundImage: getBackgroundImage,
- };
- } )();
- /////////////////////////////////////
- // DOM-related utility functions
- /////////////////////////////////////
- var domUtil = ( function () {
- // Helper matches function (not a polyfill), compatible with IE 11.
- function matches( el, sel ) {
- if ( Element.prototype.matches ) {
- return el.matches( sel );
- }
- if ( Element.prototype.msMatchesSelector ) {
- return el.msMatchesSelector( sel );
- }
- }
- // Helper closest parent node function (not a polyfill) based on
- // https://developer.mozilla.org/en-US/docs/Web/API/Element/closest#Polyfill
- function closest( el, sel ) {
- if ( el.closest ) {
- return el.closest( sel );
- }
- var current = el;
- do {
- if ( matches( current, sel ) ) {
- return current;
- }
- current = current.parentElement || current.parentNode;
- } while ( current !== null && current.nodeType === 1 );
- return null;
- }
- function hide( el ) {
- if ( el ) {
- el.style.display = 'none';
- }
- }
- function show( el ) {
- if ( el ) {
- // Everything we show and hide in Carousel is currently a block,
- // so we can make this really straightforward.
- el.style.display = 'block';
- }
- }
- function fade( el, start, end, callback ) {
- if ( ! el ) {
- return callback();
- }
- // Prepare for transition.
- // Ensure the item is in the render tree, in its initial state.
- el.style.removeProperty( 'display' );
- el.style.opacity = start;
- el.style.transition = 'opacity 0.2s';
- el.style.pointerEvents = 'none';
- var finished = function ( e ) {
- if ( e.target === el && e.propertyName === 'opacity' ) {
- el.style.removeProperty( 'transition' );
- el.style.removeProperty( 'opacity' );
- el.style.removeProperty( 'pointer-events' );
- el.removeEventListener( 'transitionend', finished );
- el.removeEventListener( 'transitioncancel', finished );
- callback();
- }
- };
- requestAnimationFrame( function () {
- // Double rAF for browser compatibility.
- requestAnimationFrame( function () {
- el.addEventListener( 'transitionend', finished );
- el.addEventListener( 'transitioncancel', finished );
- // Trigger transition.
- el.style.opacity = end;
- } );
- } );
- }
- function fadeIn( el, callback ) {
- callback = callback || util.noop;
- fade( el, '0', '1', callback );
- }
- function fadeOut( el, callback ) {
- callback = callback || util.noop;
- fade( el, '1', '0', function () {
- if ( el ) {
- el.style.display = 'none';
- }
- callback();
- } );
- }
- function emitEvent( el, type, detail ) {
- var e;
- try {
- e = new CustomEvent( type, {
- bubbles: true,
- cancelable: true,
- detail: detail || null,
- } );
- } catch ( err ) {
- e = document.createEvent( 'CustomEvent' );
- e.initCustomEvent( type, true, true, detail || null );
- }
- el.dispatchEvent( e );
- }
- // From: https://easings.net/#easeInOutQuad
- function easeInOutQuad( num ) {
- return num < 0.5 ? 2 * num * num : 1 - Math.pow( -2 * num + 2, 2 ) / 2;
- }
- function getFooterClearance( container ) {
- var footer = container.querySelector( '.jp-carousel-info-footer' );
- var infoArea = container.querySelector( '.jp-carousel-info-extra' );
- var contentArea = container.querySelector( '.jp-carousel-info-content-wrapper' );
- if ( footer && infoArea && contentArea ) {
- var styles = window.getComputedStyle( infoArea );
- var padding = parseInt( styles.paddingTop, 10 ) + parseInt( styles.paddingBottom, 10 );
- padding = isNaN( padding ) ? 0 : padding;
- return contentArea.offsetHeight + footer.offsetHeight + padding;
- }
- return 0;
- }
- function isTouch() {
- return (
- 'ontouchstart' in window || ( window.DocumentTouch && document instanceof DocumentTouch )
- );
- }
- function scrollToElement( el, container, callback ) {
- if ( ! el || ! container ) {
- if ( callback ) {
- return callback();
- }
- return;
- }
- // For iOS Safari compatibility, use JS to set the minimum height.
- var infoArea = container.querySelector( '.jp-carousel-info-extra' );
- if ( infoArea ) {
- // 64px is the same height as `.jp-carousel-info-footer` in the CSS.
- infoArea.style.minHeight = window.innerHeight - 64 + 'px';
- }
- var isScrolling = true;
- var startTime = Date.now();
- var duration = 300;
- var originalPosition = container.scrollTop;
- var targetPosition = Math.max(
- 0,
- el.offsetTop - Math.max( 0, window.innerHeight - getFooterClearance( container ) )
- );
- var distance = targetPosition - container.scrollTop;
- distance = Math.min( distance, container.scrollHeight - window.innerHeight );
- function stopScroll() {
- isScrolling = false;
- }
- function runScroll() {
- var now = Date.now();
- var progress = easeInOutQuad( ( now - startTime ) / duration );
- progress = progress > 1 ? 1 : progress;
- var newVal = progress * distance;
- container.scrollTop = originalPosition + newVal;
- if ( now <= startTime + duration && isScrolling ) {
- return requestAnimationFrame( runScroll );
- }
- if ( callback ) {
- callback();
- }
- if ( infoArea ) {
- infoArea.style.minHeight = '';
- }
- isScrolling = false;
- container.removeEventListener( 'wheel', stopScroll );
- }
- // Allow scroll to be cancelled by user interaction.
- container.addEventListener( 'wheel', stopScroll );
- runScroll();
- }
- function getJSONAttribute( el, attr ) {
- if ( ! el || ! el.hasAttribute( attr ) ) {
- return undefined;
- }
- try {
- return JSON.parse( el.getAttribute( attr ) );
- } catch ( e ) {
- return undefined;
- }
- }
- function convertToPlainText( html ) {
- var dummy = document.createElement( 'div' );
- dummy.textContent = html;
- return dummy.innerHTML;
- }
- function stripHTML( text ) {
- return text.replace( /<[^>]*>?/gm, '' );
- }
- return {
- closest: closest,
- matches: matches,
- hide: hide,
- show: show,
- fadeIn: fadeIn,
- fadeOut: fadeOut,
- scrollToElement: scrollToElement,
- getJSONAttribute: getJSONAttribute,
- convertToPlainText: convertToPlainText,
- stripHTML: stripHTML,
- emitEvent: emitEvent,
- isTouch: isTouch,
- };
- } )();
- /////////////////////////////////////
- // Carousel implementation
- /////////////////////////////////////
- function init() {
- var commentInterval;
- var screenPadding;
- var originalOverflow;
- var originalHOverflow;
- var scrollPos;
- var lastKnownLocationHash = '';
- var isUserTyping = false;
- var gallerySelector =
- 'div.gallery, div.tiled-gallery, ul.wp-block-gallery, ul.blocks-gallery-grid, ' +
- 'figure.wp-block-gallery.has-nested-images, div.wp-block-jetpack-tiled-gallery, a.single-image-gallery';
- // Selector for items within a gallery or tiled gallery.
- var galleryItemSelector =
- '.gallery-item, .tiled-gallery-item, .blocks-gallery-item, ' + ' .tiled-gallery__item';
- // Selector for all items including single images.
- var itemSelector = galleryItemSelector + ', .wp-block-image';
- var carousel = {};
- var stat =
- typeof wpcom !== 'undefined' && wpcom.carousel && wpcom.carousel.stat
- ? wpcom.carousel.stat
- : util.noop;
- var pageview =
- typeof wpcom !== 'undefined' && wpcom.carousel && wpcom.carousel.pageview
- ? wpcom.carousel.pageview
- : util.noop;
- function handleKeyboardEvent( e ) {
- if ( ! isUserTyping ) {
- switch ( e.which ) {
- case 38: // up
- e.preventDefault();
- carousel.overlay.scrollTop -= 100;
- break;
- case 40: // down
- e.preventDefault();
- carousel.overlay.scrollTop += 100;
- break;
- case 39: // right
- e.preventDefault();
- swiper.slideNext();
- break;
- case 37: // left
- case 8: // backspace
- e.preventDefault();
- swiper.slidePrev();
- break;
- case 27: // escape
- e.preventDefault();
- closeCarousel();
- break;
- default:
- break;
- }
- }
- }
- function disableKeyboardNavigation() {
- isUserTyping = true;
- }
- function enableKeyboardNavigation() {
- isUserTyping = false;
- }
- function calculatePadding() {
- var baseScreenPadding = 110;
- screenPadding = baseScreenPadding;
- if ( window.innerWidth <= 760 ) {
- screenPadding = Math.round( ( window.innerWidth / 760 ) * baseScreenPadding );
- if ( screenPadding < 40 && domUtil.isTouch() ) {
- screenPadding = 0;
- }
- }
- }
- function initializeCarousel() {
- if ( ! carousel.overlay ) {
- carousel.overlay = document.querySelector( '.jp-carousel-overlay' );
- carousel.container = carousel.overlay.querySelector( '.jp-carousel-wrap' );
- carousel.gallery = carousel.container.querySelector( '.jp-carousel' );
- carousel.info = carousel.overlay.querySelector( '.jp-carousel-info' );
- carousel.caption = carousel.info.querySelector( '.jp-carousel-caption' );
- carousel.commentField = carousel.overlay.querySelector(
- '#jp-carousel-comment-form-comment-field'
- );
- carousel.emailField = carousel.overlay.querySelector(
- '#jp-carousel-comment-form-email-field'
- );
- carousel.authorField = carousel.overlay.querySelector(
- '#jp-carousel-comment-form-author-field'
- );
- carousel.urlField = carousel.overlay.querySelector( '#jp-carousel-comment-form-url-field' );
- calculatePadding();
- [
- carousel.commentField,
- carousel.emailField,
- carousel.authorField,
- carousel.urlField,
- ].forEach( function ( field ) {
- if ( field ) {
- field.addEventListener( 'focus', disableKeyboardNavigation );
- field.addEventListener( 'blur', enableKeyboardNavigation );
- }
- } );
- carousel.overlay.addEventListener( 'click', function ( e ) {
- var target = e.target;
- var isTargetCloseHint = !! domUtil.closest( target, '.jp-carousel-close-hint' );
- var isSmallScreen = !! window.matchMedia( '(max-device-width: 760px)' ).matches;
- if ( target === carousel.overlay ) {
- if ( isSmallScreen ) {
- return;
- } else {
- closeCarousel();
- }
- } else if ( isTargetCloseHint ) {
- closeCarousel();
- } else if ( target.classList.contains( 'jp-carousel-image-download' ) ) {
- stat( 'download_original_click' );
- } else if ( target.classList.contains( 'jp-carousel-comment-login' ) ) {
- handleCommentLoginClick( e );
- } else if ( domUtil.closest( target, '#jp-carousel-comment-form-container' ) ) {
- handleCommentFormClick( e );
- } else if (
- domUtil.closest( target, '.jp-carousel-photo-icons-container' ) ||
- target.classList.contains( 'jp-carousel-photo-title' )
- ) {
- handleFooterElementClick( e );
- } else if ( ! domUtil.closest( target, '.jp-carousel-info' ) ) {
- return;
- }
- } );
- window.addEventListener( 'keydown', handleKeyboardEvent );
- carousel.overlay.addEventListener( 'jp_carousel.afterOpen', function () {
- enableKeyboardNavigation();
- // Don't show navigation if there's only one image.
- if ( carousel.slides.length <= 1 ) {
- return;
- }
- // Show dot pagination if slide count is <= 5, otherwise show n/total.
- if ( carousel.slides.length <= 5 ) {
- domUtil.show( carousel.info.querySelector( '.jp-swiper-pagination' ) );
- } else {
- domUtil.show( carousel.info.querySelector( '.jp-carousel-pagination' ) );
- }
- } );
- carousel.overlay.addEventListener( 'jp_carousel.beforeClose', function () {
- disableKeyboardNavigation();
- // Fixes some themes where closing carousel brings view back to top.
- document.documentElement.style.removeProperty( 'height' );
- // If we disable the swiper (because there's only one image)
- // we have to re-enable it here again as Swiper doesn't, for some reason,
- // show the navigation buttons again after reinitialization.
- if ( swiper ) {
- swiper.enable();
- }
- // Hide pagination.
- domUtil.hide( carousel.info.querySelector( '.jp-swiper-pagination' ) );
- domUtil.hide( carousel.info.querySelector( '.jp-carousel-pagination' ) );
- } );
- carousel.overlay.addEventListener( 'jp_carousel.afterClose', function () {
- // don't force the browser back when the carousel closes.
- if ( window.history.pushState ) {
- history.pushState(
- '',
- document.title,
- window.location.pathname + window.location.search
- );
- } else {
- window.location.href = '';
- }
- lastKnownLocationHash = '';
- carousel.isOpen = false;
- } );
- // Prevent native browser zooming
- carousel.overlay.addEventListener( 'touchstart', function ( e ) {
- if ( e.touches.length > 1 ) {
- e.preventDefault();
- }
- } );
- }
- }
- function handleCommentLoginClick() {
- var slide = carousel.currentSlide;
- var attachmentId = slide ? slide.attrs.attachmentId : '0';
- window.location.href = jetpackCarouselStrings.login_url + '%23jp-carousel-' + attachmentId;
- }
- function updatePostResults( msg, isSuccess ) {
- var results = carousel.overlay.querySelector( '#jp-carousel-comment-post-results' );
- var elClass = 'jp-carousel-comment-post-' + ( isSuccess ? 'success' : 'error' );
- results.innerHTML = '<span class="' + elClass + '">' + msg + '</span>';
- domUtil.hide( carousel.overlay.querySelector( '#jp-carousel-comment-form-spinner' ) );
- carousel.overlay
- .querySelector( '#jp-carousel-comment-form' )
- .classList.remove( 'jp-carousel-is-disabled' );
- domUtil.show( results );
- }
- function handleCommentFormClick( e ) {
- var target = e.target;
- var data = domUtil.getJSONAttribute( carousel.container, 'data-carousel-extra' ) || {};
- var attachmentId = carousel.currentSlide.attrs.attachmentId;
- var wrapper = document.querySelector( '#jp-carousel-comment-form-submit-and-info-wrapper' );
- var spinner = document.querySelector( '#jp-carousel-comment-form-spinner' );
- var submit = document.querySelector( '#jp-carousel-comment-form-button-submit' );
- var form = document.querySelector( '#jp-carousel-comment-form' );
- if (
- carousel.commentField &&
- carousel.commentField.getAttribute( 'id' ) === target.getAttribute( 'id' )
- ) {
- // For first page load
- disableKeyboardNavigation();
- domUtil.show( wrapper );
- } else if ( domUtil.matches( target, 'input[type="submit"]' ) ) {
- e.preventDefault();
- e.stopPropagation();
- domUtil.show( spinner );
- form.classList.add( 'jp-carousel-is-disabled' );
- var ajaxData = {
- action: 'post_attachment_comment',
- nonce: jetpackCarouselStrings.nonce,
- blog_id: data.blog_id,
- id: attachmentId,
- comment: carousel.commentField.value,
- };
- if ( ! ajaxData.comment.length ) {
- updatePostResults( jetpackCarouselStrings.no_comment_text, false );
- return;
- }
- if ( Number( jetpackCarouselStrings.is_logged_in ) !== 1 ) {
- ajaxData.email = carousel.emailField.value;
- ajaxData.author = carousel.authorField.value;
- ajaxData.url = carousel.urlField.value;
- if ( Number( jetpackCarouselStrings.require_name_email ) === 1 ) {
- if ( ! ajaxData.email.length || ! ajaxData.email.match( '@' ) ) {
- updatePostResults( jetpackCarouselStrings.no_comment_email, false );
- return;
- } else if ( ! ajaxData.author.length ) {
- updatePostResults( jetpackCarouselStrings.no_comment_author, false );
- return;
- }
- }
- }
- var xhr = new XMLHttpRequest();
- xhr.open( 'POST', jetpackCarouselStrings.ajaxurl, true );
- xhr.setRequestHeader( 'X-Requested-With', 'XMLHttpRequest' );
- xhr.setRequestHeader( 'Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8' );
- xhr.onreadystatechange = function () {
- if (
- this.readyState === XMLHttpRequest.DONE &&
- this.status >= 200 &&
- this.status < 300
- ) {
- var response;
- try {
- response = JSON.parse( this.response );
- } catch ( error ) {
- updatePostResults( jetpackCarouselStrings.comment_post_error, false );
- return;
- }
- if ( response.comment_status === 'approved' ) {
- updatePostResults( jetpackCarouselStrings.comment_approved, true );
- } else if ( response.comment_status === 'unapproved' ) {
- updatePostResults( jetpackCarouselStrings.comment_unapproved, true );
- } else {
- // 'deleted', 'spam', false
- updatePostResults( jetpackCarouselStrings.comment_post_error, false );
- }
- clearCommentTextAreaValue();
- fetchComments( attachmentId );
- submit.value = jetpackCarouselStrings.post_comment;
- domUtil.hide( spinner );
- form.classList.remove( 'jp-carousel-is-disabled' );
- } else {
- // TODO: Add error handling and display here
- updatePostResults( jetpackCarouselStrings.comment_post_error, false );
- }
- };
- var params = [];
- for ( var item in ajaxData ) {
- if ( item ) {
- // Encode each form element into a URI-compatible string.
- var encoded = encodeURIComponent( item ) + '=' + encodeURIComponent( ajaxData[ item ] );
- // In x-www-form-urlencoded, spaces should be `+`, not `%20`.
- params.push( encoded.replace( /%20/g, '+' ) );
- }
- }
- var encodedData = params.join( '&' );
- xhr.send( encodedData );
- }
- }
- /**
- * Handles clicks to icons and other action elements in the icon container.
- * @param {MouseEvent|TouchEvent|KeyBoardEvent} Event object.
- */
- function handleFooterElementClick( e ) {
- e.preventDefault();
- var target = e.target;
- var extraInfoContainer = carousel.info.querySelector( '.jp-carousel-info-extra' );
- var photoMetaContainer = carousel.info.querySelector( '.jp-carousel-image-meta' );
- var commentsContainer = carousel.info.querySelector( '.jp-carousel-comments-wrapper' );
- var infoIcon = carousel.info.querySelector( '.jp-carousel-icon-info' );
- var commentsIcon = carousel.info.querySelector( '.jp-carousel-icon-comments' );
- function handleInfoToggle() {
- if ( commentsIcon ) {
- commentsIcon.classList.remove( 'jp-carousel-selected' );
- }
- infoIcon.classList.toggle( 'jp-carousel-selected' );
- if ( commentsContainer ) {
- commentsContainer.classList.remove( 'jp-carousel-show' );
- }
- if ( photoMetaContainer ) {
- photoMetaContainer.classList.toggle( 'jp-carousel-show' );
- if ( photoMetaContainer.classList.contains( 'jp-carousel-show' ) ) {
- extraInfoContainer.classList.add( 'jp-carousel-show' );
- } else {
- extraInfoContainer.classList.remove( 'jp-carousel-show' );
- }
- }
- }
- function handleCommentToggle() {
- if ( infoIcon ) {
- infoIcon.classList.remove( 'jp-carousel-selected' );
- }
- commentsIcon.classList.toggle( 'jp-carousel-selected' );
- if ( photoMetaContainer ) {
- photoMetaContainer.classList.remove( 'jp-carousel-show' );
- }
- if ( commentsContainer ) {
- commentsContainer.classList.toggle( 'jp-carousel-show' );
- if ( commentsContainer.classList.contains( 'jp-carousel-show' ) ) {
- extraInfoContainer.classList.add( 'jp-carousel-show' );
- } else {
- extraInfoContainer.classList.remove( 'jp-carousel-show' );
- }
- }
- }
- if (
- domUtil.closest( target, '.jp-carousel-icon-info' ) ||
- target.classList.contains( 'jp-carousel-photo-title' )
- ) {
- if ( photoMetaContainer && photoMetaContainer.classList.contains( 'jp-carousel-show' ) ) {
- domUtil.scrollToElement( carousel.overlay, carousel.overlay, handleInfoToggle );
- } else {
- handleInfoToggle();
- domUtil.scrollToElement( carousel.info, carousel.overlay );
- }
- }
- if ( domUtil.closest( target, '.jp-carousel-icon-comments' ) ) {
- if ( commentsContainer && commentsContainer.classList.contains( 'jp-carousel-show' ) ) {
- domUtil.scrollToElement( carousel.overlay, carousel.overlay, handleCommentToggle );
- } else {
- handleCommentToggle();
- domUtil.scrollToElement( carousel.info, carousel.overlay );
- }
- }
- }
- function processSingleImageGallery() {
- var images = document.querySelectorAll( 'a img[data-attachment-id]' );
- Array.prototype.forEach.call( images, function ( image ) {
- var link = image.parentElement;
- var container = link.parentElement;
- // Skip if image was already added to gallery by shortcode.
- if ( container.classList.contains( 'gallery-icon' ) ) {
- return;
- }
- // Skip if image is part of a gallery.
- if ( domUtil.closest( container, galleryItemSelector ) ) {
- return;
- }
- // Skip if the parent is not actually a link.
- if ( ! link.hasAttribute( 'href' ) ) {
- return;
- }
- var valid = false;
- // If link points to 'Media File' (ignoring GET parameters) and flag is set, allow it.
- if (
- link.getAttribute( 'href' ).split( '?' )[ 0 ] ===
- image.getAttribute( 'data-orig-file' ).split( '?' )[ 0 ] &&
- Number( jetpackCarouselStrings.single_image_gallery_media_file ) === 1
- ) {
- valid = true;
- }
- // If link points to 'Attachment Page', allow it.
- if ( link.getAttribute( 'href' ) === image.getAttribute( 'data-permalink' ) ) {
- valid = true;
- }
- // Links to 'Custom URL' or 'Media File' when flag is not set are not valid.
- if ( ! valid ) {
- return;
- }
- // Make this node a gallery recognizable by event listener above.
- link.classList.add( 'single-image-gallery' );
- // blog_id is needed to allow posting comments to correct blog.
- link.setAttribute(
- 'data-carousel-extra',
- JSON.stringify( {
- blog_id: Number( jetpackCarouselStrings.blog_id ),
- } )
- );
- } );
- }
- function testForData( el ) {
- return !! ( el && el.getAttribute( 'data-carousel-extra' ) );
- }
- function openOrSelectSlide( gal, index ) {
- if ( ! carousel.isOpen ) {
- // The `open` method selects the correct slide during the initialization.
- loadSwiper( gal, { startIndex: index } );
- } else {
- selectSlideAtIndex( index );
- // We have to force swiper to slide to the index onHasChange.
- swiper.slideTo( index + 1 );
- }
- }
- function selectSlideAtIndex( index ) {
- if ( ! index || index < 0 || index > carousel.slides.length ) {
- index = 0;
- }
- carousel.currentSlide = carousel.slides[ index ];
- var current = carousel.currentSlide;
- var attachmentId = current.attrs.attachmentId;
- var infoIcon = carousel.info.querySelector( '.jp-carousel-icon-info' );
- var commentsIcon = carousel.info.querySelector( '.jp-carousel-icon-comments' );
- // If the comment/info section is toggled open, it's kept open, but scroll to top of the next slide.
- if (
- ( infoIcon && infoIcon.classList.contains( 'jp-carousel-selected' ) ) ||
- ( commentsIcon && commentsIcon.classList.contains( 'jp-carousel-selected' ) )
- ) {
- if ( carousel.overlay.scrollTop !== 0 ) {
- domUtil.scrollToElement( carousel.overlay, carousel.overlay );
- }
- }
- loadFullImage( carousel.slides[ index ] );
- if (
- Number( jetpackCarouselStrings.display_background_image ) === 1 &&
- ! carousel.slides[ index ].backgroundImage
- ) {
- loadBackgroundImage( carousel.slides[ index ] );
- }
- domUtil.hide( carousel.caption );
- updateTitleCaptionAndDesc( {
- caption: current.attrs.caption,
- title: current.attrs.title,
- desc: current.attrs.desc,
- } );
- var imageMeta = carousel.slides[ index ].attrs.imageMeta;
- updateExif( imageMeta );
- updateFullSizeLink( current );
- if ( Number( jetpackCarouselStrings.display_comments ) === 1 ) {
- testCommentsOpened( carousel.slides[ index ].attrs.commentsOpened );
- fetchComments( attachmentId );
- domUtil.hide( carousel.info.querySelector( '#jp-carousel-comment-post-results' ) );
- }
- // Update pagination in footer.
- var pagination = carousel.info.querySelector( '.jp-carousel-pagination' );
- if ( pagination && carousel.slides.length > 5 ) {
- var currentPage = index + 1;
- pagination.innerHTML = '<span>' + currentPage + ' / ' + carousel.slides.length + '</span>';
- }
- // 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();
- }
- pageview( attachmentId );
- window.location.hash = lastKnownLocationHash = '#jp-carousel-' + attachmentId;
- }
- function restoreScroll() {
- window.scrollTo( window.scrollX || window.pageXOffset || 0, scrollPos || 0 );
- }
- function closeCarousel() {
- // Make sure to let the page scroll again.
- document.body.style.overflow = originalOverflow;
- document.documentElement.style.overflow = originalHOverflow;
- clearCommentTextAreaValue();
- disableKeyboardNavigation();
- domUtil.emitEvent( carousel.overlay, 'jp_carousel.beforeClose' );
- restoreScroll();
- swiper.destroy();
- carousel.isOpen = false;
- // Clear slide data for DOM garbage collection.
- carousel.slides = [];
- carousel.currentSlide = undefined;
- carousel.gallery.innerHTML = '';
- domUtil.fadeOut( carousel.overlay, function () {
- domUtil.emitEvent( carousel.overlay, 'jp_carousel.afterClose' );
- } );
- }
- function calculateMaxSlideDimensions() {
- return {
- width: window.innerWidth,
- height: window.innerHeight - 64, //subtract height of bottom info bar,
- };
- }
- function selectBestImageUrl( args ) {
- if ( typeof args !== 'object' ) {
- args = {};
- }
- if ( typeof args.origFile === 'undefined' ) {
- return '';
- }
- if ( typeof args.origWidth === 'undefined' || typeof args.maxWidth === 'undefined' ) {
- return args.origFile;
- }
- if ( typeof args.mediumFile === 'undefined' || typeof args.largeFile === 'undefined' ) {
- return args.origFile;
- }
- // Check if the image is being served by Photon (using a regular expression on the hostname).
- var imageLinkParser = document.createElement( 'a' );
- imageLinkParser.href = args.largeFile;
- var isPhotonUrl = /^i[0-2]\.wp\.com$/i.test( imageLinkParser.hostname );
- var mediumSizeParts = getImageSizeParts( args.mediumFile, args.origWidth, isPhotonUrl );
- var largeSizeParts = getImageSizeParts( args.largeFile, args.origWidth, isPhotonUrl );
- var largeWidth = parseInt( largeSizeParts[ 0 ], 10 );
- var largeHeight = parseInt( largeSizeParts[ 1 ], 10 );
- var mediumWidth = parseInt( mediumSizeParts[ 0 ], 10 );
- var mediumHeight = parseInt( mediumSizeParts[ 1 ], 10 );
- args.origMaxWidth = args.maxWidth;
- args.origMaxHeight = args.maxHeight;
- // Give devices with a higher devicePixelRatio higher-res images (Retina display = 2, Android phones = 1.5, etc)
- if ( typeof window.devicePixelRatio !== 'undefined' && window.devicePixelRatio > 1 ) {
- args.maxWidth = args.maxWidth * window.devicePixelRatio;
- args.maxHeight = args.maxHeight * window.devicePixelRatio;
- }
- if ( largeWidth >= args.maxWidth || largeHeight >= args.maxHeight ) {
- return args.largeFile;
- }
- if ( mediumWidth >= args.maxWidth || mediumHeight >= args.maxHeight ) {
- return args.mediumFile;
- }
- if ( isPhotonUrl ) {
- // args.origFile doesn't point to a Photon url, so in this case we use args.largeFile
- // to return the photon url of the original image.
- var largeFileIndex = args.largeFile.lastIndexOf( '?' );
- var origPhotonUrl = args.largeFile;
- if ( largeFileIndex !== -1 ) {
- origPhotonUrl = args.largeFile.substring( 0, largeFileIndex );
- // If we have a really large image load a smaller version
- // that is closer to the viewable size
- if ( args.origWidth > args.maxWidth || args.origHeight > args.maxHeight ) {
- // @2x the max sizes so we get a high enough resolution for zooming.
- args.origMaxWidth = args.maxWidth * 2;
- args.origMaxHeight = args.maxHeight * 2;
- origPhotonUrl += '?fit=' + args.origMaxWidth + '%2C' + args.origMaxHeight;
- }
- }
- return origPhotonUrl;
- }
- return args.origFile;
- }
- function getImageSizeParts( file, origWidth, isPhotonUrl ) {
- var size = isPhotonUrl
- ? file.replace( /.*=([\d]+%2C[\d]+).*$/, '$1' )
- : file.replace( /.*-([\d]+x[\d]+)\..+$/, '$1' );
- var sizeParts =
- size !== file
- ? isPhotonUrl
- ? size.split( '%2C' )
- : size.split( 'x' )
- : [ origWidth, 0 ];
- // If one of the dimensions is set to 9999, then the actual value of that dimension can't be retrieved from the url.
- // In that case, we set the value to 0.
- if ( sizeParts[ 0 ] === '9999' ) {
- sizeParts[ 0 ] = '0';
- }
- if ( sizeParts[ 1 ] === '9999' ) {
- sizeParts[ 1 ] = '0';
- }
- return sizeParts;
- }
- /**
- * Returns a number in a fraction format that represents the shutter speed.
- * @param Number speed
- * @return String
- */
- function formatShutterSpeed( speed ) {
- var denominator;
- // round to one decimal if value > 1s by multiplying it by 10, rounding, then dividing by 10 again
- if ( speed >= 1 ) {
- return Math.round( speed * 10 ) / 10 + 's';
- }
- // If the speed is less than one, we find the denominator by inverting
- // the number. Since cameras usually use rational numbers as shutter
- // speeds, we should get a nice round number. Or close to one in cases
- // like 1/30. So we round it.
- denominator = Math.round( 1 / speed );
- return '1/' + denominator + 's';
- }
- function parseTitleOrDesc( value ) {
- if ( ! value.match( ' ' ) && value.match( '_' ) ) {
- return '';
- }
- return value;
- }
- function updateTitleCaptionAndDesc( data ) {
- var caption = '';
- var title = '';
- var desc = '';
- var captionMainElement;
- var captionInfoExtraElement;
- var titleElement;
- var descriptionElement;
- captionMainElement = carousel.overlay.querySelector( '.jp-carousel-photo-caption' );
- captionInfoExtraElement = carousel.overlay.querySelector( '.jp-carousel-caption' );
- titleElement = carousel.overlay.querySelector( '.jp-carousel-photo-title' );
- descriptionElement = carousel.overlay.querySelector( '.jp-carousel-photo-description' );
- domUtil.hide( captionMainElement );
- domUtil.hide( captionInfoExtraElement );
- domUtil.hide( titleElement );
- domUtil.hide( descriptionElement );
- caption = parseTitleOrDesc( data.caption ) || '';
- title = parseTitleOrDesc( data.title ) || '';
- desc = parseTitleOrDesc( data.desc ) || '';
- if ( caption || title || desc ) {
- if ( caption ) {
- captionMainElement.innerHTML = caption;
- captionInfoExtraElement.innerHTML = caption;
- domUtil.show( captionMainElement );
- domUtil.show( captionInfoExtraElement );
- }
- if ( domUtil.stripHTML( caption ) === domUtil.stripHTML( title ) ) {
- title = '';
- }
- if ( domUtil.stripHTML( caption ) === domUtil.stripHTML( desc ) ) {
- desc = '';
- }
- if ( domUtil.stripHTML( title ) === domUtil.stripHTML( desc ) ) {
- desc = '';
- }
- if ( desc ) {
- descriptionElement.innerHTML = desc;
- domUtil.show( descriptionElement );
- if ( ! title && ! caption ) {
- captionMainElement.innerHTML = domUtil.stripHTML( desc );
- domUtil.show( captionMainElement );
- }
- }
- if ( title ) {
- var plainTitle = domUtil.stripHTML( title );
- titleElement.innerHTML = plainTitle;
- if ( ! caption ) {
- captionMainElement.innerHTML = plainTitle;
- captionInfoExtraElement.innerHTML = plainTitle;
- domUtil.show( captionMainElement );
- }
- domUtil.show( titleElement );
- }
- }
- }
- // updateExif updates the contents of the exif UL (.jp-carousel-image-exif)
- function updateExif( meta ) {
- if ( ! meta || Number( jetpackCarouselStrings.display_exif ) !== 1 ) {
- return false;
- }
- var ul = carousel.info.querySelector( '.jp-carousel-image-meta ul.jp-carousel-image-exif' );
- var html = '';
- for ( var key in meta ) {
- var val = meta[ key ];
- var metaKeys = jetpackCarouselStrings.meta_data || [];
- if ( parseFloat( val ) === 0 || ! val.length || metaKeys.indexOf( key ) === -1 ) {
- continue;
- }
- switch ( key ) {
- case 'focal_length':
- val = val + 'mm';
- break;
- case 'shutter_speed':
- val = formatShutterSpeed( val );
- break;
- case 'aperture':
- val = 'f/' + val;
- break;
- }
- html += '<li><h5>' + jetpackCarouselStrings[ key ] + '</h5>' + val + '</li>';
- }
- ul.innerHTML = html;
- ul.style.removeProperty( 'display' );
- }
- // Update the contents of the jp-carousel-image-download link
- function updateFullSizeLink( currentSlide ) {
- if ( ! currentSlide ) {
- return false;
- }
- var original;
- var origSize = [ currentSlide.attrs.origWidth, currentSlide.attrs.origHeight ];
- var imageLinkParser = document.createElement( 'a' );
- imageLinkParser.href = currentSlide.attrs.src.replace( /\?.+$/, '' );
- // Is this a Photon URL?
- if ( imageLinkParser.hostname.match( /^i[\d]{1}\.wp\.com$/i ) !== null ) {
- original = imageLinkParser.href;
- } else {
- original = currentSlide.attrs.origFile.replace( /\?.+$/, '' );
- }
- var downloadText = carousel.info.querySelector( '.jp-carousel-download-text' );
- var permalink = carousel.info.querySelector( '.jp-carousel-image-download' );
- downloadText.innerHTML = util.applyReplacements(
- jetpackCarouselStrings.download_original,
- origSize
- );
- permalink.setAttribute( 'href', original );
- permalink.style.removeProperty( 'display' );
- }
- function testCommentsOpened( opened ) {
- var commentForm = carousel.container.querySelector( '.jp-carousel-comment-form-container' );
- var isOpened = parseInt( opened, 10 ) === 1;
- if ( isOpened ) {
- domUtil.fadeIn( commentForm );
- } else {
- domUtil.fadeOut( commentForm );
- }
- }
- function fetchComments( attachmentId, offset ) {
- var shouldClear = offset === undefined;
- var commentsIndicator = carousel.info.querySelector(
- '.jp-carousel-icon-comments .jp-carousel-has-comments-indicator'
- );
- commentsIndicator.classList.remove( 'jp-carousel-show' );
- clearInterval( commentInterval );
- if ( ! attachmentId ) {
- return;
- }
- if ( ! offset || offset < 1 ) {
- offset = 0;
- }
- var comments = carousel.info.querySelector( '.jp-carousel-comments' );
- var commentsLoading = carousel.info.querySelector( '#jp-carousel-comments-loading' );
- domUtil.show( commentsLoading );
- if ( shouldClear ) {
- domUtil.hide( comments );
- comments.innerHTML = '';
- }
- var xhr = new XMLHttpRequest();
- var url =
- jetpackCarouselStrings.ajaxurl +
- '?action=get_attachment_comments' +
- '&nonce=' +
- jetpackCarouselStrings.nonce +
- '&id=' +
- attachmentId +
- '&offset=' +
- offset;
- xhr.open( 'GET', url );
- xhr.setRequestHeader( 'X-Requested-With', 'XMLHttpRequest' );
- var onError = function () {
- domUtil.fadeIn( comments );
- domUtil.fadeOut( commentsLoading );
- };
- xhr.onload = function () {
- // Ignore the results if they arrive late and we're now on a different slide.
- if (
- ! carousel.currentSlide ||
- carousel.currentSlide.attrs.attachmentId !== attachmentId
- ) {
- return;
- }
- var isSuccess = xhr.status >= 200 && xhr.status < 300;
- var data;
- try {
- data = JSON.parse( xhr.responseText );
- } catch ( e ) {
- // Do nothing.
- }
- if ( ! isSuccess || ! data || ! Array.isArray( data ) ) {
- return onError();
- }
- if ( shouldClear ) {
- comments.innerHTML = '';
- }
- for ( var i = 0; i < data.length; i++ ) {
- var entry = data[ i ];
- var comment = document.createElement( 'div' );
- comment.classList.add( 'jp-carousel-comment' );
- comment.setAttribute( 'id', 'jp-carousel-comment-' + entry.id );
- comment.innerHTML =
- '<div class="comment-gravatar">' +
- entry.gravatar_markup +
- '</div>' +
- '<div class="comment-content">' +
- '<div class="comment-author">' +
- entry.author_markup +
- '</div>' +
- '<div class="comment-date">' +
- entry.date_gmt +
- '</div>' +
- entry.content +
- '</div>';
- comments.appendChild( comment );
- // Set the interval to check for a new page of comments.
- clearInterval( commentInterval );
- commentInterval = setInterval( function () {
- if ( carousel.container.scrollTop + 150 > window.innerHeight ) {
- fetchComments( attachmentId, offset + 10 );
- clearInterval( commentInterval );
- }
- }, 300 );
- }
- if ( data.length > 0 ) {
- domUtil.show( comments );
- commentsIndicator.innerText = data.length;
- commentsIndicator.classList.add( 'jp-carousel-show' );
- }
- domUtil.hide( commentsLoading );
- };
- xhr.onerror = onError;
- xhr.send();
- }
- function loadFullImage( slide ) {
- var el = slide.el;
- var attrs = slide.attrs;
- var image = el.querySelector( 'img' );
- if ( ! image.hasAttribute( 'data-loaded' ) ) {
- var hasPreview = !! attrs.previewImage;
- var thumbSize = attrs.thumbSize;
- if ( ! hasPreview || ( thumbSize && el.offsetWidth > thumbSize.width ) ) {
- image.src = attrs.src;
- } else {
- image.src = attrs.previewImage;
- }
- image.setAttribute( 'itemprop', 'image' );
- image.setAttribute( 'data-loaded', 1 );
- }
- }
- function loadBackgroundImage( slide ) {
- var currentSlide = slide.el;
- if ( swiper && swiper.slides ) {
- currentSlide = swiper.slides[ swiper.activeIndex ];
- }
- var image = slide.attrs.originalElement;
- var isLoaded = image.complete && image.naturalHeight !== 0;
- if ( isLoaded ) {
- applyBackgroundImage( slide, currentSlide, image );
- return;
- }
- image.onload = function () {
- applyBackgroundImage( slide, currentSlide, image );
- };
- }
- function applyBackgroundImage( slide, currentSlide, image ) {
- var url = util.getBackgroundImage( image );
- slide.backgroundImage = url;
- currentSlide.style.backgroundImage = 'url(' + url + ')';
- currentSlide.style.backgroundSize = 'cover';
- }
- function clearCommentTextAreaValue() {
- if ( carousel.commentField ) {
- carousel.commentField.value = '';
- }
- }
- function getOriginalDimensions( el ) {
- var size = el.getAttribute( 'data-orig-size' ) || '';
- if ( size ) {
- var parts = size.split( ',' );
- return { width: parseInt( parts[ 0 ], 10 ), height: parseInt( parts[ 1 ], 10 ) };
- } else {
- return {
- width:
- el.getAttribute( 'data-original-width' ) || el.getAttribute( 'width' ) || undefined,
- height:
- el.getAttribute( 'data-original-height' ) || el.getAttribute( 'height' ) || undefined,
- };
- }
- }
- function initCarouselSlides( items, startIndex ) {
- carousel.slides = [];
- var max = calculateMaxSlideDimensions();
- // If the startIndex is not 0 then preload the clicked image first.
- if ( startIndex !== 0 ) {
- var img = new Image();
- img.src = items[ startIndex ].getAttribute( 'data-gallery-src' );
- }
- var useInPageThumbnails = !! domUtil.closest( items[ 0 ], '.tiled-gallery.type-rectangular' );
- // create the 'slide'
- Array.prototype.forEach.call( items, function ( item, i ) {
- var permalinkEl = domUtil.closest( item, 'a' );
- var origFile = item.getAttribute( 'data-orig-file' ) || item.getAttribute( 'src-orig' );
- var attrID =
- item.getAttribute( 'data-attachment-id' ) || item.getAttribute( 'data-id' ) || '0';
- var caption = document.querySelector(
- 'img[data-attachment-id="' + attrID + '"] + figcaption'
- );
- if ( caption ) {
- caption = caption.innerHTML;
- } else {
- caption = item.getAttribute( 'data-image-caption' );
- }
- var attrs = {
- originalElement: item,
- attachmentId: attrID,
- commentsOpened: item.getAttribute( 'data-comments-opened' ) || '0',
- imageMeta: domUtil.getJSONAttribute( item, 'data-image-meta' ) || {},
- title: item.getAttribute( 'data-image-title' ) || '',
- desc: item.getAttribute( 'data-image-description' ) || '',
- mediumFile: item.getAttribute( 'data-medium-file' ) || '',
- largeFile: item.getAttribute( 'data-large-file' ) || '',
- origFile: origFile || '',
- thumbSize: { width: item.naturalWidth, height: item.naturalHeight },
- caption: caption || '',
- permalink: permalinkEl && permalinkEl.getAttribute( 'href' ),
- src: origFile || item.getAttribute( 'src' ) || '',
- };
- var tiledGalleryItem = domUtil.closest( item, '.tiled-gallery-item' );
- var tiledCaptionEl =
- tiledGalleryItem && tiledGalleryItem.querySelector( '.tiled-gallery-caption' );
- var tiledCaption = tiledCaptionEl && tiledCaptionEl.innerHTML;
- if ( tiledCaption ) {
- attrs.caption = tiledCaption;
- }
- var origDimensions = getOriginalDimensions( item );
- attrs.origWidth = origDimensions.width || attrs.thumbSize.width;
- attrs.origHeight = origDimensions.height || attrs.thumbSize.height;
- if ( typeof wpcom !== 'undefined' && wpcom.carousel && wpcom.carousel.generateImgSrc ) {
- attrs.src = wpcom.carousel.generateImgSrc( item, max );
- } else {
- attrs.src = selectBestImageUrl( {
- origFile: attrs.src,
- origWidth: attrs.origWidth,
- origHeight: attrs.origHeight,
- maxWidth: max.width,
- maxHeight: max.height,
- mediumFile: attrs.mediumFile,
- largeFile: attrs.largeFile,
- } );
- }
- // Set the final src.
- item.setAttribute( 'data-gallery-src', attrs.src );
- if ( attrs.attachmentId !== '0' ) {
- attrs.title = util.texturize( attrs.title );
- attrs.desc = util.texturize( attrs.desc );
- attrs.caption = util.texturize( attrs.caption );
- // Initially, the image is a 1x1 transparent gif.
- // The preview is shown as a background image on the slide itself.
- var image = new Image();
- image.src = attrs.src;
- var slideEl = document.createElement( 'div' );
- slideEl.classList.add( 'swiper-slide' );
- slideEl.setAttribute( 'itemprop', 'associatedMedia' );
- slideEl.setAttribute( 'itemscope', '' );
- slideEl.setAttribute( 'itemtype', 'https://schema.org/ImageObject' );
- var zoomEl = document.createElement( 'div' );
- zoomEl.classList.add( 'swiper-zoom-container' );
- carousel.gallery.appendChild( slideEl );
- slideEl.appendChild( zoomEl );
- zoomEl.appendChild( image );
- slideEl.setAttribute( 'data-attachment-id', attrs.attachmentId );
- slideEl.setAttribute( 'data-permalink', attrs.permalink );
- slideEl.setAttribute( 'data-orig-file', attrs.origFile );
- if ( useInPageThumbnails ) {
- // Use the image already loaded in the gallery as a preview.
- attrs.previewImage = attrs.src;
- }
- var slide = { el: slideEl, attrs: attrs, index: i };
- carousel.slides.push( slide );
- }
- } );
- }
- function loadSwiper( gallery, options ) {
- if ( ! window.Swiper670 ) {
- var loader = document.querySelector( '#jp-carousel-loading-overlay' );
- domUtil.show( loader );
- var jsScript = document.createElement( 'script' );
- jsScript.id = 'jetpack-carousel-swiper-js';
- jsScript.src = window.jetpackSwiperLibraryPath.url;
- jsScript.async = true;
- jsScript.onload = function () {
- domUtil.hide( loader );
- openCarousel( gallery, options );
- };
- jsScript.onerror = function () {
- domUtil.hide( loader );
- };
- document.head.appendChild( jsScript );
- return;
- }
- openCarousel( gallery, options );
- }
- function openCarousel( gallery, options ) {
- var settings = {
- imgSelector:
- '.gallery-item [data-attachment-id], .tiled-gallery-item [data-attachment-id], img[data-attachment-id], img[data-id]',
- startIndex: 0,
- };
- var data = domUtil.getJSONAttribute( gallery, 'data-carousel-extra' );
- var tapTimeout;
- if ( ! data ) {
- return; // don't run if the default gallery functions weren't used
- }
- initializeCarousel();
- if ( carousel.isOpen ) {
- return; // don't open if already opened
- }
- carousel.isOpen = true;
- // 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 = getComputedStyle( document.body ).overflow;
- document.body.style.overflow = 'hidden';
- // prevent html from overflowing on some of the new themes.
- originalHOverflow = getComputedStyle( document.documentElement ).overflow;
- document.documentElement.style.overflow = 'hidden';
- scrollPos = window.scrollY || window.pageYOffset || 0;
- carousel.container.setAttribute( 'data-carousel-extra', JSON.stringify( data ) );
- stat( [ 'open', 'view_image' ] );
- // If options exist, lets merge them
- // with our default settings
- for ( var option in options || {} ) {
- settings[ option ] = options[ option ];
- }
- if ( settings.startIndex === -1 ) {
- settings.startIndex = 0; // -1 returned if can't find index, so start from beginning
- }
- domUtil.emitEvent( carousel.overlay, 'jp_carousel.beforeOpen' );
- carousel.gallery.innerHTML = '';
- // Need to set the overlay manually to block or swiper does't initialise properly.
- carousel.overlay.style.opacity = 1;
- carousel.overlay.style.display = 'block';
- initCarouselSlides( gallery.querySelectorAll( settings.imgSelector ), settings.startIndex );
- swiper = new window.Swiper670( '.jp-carousel-swiper-container', {
- centeredSlides: true,
- zoom: true,
- loop: carousel.slides.length > 1,
- // Turn off interactions and hide navigation arrows if there is only one slide.
- enabled: carousel.slides.length > 1,
- pagination: {
- el: '.jp-swiper-pagination',
- clickable: true,
- },
- navigation: {
- nextEl: '.jp-swiper-button-next',
- prevEl: '.jp-swiper-button-prev',
- },
- initialSlide: settings.startIndex,
- on: {
- init: function () {
- selectSlideAtIndex( settings.startIndex );
- },
- },
- preventClicks: false,
- preventClicksPropagation: false,
- preventInteractionOnTransition: ! domUtil.isTouch(),
- threshold: 5,
- } );
- swiper.on( 'slideChange', function ( swiper ) {
- var index;
- // Swiper indexes slides from 1, plus when looping to left last slide ends up
- // as 0 and looping to right first slide as total slides + 1. These are adjusted
- // here to match index of carousel.slides.
- if ( swiper.activeIndex === 0 ) {
- index = carousel.slides.length - 1;
- } else if ( swiper.activeIndex === carousel.slides.length + 1 ) {
- index = 0;
- } else {
- index = swiper.activeIndex - 1;
- }
- selectSlideAtIndex( index );
- carousel.overlay.classList.remove( 'jp-carousel-hide-controls' );
- } );
- swiper.on( 'zoomChange', function ( swiper, scale ) {
- if ( scale > 1 ) {
- carousel.overlay.classList.add( 'jp-carousel-hide-controls' );
- }
- if ( scale === 1 ) {
- carousel.overlay.classList.remove( 'jp-carousel-hide-controls' );
- }
- } );
- swiper.on( 'doubleTap', function ( swiper ) {
- clearTimeout( tapTimeout );
- if ( swiper.zoom.scale === 1 ) {
- var zoomTimeout = setTimeout( function () {
- carousel.overlay.classList.remove( 'jp-carousel-hide-controls' );
- clearTimeout( zoomTimeout );
- }, 150 );
- }
- } );
- swiper.on( 'tap', function () {
- if ( swiper.zoom.scale > 1 ) {
- tapTimeout = setTimeout( function () {
- carousel.overlay.classList.toggle( 'jp-carousel-hide-controls' );
- }, 150 );
- }
- } );
- domUtil.fadeIn( carousel.overlay, function () {
- domUtil.emitEvent( carousel.overlay, 'jp_carousel.afterOpen' );
- } );
- }
- // Register the event listener for starting the gallery
- document.body.addEventListener( 'click', function ( e ) {
- var isCompatible =
- window.CSS && window.CSS.supports && window.CSS.supports( 'display', 'grid' );
- // IE11 support is being dropped in August 2021. The new swiper.js libray is not IE11 compat
- // so just default to opening individual image attachment/media pages for IE.
- if ( ! isCompatible ) {
- return;
- }
- var target = e.target;
- var gallery = domUtil.closest( target, gallerySelector );
- if ( gallery ) {
- if ( ! testForData( gallery ) ) {
- return;
- }
- var parent = target.parentElement;
- var grandparent = parent.parentElement;
- // If Gallery is made up of individual Image blocks check for custom link before
- // loading carousel.
- if ( grandparent && grandparent.classList.contains( 'wp-block-image' ) ) {
- var parentHref = parent.getAttribute( 'href' );
- // If the link does not point to the attachment or media file then assume Image has
- // a custom link so don't load the carousel.
- if (
- parentHref.split( '?' )[ 0 ] !==
- target.getAttribute( 'data-orig-file' ).split( '?' )[ 0 ] &&
- parentHref !== target.getAttribute( 'data-permalink' )
- ) {
- return;
- }
- }
- // Do not open the modal if we are looking at a gallery caption from before WP5, which may contain a link.
- if ( parent.classList.contains( 'gallery-caption' ) ) {
- return;
- }
- // Do not open the modal if we are looking at a caption of a gallery block, which may contain a link.
- if ( domUtil.matches( parent, 'figcaption' ) ) {
- return;
- }
- // Set height to auto.
- // Fix some themes where closing carousel brings view back to top.
- document.documentElement.style.height = 'auto';
- e.preventDefault();
- // Stopping propagation in case there are parent elements
- // with .gallery or .tiled-gallery class
- e.stopPropagation();
- var item = domUtil.closest( target, itemSelector );
- var index = Array.prototype.indexOf.call( gallery.querySelectorAll( itemSelector ), item );
- loadSwiper( gallery, { startIndex: index } );
- }
- } );
- // Handle lightbox (single image gallery) for images linking to 'Attachment Page'.
- if ( Number( jetpackCarouselStrings.single_image_gallery ) === 1 ) {
- processSingleImageGallery();
- document.body.addEventListener( 'is.post-load', function () {
- processSingleImageGallery();
- } );
- }
- // Makes carousel work on page load and when back button leads to same URL with carousel hash
- // (i.e. no actual document.ready trigger).
- window.addEventListener( 'hashchange', function () {
- var hashRegExp = /jp-carousel-(\d+)/;
- if ( ! window.location.hash || ! hashRegExp.test( window.location.hash ) ) {
- if ( carousel.isOpen ) {
- closeCarousel();
- }
- return;
- }
- if ( window.location.hash === lastKnownLocationHash && carousel.isOpen ) {
- return;
- }
- if ( window.location.hash && carousel.gallery && ! carousel.isOpen && history.back ) {
- history.back();
- return;
- }
- lastKnownLocationHash = window.location.hash;
- var matchList = window.location.hash.match( hashRegExp );
- var attachmentId = parseInt( matchList[ 1 ], 10 );
- var galleries = document.querySelectorAll( gallerySelector );
- // Find the first thumbnail that matches the attachment ID in the location
- // hash, then open the gallery that contains it.
- for ( var i = 0; i < galleries.length; i++ ) {
- var gallery = galleries[ i ];
- var selected;
- var images = gallery.querySelectorAll( 'img' );
- for ( var j = 0; j < images.length; j++ ) {
- if (
- parseInt( images[ j ].getAttribute( 'data-attachment-id' ), 10 ) === attachmentId ||
- parseInt( images[ j ].getAttribute( 'data-id' ), 10 ) === attachmentId
- ) {
- selected = j;
- break;
- }
- }
- if ( selected !== undefined ) {
- openOrSelectSlide( gallery, selected );
- break;
- }
- }
- } );
- if ( window.location.hash ) {
- domUtil.emitEvent( window, 'hashchange' );
- }
- }
- if ( document.readyState !== 'loading' ) {
- init();
- } else {
- document.addEventListener( 'DOMContentLoaded', init );
- }
- } )();
|