diff --cc core/modules/tracker/src/Tests/TrackerTest.php
index 0438495,95495fd..0000000
--- a/core/modules/tracker/src/Tests/TrackerTest.php
+++ b/core/modules/tracker/src/Tests/TrackerTest.php
@@@ -7,17 -7,11 +7,19 @@@
namespace Drupal\tracker\Tests;
-use Drupal\Core\Language\Language;
+use Drupal\comment\CommentInterface;
+use Drupal\comment\Tests\CommentTestTrait;
+use Drupal\Core\Cache\Cache;
++use Drupal\Core\Session\AccountInterface;
+use Drupal\field\Entity\FieldStorageConfig;
++use Drupal\node\Entity\Node;
use Drupal\simpletest\WebTestBase;
+use Drupal\system\Tests\Cache\AssertPageCacheContextsAndTagsTrait;
/**
- * Defines a base class for testing tracker.module.
+ * Create and delete nodes and check for their display in the tracker listings.
+ *
+ * @group tracker
*/
class TrackerTest extends WebTestBase {
@@@ -52,8 -51,14 +54,12 @@@
$permissions = array('access comments', 'create page content', 'post comments', 'skip comment approval');
$this->user = $this->drupalCreateUser($permissions);
- $this->other_user = $this->drupalCreateUser($permissions);
- user_role_grant_permissions(DRUPAL_ANONYMOUS_RID, array(
+ $this->otherUser = $this->drupalCreateUser($permissions);
+ $this->addDefaultCommentField('node', 'page');
++ user_role_grant_permissions(AccountInterface::ANONYMOUS_ROLE, array(
+ 'access content',
+ 'access user profiles',
+ ));
-
- // Make node preview optional.
- variable_set('comment_preview_page', 0);
}
/**
@@@ -168,163 -134,52 +174,118 @@@
}
/**
- * Tests for the presence of the "new" flag for nodes.
+ * Tests the metadata for the "new"/"updated" indicators.
*/
- function testTrackerNewNodes() {
+ function testTrackerHistoryMetadata() {
$this->drupalLogin($this->user);
+ // Create a page node.
$edit = array(
- 'title' => $this->randomName(8),
+ 'title' => $this->randomMachineName(8),
);
-
$node = $this->drupalCreateNode($edit);
- $title = $edit['title'];
- $this->drupalGet('activity');
- $this->assertPattern('/' . $title . '.*new/', 'New nodes are flagged as such in the activity listing.');
-
- $this->drupalGet('node/' . $node->id());
- // Simulate the JavaScript on the node page to mark the node as read.
- // @todo Get rid of curlExec() once https://www.drupal.org/node/2074037
- // lands.
- $this->curlExec(array(
- CURLOPT_URL => \Drupal::url('history.read_node', ['node' => $node->id()], array('absolute' => TRUE)),
- CURLOPT_HTTPHEADER => array(
- 'Accept: application/json',
- ),
- ));
- $this->drupalGet('activity');
- $this->assertNoPattern('/' . $title . '.*new/', 'Visited nodes are not flagged as new.');
- $this->drupalLogin($this->otherUser);
+ // Verify.
- $this->drupalGet('tracker');
+ $this->drupalGet('activity');
- $this->assertPattern('/' . $title . '.*new/', 'For another user, new nodes are flagged as such in the tracker listing.');
-
- $this->drupalGet('node/' . $node->id());
- // Simulate the JavaScript on the node page to mark the node as read.
- // @todo Get rid of curlExec() once https://www.drupal.org/node/2074037
- // lands.
- $this->curlExec(array(
- CURLOPT_URL => \Drupal::url('history.read_node', ['node' => $node->id()], array('absolute' => TRUE)),
- CURLOPT_HTTPHEADER => array(
- 'Accept: application/json',
- ),
- ));
- $this->drupalGet('activity');
- $this->assertNoPattern('/' . $title . '.*new/', 'For another user, visited nodes are not flagged as new.');
- }
-
- /**
- * Tests for comment counters on the tracker listing.
- */
- function testTrackerNewComments() {
- $this->drupalLogin($this->user);
-
- $node = $this->drupalCreateNode(array(
- 'title' => $this->randomMachineName(8),
- ));
+ $this->assertHistoryMetadata($node->id(), $node->getChangedTime(), $node->getChangedTime());
- $this->drupalGet('tracker/' . $this->user->id());
++ $this->drupalGet('activity/' . $this->user->id());
+ $this->assertHistoryMetadata($node->id(), $node->getChangedTime(), $node->getChangedTime());
- $this->drupalGet('user/' . $this->user->id() . '/track');
++ $this->drupalGet('user/' . $this->user->id() . '/activity');
+ $this->assertHistoryMetadata($node->id(), $node->getChangedTime(), $node->getChangedTime());
- // Add a comment to the page.
+ // Add a comment to the page, make sure it is created after the node.
- $edit = array(
- 'subject' => $this->randomName(),
- 'comment_body[' . Language::LANGCODE_NOT_SPECIFIED . '][0][value]' => $this->randomName(20),
+ $comment = array(
+ 'subject[0][value]' => $this->randomMachineName(),
+ 'comment_body[0][value]' => $this->randomMachineName(20),
);
+ sleep(1);
- $this->drupalPost('comment/reply/' . $node->id(), $edit, t('Save'));
+ $this->drupalPostForm('comment/reply/node/' . $node->id() . '/comment', $comment, t('Save'));
- // The new comment is automatically viewed by the current user. Simulate the
- // JavaScript that does this.
- // @todo Get rid of curlExec() once https://www.drupal.org/node/2074037
- // lands.
- $this->curlExec(array(
- CURLOPT_URL => \Drupal::url('history.read_node', ['node' => $node->id()], array('absolute' => TRUE)),
- CURLOPT_HTTPHEADER => array(
- 'Accept: application/json',
- ),
- ));
+ // Reload the node so that comment.module's hook_node_load()
+ // implementation can set $node->last_comment_timestamp for the freshly
+ // posted comment.
- $node = node_load($node->id());
++ $node = Node::load($node->id());
- $this->drupalLogin($this->otherUser);
+ // Verify.
- $this->drupalGet('tracker');
- $this->assertHistoryMetadata($node->id(), $node->getChangedTime(), $node->last_comment_timestamp);
- $this->drupalGet('tracker/' . $this->user->id());
- $this->assertHistoryMetadata($node->id(), $node->getChangedTime(), $node->last_comment_timestamp);
- $this->drupalGet('user/' . $this->user->id() . '/track');
- $this->assertHistoryMetadata($node->id(), $node->getChangedTime(), $node->last_comment_timestamp);
+ $this->drupalGet('activity');
- $this->assertText('1 new', 'New comments are counted on the tracker listing pages.');
- $this->drupalGet('node/' . $node->id());
-
- // Add another comment as otherUser.
- $comment = array(
- 'subject[0][value]' => $this->randomMachineName(),
- 'comment_body[0][value]' => $this->randomMachineName(20),
- );
- // If the comment is posted in the same second as the last one then Drupal
- // can't tell the difference, so we wait one second here.
- sleep(1);
- $this->drupalPostForm('comment/reply/node/' . $node->id(). '/comment', $comment, t('Save'));
++ $this->assertHistoryMetadata($node->id(), $node->getChangedTime(), $node->get('comment')->last_comment_timestamp);
++ $this->drupalGet('activity/' . $this->user->id());
++ $this->assertHistoryMetadata($node->id(), $node->getChangedTime(), $node->get('comment')->last_comment_timestamp);
++ $this->drupalGet('user/' . $this->user->id() . '/activity');
++ $this->assertHistoryMetadata($node->id(), $node->getChangedTime(), $node->get('comment')->last_comment_timestamp);
- $this->drupalLogin($this->user);
+ // Log out, now verify that the metadata is still there, but the library is
+ // not.
+ $this->drupalLogout();
- $this->drupalGet('tracker');
- $this->assertHistoryMetadata($node->id(), $node->getChangedTime(), $node->last_comment_timestamp, FALSE);
- $this->drupalGet('user/' . $this->user->id() . '/track');
- $this->assertHistoryMetadata($node->id(), $node->getChangedTime(), $node->last_comment_timestamp, FALSE);
+ $this->drupalGet('activity');
- $this->assertText('1 new', 'New comments are counted on the tracker listing pages.');
- $this->assertLink(t('1 new'));
++ $this->assertHistoryMetadata($node->id(), $node->getChangedTime(), $node->get('comment')->last_comment_timestamp, FALSE);
++ $this->drupalGet('user/' . $this->user->id() . '/activity');
++ $this->assertHistoryMetadata($node->id(), $node->getChangedTime(), $node->get('comment')->last_comment_timestamp, FALSE);
+ }
+
+ /**
+ * Tests for ordering on a users tracker listing when comments are posted.
+ */
+ function testTrackerOrderingNewComments() {
+ $this->drupalLogin($this->user);
+
+ $node_one = $this->drupalCreateNode(array(
+ 'title' => $this->randomMachineName(8),
+ ));
+
+ $node_two = $this->drupalCreateNode(array(
+ 'title' => $this->randomMachineName(8),
+ ));
+
+ // Now get otherUser to track these pieces of content.
+ $this->drupalLogin($this->otherUser);
+
+ // Add a comment to the first page.
+ $comment = array(
+ 'subject[0][value]' => $this->randomMachineName(),
+ 'comment_body[0][value]' => $this->randomMachineName(20),
+ );
+ $this->drupalPostForm('comment/reply/node/' . $node_one->id() . '/comment', $comment, t('Save'));
+
+ // If the comment is posted in the same second as the last one then Drupal
+ // can't tell the difference, so we wait one second here.
+ sleep(1);
+
+ // Add a comment to the second page.
+ $comment = array(
+ 'subject[0][value]' => $this->randomMachineName(),
+ 'comment_body[0][value]' => $this->randomMachineName(20),
+ );
+ $this->drupalPostForm('comment/reply/node/' . $node_two->id() . '/comment', $comment, t('Save'));
+
+ // We should at this point have in our tracker for otherUser:
+ // 1. node_two
+ // 2. node_one
+ // Because that's the reverse order of the posted comments.
+
+ // Now we're going to post a comment to node_one which should jump it to the
+ // top of the list.
+
+ $this->drupalLogin($this->user);
+ // If the comment is posted in the same second as the last one then Drupal
+ // can't tell the difference, so we wait one second here.
+ sleep(1);
+
+ // Add a comment to the second page.
+ $comment = array(
+ 'subject[0][value]' => $this->randomMachineName(),
+ 'comment_body[0][value]' => $this->randomMachineName(20),
+ );
+ $this->drupalPostForm('comment/reply/node/' . $node_one->id() . '/comment', $comment, t('Save'));
+
+ // Switch back to the otherUser and assert that the order has swapped.
+ $this->drupalLogin($this->otherUser);
+ $this->drupalGet('user/' . $this->otherUser->id() . '/activity');
+ // This is a cheeky way of asserting that the nodes are in the right order
+ // on the tracker page.
+ // It's almost certainly too brittle.
+ $pattern = '/' . preg_quote($node_one->getTitle()) . '.+' . preg_quote($node_two->getTitle()) . '/s';
+ $this->verbose($pattern);
+ $this->assertPattern($pattern, 'Most recently commented on node appears at the top of tracker');
}
/**
@@@ -370,11 -226,8 +331,9 @@@
foreach ($nodes as $i => $node) {
$this->assertText($node->label(), format_string('Node @i is displayed on the tracker listing pages.', array('@i' => $i)));
}
- $this->assertText('1 new', 'One new comment is counted on the tracker listing pages.');
- $this->assertText('updated', 'Node is listed as updated');
+
// Fetch the site-wide tracker.
- $this->drupalGet('tracker');
+ $this->drupalGet('activity');
// Assert that all node titles are displayed.
foreach ($nodes as $i => $node) {
@@@ -405,9 -257,40 +363,37 @@@
'action' => 'node_unpublish_action',
'node_bulk_form[0]' => $node->id(),
);
- $this->drupalPost('admin/content', $edit, t('Apply'));
+ $this->drupalPostForm('admin/content', $edit, t('Apply'));
- $this->drupalGet('tracker');
- $this->assertText(t('No content available.'), 'Node is displayed on the tracker listing pages.');
+ $this->drupalGet('activity');
+ $this->assertText(t('No content available.'), 'A node is displayed on the tracker listing pages.');
}
+
+ /**
+ * Passes if the appropriate history metadata exists.
+ *
+ * Verify the data-history-node-id, data-history-node-timestamp and
+ * data-history-node-last-comment-timestamp attributes, which are used by the
+ * drupal.tracker-history library to add the appropriate "new" and "updated"
+ * indicators, as well as the "x new" replies link to the tracker.
+ * We do this in JavaScript to prevent breaking the render cache.
+ *
- * @param int $node_id
++ * @param $node_id
+ * A node ID, that must exist as a data-history-node-id attribute
- * @param int $node_timestamp
++ * @param $node_timestamp
+ * A node timestamp, that must exist as a data-history-node-timestamp
+ * attribute.
- * @param int $node_last_comment_timestamp
++ * @param $node_last_comment_timestamp
+ * A node's last comment timestamp, that must exist as a
+ * data-history-node-last-comment-timestamp attribute.
+ * @param bool $library_is_present
+ * Whether the drupal.tracker-history library should be present or not.
- *
- * @return
- * TRUE if the assertion succeeded, FALSE otherwise.
+ */
+ function assertHistoryMetadata($node_id, $node_timestamp, $node_last_comment_timestamp, $library_is_present = TRUE) {
- $settings = $this->drupalGetSettings();
- $this->assertIdentical($library_is_present, isset($settings['ajaxPageState']['js']['core/modules/tracker/js/tracker-history.js']), 'drupal.tracker-history library is present.');
++ $settings = $this->getDrupalSettings();
++ $this->assertIdentical($library_is_present, isset($settings['ajaxPageState']) && in_array('tracker/history', explode(',', $settings['ajaxPageState']['libraries'])), 'drupal.tracker-history library is present.');
+ $this->assertIdentical(1, count($this->xpath('//table/tbody/tr/td[@data-history-node-id="' . $node_id . '" and @data-history-node-timestamp="' . $node_timestamp . '"]')), 'Tracker table cell contains the data-history-node-id and data-history-node-timestamp attributes for the node.');
+ $this->assertIdentical(1, count($this->xpath('//table/tbody/tr/td[@data-history-node-last-comment-timestamp="' . $node_last_comment_timestamp . '"]')), 'Tracker table cell contains the data-history-node-last-comment-timestamp attribute for the node.');
+ }
+
}
diff --cc core/modules/tracker/tracker.pages.inc
index 84a3366,b102360..0000000
--- a/core/modules/tracker/tracker.pages.inc
+++ b/core/modules/tracker/tracker.pages.inc
@@@ -44,25 -50,17 +44,32 @@@ function tracker_page($account = NULL)
->execute()
->fetchAllAssoc('nid');
- $rows = array();
+ $cache_tags = [];
+ $rows = [];
if (!empty($tracker_data)) {
- $nids = array_keys($tracker_data);
- $nodes = node_load_multiple($nids);
- // Now, get the data and put into the placeholder array.
- // @todo This should be actually filtering on the desired language and just
- // fall back to the default language.
- $result = db_query('SELECT n.nid, l.comment_count FROM {node_field_data} n INNER JOIN {node_comment_statistics} l ON n.nid = l.nid WHERE n.nid IN (:nids) AND n.default_langcode = 1 ORDER BY n.changed DESC', array(':nids' => $nids), array('target' => 'slave'))->fetchAllKeyed();
- foreach ($result as $nid => $comment_count) {
- $nodes[$nid]->last_activity = $tracker_data[$nid]->changed;
- $nodes[$nid]->comment_count = $comment_count;
+ // Load nodes into an array with the same order as $tracker_data.
+ $nodes = Node::loadMultiple(array_keys($tracker_data));
+
+ // Enrich the node data.
+ $result = \Drupal::service('comment.statistics')->read($nodes, 'node', FALSE);
+ foreach ($result as $statistics) {
+ // The node ID may not be unique; there can be multiple comment fields.
+ // Make comment_count the total of all comments.
+ $nid = $statistics->entity_id;
+ if (empty($nodes[$nid]->comment_count)
+ || !is_numeric($nodes[$nid]->comment_count)) {
+ $nodes[$nid]->comment_count = $statistics->comment_count;
+ }
+ else {
+ $nodes[$nid]->comment_count += $statistics->comment_count;
+ }
++ // Make the last comment timestamp reflect the latest comment.
++ if (!isset($nodes[$nid]->last_comment_timestamp)) {
++ $nodes[$nid]->last_comment_timestamp = $statistics->last_comment_timestamp;
++ }
++ else {
++ $nodes[$nid]->last_comment_timestamp = max($nodes[$nid]->last_comment_timestamp, $statistics->last_comment_timestamp);
++ }
}
// Display the data.
@@@ -75,59 -69,64 +82,44 @@@
$comments = 0;
if ($node->comment_count) {
$comments = $node->comment_count;
-
- if ($new = \Drupal::service('comment.manager')->getCountNewComments($node)) {
- $comments = array(
- '#type' => 'link',
- '#url' => $node->urlInfo(),
- '#title' => \Drupal::translation()->formatPlural($new, '1 new', '@count new'),
- '#options' => array(
- 'fragment' => 'new',
- ),
- '#prefix' => $node->comment_count . '
',
- );
- }
}
- $mark_build = array(
- '#theme' => 'mark',
- '#status' => node_mark($node->id(), $node->getChangedTime()),
- );
-
$row = array(
- 'type' => check_plain(node_get_type_label($node)),
+ 'type' => SafeMarkup::checkPlain(node_get_type_label($node)),
'title' => array(
+ 'data' => array(
+ '#type' => 'link',
+ '#url' => $node->urlInfo(),
+ '#title' => $node->getTitle(),
- '#suffix' => ' ' . drupal_render($mark_build),
+ ),
+ 'data-history-node-id' => $node->id(),
+ 'data-history-node-timestamp' => $node->getChangedTime(),
- 'data' => l($node->getTitle(), 'node/' . $node->id()),
),
- 'author' => array('data' => array('#theme' => 'username', '#account' => $node->getAuthor())),
- 'replies' => array(
- 'class' => array('replies'),
+ 'author' => array(
+ 'data' => array(
+ '#theme' => 'username',
+ '#account' => $node->getOwner(),
+ ),
+ ),
+ 'comments' => array(
+ 'class' => array('comments'),
+ 'data' => $comments,
+ 'data-history-node-last-comment-timestamp' => $node->last_comment_timestamp,
- 'data' => $comments
),
- 'last updated' => array('data' => t('!time ago', array('!time' => format_interval(REQUEST_TIME - $node->last_activity)))),
+ 'last updated' => array(
+ 'data' => t('!time ago', array(
+ '!time' => \Drupal::service('date.formatter')->formatTimeDiffSince($node->last_activity),
+ )),
+ ),
);
- // Adds extra RDFa markup to the $row array if the RDF module is enabled.
- if (module_exists('rdf')) {
- $mapping = rdf_get_mapping('node', $node->getType());
- // Adds RDFa markup to the title of the node. Because the RDFa markup is
- // added to the td tag which might contain HTML code, we specify an
- // empty datatype to ensure the value of the title read by the RDFa
- // parsers is a plain literal.
- $title_mapping = $mapping->getPreparedFieldMapping('title');
- $row['title'] += rdf_rdfa_attributes($title_mapping) + array('datatype' => '');
- // Annotates the td tag containing the author of the node.
- $uid_mapping = $mapping->getPreparedFieldMapping('uid');
- $row['author'] += rdf_rdfa_attributes($uid_mapping);
- // Annotates the td tag containing the number of replies. We add the
- // content attribute to ensure that only the comment count is used as
- // the value for 'num_replies'. Otherwise, other text such as a link
- // to the number of new comments could be included in the 'num_replies'
- // value.
- $comment_count_mapping = $mapping->getPreparedFieldMapping('comment_count');
- $row['replies'] += rdf_rdfa_attributes($comment_count_mapping);
- $row['replies'] += array('content' => $node->comment_count);
- // If the node has no comments, we assume the node itself was modified
- // and apply 'changed' in addition to 'last_activity'. If there are
- // comments present, we cannot infer whether the node itself was
- // modified or a comment was posted, so we use only 'last_activity'.
- $last_activity_mapping = $mapping->getPreparedFieldMapping('last_activity');
- $last_activity_attributes = rdf_rdfa_attributes($last_activity_mapping, $node->last_activity);
- if ($node->comment_count == 0) {
- $changed_mapping = $mapping->getPreparedFieldMapping('changed');
- $changed_attributes = rdf_rdfa_attributes($changed_mapping, $node->last_activity);
- $last_activity_attributes['property'] = array_merge($last_activity_attributes['property'], $changed_attributes['property']);
- }
- $row['last updated'] += $last_activity_attributes;
+ $rows[] = $row;
- // We need to add the about attribute on the tr tag to specify which
- // node the RDFa annotations above apply to. We move the content of
- // $row to a 'data' sub array so we can specify attributes for the row.
- $row = array('data' => $row);
- $row['about'] = url('node/' . $node->id());
+ // Add node and node owner to cache tags.
+ $cache_tags = Cache::mergeTags($cache_tags, $node->getCacheTags());
+ if ($node->getOwner()) {
+ $cache_tags = Cache::mergeTags($cache_tags, $node->getOwner()->getCacheTags());
}
- $rows[] = $row;
}
}
@@@ -145,8 -142,10 +137,12 @@@
'#weight' => 10,
);
$page['#sorted'] = TRUE;
+ $page['#cache']['tags'] = $cache_tags;
+ $page['#cache']['contexts'][] = 'user.node_grants:view';
- if (Drupal::moduleHandler()->moduleExists('history') && $user->isAuthenticated()) {
- $page['#attached']['library'][] = array('tracker', 'drupal.tracker-history');
++ if (Drupal::moduleHandler()->moduleExists('history') && \Drupal::currentUser()->isAuthenticated()) {
++ $page['#attached']['library'][] = 'tracker/history';
+ }
+
return $page;
}
core/modules/tracker/js/tracker-history.js | 198 ++++++++++++++---------------
core/modules/tracker/tracker.libraries.yml | 8 ++
core/modules/tracker/tracker.module | 21 ---
3 files changed, 107 insertions(+), 120 deletions(-)
diff --git a/core/modules/tracker/js/tracker-history.js b/core/modules/tracker/js/tracker-history.js
index df7b686..fa6af55 100644
--- a/core/modules/tracker/js/tracker-history.js
+++ b/core/modules/tracker/js/tracker-history.js
@@ -5,118 +5,118 @@
*/
(function ($, Drupal, window) {
-"use strict";
+ "use strict";
-/**
- * Render "new" and "updated" node indicators, as well as "X new" replies links.
- */
-Drupal.behaviors.trackerHistory = {
- attach: function (context) {
- // Find all "new" comment indicator placeholders newer than 30 days ago that
- // have not already been read after their last comment timestamp.
- var nodeIDs = [];
- var $nodeNewPlaceholders = $(context)
- .find('[data-history-node-timestamp]')
- .once('history')
- .filter(function () {
- var nodeTimestamp = parseInt(this.getAttribute('data-history-node-timestamp'), 10);
- var nodeID = this.getAttribute('data-history-node-id');
- if (Drupal.history.needsServerCheck(nodeID, nodeTimestamp)) {
- nodeIDs.push(nodeID);
- return true;
- }
- else {
- return false;
- }
- });
-
- // Find all "new" comment indicator placeholders newer than 30 days ago that
- // have not already been read after their last comment timestamp.
- var $newRepliesPlaceholders = $(context)
- .find('[data-history-node-last-comment-timestamp]')
- .once('history')
- .filter(function () {
- var lastCommentTimestamp = parseInt(this.getAttribute('data-history-node-last-comment-timestamp'), 10);
- var nodeTimestamp = parseInt(this.previousSibling.previousSibling.getAttribute('data-history-node-timestamp'), 10);
- // Discard placeholders that have zero comments.
- if (lastCommentTimestamp === nodeTimestamp) {
- return false;
- }
- var nodeID = this.previousSibling.previousSibling.getAttribute('data-history-node-id');
- if (Drupal.history.needsServerCheck(nodeID, lastCommentTimestamp)) {
- if (nodeIDs.indexOf(nodeID) === -1) {
+ /**
+ * Render "new" and "updated" node indicators, as well as "X new" replies links.
+ */
+ Drupal.behaviors.trackerHistory = {
+ attach: function (context) {
+ // Find all "new" comment indicator placeholders newer than 30 days ago that
+ // have not already been read after their last comment timestamp.
+ var nodeIDs = [];
+ var $nodeNewPlaceholders = $(context)
+ .find('[data-history-node-timestamp]')
+ .once('history')
+ .filter(function () {
+ var nodeTimestamp = parseInt(this.getAttribute('data-history-node-timestamp'), 10);
+ var nodeID = this.getAttribute('data-history-node-id');
+ if (Drupal.history.needsServerCheck(nodeID, nodeTimestamp)) {
nodeIDs.push(nodeID);
+ return true;
}
- return true;
- }
- else {
- return false;
- }
- });
+ else {
+ return false;
+ }
+ });
- if ($nodeNewPlaceholders.length === 0 && $newRepliesPlaceholders.length === 0) {
- return;
+ // Find all "new" comment indicator placeholders newer than 30 days ago that
+ // have not already been read after their last comment timestamp.
+ var $newRepliesPlaceholders = $(context)
+ .find('[data-history-node-last-comment-timestamp]')
+ .once('history')
+ .filter(function () {
+ var lastCommentTimestamp = parseInt(this.getAttribute('data-history-node-last-comment-timestamp'), 10);
+ var nodeTimestamp = parseInt(this.previousSibling.previousSibling.getAttribute('data-history-node-timestamp'), 10);
+ // Discard placeholders that have zero comments.
+ if (lastCommentTimestamp === nodeTimestamp) {
+ return false;
+ }
+ var nodeID = this.previousSibling.previousSibling.getAttribute('data-history-node-id');
+ if (Drupal.history.needsServerCheck(nodeID, lastCommentTimestamp)) {
+ if (nodeIDs.indexOf(nodeID) === -1) {
+ nodeIDs.push(nodeID);
+ }
+ return true;
+ }
+ else {
+ return false;
+ }
+ });
+
+ if ($nodeNewPlaceholders.length === 0 && $newRepliesPlaceholders.length === 0) {
+ return;
+ }
+
+ // Fetch the node read timestamps from the server.
+ Drupal.history.fetchTimestamps(nodeIDs, function () {
+ processNodeNewIndicators($nodeNewPlaceholders);
+ processNewRepliesIndicators($newRepliesPlaceholders);
+ });
}
+ };
- // Fetch the node read timestamps from the server.
- Drupal.history.fetchTimestamps(nodeIDs, function () {
- processNodeNewIndicators($nodeNewPlaceholders);
- processNewRepliesIndicators($newRepliesPlaceholders);
- });
- }
-};
+ function processNodeNewIndicators($placeholders) {
+ var newNodeString = Drupal.t('new');
+ var updatedNodeString = Drupal.t('updated');
-function processNodeNewIndicators($placeholders) {
- var newNodeString = Drupal.t('new');
- var updatedNodeString = Drupal.t('updated');
+ $placeholders.each(function (index, placeholder) {
+ var timestamp = parseInt(placeholder.getAttribute('data-history-node-timestamp'), 10);
+ var nodeID = placeholder.getAttribute('data-history-node-id');
+ var lastViewTimestamp = Drupal.history.getLastRead(nodeID);
- $placeholders.each(function (index, placeholder) {
- var timestamp = parseInt(placeholder.getAttribute('data-history-node-timestamp'), 10);
- var nodeID = placeholder.getAttribute('data-history-node-id');
- var lastViewTimestamp = Drupal.history.getLastRead(nodeID);
+ if (timestamp > lastViewTimestamp) {
+ var message = (lastViewTimestamp === 0) ? newNodeString : updatedNodeString;
+ $(placeholder).append('' + message + '');
+ }
+ });
+ }
- if (timestamp > lastViewTimestamp) {
- var message = (lastViewTimestamp === 0) ? newNodeString : updatedNodeString;
- $(placeholder).append('' + message + '');
- }
- });
-}
+ function processNewRepliesIndicators($placeholders) {
+ // Figure out which placeholders need the "x new" replies links.
+ var placeholdersToUpdate = {};
+ $placeholders.each(function (index, placeholder) {
+ var timestamp = parseInt(placeholder.getAttribute('data-history-node-last-comment-timestamp'), 10);
+ var nodeID = placeholder.previousSibling.previousSibling.getAttribute('data-history-node-id');
+ var lastViewTimestamp = Drupal.history.getLastRead(nodeID);
-function processNewRepliesIndicators($placeholders) {
- // Figure out which placeholders need the "x new" replies links.
- var placeholdersToUpdate = {};
- $placeholders.each(function (index, placeholder) {
- var timestamp = parseInt(placeholder.getAttribute('data-history-node-last-comment-timestamp'), 10);
- var nodeID = placeholder.previousSibling.previousSibling.getAttribute('data-history-node-id');
- var lastViewTimestamp = Drupal.history.getLastRead(nodeID);
+ // Queue this placeholder's "X new" replies link to be downloaded from the
+ // server.
+ if (timestamp > lastViewTimestamp) {
+ placeholdersToUpdate[nodeID] = placeholder;
+ }
+ });
- // Queue this placeholder's "X new" replies link to be downloaded from the
- // server.
- if (timestamp > lastViewTimestamp) {
- placeholdersToUpdate[nodeID] = placeholder;
+ // Perform an AJAX request to retrieve node view timestamps.
+ var nodeIDs = Object.keys(placeholdersToUpdate);
+ if (nodeIDs.length === 0) {
+ return;
}
- });
-
- // Perform an AJAX request to retrieve node view timestamps.
- var nodeIDs = Object.keys(placeholdersToUpdate);
- if (nodeIDs.length === 0) {
- return;
- }
- $.ajax({
- url: Drupal.url('comments/render_new_comments_node_links'),
- type: 'POST',
- data: { 'node_ids[]' : nodeIDs },
- dataType: 'json',
- success: function (results) {
- for (var nodeID in results) {
- if (results.hasOwnProperty(nodeID) && placeholdersToUpdate.hasOwnProperty(nodeID)) {
- var url = results[nodeID].first_new_comment_link;
- var text = Drupal.formatPlural(results[nodeID].new_comment_count, '1 new', '@count new');
- $(placeholdersToUpdate[nodeID]).append('
' + text + '');
+ $.ajax({
+ url: Drupal.url('comments/render_new_comments_node_links'),
+ type: 'POST',
+ data: {'node_ids[]': nodeIDs},
+ dataType: 'json',
+ success: function (results) {
+ for (var nodeID in results) {
+ if (results.hasOwnProperty(nodeID) && placeholdersToUpdate.hasOwnProperty(nodeID)) {
+ var url = results[nodeID].first_new_comment_link;
+ var text = Drupal.formatPlural(results[nodeID].new_comment_count, '1 new', '@count new');
+ $(placeholdersToUpdate[nodeID]).append('
' + text + '');
+ }
}
}
- }
- });
-}
+ });
+ }
})(jQuery, Drupal, window);
diff --git a/core/modules/tracker/tracker.libraries.yml b/core/modules/tracker/tracker.libraries.yml
index e69de29..11c103c 100644
--- a/core/modules/tracker/tracker.libraries.yml
+++ b/core/modules/tracker/tracker.libraries.yml
@@ -0,0 +1,8 @@
+history:
+ version: VERSION
+ js:
+ js/tracker-history.js: {}
+ dependencies:
+ - core/jquery
+ - core/drupal
+ - history/api
diff --git a/core/modules/tracker/tracker.module b/core/modules/tracker/tracker.module
index 73ba659..fdd61f4 100644
--- a/core/modules/tracker/tracker.module
+++ b/core/modules/tracker/tracker.module
@@ -133,27 +133,6 @@ function tracker_cron() {
}
/**
- * Implements hook_library_info().
- */
-function tracker_library_info() {
- $libraries['drupal.tracker-history'] = array(
- 'title' => 'Tracker history',
- 'version' => VERSION,
- 'js' => array(
- drupal_get_path('module', 'tracker') . '/js/tracker-history.js' => array(),
- ),
- 'dependencies' => array(
- array('system', 'jquery'),
- array('system', 'drupal'),
- array('history', 'drupal.history'),
- ),
- );
-
- return $libraries;
-}
-
-
-/**
* Access callback: Determines access permission for a user's own account.
*
* @param int $account