Commit eaaa8d86 authored by catch's avatar catch

Issue #2073535 by Wim Leers: Node history markers require an HTTP request .

parent 2214ca4e
......@@ -3969,14 +3969,18 @@ function drupal_render(&$elements, $is_recursive_call = FALSE) {
$suffix = isset($elements['#suffix']) ? $elements['#suffix'] : '';
$elements['#markup'] = $prefix . $elements['#children'] . $suffix;
// Cache the processed element if #cache is set.
if (isset($elements['#cache'])) {
// Collect all #post_render_cache callbacks associated with this element.
// Collect all #post_render_cache callbacks associated with this element when:
// - about to store this element in the render cache, or when;
// - about to apply #post_render_cache callbacks.
if (isset($elements['#cache']) || !$is_recursive_call) {
$post_render_cache = drupal_render_collect_post_render_cache($elements);
if ($post_render_cache) {
$elements['#post_render_cache'] = $post_render_cache;
}
}
// Cache the processed element if #cache is set.
if (isset($elements['#cache'])) {
drupal_render_cache_set($elements['#markup'], $elements);
}
......
......@@ -533,6 +533,14 @@ function comment_entity_view(EntityInterface $entity, EntityViewDisplayInterface
);
if ($view_mode == 'teaser' && \Drupal::moduleHandler()->moduleExists('history') && \Drupal::currentUser()->isAuthenticated()) {
$entity->content['links']['#attached']['library'][] = array('comment', 'drupal.node-new-comments-link');
// Embed the metadata for the "X new comments" link (if any) on this node.
$entity->content['links']['#post_render_cache']['history_attach_timestamp'] = array(
array('node_id' => $entity->id()),
);
$entity->content['links']['#post_render_cache']['Drupal\comment\CommentViewBuilder::attachNewCommentsLinkMetadata'] = array(
array('entity_type' => $entity->entityType(), 'entity_id' => $entity->id(), 'field_name' => $field_name),
);
}
}
}
......
......@@ -99,23 +99,32 @@ function processNodeNewCommentLinks($placeholders) {
if (nodeIDs.length === 0) {
return;
}
$.ajax({
url: Drupal.url('comments/render_new_comments_node_links'),
type: 'POST',
data: { 'node_ids[]' : nodeIDs, 'field_name' : fieldName },
dataType: 'json',
success: function (results) {
for (var nodeID in results) {
if (results.hasOwnProperty(nodeID) && $placeholdersToUpdate.hasOwnProperty(nodeID)) {
$placeholdersToUpdate[nodeID]
.attr('href', results[nodeID].first_new_comment_link)
.text(Drupal.formatPlural(results[nodeID].new_comment_count, '1 new comment', '@count new comments'))
.removeClass('hidden');
show($placeholdersToUpdate[nodeID]);
}
// Render the "X new comments" links. Either use the data embedded in the page
// or perform an AJAX request to retrieve the same data.
function render (results) {
for (var nodeID in results) {
if (results.hasOwnProperty(nodeID) && $placeholdersToUpdate.hasOwnProperty(nodeID)) {
$placeholdersToUpdate[nodeID]
.attr('href', results[nodeID].first_new_comment_link)
.text(Drupal.formatPlural(results[nodeID].new_comment_count, '1 new comment', '@count new comments'))
.removeClass('hidden');
show($placeholdersToUpdate[nodeID]);
}
}
});
}
if (drupalSettings.comment && drupalSettings.comment.newCommentsLinks) {
render(drupalSettings.comment.newCommentsLinks.node[fieldName]);
}
else {
$.ajax({
url: Drupal.url('comments/render_new_comments_node_links'),
type: 'POST',
data: { 'node_ids[]' : nodeIDs, 'field_name' : fieldName },
dataType: 'json',
success: render
});
}
}
})(jQuery, Drupal);
......@@ -147,6 +147,11 @@ public function buildContent(array $entities, array $displays, $view_mode, $lang
$entity->content['#attached']['library'][] = array('comment', 'drupal.comment-by-viewer');
if ($this->moduleHandler->moduleExists('history') && \Drupal::currentUser()->isAuthenticated()) {
$entity->content['#attached']['library'][] = array('comment', 'drupal.comment-new-indicator');
// Embed the metadata for the comment "new" indicators on this node.
$entity->content['#post_render_cache']['history_attach_timestamp'] = array(
array('node_id' => $commented_entity->id()),
);
}
}
}
......@@ -299,4 +304,55 @@ protected function alterBuild(array &$build, EntityInterface $comment, EntityVie
}
}
/**
* #post_render_cache callback; attaches "X new comments" link metadata.
*
* @param array $element
* A render array with the following keys:
* - #markup
* - #attached
* @param array $context
* An array with the following keys:
* - entity_type: an entity type
* - entity_id: an entity ID
* - field_name: a comment field name
*
* @return array $element
* The updated $element.
*/
public static function attachNewCommentsLinkMetadata(array $element, array $context) {
// Build "X new comments" link metadata.
$new = (int)comment_num_new($context['entity_id'], $context['entity_type']);
// Early-return if there are zero new comments for the current user.
if ($new === 0) {
return $element;
}
$entity = \Drupal::entityManager()
->getStorageController($context['entity_type'])
->load($context['entity_id']);
$field_name = $context['field_name'];
$query = comment_new_page_count($entity->{$field_name}->comment_count, $new, $entity);
// Attach metadata.
$element['#attached']['js'][] = array(
'type' => 'setting',
'data' => array(
'comment' => array(
'newCommentsLinks' => array(
$context['entity_type'] => array(
$context['field_name'] => array(
$context['entity_id'] => array(
'new_comment_count' => (int)$new,
'first_new_comment_link' => \Drupal::urlGenerator()->generateFromPath('node/' . $entity->id(), array('query' => $query, 'fragment' => 'new')),
)
)
),
)
),
),
);
return $element;
}
}
......@@ -203,3 +203,32 @@ function history_library_info() {
return $libraries;
}
/**
* #post_render_cache callback; attaches the last read timestamp for a node.
*
* @param array $element
* A render array with the following keys:
* - #markup
* - #attached
* @param array $context
* An array with the following keys:
* - node_id: the node ID for which to attach the last read timestamp.
*
* @return array $element
* The updated $element.
*/
function history_attach_timestamp(array $element, array $context) {
$element['#attached']['js'][] = array(
'type' => 'setting',
'data' => array(
'history' => array(
'lastReadTimestamps' => array(
$context['node_id'] => (int) history_read($context['node_id']),
)
),
),
);
return $element;
}
......@@ -13,6 +13,12 @@ var currentUserID = parseInt(drupalSettings.user.uid, 10);
// so for these we don't need to perform a request at all!
var thirtyDaysAgo = Math.round(new Date().getTime() / 1000) - 30 * 24 * 60 * 60;
// Use the data embedded in the page, if available.
var embeddedLastReadTimestamps = false;
if (drupalSettings.history && drupalSettings.history.lastReadTimestamps) {
embeddedLastReadTimestamps = drupalSettings.history.lastReadTimestamps;
}
Drupal.history = {
/**
......@@ -24,6 +30,12 @@ Drupal.history = {
* A callback that is called after the requested timestamps were fetched.
*/
fetchTimestamps: function (nodeIDs, callback) {
// Use the data embedded in the page, if available.
if (embeddedLastReadTimestamps) {
callback();
return;
}
$.ajax({
url: Drupal.url('history/get_node_read_timestamps'),
type: 'POST',
......@@ -50,6 +62,10 @@ Drupal.history = {
* A UNIX timestamp.
*/
getLastRead: function (nodeID) {
// Use the data embedded in the page, if available.
if (embeddedLastReadTimestamps && embeddedLastReadTimestamps[nodeID]) {
return parseInt(embeddedLastReadTimestamps[nodeID], 10);
}
return parseInt(storage.getItem('Drupal.history.' + currentUserID + '.' + nodeID) || 0, 10);
},
......@@ -65,6 +81,11 @@ Drupal.history = {
type: 'POST',
dataType: 'json',
success: function (timestamp) {
// If the data is embedded in the page, don't store on the client side.
if (embeddedLastReadTimestamps && embeddedLastReadTimestamps[nodeID]) {
return;
}
storage.setItem('Drupal.history.' + currentUserID + '.' + nodeID, timestamp);
}
});
......@@ -90,6 +111,12 @@ Drupal.history = {
if (contentTimestamp < thirtyDaysAgo) {
return false;
}
// Use the data embedded in the page, if available.
if (embeddedLastReadTimestamps && embeddedLastReadTimestamps[nodeID]) {
return contentTimestamp > parseInt(embeddedLastReadTimestamps[nodeID], 10);
}
var minLastReadTimestamp = parseInt(storage.getItem('Drupal.history.' + currentUserID + '.' + nodeID) || 0, 10);
return contentTimestamp > minLastReadTimestamp;
}
......
......@@ -632,6 +632,20 @@ function testDrupalRenderChildrenPostRenderCache() {
$this->assertIdentical($settings['common_test'], $expected_settings, '#attached is modified; JavaScript settings for each #post_render_cache callback are added to page.');
// Test case 2.
// Use the exact same element, but now unset #cache.
drupal_static_reset('drupal_add_js');
unset($test_element['#cache']);
$element = $test_element;
$output = drupal_render($element);
$this->assertIdentical($output, '<p>overridden</p>', 'Output is overridden.');
$this->assertIdentical($element['#markup'], '<p>overridden</p>', '#markup is overridden.');
$this->assertTrue(!isset($element['#context_test']), '#context_test is not set: impossible to modify $element itself, only possible to modify its #markup and #attached properties.');
$settings = $this->parseDrupalSettings(drupal_get_js());
$expected_settings = $context_1 + $context_2 + $context_3;
$this->assertIdentical($settings['foo'], 'bar', 'Original JavaScript setting is added to the page.');
$this->assertIdentical($settings['common_test'], $expected_settings, '#attached is modified; JavaScript settings for each #post_render_cache callback are added to page.');
// Test case 3.
// Create an element with a child and subchild. Each element has the same
// #post_render_cache callback, but with different contexts. Both the
// parent and the child elements have #cache set. The cached parent element
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment