PluginProbe
Jetpack – WP Security, Backup, Speed, & Growth / 7.2.2
Jetpack – WP Security, Backup, Speed, & Growth v7.2.2
16.2 16.2-beta 12.0.3 12.1.3 12.2.3 12.3.2 12.4.2 12.5.2 12.6.4 12.7.3 12.8.3 12.9.5 13.0.2 13.1.5 13.2.4 13.3.3 13.4.5 13.5.2 13.6.2 13.7.2 13.8.3 13.9.2 14.0.1 14.1.1 14.2.2 All 502 releases
jetpack / modules / infinite-scroll / infinity.js

infinity.js in Jetpack – WP Security, Backup, Speed, & Growth 7.2.2, at modules/infinite-scroll/infinity.js

751 lines 23.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 (function($){ // Open closure
2 // Local vars
3 var Scroller, ajaxurl, stats, type, text, totop;
4
5 // IE requires special handling
6 var isIE = ( -1 != navigator.userAgent.search( 'MSIE' ) );
7 if ( isIE ) {
8 var IEVersion = navigator.userAgent.match(/MSIE\s?(\d+)\.?\d*;/);
9 var IEVersion = parseInt( IEVersion[1] );
10 }
11
12 // HTTP ajaxurl when site is HTTPS causes Access-Control-Allow-Origin failure in Desktop and iOS Safari
13 if ( "https:" == document.location.protocol ) {
14 infiniteScroll.settings.ajaxurl = infiniteScroll.settings.ajaxurl.replace( "http://", "https://" );
15 }
16
17 /**
18 * Loads new posts when users scroll near the bottom of the page.
19 */
20 Scroller = function( settings ) {
21 var self = this;
22
23 // Initialize our variables
24 this.id = settings.id;
25 this.body = $( document.body );
26 this.window = $( window );
27 this.element = $( '#' + settings.id );
28 this.wrapperClass = settings.wrapper_class;
29 this.ready = true;
30 this.disabled = false;
31 this.page = 1;
32 this.offset = settings.offset;
33 this.currentday = settings.currentday;
34 this.order = settings.order;
35 this.throttle = false;
36 this.handle = '<div id="infinite-handle"><span><button>' + text.replace( '\\', '' ) + '</button></span></div>';
37 this.click_handle = settings.click_handle;
38 this.google_analytics = settings.google_analytics;
39 this.history = settings.history;
40 this.origURL = window.location.href;
41 this.pageCache = {};
42
43 // Footer settings
44 this.footer = $( '#infinite-footer' );
45 this.footer.wrap = settings.footer;
46
47 // Core's native MediaElement.js implementation needs special handling
48 this.wpMediaelement = null;
49
50 // We have two type of infinite scroll
51 // cases 'scroll' and 'click'
52
53 if ( type == 'scroll' ) {
54 // Bind refresh to the scroll event
55 // Throttle to check for such case every 300ms
56
57 // On event the case becomes a fact
58 this.window.bind( 'scroll.infinity', function() {
59 this.throttle = true;
60 });
61
62 // Go back top method
63 self.gotop();
64
65 setInterval( function() {
66 if ( this.throttle ) {
67 // Once the case is the case, the action occurs and the fact is no more
68 this.throttle = false;
69 // Reveal or hide footer
70 self.thefooter();
71 // Fire the refresh
72 self.refresh();
73 self.determineURL(); // determine the url
74 }
75 }, 250 );
76
77 // Ensure that enough posts are loaded to fill the initial viewport, to compensate for short posts and large displays.
78 self.ensureFilledViewport();
79 this.body.bind( 'post-load', { self: self }, self.checkViewportOnLoad );
80 } else if ( type == 'click' ) {
81 if ( this.click_handle ) {
82 this.element.append( this.handle );
83 }
84
85 this.body.delegate( '#infinite-handle', 'click.infinity', function() {
86 // Handle the handle
87 if ( self.click_handle ) {
88 $( '#infinite-handle' ).remove();
89 }
90
91 // Fire the refresh
92 self.refresh();
93 });
94 }
95
96 // Initialize any Core audio or video players loaded via IS
97 this.body.bind( 'post-load', { self: self }, self.initializeMejs );
98 };
99
100 /**
101 * Check whether we should fetch any additional posts.
102 */
103 Scroller.prototype.check = function() {
104 var container = this.element.offset();
105
106 // If the container can't be found, stop otherwise errors result
107 if ( 'object' !== typeof container ) {
108 return false;
109 }
110
111 var bottom = this.window.scrollTop() + this.window.height(),
112 threshold = container.top + this.element.outerHeight(false) - (this.window.height() * 2);
113
114 return bottom > threshold;
115 };
116
117 /**
118 * Renders the results from a successful response.
119 */
120 Scroller.prototype.render = function( response ) {
121 this.body.addClass( 'infinity-success' );
122
123 // Check if we can wrap the html
124 this.element.append( response.html );
125 this.body.trigger( 'post-load', response );
126 this.ready = true;
127 };
128
129 /**
130 * Returns the object used to query for new posts.
131 */
132 Scroller.prototype.query = function() {
133 return {
134 page : this.page + this.offset, // Load the next page.
135 currentday : this.currentday,
136 order : this.order,
137 scripts : window.infiniteScroll.settings.scripts,
138 styles : window.infiniteScroll.settings.styles,
139 query_args : window.infiniteScroll.settings.query_args,
140 query_before : window.infiniteScroll.settings.query_before,
141 last_post_date: window.infiniteScroll.settings.last_post_date
142 };
143 };
144
145 /**
146 * Scroll back to top.
147 */
148 Scroller.prototype.gotop = function() {
149 var blog = $( '#infinity-blog-title' );
150
151 blog.attr( 'title', totop );
152
153 // Scroll to top on blog title
154 blog.bind( 'click', function( e ) {
155 $( 'html, body' ).animate( { scrollTop: 0 }, 'fast' );
156 e.preventDefault();
157 });
158 };
159
160
161 /**
162 * The infinite footer.
163 */
164 Scroller.prototype.thefooter = function() {
165 var self = this,
166 width;
167
168 // Check if we have an id for the page wrapper
169 if ( $.type( this.footer.wrap ) === "string" ) {
170 width = $( 'body #' + this.footer.wrap ).outerWidth( false );
171
172 // Make the footer match the width of the page
173 if ( width > 479 )
174 this.footer.find( '.container' ).css( 'width', width );
175 }
176
177 // Reveal footer
178 if ( this.window.scrollTop() >= 350 )
179 self.footer.animate( { 'bottom': 0 }, 'fast' );
180 else if ( this.window.scrollTop() < 350 )
181 self.footer.animate( { 'bottom': '-50px' }, 'fast' );
182 };
183
184
185 /**
186 * Controls the flow of the refresh. Don't mess.
187 */
188 Scroller.prototype.refresh = function() {
189 var self = this,
190 query, jqxhr, load, loader, color, customized;
191
192 // If we're disabled, ready, or don't pass the check, bail.
193 if ( this.disabled || ! this.ready || ! this.check() )
194 return;
195
196 // Let's get going -- set ready to false to prevent
197 // multiple refreshes from occurring at once.
198 this.ready = false;
199
200 // Create a loader element to show it's working.
201 if ( this.click_handle ) {
202 loader = '<span class="infinite-loader"></span>';
203 this.element.append( loader );
204
205 loader = this.element.find( '.infinite-loader' );
206 color = loader.css( 'color' );
207
208 try {
209 loader.spin( 'medium-left', color );
210 } catch ( error ) { }
211 }
212
213 // Generate our query vars.
214 query = $.extend({
215 action: 'infinite_scroll'
216 }, this.query() );
217
218 // Inject Customizer state.
219 if ( 'undefined' !== typeof wp && wp.customize && wp.customize.settings.theme ) {
220 customized = {};
221 query.wp_customize = 'on';
222 query.theme = wp.customize.settings.theme.stylesheet;
223 wp.customize.each( function( setting ) {
224 if ( setting._dirty ) {
225 customized[ setting.id ] = setting();
226 }
227 } );
228 query.customized = JSON.stringify( customized );
229 query.nonce = wp.customize.settings.nonce.preview;
230 }
231
232 // Fire the ajax request.
233 jqxhr = $.post( infiniteScroll.settings.ajaxurl, query );
234
235 // Allow refreshes to occur again if an error is triggered.
236 jqxhr.fail( function() {
237 if ( self.click_handle ) {
238 loader.hide();
239 }
240
241 self.ready = true;
242 });
243
244 // Success handler
245 jqxhr.done( function( response ) {
246 // On success, let's hide the loader circle.
247 if ( self.click_handle ) {
248 loader.hide();
249 }
250
251 // Check for and parse our response.
252 if ( ! response || ! response.type ) {
253 return;
254 }
255
256 // If we've succeeded...
257 if ( response.type == 'success' ) {
258 // If additional scripts are required by the incoming set of posts, parse them
259 if ( response.scripts ) {
260 $( response.scripts ).each( function() {
261 var elementToAppendTo = this.footer ? 'body' : 'head';
262
263 // Add script handle to list of those already parsed
264 window.infiniteScroll.settings.scripts.push( this.handle );
265
266 // Output extra data, if present
267 if ( this.extra_data ) {
268 var data = document.createElement('script'),
269 dataContent = document.createTextNode( "//<![CDATA[ \n" + this.extra_data + "\n//]]>" );
270
271 data.type = 'text/javascript';
272 data.appendChild( dataContent );
273
274 document.getElementsByTagName( elementToAppendTo )[0].appendChild(data);
275 }
276
277 // Build script tag and append to DOM in requested location
278 var script = document.createElement('script');
279 script.type = 'text/javascript';
280 script.src = this.src;
281 script.id = this.handle;
282
283 // If MediaElement.js is loaded in by this set of posts, don't initialize the players a second time as it breaks them all
284 if ( 'wp-mediaelement' === this.handle ) {
285 self.body.unbind( 'post-load', self.initializeMejs );
286 }
287
288 if ( 'wp-mediaelement' === this.handle && 'undefined' === typeof mejs ) {
289 self.wpMediaelement = {};
290 self.wpMediaelement.tag = script;
291 self.wpMediaelement.element = elementToAppendTo;
292 setTimeout( self.maybeLoadMejs.bind( self ), 250 );
293 } else {
294 document.getElementsByTagName( elementToAppendTo )[0].appendChild(script);
295 }
296 } );
297 }
298
299 // If additional stylesheets are required by the incoming set of posts, parse them
300 if ( response.styles ) {
301 $( response.styles ).each( function() {
302 // Add stylesheet handle to list of those already parsed
303 window.infiniteScroll.settings.styles.push( this.handle );
304
305 // Build link tag
306 var style = document.createElement('link');
307 style.rel = 'stylesheet';
308 style.href = this.src;
309 style.id = this.handle + '-css';
310
311 // Destroy link tag if a conditional statement is present and either the browser isn't IE, or the conditional doesn't evaluate true
312 if ( this.conditional && ( ! isIE || ! eval( this.conditional.replace( /%ver/g, IEVersion ) ) ) )
313 var style = false;
314
315 // Append link tag if necessary
316 if ( style )
317 document.getElementsByTagName('head')[0].appendChild(style);
318 } );
319 }
320
321 // stash the response in the page cache
322 self.pageCache[self.page+self.offset] = response;
323
324 // Increment the page number
325 self.page++;
326
327 // Record pageview in WP Stats, if available.
328 if ( stats )
329 new Image().src = document.location.protocol + '//pixel.wp.com/g.gif?' + stats + '&post=0&baba=' + Math.random();
330
331 // Add new posts to the postflair object
332 if ( 'object' == typeof response.postflair && 'object' == typeof WPCOM_sharing_counts )
333 WPCOM_sharing_counts = $.extend( WPCOM_sharing_counts, response.postflair );
334
335 // Render the results
336 self.render.apply( self, arguments );
337
338 // If 'click' type and there are still posts to fetch, add back the handle
339 if ( type == 'click' ) {
340 if ( response.lastbatch ) {
341 if ( self.click_handle ) {
342 $( '#infinite-handle' ).remove();
343 // Update body classes
344 self.body.addClass( 'infinity-end' ).removeClass( 'infinity-success' );
345 } else {
346 self.body.trigger( 'infinite-scroll-posts-end' );
347 }
348 } else {
349 if ( self.click_handle ) {
350 self.element.append( self.handle );
351 } else {
352 self.body.trigger( 'infinite-scroll-posts-more' );
353 }
354 }
355 } else if ( response.lastbatch ) {
356 self.disabled = true;
357 self.body.addClass( 'infinity-end' ).removeClass( 'infinity-success' );
358 }
359
360 // Update currentday to the latest value returned from the server
361 if ( response.currentday ) {
362 self.currentday = response.currentday;
363 }
364
365 // Fire Google Analytics pageview
366 if ( self.google_analytics ) {
367 var ga_url = self.history.path.replace( /%d/, self.page );
368 if ( 'object' === typeof _gaq ) {
369 _gaq.push( [ '_trackPageview', ga_url ] );
370 }
371 if ( 'function' === typeof ga ) {
372 ga( 'send', 'pageview', ga_url );
373 }
374 }
375 }
376 });
377
378 return jqxhr;
379 };
380
381 /**
382 * Core's native media player uses MediaElement.js
383 * 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.
384 */
385 Scroller.prototype.maybeLoadMejs = function() {
386 if ( null === this.wpMediaelement ) {
387 return;
388 }
389
390 if ( 'undefined' === typeof mejs ) {
391 setTimeout( this.maybeLoadMejs, 250 );
392 } else {
393 document.getElementsByTagName( this.wpMediaelement.element )[0].appendChild( this.wpMediaelement.tag );
394 this.wpMediaelement = null;
395
396 // Ensure any subsequent IS loads initialize the players
397 this.body.bind( 'post-load', { self: this }, this.initializeMejs );
398 }
399 }
400
401 /**
402 * Initialize the MediaElement.js player for any posts not previously initialized
403 */
404 Scroller.prototype.initializeMejs = function( ev, response ) {
405 // Are there media players in the incoming set of posts?
406 if ( ! response.html || -1 === response.html.indexOf( 'wp-audio-shortcode' ) && -1 === response.html.indexOf( 'wp-video-shortcode' ) ) {
407 return;
408 }
409
410 // Don't bother if mejs isn't loaded for some reason
411 if ( 'undefined' === typeof mejs ) {
412 return;
413 }
414
415 // Adapted from wp-includes/js/mediaelement/wp-mediaelement.js
416 // Modified to not initialize already-initialized players, as Mejs doesn't handle that well
417 $(function () {
418 var settings = {};
419
420 if ( typeof _wpmejsSettings !== 'undefined' ) {
421 settings.pluginPath = _wpmejsSettings.pluginPath;
422 }
423
424 settings.success = function (mejs) {
425 var autoplay = mejs.attributes.autoplay && 'false' !== mejs.attributes.autoplay;
426 if ( 'flash' === mejs.pluginType && autoplay ) {
427 mejs.addEventListener( 'canplay', function () {
428 mejs.play();
429 }, false );
430 }
431 };
432
433 $('.wp-audio-shortcode, .wp-video-shortcode').not( '.mejs-container' ).mediaelementplayer( settings );
434 });
435 }
436
437 /**
438 * Trigger IS to load additional posts if the initial posts don't fill the window.
439 * 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.
440 */
441 Scroller.prototype.ensureFilledViewport = function() {
442 var self = this,
443 windowHeight = self.window.height(),
444 postsHeight = self.element.height(),
445 aveSetHeight = 0,
446 wrapperQty = 0;
447
448 // Account for situations where postsHeight is 0 because child list elements are floated
449 if ( postsHeight === 0 ) {
450 $( self.element.selector + ' > li' ).each( function() {
451 postsHeight += $( this ).height();
452 } );
453
454 if ( postsHeight === 0 ) {
455 self.body.unbind( 'post-load', self.checkViewportOnLoad );
456 return;
457 }
458 }
459
460 // Calculate average height of a set of posts to prevent more posts than needed from being loaded.
461 $( '.' + self.wrapperClass ).each( function() {
462 aveSetHeight += $( this ).height();
463 wrapperQty++;
464 } );
465
466 if ( wrapperQty > 0 )
467 aveSetHeight = aveSetHeight / wrapperQty;
468 else
469 aveSetHeight = 0;
470
471 // Load more posts if space permits, otherwise stop checking for a full viewport
472 if ( postsHeight < windowHeight && ( postsHeight + aveSetHeight < windowHeight ) ) {
473 self.ready = true;
474 self.refresh();
475 }
476 else {
477 self.body.unbind( 'post-load', self.checkViewportOnLoad );
478 }
479 }
480
481 /**
482 * Event handler for ensureFilledViewport(), tied to the post-load trigger.
483 * 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.
484 */
485 Scroller.prototype.checkViewportOnLoad = function( ev ) {
486 ev.data.self.ensureFilledViewport();
487 }
488
489 function fullscreenState() {
490 return document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement || document.msFullscreenElement
491 ? 1
492 : 0;
493 }
494
495 var previousFullScrenState = fullscreenState();
496
497 /**
498 * Identify archive page that corresponds to majority of posts shown in the current browser window.
499 */
500 Scroller.prototype.determineURL = function () {
501 var self = this,
502 windowTop = $( window ).scrollTop(),
503 windowBottom = windowTop + $( window ).height(),
504 windowSize = windowBottom - windowTop,
505 setsInView = [],
506 setsHidden = [],
507 pageNum = false,
508 currentFullScreenState = fullscreenState();
509
510 // xor - check if the state has changed
511 if ( previousFullScrenState ^ currentFullScreenState ) {
512 // If we just switched to/from fullscreen,
513 // don't do the div clearing/caching or the
514 // URL setting. Doing so can break video playback
515 // if the video goes to fullscreen.
516
517 previousFullScrenState = currentFullScreenState;
518 return;
519 }
520 previousFullScrenState = currentFullScreenState;
521
522 // Find out which sets are in view
523 $( '.' + self.wrapperClass ).each( function() {
524 var id = $( this ).attr( 'id' ),
525 setTop = $( this ).offset().top,
526 setHeight = $( this ).outerHeight( false ),
527 setBottom = 0,
528 setPageNum = $( this ).data( 'page-num' );
529
530 // Account for containers that have no height because their children are floated elements.
531 if ( 0 === setHeight ) {
532 $( '> *', this ).each( function() {
533 setHeight += $( this ).outerHeight( false );
534 } );
535 }
536
537 // Determine position of bottom of set by adding its height to the scroll position of its top.
538 setBottom = setTop + setHeight;
539
540 // Populate setsInView object. While this logic could all be combined into a single conditional statement, this is easier to understand.
541 if ( setTop < windowTop && setBottom > windowBottom ) { // top of set is above window, bottom is below
542 setsInView.push({'id': id, 'top': setTop, 'bottom': setBottom, 'pageNum': setPageNum });
543 }
544 else if( setTop > windowTop && setTop < windowBottom ) { // top of set is between top (gt) and bottom (lt)
545 setsInView.push({'id': id, 'top': setTop, 'bottom': setBottom, 'pageNum': setPageNum });
546 }
547 else if( setBottom > windowTop && setBottom < windowBottom ) { // bottom of set is between top (gt) and bottom (lt)
548 setsInView.push({'id': id, 'top': setTop, 'bottom': setBottom, 'pageNum': setPageNum });
549 } else {
550 setsHidden.push({'id': id, 'top': setTop, 'bottom': setBottom, 'pageNum': setPageNum });
551 }
552 } );
553
554 $.each(setsHidden, function() {
555 var $set = $('#' + this.id);
556 if( $set.hasClass( 'is--replaced' ) ) {
557 return;
558 }
559
560 self.pageCache[ this.pageNum].html = $set.html();
561
562 $set.css('min-height', ( this.bottom - this.top ) + 'px' )
563 .addClass('is--replaced')
564 .empty();
565 });
566
567 $.each(setsInView, function() {
568 var $set = $('#' + this.id);
569
570 if( $set.hasClass('is--replaced') ) {
571 $set.css('min-height', '').removeClass('is--replaced');
572 if( this.pageNum in self.pageCache ) {
573 $set.html( self.pageCache[this.pageNum].html );
574 self.body.trigger( 'post-load', self.pageCache[this.pageNum] );
575 }
576 }
577
578 });
579
580 // 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.
581 if ( 0 == setsInView.length ) {
582 pageNum = -1;
583 }
584 else if ( 1 == setsInView.length ) {
585 var setData = setsInView.pop();
586
587 // 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
588 if ( ( ( windowBottom - setData.top ) / windowSize ) < 0.5 )
589 pageNum = -1;
590 else
591 pageNum = setData.pageNum;
592 }
593 else {
594 var majorityPercentageInView = 0;
595
596 // Identify the IS set that comprises the majority of the current window and set the URL to it.
597 $.each( setsInView, function( i, setData ) {
598 var topInView = 0,
599 bottomInView = 0,
600 percentOfView = 0;
601
602 // Figure percentage of view the current set represents
603 if ( setData.top > windowTop && setData.top < windowBottom )
604 topInView = ( windowBottom - setData.top ) / windowSize;
605
606 if ( setData.bottom > windowTop && setData.bottom < windowBottom )
607 bottomInView = ( setData.bottom - windowTop ) / windowSize;
608
609 // Figure out largest percentage of view for current set
610 if ( topInView >= bottomInView )
611 percentOfView = topInView;
612 else if ( bottomInView >= topInView )
613 percentOfView = bottomInView;
614
615 // Does current set's percentage of view supplant the largest previously-found set?
616 if ( percentOfView > majorityPercentageInView ) {
617 pageNum = setData.pageNum;
618 majorityPercentageInView = percentOfView;
619 }
620 } );
621 }
622
623 // If a page number could be determined, update the URL
624 // -1 indicates that the original requested URL should be used.
625 if ( 'number' == typeof pageNum ) {
626 self.updateURL( pageNum );
627 }
628 }
629
630 /**
631 * Update address bar to reflect archive page URL for a given page number.
632 * Checks if URL is different to prevent pollution of browser history.
633 */
634 Scroller.prototype.updateURL = function( page ) {
635 // IE only supports pushState() in v10 and above, so don't bother if those conditions aren't met.
636 if ( ! window.history.pushState ) {
637 return;
638 }
639 var self = this,
640 pageSlug = -1 == page ? self.origURL : window.location.protocol + '//' + self.history.host + self.history.path.replace( /%d/, page ) + self.history.parameters;
641
642 if ( window.location.href != pageSlug ) {
643 history.pushState( null, null, pageSlug );
644 }
645 }
646
647 /**
648 * Pause scrolling.
649 */
650 Scroller.prototype.pause = function() {
651 this.disabled = true;
652 };
653
654 /**
655 * Resume scrolling.
656 */
657 Scroller.prototype.resume = function() {
658 this.disabled = false;
659 };
660
661 /**
662 * Ready, set, go!
663 */
664 $( document ).ready( function() {
665 // Check for our variables
666 if ( 'object' != typeof infiniteScroll )
667 return;
668
669 $( document.body ).addClass( infiniteScroll.settings.body_class );
670
671 // Set ajaxurl (for brevity)
672 ajaxurl = infiniteScroll.settings.ajaxurl;
673
674 // Set stats, used for tracking stats
675 stats = infiniteScroll.settings.stats;
676
677 // Define what type of infinity we have, grab text for click-handle
678 type = infiniteScroll.settings.type;
679 text = infiniteScroll.settings.text;
680 totop = infiniteScroll.settings.totop;
681
682 // Initialize the scroller (with the ID of the element from the theme)
683 infiniteScroll.scroller = new Scroller( infiniteScroll.settings );
684
685 /**
686 * Monitor user scroll activity to update URL to correspond to archive page for current set of IS posts
687 */
688 if( type == 'click' ) {
689 var timer = null;
690 $( window ).bind( 'scroll', function() {
691 // run the real scroll handler once every 250 ms.
692 if ( timer ) { return; }
693 timer = setTimeout( function() {
694 infiniteScroll.scroller.determineURL();
695 timer = null;
696 } , 250 );
697 });
698 }
699
700 // Integrate with Selective Refresh in the Customizer.
701 if ( 'undefined' !== typeof wp && wp.customize && wp.customize.selectiveRefresh ) {
702
703 /**
704 * Handle rendering of selective refresh partials.
705 *
706 * Make sure that when a partial is rendered, the Jetpack post-load event
707 * will be triggered so that any dynamic elements will be re-constructed,
708 * such as ME.js elements, Photon replacements, social sharing, and more.
709 * Note that this is applying here not strictly to posts being loaded.
710 * If a widget contains a ME.js element and it is previewed via selective
711 * refresh, the post-load would get triggered allowing any dynamic elements
712 * therein to also be re-constructed.
713 *
714 * @param {wp.customize.selectiveRefresh.Placement} placement
715 */
716 wp.customize.selectiveRefresh.bind( 'partial-content-rendered', function( placement ) {
717 var content;
718 if ( 'string' === typeof placement.addedContent ) {
719 content = placement.addedContent;
720 } else if ( placement.container ) {
721 content = $( placement.container ).html();
722 }
723
724 if ( content ) {
725 $( document.body ).trigger( 'post-load', { html: content } );
726 }
727 } );
728
729 /*
730 * Add partials for posts added via infinite scroll.
731 *
732 * This is unnecessary when MutationObserver is supported by the browser
733 * since then this will be handled by Selective Refresh in core.
734 */
735 if ( 'undefined' === typeof MutationObserver ) {
736 $( document.body ).on( 'post-load', function( e, response ) {
737 var rootElement = null;
738 if ( response.html && -1 !== response.html.indexOf( 'data-customize-partial' ) ) {
739 if ( infiniteScroll.settings.id ) {
740 rootElement = $( '#' + infiniteScroll.settings.id );
741 }
742 wp.customize.selectiveRefresh.addPartials( rootElement );
743 }
744 } );
745 }
746 }
747 });
748
749
750 })(jQuery); // Close closure
751