Commit c613f4f4 authored by Richard Mansfield's avatar Richard Mansfield
Browse files

Merge branch 'usability3'

Conflicts:

	htdocs/theme/raw/templates/header/navigation.tpl
	htdocs/theme/raw/templates/sideblocks/profile.tpl
parents 7ca53aa7 1ad1fb58
......@@ -30,116 +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 ($readone) {
set_field('notification_internal_activity', 'read', 1, 'id', $readone, 'usr', $USER->get('id'));
json_reply(false, null);
}
require_once(get_config('libroot') . 'activity.php');
$type = param_variable('type', 'all');
$limit = param_integer('limit', 10);
$offset = param_integer('offset', 0);
$message = false;
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++;
}
$ids = array();
foreach ($_GET as $k => $v) {
if (preg_match('/^unread\-(\d+)$/',$k,$m)) {
$ids[] = $m[1];
}
}
catch (Exception $e) {
db_rollback();
json_reply('local', get_string('failedtomarkasread', 'activity') . ': ' . $e->getMessage());
}
db_commit();
if ($quiet) {
json_reply(false, null);
if ($ids) {
set_field_select(
'notification_internal_activity', 'read', 1,
'id IN (' . join(',', $ids) . ') AND usr = ?',
array($USER->get('id'))
);
}
json_reply(false, array('message' => get_string('markedasread', 'activity'), 'count' => $count));
$message = get_string('markedasread', 'activity');
}
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++;
}
$ids = array();
foreach ($_GET as $k => $v) {
if (preg_match('/^delete\-(\d+)$/',$k,$m)) {
$ids[] = $m[1];
}
}
catch (Exception $e) {
db_rollback();
json_reply('local', get_string('failedtodeletenotifications', 'activity') . ': ' . $e->getMessage());
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();
}
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'))
));
$message = get_string('deletednotifications', 'activity', count($ids));
}
// normal processing
$newhtml = activitylist_html($type, $limit, $offset);
$type = param_alphanum('type', 'all');
$limit = param_integer('limit', 10);
$offset = param_integer('offset', 0);
$userid = $USER->get('id');
if ($type == 'all') {
$count = count_records('notification_internal_activity', 'usr', $userid);
$sql = 'SELECT a.*, at.name AS type,at.plugintype, at.pluginname FROM {notification_internal_activity} a
JOIN {activity_type} at ON a.type = at.id
WHERE a.usr = ? ORDER BY ctime DESC';
$records = get_records_sql_array($sql, array($userid), $offset, $limit);
} else if ($type == 'adminmessages' && $USER->get('admin')) {
$count = count_records_select('notification_internal_activity', 'usr = ? AND type IN (
SELECT id FROM {activity_type} WHERE admin = ?)',
array($userid, 1));
$sql = 'SELECT a.*, at.name AS type,at.plugintype, at.pluginname FROM {notification_internal_activity} a
JOIN {activity_type} at ON a.type = at.id
WHERE a.usr = ? AND at.admin = ? ORDER BY ctime DESC';
$records = get_records_sql_array($sql, array($userid, 1), $offset, $limit);
}
else {
$count = count_records_select('notification_internal_activity', 'usr = ? AND type = ?',
array($userid,$type));
$sql = 'SELECT a.*, at.name AS type,at.plugintype, at.pluginname FROM {notification_internal_activity} a
JOIN {activity_type} at ON a.type = at.id
WHERE a.usr = ? AND a.type = ?';
$records = get_records_sql_array($sql, array($userid, $type), $offset, $limit);
}
if (empty($records)) {
$records = array();
}
$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));
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);
?>
......@@ -26,75 +26,52 @@
*/
define('INTERNAL', 1);
define('MENUITEM', 'settings/notifications');
define('MENUITEM', 'inbox');
define('SECTION_PLUGINTYPE', 'core');
define('SECTION_PLUGINNAME', 'account');
define('SECTION_PAGE', 'activity');
require(dirname(dirname(dirname(__FILE__))) . '/init.php');
require_once('pieforms/pieform.php');
define('TITLE', get_string('notifications'));
define('TITLE', get_string('inbox'));
$types = get_records_assoc('activity_type', 'admin', 0, 'plugintype,pluginname,name', 'id,name,plugintype,pluginname');
$types = array_map(create_function('$a', '
if (!empty($a->plugintype)) {
$section = "{$a->plugintype}.{$a->pluginname}";
}
else {
$section = "activity";
$installedtypes = get_records_assoc(
'activity_type', '', '',
'plugintype,pluginname,name',
'name,admin,plugintype,pluginname'
);
$options = array(
'all' => get_string('alltypes', 'activity'),
);
foreach ($installedtypes as &$t) {
if (!$t->admin) {
$section = $t->pluginname ? "{$t->plugintype}.{$t->pluginname}" : 'activity';
$options[$t->name] = get_string('type' . $t->name, $section);
}
return get_string("type" . $a->name, $section);
'), $types);
}
if ($USER->get('admin')) {
$types['adminmessages'] = get_string('typeadminmessages', 'activity');
$options['adminmessages'] = get_string('typeadminmessages', 'activity');
}
$morestr = get_string('more...');
$type = param_variable('type', 'all');
if (!isset($options[$type])) {
// Comma-separated list; filter out anything that's not an installed type
$type = join(',', array_unique(array_filter(
split(',', $type),
create_function('$a', 'global $installedtypes; return isset($installedtypes[$a]);')
)));
}
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 = 'all';
activitylist.statevars.push('type');
activitylist.updateOnLoad();
function markread(form, action) {
......@@ -112,64 +89,77 @@ function markread(form, action) {
} else if (action == 'del') {
pd['delete'] = 1;
}
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');
}
}
}
}, function () {
activitylist.doupdate();
});
}
function updateUnreadCount(n, decrement) {
forEach(getElementsByTagAndClassName('span', 'unreadmessagescontainer'), function(message) {
var countnode = message.firstChild;
if (decrement == 'decrement') {
var oldcount = parseInt(countnode.innerHTML);
var newcount = (oldcount - n);
}
else {
var newcount = n;
}
var messagenode = message.lastChild;
if (newcount == 1) { // jump through hoops to change between plural and singular
messagenode.innerHTML = get_string('unreadmessage');
if (paginatorData) {
for (p in paginatorData.params) {
pd[p] = paginatorData.params[p];
}
else {
messagenode.innerHTML = get_string('unreadmessages');
}
sendjsonrequest('index.json.php', pd, 'GET', function (data) {
paginator.updateResults(data);
if (data.newunreadcount && typeof(data.newunreadcount) != 'undefined') {
updateUnreadCount(data.newunreadcount, 'reset');
}
countnode.innerHTML = newcount;
});
}
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(
......@@ -195,15 +185,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('types', $types);
$smarty->assign('options', $options);
$smarty->assign('type', $type);
$smarty->assign('INLINEJAVASCRIPT', $javascript);
$smarty->assign('PAGEHEADING', hsc(get_string('notifications')));
$smarty->assign('PAGEHEADING', hsc(get_string('inbox')));
$smarty->assign('deleteall', $deleteall);
$smarty->assign('activitylist', $activitylist);
$smarty->display('account/activity/index.tpl');
?>
......@@ -26,13 +26,13 @@
*/
define('INTERNAL', 1);
define('MENUITEM', 'settings/activitypreferences');
define('MENUITEM', 'settings/notifications');
define('SECTION_PLUGINTYPE', 'core');
define('SECTION_PLUGINNAME', 'account');
define('SECTION_PAGE', 'activitypreferences');
define('SECTION_PAGE', 'notifications');
require(dirname(dirname(dirname(dirname(__FILE__)))) . '/init.php');
define('TITLE', get_string('activityprefs'));
define('TITLE', get_string('notifications'));
require_once('pieforms/pieform.php');
require_once(get_config('libroot') . 'activity.php');
......@@ -100,7 +100,7 @@ $prefsform = pieform(array(
$smarty = smarty();
$smarty->assign('prefsdescr', get_string('prefsdescr', 'activity'));
$smarty->assign('form', $prefsform);
$smarty->assign('PAGEHEADING', hsc(get_string('activityprefs')));
$smarty->assign('PAGEHEADING', hsc(get_string('notifications')));
$smarty->display('account/activity/preferences/index.tpl');
function activityprefs_submit(Pieform $form, $values) {
......
......@@ -26,13 +26,13 @@
*/
define('INTERNAL', 1);
define('MENUITEM', 'settings/preferences');
define('MENUITEM', 'settings/account');
define('SECTION_PLUGINTYPE', 'core');
define('SECTION_PLUGINNAME', 'account');
define('SECTION_PAGE', 'preferences');
require(dirname(dirname(__FILE__)) . '/init.php');
define('TITLE', get_string('preferences'));
define('TITLE', get_string('account'));
require_once('pieforms/pieform.php');
// load up user preferences
......@@ -179,6 +179,19 @@ if (get_config('userscanhiderealnames')) {
'defaultvalue' => $prefs->hiderealname,
);
}
if (get_config('homepageinfo')) {
$elements['showhomeinfo'] = array(
'type' => 'radio',
'options' => array(
1 => get_string('on', 'account'),
0 => get_string('off', 'account'),
),
'defaultvalue' => $prefs->showhomeinfo,
'title' => get_string('showhomeinfo', 'account'),
'separator' => '<br>',
'help' => 'true'
);
}
$elements['submit'] = array(
'type' => 'submit',
'value' => get_string('save')
......@@ -305,7 +318,7 @@ function clearPasswords(form, data) {
}
}
");
$smarty->assign('PAGEHEADING', hsc(get_string('preferences')));
$smarty->assign('PAGEHEADING', hsc(get_string('account')));
$smarty->display('account/index.tpl');
......
......@@ -282,6 +282,12 @@ $siteoptionform = array(
'description' => get_string('anonymouscommentsdescription', 'admin'),
'defaultvalue' => get_config('anonymouscomments'),
),
'homepageinfo' => array(
'type' => 'checkbox',
'title' => get_string('homepageinfo', 'admin'),
'description' => get_string('homepageinfodescription', 'admin'),
'defaultvalue' => get_config('homepageinfo'),
),
)
);
......@@ -308,6 +314,7 @@ function siteoptions_submit(Pieform $form, $values) {
'showselfsearchsideblock', 'showtagssideblock',
'tagssideblockmaxtags', 'country', 'viewmicroheaders', 'userscanchooseviewthemes',
'remoteavatars', 'userscanhiderealnames', 'antispam', 'spamhaus', 'surbl', 'anonymouscomments',
'homepageinfo',
);
$oldlanguage = get_config('lang');
$oldtheme = get_config('theme');
......
......@@ -31,8 +31,8 @@ $string['pluginname'] = 'Blogs';
$string['blog'] = 'Blog';
$string['blogs'] = 'Blogs';
$string['addblog'] = 'Add Blog';
$string['addpost'] = 'Add Post';
$string['addblog'] = 'Create Blog';
$string['addpost'] = 'New Post';
$string['alignment'] = 'Alignment';
$string['allowcommentsonpost'] = 'Allow comments on your post.';
$string['attach'] = 'Attach';
......
<h3>My Blogs</h3>
<p>A blog is journal-like tool that allows you to record your thoughts and experiences.</p>
<p>By default, your blogs can only be seen by you. By adding a blog to a view you can allow people to read it and post comments.</p>
<p>You need to create a blog before you can post entries. You can have as many different blogs as you want.</p>
<p>By default, your blogs can only be seen by you. By adding a blog to a view that is shared with others you can allow people to read it and post comments.</p>
<p>You can have as many different blogs as you want.</p>
......@@ -638,6 +638,10 @@ function make_public_submit(Pieform $form, $values) {
'section' => 'artefact.comment',
'args' => array(hsc($arg)),
),
'urltext' => (object) array(
'key' => 'Comment',
'section' => 'artefact.comment',
),
),
'users' => array($userid),
'url' => $url,
......@@ -700,6 +704,9 @@ function delete_comment_submit(Pieform $form, $values) {
'section' => 'artefact.comment',
'args' => array($title, html2text($comment->get('description'))),
),
'urltext' => (object) array(
'key' => $artefact ? 'artefact' : 'view',
),
),
'users' => array($comment->get('author')),
'url' => $url,
......@@ -915,6 +922,7 @@ class ActivityTypeArtefactCommentFeedback extends ActivityTypePlugin {
'args' => array($title),
),
);
$this->urltext = $title;
if ($deletedby) {
$deletedmessage = ArtefactTypeComment::deleted_messages();
......
......@@ -72,7 +72,7 @@ $string['fileexistsoverwritecancel'] = 'A file with that name already exists.
$string['filelistloaded'] = 'File list loaded';
$string['filemoved'] = 'File moved successfully';
$string['filenamefieldisrequired'] = 'The file field is required';
$string['fileinstructions'] = 'Upload your images, documents, or other files for inclusion in views. To move a file or folder, drag and drop it onto a folder.';
$string['fileinstructions'] = 'Upload your images, documents, or other files for inclusion in views. Drag and drop the icons to move files between folders.';
$string['filethingdeleted'] = '%s deleted';
$string['filewithnameexists'] = 'A file or folder with the name "%s" already exists.';
$string['folder'] = 'Folder';
......
<h3>Group Files</h3>
<p>The group files area is a repository for shared folders and files to use within your group's views.</p>
<p>You can use drag and drop to organise group files and folders.</p>
<p>For security reasons your Site Administrator may restrict some file types from being uploaded to the system. </p>
<p>For security reasons your Site Administrator may restrict some file types from being uploaded. </p>
......@@ -2,4 +2,4 @@
<p>Your files area is a repository for folders and files to use within your portfolio.</p>
<p>The number of files you may upload into your files area is dependant on your set file storage limit which is displayed in the quota box on the right of the screen.</p>
<p>You can use drag and drop to organise your files and folders.</p>
<p>For security reasons your Site Administrator may restrict some file types from being uploaded to the system. </p>
<p>For security reasons your Site Administrator may restrict some file types from being uploaded. </p>
......@@ -5,15 +5,15 @@
</p>
<p>
You may have up to 5 icons in your Profile Icons area at once. Images you
upload need to be at least 16x16 pixels big. The images you upload count
towards your file quota.
upload must be at least 16x16 pixels and no greater than 1024x1024 pixels.
The images you upload count towards your file quota.
</p>
<p>
Your default image will be shown to other people beside your name, and you
may use the other images in views you create.
Your default icon will be shown to other people beside your name around the
site, and you may use the other images in the views you create.
</p>
<p>