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