history.es6.js 4.3 KB

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