loop.js 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. ( function( $, Backbone, _, settings, undefined ) {
  2. 'use strict';
  3. var document = window.document;
  4. var $postContainer = $( document.getElementById( 'main' ) );
  5. var moreButtonTemplate = document.getElementById( 'more-button-template' );
  6. var contentTemplate = document.getElementById( 'content-template' );
  7. // Abort completely if we don't have this stuff
  8. if ( ! $postContainer || ! moreButtonTemplate || ! contentTemplate ) {
  9. return false;
  10. }
  11. var $moreButton = $( _.template( moreButtonTemplate.innerHTML )() );
  12. var postTemplate = _.template( contentTemplate.innerHTML );
  13. var origURL = window.location.href;
  14. var offset = 1;
  15. var page = 1;
  16. var timer;
  17. wp.api.loadPromise.done( function() {
  18. var posts = new wp.api.collections.Posts();
  19. var options = {
  20. data: {
  21. page: settings.page || 2
  22. }
  23. };
  24. if ( 'archive' === settings.loopType ) {
  25. options.data.filter = {};
  26. options.data.filter[settings.taxonomy['query_var']] = settings.queriedObject.slug;
  27. } else if ( 'search' === settings.loopType ) {
  28. options.data.filter = {
  29. s: settings.searchQuery
  30. };
  31. } else if ( 'author' === settings.loopType ) {
  32. options.data.filter = {
  33. author: settings.queriedObject.data.ID
  34. };
  35. }
  36. /**
  37. * Initial posts fetch
  38. */
  39. posts.fetch( options ).done( function() {
  40. if ( posts.length > 0 ) {
  41. $postContainer.append( $moreButton );
  42. setupMoreListener();
  43. setupScrollListener();
  44. }
  45. });
  46. /**
  47. * Grab more posts if more button is clicked and append them to loop
  48. */
  49. function setupMoreListener() {
  50. $postContainer.on( 'click', '.more-button', function( event ) {
  51. event.preventDefault();
  52. $moreButton.hide();
  53. var $setContainer = $( '<div data-page-num="' + posts.state.currentPage + '" class="post-set"></div>' );
  54. posts.each( function( model ) {
  55. $setContainer.append( postTemplate( { post: model.attributes, settings: settings } ) );
  56. });
  57. $postContainer.append( $setContainer );
  58. if ( posts.hasMore() ) {
  59. posts.more().done( function() {
  60. $moreButton.appendTo( $postContainer).show();
  61. } );
  62. }
  63. });
  64. };
  65. });
  66. /**
  67. * Update current url using HTML5 history API
  68. *
  69. * @param {Number} pageNum
  70. */
  71. function updateURL( pageNum ) {
  72. var offset = offset > 0 ? offset - 1 : 0;
  73. var pageSlug = ( -1 === pageNum ) ? origURL : window.location.protocol + '//' + settings.pathInfo.host + settings.pathInfo.path.replace( /%d/, pageNum + offset ) + settings.pathInfo.parameters;
  74. if ( window.location.href !== pageSlug ) {
  75. history.pushState( null, null, pageSlug );
  76. }
  77. }
  78. /**
  79. * Determine URL for pushing new history. Props to Automattic's Jetpack plugin
  80. */
  81. function determineURL() {
  82. var windowTop = $( window ).scrollTop();
  83. var windowBottom = windowTop + $( window ).height();
  84. var windowSize = $( window ).height();
  85. var setsInView = [];
  86. var pageNum = false;
  87. $postContainer.find( '.post-set' ).each( function() {
  88. var $currentSet = $( this );
  89. var setTop = $currentSet.offset().top;
  90. var setHeight = $currentSet.outerHeight( false );
  91. var setBottom = setTop + setHeight;
  92. var setPageNum = parseInt( $currentSet.attr( 'data-page-num' ) );
  93. if ( 0 === setHeight ) {
  94. $( '> *', this ).each( function() {
  95. setHeight += $currentSet.outerHeight( false );
  96. });
  97. }
  98. if ( setTop < windowTop && setBottom > windowBottom ) { // top of set is above window, bottom is below
  99. setsInView.push( { 'id': $currentSet.attr( 'id' ), 'top': setTop, 'bottom': setBottom, 'pageNum': setPageNum } );
  100. } else if( setTop > windowTop && setTop < windowBottom ) { // top of set is between top (gt) and bottom (lt)
  101. setsInView.push( { 'id': $currentSet.attr( 'id' ), 'top': setTop, 'bottom': setBottom, 'pageNum': setPageNum } );
  102. } else if( setBottom > windowTop && setBottom < windowBottom ) { // bottom of set is between top (gt) and bottom (lt)
  103. setsInView.push( { 'id': $currentSet.attr( 'id' ), 'top': setTop, 'bottom': setBottom, 'pageNum': setPageNum } );
  104. }
  105. });
  106. // 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.
  107. if ( 0 === setsInView.length ) {
  108. pageNum = -1;
  109. } else if ( 1 === setsInView.length ) {
  110. var setData = setsInView.pop();
  111. // 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
  112. if ( ( ( windowBottom - setData.top ) / windowSize ) < 0.5 ) {
  113. pageNum = -1;
  114. } else {
  115. pageNum = setData.pageNum;
  116. }
  117. } else {
  118. var majorityPercentageInView = 0;
  119. // Identify the IS set that comprises the majority of the current window and set the URL to it.
  120. $.each( setsInView, function( i, setData ) {
  121. var topInView = 0;
  122. var bottomInView = 0;
  123. var percentOfView = 0;
  124. // Figure percentage of view the current set represents
  125. if ( setData.top > windowTop && setData.top < windowBottom ) {
  126. topInView = ( windowBottom - setData.top ) / windowSize;
  127. }
  128. if ( setData.bottom > windowTop && setData.bottom < windowBottom ) {
  129. bottomInView = ( setData.bottom - windowTop ) / windowSize;
  130. }
  131. // Figure out largest percentage of view for current set
  132. if ( topInView >= bottomInView ) {
  133. percentOfView = topInView;
  134. } else if ( bottomInView >= topInView ) {
  135. percentOfView = bottomInView;
  136. }
  137. // Does current set's percentage of view supplant the largest previously-found set?
  138. if ( percentOfView > majorityPercentageInView ) {
  139. pageNum = setData.pageNum;
  140. majorityPercentageInView = percentOfView;
  141. }
  142. } );
  143. }
  144. // We do this last check in case something bad happened
  145. if ( 'number' == typeof pageNum ) {
  146. updateURL( pageNum );
  147. }
  148. }
  149. /**
  150. * Setup scroll listeners for changing history
  151. */
  152. function setupScrollListener() {
  153. $( window ).on( 'scroll', function() {
  154. clearTimeout( timer );
  155. timer = setTimeout( determineURL , 100 );
  156. });
  157. }
  158. })( jQuery, Backbone, _, settings );