9f1588fd99acb36f8c3d48f696d1c6600cec731b
[yaffs-website] / web / core / modules / comment / js / node-new-comments-link.es6.js
1 /**
2  * @file
3  * Attaches behaviors for the Comment module's "X new comments" link.
4  *
5  * May only be loaded for authenticated users, with the History module
6  * installed.
7  */
8
9 (function ($, Drupal, drupalSettings) {
10   /**
11    * Render "X new comments" links wherever necessary.
12    *
13    * @type {Drupal~behavior}
14    *
15    * @prop {Drupal~behaviorAttach} attach
16    *   Attaches new comment links behavior.
17    */
18   Drupal.behaviors.nodeNewCommentsLink = {
19     attach(context) {
20       // Collect all "X new comments" node link placeholders (and their
21       // corresponding node IDs) newer than 30 days ago that have not already
22       // been read after their last comment timestamp.
23       const nodeIDs = [];
24       const $placeholders = $(context)
25         .find('[data-history-node-last-comment-timestamp]')
26         .once('history')
27         .filter(function () {
28           const $placeholder = $(this);
29           const lastCommentTimestamp = parseInt($placeholder.attr('data-history-node-last-comment-timestamp'), 10);
30           const nodeID = $placeholder.closest('[data-history-node-id]').attr('data-history-node-id');
31           if (Drupal.history.needsServerCheck(nodeID, lastCommentTimestamp)) {
32             nodeIDs.push(nodeID);
33             // Hide this placeholder link until it is certain we'll need it.
34             hide($placeholder);
35             return true;
36           }
37
38             // Remove this placeholder link from the DOM because we won't need
39             // it.
40           remove($placeholder);
41           return false;
42         });
43
44       if ($placeholders.length === 0) {
45         return;
46       }
47
48       // Perform an AJAX request to retrieve node read timestamps.
49       Drupal.history.fetchTimestamps(nodeIDs, () => {
50         processNodeNewCommentLinks($placeholders);
51       });
52     },
53   };
54
55   /**
56    * Hides a "new comment" element.
57    *
58    * @param {jQuery} $placeholder
59    *   The placeholder element of the new comment link.
60    *
61    * @return {jQuery}
62    *   The placeholder element passed in as a parameter.
63    */
64   function hide($placeholder) {
65     return $placeholder
66       // Find the parent <li>.
67       .closest('.comment-new-comments')
68       // Find the preceding <li>, if any, and give it the 'last' class.
69       .prev().addClass('last')
70       // Go back to the parent <li> and hide it.
71       .end().hide();
72   }
73
74   /**
75    * Removes a "new comment" element.
76    *
77    * @param {jQuery} $placeholder
78    *   The placeholder element of the new comment link.
79    */
80   function remove($placeholder) {
81     hide($placeholder).remove();
82   }
83
84   /**
85    * Shows a "new comment" element.
86    *
87    * @param {jQuery} $placeholder
88    *   The placeholder element of the new comment link.
89    *
90    * @return {jQuery}
91    *   The placeholder element passed in as a parameter.
92    */
93   function show($placeholder) {
94     return $placeholder
95       // Find the parent <li>.
96       .closest('.comment-new-comments')
97       // Find the preceding <li>, if any, and remove its 'last' class, if any.
98       .prev().removeClass('last')
99       // Go back to the parent <li> and show it.
100       .end().show();
101   }
102
103   /**
104    * Processes new comment links and adds appropriate text in relevant cases.
105    *
106    * @param {jQuery} $placeholders
107    *   The placeholder elements of the current page.
108    */
109   function processNodeNewCommentLinks($placeholders) {
110     // Figure out which placeholders need the "x new comments" links.
111     const $placeholdersToUpdate = {};
112     let fieldName = 'comment';
113     let $placeholder;
114     $placeholders.each((index, placeholder) => {
115       $placeholder = $(placeholder);
116       const timestamp = parseInt($placeholder.attr('data-history-node-last-comment-timestamp'), 10);
117       fieldName = $placeholder.attr('data-history-node-field-name');
118       const nodeID = $placeholder.closest('[data-history-node-id]').attr('data-history-node-id');
119       const lastViewTimestamp = Drupal.history.getLastRead(nodeID);
120
121       // Queue this placeholder's "X new comments" link to be downloaded from
122       // the server.
123       if (timestamp > lastViewTimestamp) {
124         $placeholdersToUpdate[nodeID] = $placeholder;
125       }
126       // No "X new comments" link necessary; remove it from the DOM.
127       else {
128         remove($placeholder);
129       }
130     });
131
132     // Perform an AJAX request to retrieve node view timestamps.
133     const nodeIDs = Object.keys($placeholdersToUpdate);
134     if (nodeIDs.length === 0) {
135       return;
136     }
137
138     /**
139      * Renders the "X new comments" links.
140      *
141      * Either use the data embedded in the page or perform an AJAX request to
142      * retrieve the same data.
143      *
144      * @param {object} results
145      *   Data about new comment links indexed by nodeID.
146      */
147     function render(results) {
148       for (const nodeID in results) {
149         if (results.hasOwnProperty(nodeID) && $placeholdersToUpdate.hasOwnProperty(nodeID)) {
150           $placeholdersToUpdate[nodeID]
151             .attr('href', results[nodeID].first_new_comment_link)
152             .text(Drupal.formatPlural(results[nodeID].new_comment_count, '1 new comment', '@count new comments'))
153             .removeClass('hidden');
154           show($placeholdersToUpdate[nodeID]);
155         }
156       }
157     }
158
159     if (drupalSettings.comment && drupalSettings.comment.newCommentsLinks) {
160       render(drupalSettings.comment.newCommentsLinks.node[fieldName]);
161     }
162     else {
163       $.ajax({
164         url: Drupal.url('comments/render_new_comments_node_links'),
165         type: 'POST',
166         data: { 'node_ids[]': nodeIDs, field_name: fieldName },
167         dataType: 'json',
168         success: render,
169       });
170     }
171   }
172 }(jQuery, Drupal, drupalSettings));