Security update for Core, with self-updated composer
[yaffs-website] / web / core / modules / history / js / history.es6.js
1 /**
2  * @file
3  * JavaScript API for the History module, with client-side caching.
4  *
5  * May only be loaded for authenticated users, with the History module enabled.
6  */
7
8 (function ($, Drupal, drupalSettings, storage) {
9   const currentUserID = parseInt(drupalSettings.user.uid, 10);
10
11   // Any comment that is older than 30 days is automatically considered read,
12   // so for these we don't need to perform a request at all!
13   const thirtyDaysAgo = Math.round(new Date().getTime() / 1000) - 30 * 24 * 60 * 60;
14
15   // Use the data embedded in the page, if available.
16   let embeddedLastReadTimestamps = false;
17   if (drupalSettings.history && drupalSettings.history.lastReadTimestamps) {
18     embeddedLastReadTimestamps = drupalSettings.history.lastReadTimestamps;
19   }
20
21   /**
22    * @namespace
23    */
24   Drupal.history = {
25
26     /**
27      * Fetch "last read" timestamps for the given nodes.
28      *
29      * @param {Array} nodeIDs
30      *   An array of node IDs.
31      * @param {function} callback
32      *   A callback that is called after the requested timestamps were fetched.
33      */
34     fetchTimestamps(nodeIDs, callback) {
35       // Use the data embedded in the page, if available.
36       if (embeddedLastReadTimestamps) {
37         callback();
38         return;
39       }
40
41       $.ajax({
42         url: Drupal.url('history/get_node_read_timestamps'),
43         type: 'POST',
44         data: { 'node_ids[]': nodeIDs },
45         dataType: 'json',
46         success(results) {
47           for (const nodeID in results) {
48             if (results.hasOwnProperty(nodeID)) {
49               storage.setItem(`Drupal.history.${currentUserID}.${nodeID}`, results[nodeID]);
50             }
51           }
52           callback();
53         },
54       });
55     },
56
57     /**
58      * Get the last read timestamp for the given node.
59      *
60      * @param {number|string} nodeID
61      *   A node ID.
62      *
63      * @return {number}
64      *   A UNIX timestamp.
65      */
66     getLastRead(nodeID) {
67       // Use the data embedded in the page, if available.
68       if (embeddedLastReadTimestamps && embeddedLastReadTimestamps[nodeID]) {
69         return parseInt(embeddedLastReadTimestamps[nodeID], 10);
70       }
71       return parseInt(storage.getItem(`Drupal.history.${currentUserID}.${nodeID}`) || 0, 10);
72     },
73
74     /**
75      * Marks a node as read, store the last read timestamp client-side.
76      *
77      * @param {number|string} nodeID
78      *   A node ID.
79      */
80     markAsRead(nodeID) {
81       $.ajax({
82         url: Drupal.url(`history/${nodeID}/read`),
83         type: 'POST',
84         dataType: 'json',
85         success(timestamp) {
86           // If the data is embedded in the page, don't store on the client
87           // side.
88           if (embeddedLastReadTimestamps && embeddedLastReadTimestamps[nodeID]) {
89             return;
90           }
91
92           storage.setItem(`Drupal.history.${currentUserID}.${nodeID}`, timestamp);
93         },
94       });
95     },
96
97     /**
98      * Determines whether a server check is necessary.
99      *
100      * Any content that is >30 days old never gets a "new" or "updated"
101      * indicator. Any content that was published before the oldest known reading
102      * also never gets a "new" or "updated" indicator, because it must've been
103      * read already.
104      *
105      * @param {number|string} nodeID
106      *   A node ID.
107      * @param {number} contentTimestamp
108      *   The time at which some content (e.g. a comment) was published.
109      *
110      * @return {bool}
111      *   Whether a server check is necessary for the given node and its
112      *   timestamp.
113      */
114     needsServerCheck(nodeID, contentTimestamp) {
115       // First check if the content is older than 30 days, then we can bail
116       // early.
117       if (contentTimestamp < thirtyDaysAgo) {
118         return false;
119       }
120
121       // Use the data embedded in the page, if available.
122       if (embeddedLastReadTimestamps && embeddedLastReadTimestamps[nodeID]) {
123         return contentTimestamp > parseInt(embeddedLastReadTimestamps[nodeID], 10);
124       }
125
126       const minLastReadTimestamp = parseInt(storage.getItem(`Drupal.history.${currentUserID}.${nodeID}`) || 0, 10);
127       return contentTimestamp > minLastReadTimestamp;
128     },
129   };
130 }(jQuery, Drupal, drupalSettings, window.localStorage));