Chris@0: /** Chris@0: * @file Chris@0: * Attaches behaviors for the Comment module's "X new comments" link. Chris@0: * Chris@0: * May only be loaded for authenticated users, with the History module Chris@0: * installed. Chris@0: */ Chris@0: Chris@17: (function($, Drupal, drupalSettings) { Chris@0: /** Chris@0: * Hides a "new comment" element. Chris@0: * Chris@0: * @param {jQuery} $placeholder Chris@0: * The placeholder element of the new comment link. Chris@0: * Chris@0: * @return {jQuery} Chris@0: * The placeholder element passed in as a parameter. Chris@0: */ Chris@0: function hide($placeholder) { Chris@17: return ( Chris@17: $placeholder Chris@17: // Find the parent
  • . Chris@17: .closest('.comment-new-comments') Chris@17: // Find the preceding
  • , if any, and give it the 'last' class. Chris@17: .prev() Chris@17: .addClass('last') Chris@17: // Go back to the parent
  • and hide it. Chris@17: .end() Chris@17: .hide() Chris@17: ); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Removes a "new comment" element. Chris@0: * Chris@0: * @param {jQuery} $placeholder Chris@0: * The placeholder element of the new comment link. Chris@0: */ Chris@0: function remove($placeholder) { Chris@0: hide($placeholder).remove(); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Shows a "new comment" element. Chris@0: * Chris@0: * @param {jQuery} $placeholder Chris@0: * The placeholder element of the new comment link. Chris@0: * Chris@0: * @return {jQuery} Chris@0: * The placeholder element passed in as a parameter. Chris@0: */ Chris@0: function show($placeholder) { Chris@17: return ( Chris@17: $placeholder Chris@17: // Find the parent
  • . Chris@17: .closest('.comment-new-comments') Chris@17: // Find the preceding
  • , if any, and remove its 'last' class, if any. Chris@17: .prev() Chris@17: .removeClass('last') Chris@17: // Go back to the parent
  • and show it. Chris@17: .end() Chris@17: .show() Chris@17: ); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Processes new comment links and adds appropriate text in relevant cases. Chris@0: * Chris@0: * @param {jQuery} $placeholders Chris@0: * The placeholder elements of the current page. Chris@0: */ Chris@0: function processNodeNewCommentLinks($placeholders) { Chris@0: // Figure out which placeholders need the "x new comments" links. Chris@0: const $placeholdersToUpdate = {}; Chris@0: let fieldName = 'comment'; Chris@0: let $placeholder; Chris@0: $placeholders.each((index, placeholder) => { Chris@0: $placeholder = $(placeholder); Chris@17: const timestamp = parseInt( Chris@17: $placeholder.attr('data-history-node-last-comment-timestamp'), Chris@17: 10, Chris@17: ); Chris@0: fieldName = $placeholder.attr('data-history-node-field-name'); Chris@17: const nodeID = $placeholder Chris@17: .closest('[data-history-node-id]') Chris@17: .attr('data-history-node-id'); Chris@0: const lastViewTimestamp = Drupal.history.getLastRead(nodeID); Chris@0: Chris@0: // Queue this placeholder's "X new comments" link to be downloaded from Chris@0: // the server. Chris@0: if (timestamp > lastViewTimestamp) { Chris@0: $placeholdersToUpdate[nodeID] = $placeholder; Chris@0: } Chris@0: // No "X new comments" link necessary; remove it from the DOM. Chris@0: else { Chris@0: remove($placeholder); Chris@0: } Chris@0: }); Chris@0: Chris@0: // Perform an AJAX request to retrieve node view timestamps. Chris@0: const nodeIDs = Object.keys($placeholdersToUpdate); Chris@0: if (nodeIDs.length === 0) { Chris@0: return; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Renders the "X new comments" links. Chris@0: * Chris@0: * Either use the data embedded in the page or perform an AJAX request to Chris@0: * retrieve the same data. Chris@0: * Chris@0: * @param {object} results Chris@0: * Data about new comment links indexed by nodeID. Chris@0: */ Chris@0: function render(results) { Chris@17: Object.keys(results || {}).forEach(nodeID => { Chris@14: if ($placeholdersToUpdate.hasOwnProperty(nodeID)) { Chris@0: $placeholdersToUpdate[nodeID] Chris@0: .attr('href', results[nodeID].first_new_comment_link) Chris@17: .text( Chris@17: Drupal.formatPlural( Chris@17: results[nodeID].new_comment_count, Chris@17: '1 new comment', Chris@17: '@count new comments', Chris@17: ), Chris@17: ) Chris@0: .removeClass('hidden'); Chris@0: show($placeholdersToUpdate[nodeID]); Chris@0: } Chris@14: }); Chris@0: } Chris@0: Chris@0: if (drupalSettings.comment && drupalSettings.comment.newCommentsLinks) { Chris@0: render(drupalSettings.comment.newCommentsLinks.node[fieldName]); Chris@17: } else { Chris@0: $.ajax({ Chris@0: url: Drupal.url('comments/render_new_comments_node_links'), Chris@0: type: 'POST', Chris@0: data: { 'node_ids[]': nodeIDs, field_name: fieldName }, Chris@0: dataType: 'json', Chris@0: success: render, Chris@0: }); Chris@0: } Chris@0: } Chris@17: Chris@17: /** Chris@17: * Render "X new comments" links wherever necessary. Chris@17: * Chris@17: * @type {Drupal~behavior} Chris@17: * Chris@17: * @prop {Drupal~behaviorAttach} attach Chris@17: * Attaches new comment links behavior. Chris@17: */ Chris@17: Drupal.behaviors.nodeNewCommentsLink = { Chris@17: attach(context) { Chris@17: // Collect all "X new comments" node link placeholders (and their Chris@17: // corresponding node IDs) newer than 30 days ago that have not already Chris@17: // been read after their last comment timestamp. Chris@17: const nodeIDs = []; Chris@17: const $placeholders = $(context) Chris@17: .find('[data-history-node-last-comment-timestamp]') Chris@17: .once('history') Chris@17: .filter(function() { Chris@17: const $placeholder = $(this); Chris@17: const lastCommentTimestamp = parseInt( Chris@17: $placeholder.attr('data-history-node-last-comment-timestamp'), Chris@17: 10, Chris@17: ); Chris@17: const nodeID = $placeholder Chris@17: .closest('[data-history-node-id]') Chris@17: .attr('data-history-node-id'); Chris@17: if (Drupal.history.needsServerCheck(nodeID, lastCommentTimestamp)) { Chris@17: nodeIDs.push(nodeID); Chris@17: // Hide this placeholder link until it is certain we'll need it. Chris@17: hide($placeholder); Chris@17: return true; Chris@17: } Chris@17: Chris@17: // Remove this placeholder link from the DOM because we won't need Chris@17: // it. Chris@17: remove($placeholder); Chris@17: return false; Chris@17: }); Chris@17: Chris@17: if ($placeholders.length === 0) { Chris@17: return; Chris@17: } Chris@17: Chris@17: // Perform an AJAX request to retrieve node read timestamps. Chris@17: Drupal.history.fetchTimestamps(nodeIDs, () => { Chris@17: processNodeNewCommentLinks($placeholders); Chris@17: }); Chris@17: }, Chris@17: }; Chris@17: })(jQuery, Drupal, drupalSettings);