a2bdc35b9d7272b4950f55f303a27b73eacf0486
[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()
70       .addClass('last')
71       // Go back to the parent <li> and hide it.
72       .end()
73       .hide();
74   }
75
76   /**
77    * Removes a "new comment" element.
78    *
79    * @param {jQuery} $placeholder
80    *   The placeholder element of the new comment link.
81    */
82   function remove($placeholder) {
83     hide($placeholder).remove();
84   }
85
86   /**
87    * Shows a "new comment" element.
88    *
89    * @param {jQuery} $placeholder
90    *   The placeholder element of the new comment link.
91    *
92    * @return {jQuery}
93    *   The placeholder element passed in as a parameter.
94    */
95   function show($placeholder) {
96     return $placeholder
97       // Find the parent <li>.
98       .closest('.comment-new-comments')
99       // Find the preceding <li>, if any, and remove its 'last' class, if any.
100       .prev()
101       .removeClass('last')
102       // Go back to the parent <li> and show it.
103       .end()
104       .show();
105   }
106
107   /**
108    * Processes new comment links and adds appropriate text in relevant cases.
109    *
110    * @param {jQuery} $placeholders
111    *   The placeholder elements of the current page.
112    */
113   function processNodeNewCommentLinks($placeholders) {
114     // Figure out which placeholders need the "x new comments" links.
115     const $placeholdersToUpdate = {};
116     let fieldName = 'comment';
117     let $placeholder;
118     $placeholders.each((index, placeholder) => {
119       $placeholder = $(placeholder);
120       const timestamp = parseInt($placeholder.attr('data-history-node-last-comment-timestamp'), 10);
121       fieldName = $placeholder.attr('data-history-node-field-name');
122       const nodeID = $placeholder.closest('[data-history-node-id]').attr('data-history-node-id');
123       const lastViewTimestamp = Drupal.history.getLastRead(nodeID);
124
125       // Queue this placeholder's "X new comments" link to be downloaded from
126       // the server.
127       if (timestamp > lastViewTimestamp) {
128         $placeholdersToUpdate[nodeID] = $placeholder;
129       }
130       // No "X new comments" link necessary; remove it from the DOM.
131       else {
132         remove($placeholder);
133       }
134     });
135
136     // Perform an AJAX request to retrieve node view timestamps.
137     const nodeIDs = Object.keys($placeholdersToUpdate);
138     if (nodeIDs.length === 0) {
139       return;
140     }
141
142     /**
143      * Renders the "X new comments" links.
144      *
145      * Either use the data embedded in the page or perform an AJAX request to
146      * retrieve the same data.
147      *
148      * @param {object} results
149      *   Data about new comment links indexed by nodeID.
150      */
151     function render(results) {
152       Object.keys(results || {}).forEach((nodeID) => {
153         if ($placeholdersToUpdate.hasOwnProperty(nodeID)) {
154           $placeholdersToUpdate[nodeID]
155             .attr('href', results[nodeID].first_new_comment_link)
156             .text(Drupal.formatPlural(results[nodeID].new_comment_count, '1 new comment', '@count new comments'))
157             .removeClass('hidden');
158           show($placeholdersToUpdate[nodeID]);
159         }
160       });
161     }
162
163     if (drupalSettings.comment && drupalSettings.comment.newCommentsLinks) {
164       render(drupalSettings.comment.newCommentsLinks.node[fieldName]);
165     }
166     else {
167       $.ajax({
168         url: Drupal.url('comments/render_new_comments_node_links'),
169         type: 'POST',
170         data: { 'node_ids[]': nodeIDs, field_name: fieldName },
171         dataType: 'json',
172         success: render,
173       });
174     }
175   }
176 }(jQuery, Drupal, drupalSettings));