235 lines
6.5 KiB
Plaintext
235 lines
6.5 KiB
Plaintext
<?php
|
|
|
|
/**
|
|
* @file
|
|
* Records which users have read which content.
|
|
*
|
|
* @todo
|
|
* - Generic helper for _forum_user_last_visit() + history_read().
|
|
* - Generic helper for node_mark().
|
|
*/
|
|
|
|
use Drupal\Core\Entity\EntityInterface;
|
|
use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
|
|
|
|
/**
|
|
* Entities changed before this time are always shown as read.
|
|
*
|
|
* Entities changed within this time may be marked as new, updated, or read,
|
|
* depending on their state for the current user. Defaults to 30 days ago.
|
|
*/
|
|
define('HISTORY_READ_LIMIT', REQUEST_TIME - 30 * 24 * 60 * 60);
|
|
|
|
/**
|
|
* Implements hook_help().
|
|
*/
|
|
function history_help($path, $arg) {
|
|
switch ($path) {
|
|
case 'admin/help#history':
|
|
$output = '<h3>' . t('About') . '</h3>';
|
|
$output .= '<p>' . t('The History module keeps track of which content a user has read. Its data is available through the Views module. The History module marks content as <em>new</em> or <em>updated</em> depending on the last time the user viewed that content. It also provides a filter to <a href="!views-help">Views</a> to show new or updated content. History records older than one month will be removed during cron. This means that content older than one month will always be considered <em>read</em>. The module does not provide a user interface. For more information, see the online documentation for the <a href="!url">History module</a>.', array('!views-help' => \Drupal::url('help.page', array ('name' => 'views')), '!url' => 'https://drupal.org/documentation/modules/history')) . '</p>';
|
|
return $output;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Retrieves the timestamp for the current user's last view of a specified node.
|
|
*
|
|
* @param int $nid
|
|
* A node ID.
|
|
*
|
|
* @return int
|
|
* If a node has been previously viewed by the user, the timestamp in seconds
|
|
* of when the last view occurred; otherwise, zero.
|
|
*/
|
|
function history_read($nid) {
|
|
$history = history_read_multiple(array($nid));
|
|
return $history[$nid];
|
|
}
|
|
|
|
/**
|
|
* Retrieves the last viewed timestamp for each of the passed node IDs.
|
|
*
|
|
* @param array $nids
|
|
* An array of node IDs.
|
|
*
|
|
* @return array
|
|
* Array of timestamps keyed by node ID. If a node has been previously viewed
|
|
* by the user, the timestamp in seconds of when the last view occurred;
|
|
* otherwise, zero.
|
|
*/
|
|
function history_read_multiple($nids) {
|
|
$history = &drupal_static(__FUNCTION__, array());
|
|
|
|
$return = array();
|
|
|
|
$nodes_to_read = array();
|
|
foreach ($nids as $nid) {
|
|
if (isset($history[$nid])) {
|
|
$return[$nid] = $history[$nid];
|
|
}
|
|
else {
|
|
// Initialize value if current user has not viewed the node.
|
|
$nodes_to_read[$nid] = 0;
|
|
}
|
|
}
|
|
|
|
if (empty($nodes_to_read)) {
|
|
return $return;
|
|
}
|
|
|
|
$result = db_query('SELECT nid, timestamp FROM {history} WHERE uid = :uid AND nid IN(:nids)', array(
|
|
':uid' => \Drupal::currentUser()->id(),
|
|
':nids' => array_keys($nodes_to_read),
|
|
));
|
|
foreach ($result as $row) {
|
|
$nodes_to_read[$row->nid] = (int) $row->timestamp;
|
|
}
|
|
$history += $nodes_to_read;
|
|
|
|
return $return + $nodes_to_read;
|
|
}
|
|
|
|
/**
|
|
* Updates 'last viewed' timestamp of the specified entity for the current user.
|
|
*
|
|
* @param $nid
|
|
* The node ID that has been read.
|
|
* @param $account
|
|
* (optional) The user account to update the history for. Defaults to the
|
|
* current user.
|
|
*/
|
|
function history_write($nid, $account = NULL) {
|
|
|
|
if (!isset($account)) {
|
|
$account = \Drupal::currentUser();
|
|
}
|
|
|
|
if ($account->isAuthenticated()) {
|
|
db_merge('history')
|
|
->key(array(
|
|
'uid' => $account->id(),
|
|
'nid' => $nid,
|
|
))
|
|
->fields(array('timestamp' => REQUEST_TIME))
|
|
->execute();
|
|
// Update static cache.
|
|
$history = &drupal_static('history_read_multiple', array());
|
|
$history[$nid] = REQUEST_TIME;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Implements hook_cron().
|
|
*/
|
|
function history_cron() {
|
|
db_delete('history')
|
|
->condition('timestamp', HISTORY_READ_LIMIT, '<')
|
|
->execute();
|
|
}
|
|
|
|
/**
|
|
* Implements hook_node_view_alter().
|
|
*/
|
|
function history_node_view_alter(&$build, EntityInterface $node, EntityViewDisplayInterface $display) {
|
|
// Update the history table, stating that this user viewed this node.
|
|
if (($display->originalMode === 'full') && \Drupal::currentUser()->isAuthenticated()) {
|
|
$build['#attached'] = array(
|
|
'js' => array(
|
|
// When the window's "load" event is triggered, mark the node as read.
|
|
// This still allows for Drupal behaviors (which are triggered on the
|
|
// "DOMContentReady" event) to add "new" and "updated" indicators.
|
|
array(
|
|
'data' => 'window.addEventListener("load",function(){Drupal.history.markAsRead(' . $node->id() . ');},false);',
|
|
'type' => 'inline',
|
|
),
|
|
),
|
|
'library' => array(
|
|
array('history', 'drupal.history'),
|
|
),
|
|
);
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* Implements hook_node_delete().
|
|
*/
|
|
function history_node_delete(EntityInterface $node) {
|
|
db_delete('history')
|
|
->condition('nid', $node->id())
|
|
->execute();
|
|
}
|
|
|
|
/**
|
|
* Implements hook_user_cancel().
|
|
*/
|
|
function history_user_cancel($edit, $account, $method) {
|
|
switch ($method) {
|
|
case 'user_cancel_reassign':
|
|
db_delete('history')
|
|
->condition('uid', $account->id())
|
|
->execute();
|
|
break;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Implements hook_user_delete().
|
|
*/
|
|
function history_user_delete($account) {
|
|
db_delete('history')
|
|
->condition('uid', $account->id())
|
|
->execute();
|
|
}
|
|
|
|
/**
|
|
* Implements hook_library_info().
|
|
*/
|
|
function history_library_info() {
|
|
$libraries['drupal.history'] = array(
|
|
'title' => 'History',
|
|
'version' => \Drupal::VERSION,
|
|
'js' => array(
|
|
drupal_get_path('module', 'history') . '/js/history.js' => array(),
|
|
),
|
|
'dependencies' => array(
|
|
array('system', 'jquery'),
|
|
array('system', 'drupalSettings'),
|
|
array('system', 'drupal'),
|
|
array('system', 'drupal.ajax'),
|
|
),
|
|
);
|
|
|
|
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;
|
|
}
|