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