| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922 |
- /* globals infiniteScroll, _wpmejsSettings, ga, _gaq, WPCOM_sharing_counts, MediaElementPlayer */
- ( function () {
- // Open closure.
- // Local vars.
- var Scroller, ajaxurl, stats, type, text, totop, loading_text;
- // IE requires special handling
- var isIE = -1 != navigator.userAgent.search( 'MSIE' );
- if ( isIE ) {
- var IEVersion = navigator.userAgent.match( /MSIE\s?(\d+)\.?\d*;/ );
- IEVersion = parseInt( IEVersion[ 1 ] );
- }
- // HTTP ajaxurl when site is HTTPS causes Access-Control-Allow-Origin failure in Desktop and iOS Safari
- if ( 'https:' == document.location.protocol ) {
- infiniteScroll.settings.ajaxurl = infiniteScroll.settings.ajaxurl.replace(
- 'http://',
- 'https://'
- );
- }
- /**
- * Loads new posts when users scroll near the bottom of the page.
- */
- Scroller = function ( settings ) {
- var self = this;
- // Initialize our variables
- this.id = settings.id;
- this.body = document.body;
- this.window = window;
- this.element = document.getElementById( settings.id );
- this.wrapperClass = settings.wrapper_class;
- this.ready = true;
- this.disabled = false;
- this.page = 1;
- this.offset = settings.offset;
- this.currentday = settings.currentday;
- this.order = settings.order;
- this.throttle = false;
- this.click_handle = settings.click_handle;
- this.google_analytics = settings.google_analytics;
- this.history = settings.history;
- this.origURL = window.location.href;
- // Handle element
- this.handle = document.createElement( 'div' );
- this.handle.setAttribute( 'id', 'infinite-handle' );
- this.handle.innerHTML = '<span><button>' + text.replace( '\\', '' ) + '</button></span>';
- // Footer settings
- this.footer = {
- el: document.getElementById( 'infinite-footer' ),
- wrap: settings.footer,
- };
- // Bind methods used as callbacks
- this.checkViewportOnLoadBound = self.checkViewportOnLoad.bind( this );
- // Core's native MediaElement.js implementation needs special handling
- this.wpMediaelement = null;
- // We have two type of infinite scroll
- // cases 'scroll' and 'click'
- if ( type == 'scroll' ) {
- // Bind refresh to the scroll event
- // Throttle to check for such case every 300ms
- // On event the case becomes a fact
- this.window.addEventListener( 'scroll', function () {
- self.throttle = true;
- } );
- // Go back top method
- self.gotop();
- setInterval( function () {
- if ( self.throttle ) {
- // Once the case is the case, the action occurs and the fact is no more
- self.throttle = false;
- // Reveal or hide footer
- self.thefooter();
- // Fire the refresh
- self.refresh();
- self.determineURL(); // determine the url
- }
- }, 250 );
- // Ensure that enough posts are loaded to fill the initial viewport, to compensate for short posts and large displays.
- self.ensureFilledViewport();
- this.body.addEventListener( 'is.post-load', self.checkViewportOnLoadBound );
- } else if ( type == 'click' ) {
- if ( this.click_handle ) {
- this.element.appendChild( this.handle );
- }
- this.handle.addEventListener( 'click', function () {
- // Handle the handle
- if ( self.click_handle ) {
- self.handle.parentNode.removeChild( self.handle );
- }
- // Fire the refresh
- self.refresh();
- } );
- }
- // Initialize any Core audio or video players loaded via IS
- this.body.addEventListener( 'is.post-load', self.initializeMejs );
- };
- /**
- * Normalize the access to the document scrollTop value.
- */
- Scroller.prototype.getScrollTop = function () {
- return window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0;
- };
- /**
- * Polyfill jQuery.extend.
- */
- Scroller.prototype.extend = function ( out ) {
- out = out || {};
- for ( var i = 1; i < arguments.length; i++ ) {
- if ( ! arguments[ i ] ) {
- continue;
- }
- for ( var key in arguments[ i ] ) {
- if ( arguments[ i ].hasOwnProperty( key ) ) {
- out[ key ] = arguments[ i ][ key ];
- }
- }
- }
- return out;
- };
- /**
- * Check whether we should fetch any additional posts.
- */
- Scroller.prototype.check = function () {
- var wrapperMeasurements = this.measure( this.element, [ this.wrapperClass ] );
- // Fetch more posts when we're less than 2 screens away from the bottom.
- return wrapperMeasurements.bottom < 2 * this.window.innerHeight;
- };
- /**
- * Renders the results from a successful response.
- */
- Scroller.prototype.render = function ( response ) {
- var childrenToAppend = Array.prototype.slice.call( response.fragment.childNodes );
- this.body.classList.add( 'infinity-success' );
- // Render the retrieved nodes.
- while ( childrenToAppend.length > 0 ) {
- var currentNode = childrenToAppend.shift();
- this.element.appendChild( currentNode );
- }
- this.trigger( this.body, 'is.post-load', {
- jqueryEventName: 'post-load',
- data: response,
- } );
- this.ready = true;
- };
- /**
- * Returns the object used to query for new posts.
- */
- Scroller.prototype.query = function () {
- return {
- page: this.page + this.offset, // Load the next page.
- currentday: this.currentday,
- order: this.order,
- scripts: window.infiniteScroll.settings.scripts,
- styles: window.infiniteScroll.settings.styles,
- query_args: window.infiniteScroll.settings.query_args,
- query_before: window.infiniteScroll.settings.query_before,
- last_post_date: window.infiniteScroll.settings.last_post_date,
- };
- };
- Scroller.prototype.animate = function ( cb, duration ) {
- var start = performance.now();
- requestAnimationFrame( function animate( time ) {
- var timeFraction = Math.min( 1, ( time - start ) / duration );
- cb( timeFraction );
- if ( timeFraction < 1 ) {
- requestAnimationFrame( animate );
- }
- } );
- };
- /**
- * Scroll back to top.
- */
- Scroller.prototype.gotop = function () {
- var blog = document.getElementById( 'infinity-blog-title' );
- var self = this;
- if ( ! blog ) {
- return;
- }
- blog.setAttribute( 'title', totop );
- blog.addEventListener( 'click', function ( e ) {
- var sourceScroll = self.window.pageYOffset;
- e.preventDefault();
- self.animate( function ( progress ) {
- var currentScroll = sourceScroll - sourceScroll * progress;
- document.documentElement.scrollTop = document.body.scrollTop = currentScroll;
- }, 200 );
- } );
- };
- /**
- * The infinite footer.
- */
- Scroller.prototype.thefooter = function () {
- var self = this,
- pageWrapper,
- footerContainer,
- width,
- sourceBottom,
- targetBottom,
- footerEnabled = this.footer && this.footer.el;
- if ( ! footerEnabled ) {
- return;
- }
- // Check if we have an id for the page wrapper
- if ( 'string' === typeof this.footer.wrap ) {
- try {
- pageWrapper = document.getElementById( this.footer.wrap );
- width = pageWrapper.getBoundingClientRect();
- width = width.width;
- } catch ( err ) {
- width = 0;
- }
- // Make the footer match the width of the page
- if ( width > 479 ) {
- footerContainer = this.footer.el.querySelector( '.container' );
- if ( footerContainer ) {
- footerContainer.style.width = width + 'px';
- }
- }
- }
- // Reveal footer
- sourceBottom = parseInt( self.footer.el.style.bottom || -50, 10 );
- targetBottom = this.window.pageYOffset >= 350 ? 0 : -50;
- if ( sourceBottom !== targetBottom ) {
- self.animate( function ( progress ) {
- var currentBottom = sourceBottom + ( targetBottom - sourceBottom ) * progress;
- self.footer.el.style.bottom = currentBottom + 'px';
- if ( 1 === progress ) {
- sourceBottom = targetBottom;
- }
- }, 200 );
- }
- };
- /**
- * Recursively convert a JS object into URL encoded data.
- */
- Scroller.prototype.urlEncodeJSON = function ( obj, prefix ) {
- var params = [],
- encodedKey,
- newPrefix;
- for ( var key in obj ) {
- encodedKey = encodeURIComponent( key );
- newPrefix = prefix ? prefix + '[' + encodedKey + ']' : encodedKey;
- if ( 'object' === typeof obj[ key ] ) {
- if ( ! Array.isArray( obj[ key ] ) || obj[ key ].length > 0 ) {
- params.push( this.urlEncodeJSON( obj[ key ], newPrefix ) );
- } else {
- // Explicitly expose empty arrays with no values
- params.push( newPrefix + '[]=' );
- }
- } else {
- params.push( newPrefix + '=' + encodeURIComponent( obj[ key ] ) );
- }
- }
- return params.join( '&' );
- };
- /**
- * Controls the flow of the refresh. Don't mess.
- */
- Scroller.prototype.refresh = function () {
- var self = this,
- query,
- xhr,
- loader,
- customized;
- // If we're disabled, ready, or don't pass the check, bail.
- if ( this.disabled || ! this.ready || ! this.check() ) {
- return;
- }
- // Let's get going -- set ready to false to prevent
- // multiple refreshes from occurring at once.
- this.ready = false;
- // Create a loader element to show it's working.
- if ( this.click_handle ) {
- if ( ! loader ) {
- document.getElementById( 'infinite-aria' ).textContent = loading_text;
- loader = document.createElement( 'div' );
- loader.classList.add( 'infinite-loader' );
- loader.setAttribute( 'role', 'progress' );
- loader.innerHTML =
- '<div class="spinner"><div class="spinner-inner"><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div></div></div>';
- }
- this.element.appendChild( loader );
- }
- // Generate our query vars.
- query = self.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.
- xhr = new XMLHttpRequest();
- xhr.open( 'POST', infiniteScroll.settings.ajaxurl, true );
- xhr.setRequestHeader( 'X-Requested-With', 'XMLHttpRequest' );
- xhr.setRequestHeader( 'Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8' );
- xhr.send( self.urlEncodeJSON( query ) );
- // Allow refreshes to occur again if an error is triggered.
- xhr.onerror = function () {
- if ( self.click_handle ) {
- loader.parentNode.removeChild( loader );
- }
- self.ready = true;
- };
- // Success handler
- xhr.onload = function () {
- var response = JSON.parse( xhr.responseText ),
- httpCheck = xhr.status >= 200 && xhr.status < 300,
- responseCheck = 'undefined' !== typeof response.html;
- if ( ! response || ! httpCheck || ! responseCheck ) {
- if ( self.click_handle ) {
- loader.parentNode.removeChild( loader );
- }
- return;
- }
- // On success, let's hide the loader circle.
- if ( self.click_handle ) {
- loader.parentNode.removeChild( loader );
- }
- // If additional scripts are required by the incoming set of posts, parse them
- if ( response.scripts && Array.isArray( response.scripts ) ) {
- response.scripts.forEach( function ( item ) {
- var elementToAppendTo = item.footer ? 'body' : 'head';
- // Add script handle to list of those already parsed
- window.infiniteScroll.settings.scripts.push( item.handle );
- // Output extra data, if present
- if ( item.extra_data ) {
- self.appendInlineScript( item.extra_data, elementToAppendTo );
- }
- if ( item.before_handle ) {
- self.appendInlineScript( item.before_handle, elementToAppendTo );
- }
- // Build script tag and append to DOM in requested location
- var script = document.createElement( 'script' );
- script.type = 'text/javascript';
- script.src = item.src;
- script.id = item.handle;
- // Dynamically loaded scripts are async by default.
- // We don't want that, it breaks stuff, e.g. wp-mediaelement init.
- script.async = false;
- if ( item.after_handle ) {
- script.onload = function () {
- self.appendInlineScript( item.after_handle, elementToAppendTo );
- };
- }
- // If MediaElement.js is loaded in by item set of posts, don't initialize the players a second time as it breaks them all
- if ( 'wp-mediaelement' === item.handle ) {
- self.body.removeEventListener( 'is.post-load', self.initializeMejs );
- }
- if ( 'wp-mediaelement' === item.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 && Array.isArray( response.styles ) ) {
- response.styles.forEach( function ( item ) {
- // Add stylesheet handle to list of those already parsed
- window.infiniteScroll.settings.styles.push( item.handle );
- // Build link tag
- var style = document.createElement( 'link' );
- style.rel = 'stylesheet';
- style.href = item.src;
- style.id = item.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 (
- item.conditional &&
- ( ! isIE || ! eval( item.conditional.replace( /%ver/g, IEVersion ) ) )
- ) {
- style = false;
- }
- // Append link tag if necessary
- if ( style ) {
- document.getElementsByTagName( 'head' )[ 0 ].appendChild( style );
- }
- } );
- }
- // Convert the response.html to a fragment element.
- // Using a div instead of DocumentFragment, because the latter doesn't support innerHTML.
- response.fragment = document.createElement( 'div' );
- response.fragment.innerHTML = response.html;
- // 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 = self.extend( WPCOM_sharing_counts, response.postflair ); // eslint-disable-line no-global-assign
- }
- // Render the results
- self.render.call( self, response );
- // If 'click' type and there are still posts to fetch, add back the handle
- if ( type == 'click' ) {
- // add focus to new posts, only in button mode as we know where page focus currently is and only if we have a wrapper
- if ( infiniteScroll.settings.wrapper ) {
- document
- .querySelector(
- '#infinite-view-' + ( self.page + self.offset - 1 ) + ' a:first-of-type'
- )
- .focus( {
- preventScroll: true,
- } );
- }
- if ( response.lastbatch ) {
- if ( self.click_handle ) {
- // Update body classes
- self.body.classList.add( 'infinity-end' );
- self.body.classList.remove( 'infinity-success' );
- } else {
- self.trigger( this.body, 'infinite-scroll-posts-end' );
- }
- } else {
- if ( self.click_handle ) {
- self.element.appendChild( self.handle );
- } else {
- self.trigger( this.body, 'infinite-scroll-posts-more' );
- }
- }
- } else if ( response.lastbatch ) {
- self.disabled = true;
- self.body.classList.add( 'infinity-end' );
- self.body.classList.remove( '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 xhr;
- };
- /**
- * Given JavaScript blob and the name of a parent tag, this helper function will
- * generate a script tag, insert the JavaScript blob, and append it to the parent.
- *
- * It's important to note that the JavaScript blob will be evaluated immediately. If
- * you need a parent script to load first, use that script element's onload handler.
- *
- * @param {string} script The blob of JavaScript to run.
- * @param {string} parentTag The tag name of the parent element.
- */
- Scroller.prototype.appendInlineScript = function ( script, parentTag ) {
- var element = document.createElement( 'script' ),
- scriptContent = document.createTextNode( '//<![CDATA[ \n' + script + '\n//]]>' );
- element.type = 'text/javascript';
- element.appendChild( scriptContent );
- document.getElementsByTagName( parentTag )[ 0 ].appendChild( element );
- };
- /**
- * 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.bind( this ), 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.addEventListener( 'is.post-load', this.initializeMejs );
- }
- };
- /**
- * Initialize the MediaElement.js player for any posts not previously initialized
- */
- Scroller.prototype.initializeMejs = function ( e ) {
- // Are there media players in the incoming set of posts?
- if (
- ! e.detail ||
- ! e.detail.html ||
- ( -1 === e.detail.html.indexOf( 'wp-audio-shortcode' ) &&
- -1 === e.detail.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
- var settings = {};
- var audioVideoElements;
- 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
- );
- }
- };
- audioVideoElements = document.querySelectorAll( '.wp-audio-shortcode, .wp-video-shortcode' );
- audioVideoElements = Array.prototype.slice.call( audioVideoElements );
- // Only process already unprocessed shortcodes.
- audioVideoElements = audioVideoElements.filter( function ( el ) {
- while ( el.parentNode ) {
- if ( el.classList.contains( 'mejs-container' ) ) {
- return false;
- }
- el = el.parentNode;
- }
- return true;
- } );
- for ( var i = 0; i < audioVideoElements.length; i++ ) {
- new MediaElementPlayer( audioVideoElements[ i ], settings );
- }
- };
- /**
- * Get element measurements relative to the viewport.
- *
- * @returns {object}
- */
- Scroller.prototype.measure = function ( element, expandClasses ) {
- expandClasses = expandClasses || [];
- var childrenToTest = Array.prototype.slice.call( element.children );
- var currentChild,
- minTop = Number.MAX_VALUE,
- maxBottom = 0,
- currentChildRect,
- i;
- while ( childrenToTest.length > 0 ) {
- currentChild = childrenToTest.shift();
- for ( i = 0; i < expandClasses.length; i++ ) {
- // Expand (= measure) child elements of nodes with class names from expandClasses.
- if ( currentChild.classList.contains( expandClasses[ i ] ) ) {
- childrenToTest = childrenToTest.concat(
- Array.prototype.slice.call( currentChild.children )
- );
- break;
- }
- }
- currentChildRect = currentChild.getBoundingClientRect();
- minTop = Math.min( minTop, currentChildRect.top );
- maxBottom = Math.max( maxBottom, currentChildRect.bottom );
- }
- var viewportMiddle = Math.round( window.innerHeight / 2 );
- // isActive = does the middle of the viewport cross the element?
- var isActive = minTop <= viewportMiddle && maxBottom >= viewportMiddle;
- /**
- * Factor = percentage of viewport above the middle line occupied by the element.
- *
- * Negative factors are assigned for elements below the middle line. That's on purpose
- * to only allow "page 2" to change the URL once it's in the middle of the viewport.
- */
- var factor = ( Math.min( maxBottom, viewportMiddle ) - Math.max( minTop, 0 ) ) / viewportMiddle;
- return {
- top: minTop,
- bottom: maxBottom,
- height: maxBottom - minTop,
- factor: factor,
- isActive: isActive,
- };
- };
- /**
- * 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.innerHeight,
- wrapperMeasurements = self.measure( self.element, [ self.wrapperClass ] );
- // Only load more posts once. This prevents infinite loops when there are no more posts.
- self.body.removeEventListener( 'is.post-load', self.checkViewportOnLoadBound );
- // Load more posts if space permits, otherwise stop checking for a full viewport.
- if ( wrapperMeasurements.bottom < windowHeight ) {
- self.ready = true;
- self.refresh();
- }
- };
- /**
- * 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 () {
- this.ensureFilledViewport();
- };
- function fullscreenState() {
- return document.fullscreenElement ||
- document.mozFullScreenElement ||
- document.webkitFullscreenElement ||
- document.msFullscreenElement
- ? 1
- : 0;
- }
- var previousFullScrenState = fullscreenState();
- /**
- * Identify archive page that corresponds to majority of posts shown in the current browser window.
- */
- Scroller.prototype.determineURL = function () {
- var self = this,
- pageNum = -1,
- currentFullScreenState = fullscreenState(),
- wrapperEls,
- maxFactor = 0;
- // xor - check if the state has changed
- if ( previousFullScrenState ^ currentFullScreenState ) {
- // If we just switched to/from fullscreen,
- // don't do the div clearing/caching or the
- // URL setting. Doing so can break video playback
- // if the video goes to fullscreen.
- previousFullScrenState = currentFullScreenState;
- return;
- }
- previousFullScrenState = currentFullScreenState;
- wrapperEls = document.querySelectorAll( '.' + self.wrapperClass );
- for ( var i = 0; i < wrapperEls.length; i++ ) {
- var setMeasurements = self.measure( wrapperEls[ i ] );
- // If it exists, pick a set that is crossed by the middle of the viewport.
- if ( setMeasurements.isActive ) {
- pageNum = parseInt( wrapperEls[ i ].dataset.pageNum, 10 );
- break;
- }
- // If there is such a set, pick the one that occupies the most space
- // above the middle of the viewport.
- if ( setMeasurements.factor > maxFactor ) {
- pageNum = parseInt( wrapperEls[ i ].dataset.pageNum, 10 );
- maxFactor = setMeasurements.factor;
- }
- // Otherwise default to -1
- }
- 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,
- pageSlug = self.origURL;
- if ( -1 !== page ) {
- pageSlug =
- window.location.protocol +
- '//' +
- self.history.host +
- self.history.path.replace( /%d/, page ) +
- 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;
- };
- /**
- * Emits custom JS events.
- *
- * @param {Node} el
- * @param {string} eventName
- * @param {*} data
- */
- Scroller.prototype.trigger = function ( el, eventName, opts ) {
- opts = opts || {};
- /**
- * Emit the event in a jQuery way for backwards compatibility where necessary.
- */
- if ( opts.jqueryEventName && 'undefined' !== typeof jQuery ) {
- jQuery( el ).trigger( opts.jqueryEventName, opts.data || null );
- }
- /**
- * Emit the event in a standard way.
- */
- var e;
- try {
- e = new CustomEvent( eventName, {
- bubbles: true,
- cancelable: true,
- detail: opts.data || null,
- } );
- } catch ( err ) {
- e = document.createEvent( 'CustomEvent' );
- e.initCustomEvent( eventName, true, true, opts.data || null );
- }
- el.dispatchEvent( e );
- };
- /**
- * Ready, set, go!
- */
- var jetpackInfinityModule = function () {
- var bodyClasses = infiniteScroll.settings.body_class.split( ' ' );
- // Check for our variables
- if ( 'object' !== typeof infiniteScroll ) {
- return;
- }
- bodyClasses.forEach( function ( className ) {
- if ( className ) {
- document.body.classList.add( className );
- }
- } );
- // 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;
- // aria text
- loading_text = infiniteScroll.settings.loading_text;
- // 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.addEventListener( 'scroll', function () {
- // run the real scroll handler once every 250 ms.
- if ( timer ) {
- return;
- }
- timer = setTimeout( function () {
- infiniteScroll.scroller.determineURL();
- timer = null;
- }, 250 );
- } );
- }
- };
- /**
- * Ready, set, go!
- */
- if ( document.readyState === 'interactive' || document.readyState === 'complete' ) {
- jetpackInfinityModule();
- } else {
- document.addEventListener( 'DOMContentLoaded', jetpackInfinityModule );
- }
- } )(); // Close closure
|