related-posts.js 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. /* jshint onevar: false */
  2. /* globals related_posts_js_options */
  3. /**
  4. * Load related posts
  5. */
  6. (function($) {
  7. var jprp = {
  8. response: null,
  9. /**
  10. * Utility get related posts JSON endpoint from URLs
  11. *
  12. * @param {string} URL (optional)
  13. * @return {string} Endpoint URL
  14. */
  15. getEndpointURL: function( URL ) {
  16. var locationObject,
  17. is_customizer = 'undefined' !== typeof wp && wp.customize && wp.customize.settings && wp.customize.settings.url && wp.customize.settings.url.self;
  18. // If we're in Customizer, write the correct URL.
  19. if ( is_customizer ) {
  20. locationObject = document.createElement( 'a' );
  21. locationObject.href = wp.customize.settings.url.self;
  22. } else {
  23. locationObject = document.location;
  24. }
  25. if ( 'string' === typeof( URL ) && URL.match( /^https?:\/\// ) ) {
  26. locationObject = document.createElement( 'a' );
  27. locationObject.href = URL;
  28. }
  29. var args = 'relatedposts=1';
  30. if ( $( '#jp-relatedposts' ).data( 'exclude' ) ) {
  31. args += '&relatedposts_exclude=' + $( '#jp-relatedposts' ).data( 'exclude' );
  32. }
  33. if ( is_customizer ) {
  34. args += '&jetpackrpcustomize=1';
  35. }
  36. var pathname = locationObject.pathname;
  37. if ( '/' !== pathname[0] ) {
  38. pathname = '/' + pathname;
  39. }
  40. if ( '' === locationObject.search ) {
  41. return pathname + '?' + args;
  42. } else {
  43. return pathname + locationObject.search + '&' + args;
  44. }
  45. },
  46. getAnchor: function( post, classNames ) {
  47. var anchor_title = post.title;
  48. if ( '' !== ( '' + post.excerpt ) ) {
  49. anchor_title += '\n\n' + post.excerpt;
  50. }
  51. var anchor = $( '<a>' );
  52. anchor.attr({
  53. 'class': classNames,
  54. 'href': post.url,
  55. 'title': anchor_title,
  56. 'rel': post.rel,
  57. 'data-origin': post.url_meta.origin,
  58. 'data-position': post.url_meta.position
  59. });
  60. var anchor_html = $( '<div>' ).append( anchor ).html();
  61. return [
  62. anchor_html.substring( 0, anchor_html.length-4 ),
  63. '</a>'
  64. ];
  65. },
  66. generateMinimalHtml: function( posts, options ) {
  67. var self = this;
  68. var html = '';
  69. $.each( posts, function( index, post ) {
  70. var anchor = self.getAnchor( post, 'jp-relatedposts-post-a' );
  71. var classes = 'jp-relatedposts-post jp-relatedposts-post' + index;
  72. if ( post.classes.length > 0 ) {
  73. classes += ' ' + post.classes.join( ' ' );
  74. }
  75. html += '<p class="' + classes + '" data-post-id="' + post.id + '" data-post-format="' + post.format + '">';
  76. html += '<span class="jp-relatedposts-post-title">' + anchor[0] + post.title + anchor[1] + '</span>';
  77. if ( options.showDate ) {
  78. html += '<span class="jp-relatedposts-post-date">' + post.date + '</span>';
  79. }
  80. if ( options.showContext ) {
  81. html += '<span class="jp-relatedposts-post-context">' + post.context + '</span>';
  82. }
  83. html += '</p>';
  84. } );
  85. return '<div class="jp-relatedposts-items jp-relatedposts-items-minimal jp-relatedposts-' + options.layout + ' ">' + html + '</div>';
  86. },
  87. generateVisualHtml: function( posts, options ) {
  88. var self = this;
  89. var html = '';
  90. $.each( posts, function( index, post ) {
  91. var anchor = self.getAnchor( post, 'jp-relatedposts-post-a' );
  92. var classes = 'jp-relatedposts-post jp-relatedposts-post' + index;
  93. if ( post.classes.length > 0 ) {
  94. classes += ' ' + post.classes.join( ' ' );
  95. }
  96. if ( ! post.img.src ) {
  97. classes += ' jp-relatedposts-post-nothumbs';
  98. } else {
  99. classes += ' jp-relatedposts-post-thumbs';
  100. }
  101. html += '<div class="' + classes + '" data-post-id="' + post.id + '" data-post-format="' + post.format + '">';
  102. if ( post.img.src ) {
  103. html += anchor[0] + '<img class="jp-relatedposts-post-img" src="' + post.img.src + '" width="' + post.img.width + '" alt="' + post.title + '" />' + anchor[1];
  104. } else {
  105. var anchor_overlay = self.getAnchor( post, 'jp-relatedposts-post-a jp-relatedposts-post-aoverlay' );
  106. html += anchor_overlay[0] + anchor_overlay[1];
  107. }
  108. html += '<' + related_posts_js_options.post_heading + ' class="jp-relatedposts-post-title">' + anchor[0] + post.title + anchor[1] + '</' + related_posts_js_options.post_heading + '>';
  109. html += '<p class="jp-relatedposts-post-excerpt">' + $( '<p>' ).text( post.excerpt ).html() + '</p>';
  110. if ( options.showDate ) {
  111. html += '<p class="jp-relatedposts-post-date">' + post.date + '</p>';
  112. }
  113. if ( options.showContext ) {
  114. html += '<p class="jp-relatedposts-post-context">' + post.context + '</p>';
  115. }
  116. html += '</div>';
  117. } );
  118. return '<div class="jp-relatedposts-items jp-relatedposts-items-visual jp-relatedposts-' + options.layout + ' ">' + html + '</div>';
  119. },
  120. /**
  121. * We want to set a max height on the excerpt however we want to set
  122. * this according to the natual pacing of the page as we never want to
  123. * cut off a line of text in the middle so we need to do some detective
  124. * work.
  125. */
  126. setVisualExcerptHeights: function() {
  127. var elements = $( '#jp-relatedposts .jp-relatedposts-post-nothumbs .jp-relatedposts-post-excerpt' );
  128. if ( 0 >= elements.length ) {
  129. return;
  130. }
  131. var fontSize = parseInt( elements.first().css( 'font-size' ), 10 ),
  132. lineHeight = parseInt( elements.first().css( 'line-height' ), 10 );
  133. // Show 5 lines of text
  134. elements.css(
  135. 'max-height',
  136. ( 5 * lineHeight / fontSize ) + 'em'
  137. );
  138. },
  139. getTrackedUrl: function( anchor ) {
  140. var args = 'relatedposts_hit=1';
  141. args += '&relatedposts_origin=' + $( anchor ).data( 'origin' );
  142. args += '&relatedposts_position=' + $( anchor ).data( 'position' );
  143. var pathname = anchor.pathname;
  144. if ( '/' !== pathname[0] ) {
  145. pathname = '/' + pathname;
  146. }
  147. if ( '' === anchor.search ) {
  148. return pathname + '?' + args;
  149. } else {
  150. return pathname + anchor.search + '&' + args;
  151. }
  152. },
  153. cleanupTrackedUrl: function() {
  154. if ( 'function' !== typeof history.replaceState ) {
  155. return;
  156. }
  157. var cleaned_search = document.location.search.replace( /\brelatedposts_[a-z]+=[0-9]*&?\b/gi, '' );
  158. if ( '?' === cleaned_search ) {
  159. cleaned_search = '';
  160. }
  161. if ( document.location.search !== cleaned_search ) {
  162. history.replaceState( {}, document.title, document.location.pathname + cleaned_search );
  163. }
  164. }
  165. };
  166. /**
  167. * Initialize Related Posts.
  168. */
  169. function startRelatedPosts() {
  170. jprp.cleanupTrackedUrl();
  171. var endpointURL = jprp.getEndpointURL(),
  172. $relatedPosts = $( '#jp-relatedposts' );
  173. $.getJSON( endpointURL, function( response ) {
  174. if ( 0 === response.items.length || 0 === $relatedPosts.length ) {
  175. return;
  176. }
  177. jprp.response = response;
  178. var html,
  179. showThumbnails,
  180. options = {};
  181. if ( 'undefined' !== typeof wp && wp.customize ) {
  182. showThumbnails = wp.customize.instance( 'jetpack_relatedposts[show_thumbnails]' ).get();
  183. options.showDate = wp.customize.instance( 'jetpack_relatedposts[show_date]' ).get();
  184. options.showContext = wp.customize.instance( 'jetpack_relatedposts[show_context]' ).get();
  185. options.layout = wp.customize.instance( 'jetpack_relatedposts[layout]' ).get();
  186. } else {
  187. showThumbnails = response.show_thumbnails;
  188. options.showDate = response.show_date;
  189. options.showContext = response.show_context;
  190. options.layout = response.layout;
  191. }
  192. html = ! showThumbnails ? jprp.generateMinimalHtml( response.items, options ) : jprp.generateVisualHtml( response.items, options );
  193. $relatedPosts.append( html );
  194. jprp.setVisualExcerptHeights();
  195. if ( options.showDate ) {
  196. $relatedPosts.find( '.jp-relatedposts-post-date' ).show();
  197. }
  198. $relatedPosts.show();
  199. $( '#jp-relatedposts a.jp-relatedposts-post-a' ).click(function() {
  200. this.href = jprp.getTrackedUrl( this );
  201. });
  202. } );
  203. }
  204. $( function() {
  205. if ( 'undefined' !== typeof wp && wp.customize ) {
  206. if ( wp.customize.selectiveRefresh ) {
  207. wp.customize.selectiveRefresh.bind( 'partial-content-rendered', function( placement ) {
  208. if ( 'jetpack_relatedposts' === placement.partial.id ) {
  209. startRelatedPosts();
  210. }
  211. } );
  212. }
  213. wp.customize.bind( 'preview-ready', startRelatedPosts );
  214. } else {
  215. startRelatedPosts();
  216. }
  217. } );
  218. })(jQuery);