| @@ -1,0 +1,245 @@ | ||
| 1 | +/* global jetpackSlideshowSettings */ | |
| 2 | + | |
| 3 | +/** | |
| 4 | + * Turn a gallery caption into the plain text it is meant to be. | |
| 5 | + * | |
| 6 | + * A caption is meant to read as text, but wptexturize() leaves HTML entities behind, so it needs | |
| 7 | + * decoding before it can be set as one. | |
| 8 | + * | |
| 9 | + * @param {*} caption - Caption value from the gallery data. | |
| 10 | + * @return {string} The decoded caption, as text. | |
| 11 | + */ | |
| 12 | +function jetpackSlideshowCaptionText( caption ) { | |
| 13 | + if ( typeof caption !== 'string' || '' === caption ) { | |
| 14 | + return ''; | |
| 15 | + } | |
| 16 | + | |
| 17 | + var parsed = new DOMParser().parseFromString( caption, 'text/html' ); | |
| 18 | + | |
| 19 | + // These land in the body when they appear mid-caption, and their source is not caption text. | |
| 20 | + parsed.body | |
| 21 | + .querySelectorAll( 'script, style, noscript, template' ) | |
| 22 | + .forEach( function ( element ) { | |
| 23 | + element.remove(); | |
| 24 | + } ); | |
| 25 | + | |
| 26 | + // Without a space in its place, a caption broken over two lines reads as "Ada LovelaceLondon". | |
| 27 | + parsed.body.querySelectorAll( 'br' ).forEach( function ( element ) { | |
| 28 | + element.replaceWith( ' ' ); | |
| 29 | + } ); | |
| 30 | + | |
| 31 | + return parsed.body.textContent; | |
| 32 | +} | |
| 33 | + | |
| 34 | +function JetpackSlideshow( element, transition, autostart ) { | |
| 35 | + this.element = element; | |
| 36 | + this.images = []; | |
| 37 | + this.controls = {}; | |
| 38 | + this.transition = transition || 'fade'; | |
| 39 | + this.autostart = autostart; | |
| 40 | +} | |
| 41 | + | |
| 42 | +JetpackSlideshow.prototype.showLoadingImage = function ( toggle ) { | |
| 43 | + if ( toggle ) { | |
| 44 | + this.loadingImage_ = document.createElement( 'div' ); | |
| 45 | + this.loadingImage_.className = 'jetpack-slideshow-loading'; | |
| 46 | + var img = document.createElement( 'img' ); | |
| 47 | + img.src = jetpackSlideshowSettings.spinner; | |
| 48 | + this.loadingImage_.appendChild( img ); | |
| 49 | + this.loadingImage_.appendChild( this.makeZeroWidthSpan() ); | |
| 50 | + this.element.append( this.loadingImage_ ); | |
| 51 | + } else if ( this.loadingImage_ ) { | |
| 52 | + this.loadingImage_.parentNode.removeChild( this.loadingImage_ ); | |
| 53 | + this.loadingImage_ = null; | |
| 54 | + } | |
| 55 | +}; | |
| 56 | + | |
| 57 | +JetpackSlideshow.prototype.init = function () { | |
| 58 | + this.showLoadingImage( true ); | |
| 59 | + | |
| 60 | + var self = this; | |
| 61 | + // Set up DOM. | |
| 62 | + for ( var i = 0; i < this.images.length; i++ ) { | |
| 63 | + var imageInfo = this.images[ i ]; | |
| 64 | + var img = document.createElement( 'img' ); | |
| 65 | + img.src = imageInfo.src; | |
| 66 | + img.title = typeof imageInfo.title !== 'undefined' ? imageInfo.title : ''; | |
| 67 | + img.alt = typeof imageInfo.alt !== 'undefined' ? imageInfo.alt : ''; | |
| 68 | + img.setAttribute( 'itemprop', 'image' ); | |
| 69 | + img.nopin = 'nopin'; | |
| 70 | + var caption = document.createElement( 'div' ); | |
| 71 | + caption.className = 'jetpack-slideshow-slide-caption'; | |
| 72 | + caption.setAttribute( 'itemprop', 'caption description' ); | |
| 73 | + caption.textContent = jetpackSlideshowCaptionText( imageInfo.caption ); | |
| 74 | + var container = document.createElement( 'div' ); | |
| 75 | + container.className = 'jetpack-slideshow-slide'; | |
| 76 | + container.setAttribute( 'itemprop', 'associatedMedia' ); | |
| 77 | + container.setAttribute( 'itemscope', '' ); | |
| 78 | + container.setAttribute( 'itemtype', 'https://schema.org/ImageObject' ); | |
| 79 | + | |
| 80 | + // Hide loading image once first image has loaded. | |
| 81 | + if ( i === 0 ) { | |
| 82 | + if ( img.complete ) { | |
| 83 | + // IE, image in cache | |
| 84 | + setTimeout( function () { | |
| 85 | + self.finishInit_(); | |
| 86 | + }, 1 ); | |
| 87 | + } else { | |
| 88 | + img.addEventListener( 'load', function () { | |
| 89 | + self.finishInit_(); | |
| 90 | + } ); | |
| 91 | + } | |
| 92 | + } | |
| 93 | + container.appendChild( img ); | |
| 94 | + // I'm not sure where these were coming from, but IE adds | |
| 95 | + // bad values for width/height for portrait-mode images | |
| 96 | + img.removeAttribute( 'width' ); | |
| 97 | + img.removeAttribute( 'height' ); | |
| 98 | + container.appendChild( this.makeZeroWidthSpan() ); | |
| 99 | + container.appendChild( caption ); | |
| 100 | + this.element.append( container ); | |
| 101 | + } | |
| 102 | +}; | |
| 103 | + | |
| 104 | +JetpackSlideshow.prototype.makeZeroWidthSpan = function () { | |
| 105 | + var emptySpan = document.createElement( 'span' ); | |
| 106 | + emptySpan.className = 'jetpack-slideshow-line-height-hack'; | |
| 107 | + // Having a NBSP makes IE act weird during transitions, but other | |
| 108 | + // browsers ignore a text node with a space in it as whitespace. | |
| 109 | + if ( -1 !== window.navigator.userAgent.indexOf( 'MSIE ' ) ) { | |
| 110 | + emptySpan.appendChild( document.createTextNode( ' ' ) ); | |
| 111 | + } else { | |
| 112 | + emptySpan.innerHTML = ' '; | |
| 113 | + } | |
| 114 | + return emptySpan; | |
| 115 | +}; | |
| 116 | + | |
| 117 | +JetpackSlideshow.prototype.finishInit_ = function () { | |
| 118 | + this.showLoadingImage( false ); | |
| 119 | + | |
| 120 | + var self = this; | |
| 121 | + if ( this.images.length > 1 ) { | |
| 122 | + this.renderControls_(); | |
| 123 | + | |
| 124 | + // Initialize Cycle instance. | |
| 125 | + jQuery( this.element ).cycle( { | |
| 126 | + fx: this.transition, | |
| 127 | + prev: this.controls.prev, | |
| 128 | + next: this.controls.next, | |
| 129 | + timeout: jetpackSlideshowSettings.speed, | |
| 130 | + slideExpr: '.jetpack-slideshow-slide', | |
| 131 | + onPrevNextEvent: function () { | |
| 132 | + return self.onCyclePrevNextClick_.apply( self, arguments ); | |
| 133 | + }, | |
| 134 | + } ); | |
| 135 | + | |
| 136 | + var slideshow = this.element; | |
| 137 | + | |
| 138 | + if ( ! this.autostart ) { | |
| 139 | + jQuery( slideshow ).cycle( 'pause' ); | |
| 140 | + this.controls.stop.classList.remove( 'running' ); | |
| 141 | + this.controls.stop.classList.add( 'paused' ); | |
| 142 | + } | |
| 143 | + | |
| 144 | + this.controls.stop.addEventListener( 'click', function ( event ) { | |
| 145 | + var button = event.currentTarget; | |
| 146 | + | |
| 147 | + if ( button === event.target ) { | |
| 148 | + event.preventDefault(); | |
| 149 | + | |
| 150 | + if ( ! button.classList.contains( 'paused' ) ) { | |
| 151 | + jQuery( slideshow ).cycle( 'pause' ); | |
| 152 | + button.classList.remove( 'running' ); | |
| 153 | + button.classList.add( 'paused' ); | |
| 154 | + } else { | |
| 155 | + button.classList.add( 'running' ); | |
| 156 | + button.classList.remove( 'paused' ); | |
| 157 | + jQuery( slideshow ).cycle( 'resume', true ); | |
| 158 | + } | |
| 159 | + } | |
| 160 | + } ); | |
| 161 | + } else if ( this.element.children.length ) { | |
| 162 | + this.element.children[ 0 ].style.display = 'block'; | |
| 163 | + this.element.style.position = 'relative'; | |
| 164 | + } | |
| 165 | + this.initialized_ = true; | |
| 166 | +}; | |
| 167 | + | |
| 168 | +JetpackSlideshow.prototype.renderControls_ = function () { | |
| 169 | + if ( this.controlsDiv_ ) { | |
| 170 | + return; | |
| 171 | + } | |
| 172 | + | |
| 173 | + var controlsDiv = document.createElement( 'div' ); | |
| 174 | + controlsDiv.className = 'jetpack-slideshow-controls'; | |
| 175 | + | |
| 176 | + var controls = [ 'prev', 'stop', 'next' ]; | |
| 177 | + for ( var i = 0; i < controls.length; i++ ) { | |
| 178 | + var controlName = controls[ i ]; | |
| 179 | + var label_name = 'label_' + controlName; | |
| 180 | + var a = document.createElement( 'a' ); | |
| 181 | + | |
| 182 | + a.href = '#'; | |
| 183 | + a.className = 'button-' + controlName; | |
| 184 | + a.setAttribute( 'aria-label', jetpackSlideshowSettings[ label_name ] ); | |
| 185 | + a.setAttribute( 'role', 'button' ); | |
| 186 | + | |
| 187 | + controlsDiv.appendChild( a ); | |
| 188 | + this.controls[ controlName ] = a; | |
| 189 | + } | |
| 190 | + this.element.append( controlsDiv ); | |
| 191 | + this.controlsDiv_ = controlsDiv; | |
| 192 | +}; | |
| 193 | + | |
| 194 | +JetpackSlideshow.prototype.onCyclePrevNextClick_ = function ( isNext, i /*, slideElement*/ ) { | |
| 195 | + // If blog_id not present don't track page views | |
| 196 | + if ( ! jetpackSlideshowSettings.blog_id ) { | |
| 197 | + return; | |
| 198 | + } | |
| 199 | + | |
| 200 | + var postid = this.images[ i ].id; | |
| 201 | + var stats = new Image(); | |
| 202 | + stats.src = | |
| 203 | + document.location.protocol + | |
| 204 | + '//pixel.wp.com/g.gif?host=' + | |
| 205 | + encodeURIComponent( document.location.host ) + | |
| 206 | + '&rand=' + | |
| 207 | + Math.random() + | |
| 208 | + '&blog=' + | |
| 209 | + jetpackSlideshowSettings.blog_id + | |
| 210 | + '&subd=' + | |
| 211 | + jetpackSlideshowSettings.blog_subdomain + | |
| 212 | + '&user_id=' + | |
| 213 | + jetpackSlideshowSettings.user_id + | |
| 214 | + '&post=' + | |
| 215 | + postid + | |
| 216 | + '&ref=' + | |
| 217 | + encodeURIComponent( document.location ); | |
| 218 | +}; | |
| 219 | + | |
| 220 | +( function () { | |
| 221 | + function jetpack_slideshow_init() { | |
| 222 | + document.querySelectorAll( '.jetpack-slideshow-noscript' ).forEach( function ( element ) { | |
| 223 | + element.remove(); | |
| 224 | + } ); | |
| 225 | + document.querySelectorAll( '.jetpack-slideshow' ).forEach( function ( container ) { | |
| 226 | + if ( container.dataset.processed === 'true' ) { | |
| 227 | + return; | |
| 228 | + } | |
| 229 | + | |
| 230 | + // Extract data attributes manually | |
| 231 | + var transition = container.dataset.trans; | |
| 232 | + var autostart = container.dataset.autostart === 'true'; | |
| 233 | + var gallery = JSON.parse( container.dataset.gallery || '[]' ); | |
| 234 | + | |
| 235 | + var slideshow = new JetpackSlideshow( container, transition, autostart ); | |
| 236 | + slideshow.images = gallery; | |
| 237 | + slideshow.init(); | |
| 238 | + | |
| 239 | + container.dataset.processed = 'true'; | |
| 240 | + } ); | |
| 241 | + } | |
| 242 | + | |
| 243 | + document.addEventListener( 'DOMContentLoaded', jetpack_slideshow_init ); | |
| 244 | + document.body.addEventListener( 'post-load', jetpack_slideshow_init ); | |
| 245 | +} )(); | |