Commit 82519cc6 authored by Richard Mansfield's avatar Richard Mansfield
Browse files

Use paginator for inbox instead of tablerender; use notification icons


Signed-off-by: default avatarRichard Mansfield <richardm@catalyst.net.nz>
parent bd3c9f41
......@@ -30,115 +30,80 @@ define('JSON', 1);
require(dirname(dirname(dirname(__FILE__))) . '/init.php');
json_headers();
$readone = param_integer('readone', 0);
$markasread = param_integer('markasread', 0);
$delete = param_integer('delete', 0);
$quiet = param_integer('quiet', 0);
if ($markasread) {
$count = 0;
db_begin();
try {
foreach ($_GET as $k => $v) {
if (preg_match('/^unread\-(\d+)$/',$k,$m)) {
set_field('notification_internal_activity', 'read', 1, 'id', $m[1], 'usr', $USER->get('id'));
$count++;
}
}
}
catch (Exception $e) {
db_rollback();
json_reply('local', get_string('failedtomarkasread', 'activity') . ': ' . $e->getMessage());
}
db_commit();
if ($quiet) {
json_reply(false, null);
}
json_reply(false, array('message' => get_string('markedasread', 'activity'), 'count' => $count));
}
else if ($delete) {
$count = 0;
db_begin();
try {
foreach ($_GET as $k => $v) {
if (preg_match('/^delete\-(\d+)$/',$k,$m)) {
delete_records('notification_internal_activity', 'id', $m[1], 'usr', $USER->get('id'));
$count++;
}
}
}
catch (Exception $e) {
db_rollback();
json_reply('local', get_string('failedtodeletenotifications', 'activity') . ': ' . $e->getMessage());
}
db_commit();
safe_require('notification', 'internal');
json_reply(false, array(
'message' => get_string('deletednotifications', 'activity', $count),
'count' => $count,
'newunreadcount' => call_static_method(generate_class_name('notification', 'internal'), 'unread_count', $USER->get('id'))
));
if ($readone) {
set_field('notification_internal_activity', 'read', 1, 'id', $readone, 'usr', $USER->get('id'));
json_reply(false, null);
}
// normal processing
require_once(get_config('libroot') . 'activity.php');
$type = param_variable('type', 'all');
$limit = param_integer('limit', 10);
$offset = param_integer('offset', 0);
$userid = $USER->get('id');
$message = false;
$typesql = '';
if ($type != 'all') {
$types = split(',', preg_replace('/[^a-z,]+/', '', $type));
if ($types) {
$typesql = ' at.name IN (' . join(',', array_map('db_quote', $types)) . ')';
if (in_array('adminmessages', $types)) {
$typesql = '(' . $typesql . ' OR at.admin = 1)';
if ($markasread) {
$ids = array();
foreach ($_GET as $k => $v) {
if (preg_match('/^unread\-(\d+)$/',$k,$m)) {
$ids[] = $m[1];
}
$typesql = ' AND ' . $typesql;
}
if ($ids) {
set_field_select(
'notification_internal_activity', 'read', 1,
'id IN (' . join(',', $ids) . ') AND usr = ?',
array($USER->get('id'))
);
}
$message = get_string('markedasread', 'activity');
}
$from = "
FROM {notification_internal_activity} a
JOIN {activity_type} at ON a.type = at.id
WHERE a.usr = ? $typesql";
$values = array($userid);
$count = count_records_sql('SELECT COUNT(*)' . $from, $values);
$records = get_records_sql_array('
SELECT a.*, at.name AS type,at.plugintype, at.pluginname' . $from . '
ORDER BY a.ctime DESC', $values, $offset, $limit);
if (empty($records)) {
$records = array();
else if ($delete) {
$ids = array();
foreach ($_GET as $k => $v) {
if (preg_match('/^delete\-(\d+)$/',$k,$m)) {
$ids[] = $m[1];
}
}
if ($ids) {
$strids = join(',', $ids);
$userid = $USER->get('id');
db_begin();
execute_sql("
UPDATE {notification_internal_activity}
SET parent = NULL
WHERE parent IN (
SELECT id
FROM {notification_internal_activity}
WHERE id IN ($strids) AND usr = ?
)",
array($userid)
);
delete_records_select(
'notification_internal_activity',
"id IN ($strids) AND usr = ?",
array($userid)
);
db_commit();
}
$message = get_string('deletednotifications', 'activity', count($ids));
}
$data = array();
$star = $THEME->get_url('images/star.png');
$unread = get_string('unread', 'activity');
foreach ($records as &$r) {
$r->date = format_date(strtotime($r->ctime));
$section = 'activity';
if (!empty($r->plugintype)) {
$section = $r->plugintype . '.' . $r->pluginname;
}
$r->type = get_string('type' . $r->type, $section);
$r->message = clean_html(format_whitespace($r->message));
$newhtml = activitylist_html($type, $limit, $offset);
if ($message) {
safe_require('notification', 'internal');
$newhtml['newunreadcount'] = call_static_method(
generate_class_name('notification', 'internal'),
'unread_count',
$USER->get('id')
);
}
$activity = array(
'count' => $count,
'offset' => $offset,
'limit' => $limit,
'data' => $records,
'star' => $star,
'unread' => $unread,
);
json_reply(false, (object) array('message' => $message, 'data' => $newhtml));
echo json_encode($activity);
?>
......@@ -59,60 +59,19 @@ if ($USER->get('admin')) {
$type = param_variable('type', 'all');
if (!isset($options[$type])) {
// Comma-separated list; filter out anything that's not an installed type
$types = join(',', array_unique(array_filter(
$type = join(',', array_unique(array_filter(
split(',', $type),
create_function('$a', 'global $installedtypes; return isset($installedtypes[$a]);')
)));
}
$strtype = json_encode($type);
$morestr = get_string('more...');
require_once('activity.php');
$activitylist = activitylist_html($type);
$star = json_encode($THEME->get_url('images/star.png'));
$unread = json_encode(get_string('unread', 'activity'));
$strread = json_encode(get_string('read', 'activity'));
$javascript = <<<JAVASCRIPT
var activitylist = new TableRenderer(
'activitylist',
'index.json.php',
[
function(r) {
if (r.message) {
var messagemore = DIV({'id' : 'message-' + r.id, 'style': 'display:none'});
messagemore.innerHTML = r.message;
if (r.url) {
appendChildNodes(messagemore, BR(null), A({'href' : r.url, 'class': 's'}, '{$morestr}'));
}
return TD(null, A({'href': '', 'onclick': 'showHideMessage(' + r.id + '); return false;'}, r.subject),
messagemore);
}
else if (r.url) {
return TD(null, A({'href': r.url}, r.subject));
}
else {
return TD(null, r.subject);
}
},
'type',
'date',
function (r, d) {
if (r.read == 1) {
return TD({'class': 'center'},IMG({'src' : d.star, 'alt' : d.unread}));
}
else {
return TD({'class': 'center'}, INPUT({'type' : 'checkbox', 'class' : 'tocheckread', 'name' : 'unread-' + r.id}));
}
},
function (r, d) {
return TD({'class': 'center'}, INPUT({'type' : 'checkbox', 'class' : 'tocheckdel', 'name' : 'delete-' + r.id}));
}
]
);
activitylist.type = {$strtype};
activitylist.statevars.push('type');
activitylist.updateOnLoad();
function markread(form, action) {
......@@ -130,20 +89,18 @@ function markread(form, action) {
} else if (action == 'del') {
pd['delete'] = 1;
}
if (paginatorData) {
for (p in paginatorData.params) {
pd[p] = paginatorData.params[p];
}
}
sendjsonrequest('index.json.php', pd, 'GET', function (data) {
if (!data.error) {
if (data.count > 0) {
activitylist.doupdate();
if (data.newunreadcount && typeof(data.newunreadcount) != 'undefined') {
updateUnreadCount(data.newunreadcount, 'reset');
} else {
updateUnreadCount(data.count, 'decrement');
}
}
paginator.updateResults(data);
if (data.newunreadcount && typeof(data.newunreadcount) != 'undefined') {
updateUnreadCount(data.newunreadcount, 'reset');
}
}, function () {
activitylist.doupdate();
});
}
......@@ -175,25 +132,61 @@ function updateUnreadCount(n, decrement) {
}
function showHideMessage(id) {
if (getStyle('message-' + id, 'display') == 'none') {
var unread = getFirstElementByTagAndClassName('input', 'tocheckread',
$('message-' + id).parentNode.parentNode);
var message = $('message-' + id);
if (!message) {
return;
}
if (hasElementClass(message, 'hidden')) {
var unread = getFirstElementByTagAndClassName(
'input', 'tocheckread', message.parentNode.parentNode
);
if (unread) {
var pd = {'markasread':1, 'quiet':1};
pd['unread-'+id] = 1;
var pd = {'readone':id};
sendjsonrequest('index.json.php', pd, 'GET', function(data) {
return !!data.error;
swapDOM(unread, IMG({'src' : {$star}, 'alt' : {$strread}}));
updateUnreadCount(1, 'decrement');
});
swapDOM(unread, IMG({'src' : {$star}, 'alt' : {$unread}}));
updateUnreadCount(1, 'decrement');
}
showElement('message-' + id);
removeElementClass(message, 'hidden');
}
else {
hideElement('message-' + id);
addElementClass(message, 'hidden');
}
}
function changeactivitytype() {
var params = {'type': this.options[this.selectedIndex].value};
sendjsonrequest('index.json.php', params, 'GET', function(data) {
paginator.updateResults(data);
});
}
// We want the paginator to tell us when a page gets changed.
// @todo: remember checked/unchecked state when changing pages
function PaginatorData() {
var self = this;
var params = {};
this.pageChanged = function(data) {
self.params = {
'offset': data.offset,
'limit': data.limit,
'type': data.type
}
}
paginatorProxy.addObserver(self);
connect(self, 'pagechanged', self.pageChanged);
}
var paginator;
var paginatorData = new PaginatorData();
addLoadEvent(function () {
paginator = {$activitylist['pagination_js']}
connect('notifications_type', 'onchange', changeactivitytype);
});
JAVASCRIPT;
$deleteall = pieform(array(
......@@ -219,16 +212,16 @@ function delete_all_notifications_submit() {
redirect(get_config('wwwroot') . 'account/activity/index.php');
}
$smarty = smarty(array('tablerenderer'));
$smarty = smarty(array('paginator'));
$smarty->assign('selectallread', 'toggleChecked(\'tocheckread\'); return false;');
$smarty->assign('selectalldel', 'toggleChecked(\'tocheckdel\'); return false;');
$smarty->assign('markread', 'markread(this, \'read\'); return false;');
$smarty->assign('markdel', 'markread(document.notificationlist, \'del\'); return false;');
$smarty->assign('typechange', 'activitylist.type = this.options[this.selectedIndex].value; activitylist.doupdate();');
$smarty->assign('options', $options);
$smarty->assign('type', $type);
$smarty->assign('INLINEJAVASCRIPT', $javascript);
$smarty->assign('PAGEHEADING', hsc(get_string('inbox')));
$smarty->assign('deleteall', $deleteall);
$smarty->assign('activitylist', $activitylist);
$smarty->display('account/activity/index.tpl');
?>
......@@ -883,4 +883,79 @@ abstract class ActivityTypePlugin extends ActivityType {
}
}
?>
/**
* Get one page of notifications and return html
*/
function activitylist_html($type='all', $limit=10, $offset=0) {
global $USER;
$userid = $USER->get('id');
$typesql = '';
if ($type != 'all') {
// Treat as comma-separated list of activity type names
$types = split(',', preg_replace('/[^a-z,]+/', '', $type));
if ($types) {
$typesql = ' at.name IN (' . join(',', array_map('db_quote', $types)) . ')';
if (in_array('adminmessages', $types)) {
$typesql = '(' . $typesql . ' OR at.admin = 1)';
}
$typesql = ' AND ' . $typesql;
}
}
$from = "
FROM {notification_internal_activity} a
JOIN {activity_type} at ON a.type = at.id
WHERE a.usr = ? $typesql";
$values = array($userid);
$count = count_records_sql('SELECT COUNT(*)' . $from, $values);
$pagination = build_pagination(array(
'id' => 'activitylist_pagination',
'url' => get_config('wwwroot') . 'account/activity/index.php?type=' . hsc($type),
'jsonscript' => 'account/activity/index.json.php',
'datatable' => 'activitylist',
'count' => $count,
'limit' => $limit,
'offset' => $offset,
));
$result = array(
'count' => $count,
'limit' => $limit,
'offset' => $offset,
'type' => $type,
'tablerows' => '',
'pagination' => $pagination['html'],
'pagination_js' => $pagination['javascript'],
);
if ($count < 1) {
return $result;
}
$records = get_records_sql_array('
SELECT
a.*, at.name AS type, at.plugintype, at.pluginname' . $from . '
ORDER BY a.ctime DESC',
$values,
$offset,
$limit
);
if ($records) {
foreach ($records as &$r) {
$r->date = format_date(strtotime($r->ctime), 'strfdaymonthyearshort');
$section = empty($r->plugintype) ? 'activity' : "{$r->plugintype}.{$r->pluginname}";
$r->strtype = get_string('type' . $r->type, $section);
$r->message = clean_html(format_whitespace($r->message));
}
}
$smarty = smarty_core();
$smarty->assign('data', $records);
$result['tablerows'] = $smarty->fetch('account/activity/activitylist.tpl');
return $result;
}
......@@ -1564,7 +1564,7 @@ form#search input.text {
position: relative;
top: -30px;
left: -15px;
width: 50%;
width: 10%;
}
/* Settings > Institution membership */
......
{foreach from=$data item=item}
<tr class="{cycle values='r0,r1'}">
<td>
<img src="{theme_url filename=cat('images/' $item->type '.gif')}" alt="{$item->strtype|escape}" />
</td>
<td>
{if $item->message}
<a href="" onclick="showHideMessage({$item->id}); return false;">{$item->subject|escape}</a>
<div id="message-{$item->id}" class="hidden">{$item->message|clean_html}
{if $item->url}<br><a href="{$item->url|escape}" class="s">{str tag="more..."}</a>{/if}
</div>
{elseif $item->url}
<a href="{$item->url|escape}">{$item->subject|escape}</a>
{else}
{$item->subject|escape}
{/if}
</td>
<td>{$item->date|escape}</td>
<td class="center">
{if $item->read}
<img src="{theme_url filename='images/star.png'}" alt="{str tag=read section=activity}">
{else}
<input type="checkbox" class="tocheckread" name="unread-{$item->id|escape}">
{/if}
</td>
<td class="center"><input type="checkbox" class="tocheckdel" name="delete-{$item->id|escape}"></td>
</tr>
{/foreach}
......@@ -3,7 +3,7 @@
<div id="notifications">
<form method="post">
<label>{str section='activity' tag='type'}:</label>
<select name="type" onChange="{$typechange}">
<select id="notifications_type" name="type">
<option value="all">--</option>
{foreach from=$options item=name key=t}
<option value="{$t}"{if $type == $t} selected{/if}>{$name}</option>
......@@ -14,8 +14,8 @@
<table id="activitylist" class="fullwidth">
<thead>
<tr>
<th></th>
<th>{str section='activity' tag='subject'}</th>
<th>{str section='activity' tag='type'}</th>
<th>{str section='activity' tag='date'}</th>
<th width="50" class="center">{str section='activity' tag='read'}<br><a href="" onclick="{$selectallread}">{str section='activity' tag='selectall'}</a></th>
<th width="50" class="center">{str tag='delete'}<br><a href="" onclick="{$selectalldel}">{str section='activity' tag='selectall'}</a></th>
......@@ -29,10 +29,13 @@
</td>
</tr>
</tfoot>
<tbody></tbody>
<tbody>
{$activitylist.tablerows}
</tbody>
</table>
{$activitylist.pagination}
</form>
</div>
{$deleteall}
<div class="left">{$deleteall}</div>
{include file="footer.tpl"}
Supports Markdown
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