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);