loop.js 5.8 KB

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