Commit 1a287da3 authored by Richard Mansfield's avatar Richard Mansfield
Browse files

Remove use of tablerenderer for view/artefact feedback; create feedback list...


Remove use of tablerenderer for view/artefact feedback; create feedback list using templates; use artefactchooser paginator
Signed-off-by: default avatarRichard Mansfield <richardm@catalyst.net.nz>
parent 6cbbe30a
...@@ -1050,6 +1050,54 @@ abstract class ArtefactType { ...@@ -1050,6 +1050,54 @@ abstract class ArtefactType {
public static function attached_id_list($attachmentid) { public static function attached_id_list($attachmentid) {
return get_column('artefact_attachment', 'artefact', 'attachment', $attachmentid); return get_column('artefact_attachment', 'artefact', 'attachment', $attachmentid);
} }
public function get_feedback($limit=10, $offset=0, $viewid, $lastpage=false) {
global $USER;
$userid = $USER->get('id');
$artefactid = $this->id;
$canedit = $USER->can_edit_artefact($this);
$count = count_records_sql('
SELECT COUNT(*)
FROM {artefact_feedback}
WHERE view = ' . $viewid . ' AND artefact = ' . $artefactid
. (!$canedit ? ' AND (public = 1 OR author = ' . $userid . ')' : ''));
if ($lastpage) { // Ignore $offset and just get the last page of feedback
$offset = (ceil($count / $limit) - 1) * $limit;
}
$feedback = get_records_sql_array('
SELECT
id, author, authorname, ctime, message, public
FROM {artefact_feedback}
WHERE view = ' . $viewid . ' AND artefact = ' . $artefactid
. (!$canedit ? ' AND (f.public = 1 OR f.author = ' . $userid . ')' : '') . '
ORDER BY id', '', $offset, $limit);
if ($feedback) {
require_once(get_config('libroot') . 'view.php');
require_once(get_config('libroot') . 'pieforms/pieform.php');
foreach ($feedback as &$f) {
if ($f->public && $canedit) {
$f->pubmessage = get_string('thisfeedbackispublic', 'view');
$f->makeprivateform = pieform(make_private_form($f->id));
}
else if (!$f->public) {
$f->pubmessage = get_string('thisfeedbackisprivate', 'view');
}
}
}
return (object) array(
'count' => $count,
'limit' => $limit,
'offset' => $offset,
'lastpage' => $lastpage,
'data' => $feedback ? $feedback : array(),
'view' => $viewid,
'artefact' => $artefactid,
'canedit' => $canedit,
'isowner' => $userid && $userid == $this->get('owner'),
);
}
} }
/** /**
......
// The list of existing feedback. // The list of existing feedback.
var feedbacklist = new TableRenderer('feedbacktable', config.wwwroot + 'view/getfeedback.json.php', []);
feedbacklist.limit = 10; function addFeedbackSuccess(form, data) {
feedbacklist.rowfunction = function(r, n, d) {
var td = TD(null);
td.innerHTML = r.message;
if (r.attachid && r.ownedbythisuser) {
appendChildNodes(td, DIV(null, get_string('feedbackattachmessage')));
}
var publicPrivate = null;
if (r.ispublic == 1) {
var makePrivate = null;
if (r.ownedbythisuser) {
makePrivateLink = A({'href': ''}, get_string('makeprivate'));
connect(makePrivateLink, 'onclick', function (e) {
sendjsonrequest(
'changefeedback.json.php',
r,
'POST',
function (data) {
if (!data.error) {
replaceChildNodes(makePrivateLink.parentNode, get_string('thisfeedbackisprivate'));
}
}
);
e.stop();
});
makePrivate = [' - ', makePrivateLink];
}
publicPrivate = SPAN(null, get_string('thisfeedbackispublic'), makePrivate);
}
else {
publicPrivate = get_string('thisfeedbackisprivate');
}
var attachment = null;
if (r.attachid) {
attachment = [' | ', get_string('attachment'), ': ', A({'href':config.wwwroot + 'artefact/file/download.php?file=' + r.attachid}, r.attachtitle), ' (', r.attachsize, ')'];
}
if (r.author) {
var icon = DIV({'class': 'icon'}, A({'href': config.wwwroot + 'user/view.php?id=' + r.author}, IMG({'src': config.wwwroot + 'thumb.php?type=profileicon&id=' + r.author + '&maxsize=20', 'valign': 'middle'})));
var authorname = A({'href': config.wwwroot + 'user/view.php?id=' + r.author}, r.name);
}
else {
var icon = null;
var authorname = r.name;
}
appendChildNodes(td, DIV({'class': 'details'}, icon, authorname, ' | ', r.date, ' | ', publicPrivate, attachment));
return TR({'class': 'r' + (n % 2)}, td);
};
feedbacklist.emptycontent = get_string('nopublicfeedback');
function addFeedbackSuccess() {
addElementClass('add_feedback_form', 'js-hidden'); addElementClass('add_feedback_form', 'js-hidden');
$('add_feedback_form_message').innerHTML = ''; $('add_feedback_form_message').innerHTML = '';
feedbacklist.doupdate(); paginator.updateResults(data);
} }
function objectionSuccess() { function objectionSuccess() {
...@@ -108,7 +53,7 @@ addLoadEvent(function () { ...@@ -108,7 +53,7 @@ addLoadEvent(function () {
if ($('toggle_watchlist_link')) { if ($('toggle_watchlist_link')) {
connect('toggle_watchlist_link', 'onclick', function (e) { connect('toggle_watchlist_link', 'onclick', function (e) {
e.stop(); e.stop();
sendjsonrequest('togglewatchlist.json.php', {'view': feedbacklist.view}, 'POST', function(data) { sendjsonrequest('togglewatchlist.json.php', {'view': viewid}, 'POST', function(data) {
$('toggle_watchlist_link').innerHTML = data.newtext; $('toggle_watchlist_link').innerHTML = data.newtext;
}); });
}); });
......
...@@ -298,4 +298,8 @@ $string['viewcopywouldexceedquota'] = 'Copying this View would exceed your file ...@@ -298,4 +298,8 @@ $string['viewcopywouldexceedquota'] = 'Copying this View would exceed your file
$string['blockcopypermission'] = 'Block copy permission'; $string['blockcopypermission'] = 'Block copy permission';
$string['blockcopypermissiondesc'] = 'If you allow other users to copy this View, you may choose how this block will be copied'; $string['blockcopypermissiondesc'] = 'If you allow other users to copy this View, you may choose how this block will be copied';
// Feedback list
$string['comment'] = 'comment';
$string['comments'] = 'comments';
?> ?>
...@@ -2216,4 +2216,53 @@ function build_portfolio_search_html(&$data) { ...@@ -2216,4 +2216,53 @@ function build_portfolio_search_html(&$data) {
$data->pagination_js = $pagination['javascript']; $data->pagination_js = $pagination['javascript'];
} }
// When feedback becomes an artefact type, move this into the feedback artefact plugin
function build_feedback_html(&$data) {
foreach ($data->data as &$item) {
$item->date = format_date(strtotime($item->ctime), 'strftimedatetime');
$item->message = clean_html(parse_bbcode($item->message));
$item->name = $item->author ? display_name($item->author) : $item->authorname;
if (!empty($item->attachment)) {
$item->attachid = $item->attachment;
$item->attachtitle = $item->title;
$item->attachsize = display_size($item->size);
if ($data->isowner) {
$item->attachmessage = get_string('feedbackattachmessage', 'view', get_string('feedbackattachdirname', 'view'));
}
}
}
$extradata = array('view' => $data->view);
if (!empty($data->artefact)) {
$data->baseurl = get_config('wwwroot') . 'view/artefact.php?view=' . $data->view . '&artefact=' . $data->artefact;
$data->jsonscript = 'view/artefactfeedback.json.php';
$extradata['artefact'] = $data->artefact;
}
else {
$data->baseurl = get_config('wwwroot') . 'view/view.php?id=' . $data->view;
$data->jsonscript = 'view/viewfeedback.json.php';
}
$smarty = smarty_core();
$smarty->assign_by_ref('data', $data->data);
$smarty->assign('canedit', $data->canedit);
$smarty->assign('baseurl', $data->baseurl);
$data->tablerows = $smarty->fetch('view/feedbacklist.tpl');
$pagination = build_pagination(array(
'id' => 'feedback_pagination',
'class' => 'center',
'url' => $data->baseurl,
'jsonscript' => $data->jsonscript,
'datatable' => 'feedbacktable',
'count' => $data->count,
'limit' => $data->limit,
'offset' => $data->offset,
'lastpage' => $data->lastpage,
'resultcounttextsingular' => get_string('comment', 'view'),
'resultcounttextplural' => get_string('comments', 'view'),
'extradata' => $extradata,
));
$data->pagination = $pagination['html'];
$data->pagination_js = $pagination['javascript'];
}
?> ?>
...@@ -2525,6 +2525,49 @@ class View { ...@@ -2525,6 +2525,49 @@ class View {
return false; return false;
} }
public function get_feedback($limit=10, $offset=0, $lastpage=false) {
global $USER;
$userid = $USER->get('id');
$viewid = $this->id;
$canedit = $USER->can_edit_view($this);
$count = count_records_sql('
SELECT COUNT(*)
FROM {view_feedback}
WHERE view = ' . $viewid . (!$canedit ? ' AND (public = 1 OR author = ' . $userid . ')' : ''));
if ($lastpage) { // Ignore $offset and just get the last page of feedback
$offset = (ceil($count / $limit) - 1) * $limit;
}
$feedback = get_records_sql_array('
SELECT
f.id, f.author, f.authorname, f.ctime, f.message, f.public, f.attachment, a.title, af.size
FROM {view_feedback} f
LEFT OUTER JOIN {artefact} a ON f.attachment = a.id
LEFT OUTER JOIN {artefact_file_files} af ON af.artefact = a.id
WHERE view = ' . $viewid . (!$canedit ? ' AND (f.public = 1 OR f.author = ' . $userid . ')' : '') . '
ORDER BY id', '', $offset, $limit);
if ($feedback) {
foreach ($feedback as &$f) {
if ($f->public && $canedit) {
$f->pubmessage = get_string('thisfeedbackispublic', 'view');
$f->makeprivateform = pieform(make_private_form($f->id));
}
else if (!$f->public) {
$f->pubmessage = get_string('thisfeedbackisprivate', 'view');
}
}
}
return (object) array(
'count' => $count,
'limit' => $limit,
'offset' => $offset,
'lastpage' => $lastpage,
'data' => $feedback ? $feedback : array(),
'view' => $viewid,
'canedit' => $canedit,
'isowner' => $userid && $userid == $this->get('owner'),
);
}
} }
...@@ -2746,15 +2789,20 @@ function add_feedback_form_submit(Pieform $form, $values) { ...@@ -2746,15 +2789,20 @@ function add_feedback_form_submit(Pieform $form, $values) {
db_commit(); db_commit();
$newlist = null;
if ($artefact) { if ($artefact) {
$goto = get_config('wwwroot') . 'view/artefact.php?artefact=' . $artefact->get('id') . '&view='.$view->get('id'); $goto = get_config('wwwroot') . 'view/artefact.php?artefact=' . $artefact->get('id') . '&view='.$view->get('id');
$newlist = $artefact->get_feedback(10, null, $view->get('id'), true);
} }
else { else {
$goto = get_config('wwwroot') . 'view/view.php?id='.$view->get('id'); $goto = get_config('wwwroot') . 'view/view.php?id='.$view->get('id');
$newlist = $view->get_feedback(10, null, true);
} }
build_feedback_html($newlist);
$form->reply(PIEFORM_OK, array( $form->reply(PIEFORM_OK, array(
'message' => get_string('feedbacksubmitted', 'view'), 'message' => get_string('feedbacksubmitted', 'view'),
'goto' => $goto, 'goto' => $goto,
'data' => $newlist,
)); ));
} }
...@@ -2765,6 +2813,34 @@ function add_feedback_form_cancel_submit(Pieform $form) { ...@@ -2765,6 +2813,34 @@ function add_feedback_form_cancel_submit(Pieform $form) {
)); ));
} }
function make_private_form($feedbackid) {
return array(
'name' => 'make_private',
'renderer' => 'oneline',
'class' => 'makeprivate',
'elements' => array(
'feedback' => array('type' => 'hidden', 'value' => $feedbackid),
'submit' => array(
'type' => 'submit',
'name' => 'make_private_submit',
'value' => get_string('makeprivate', 'view'),
),
),
);
}
function make_private_submit(Pieform $form, $values) {
global $SESSION, $view, $artefact;
if (isset($artefact) && $artefact instanceof ArtefactType) {
update_record('artefact_feedback', (object) array('public' => 0, 'id' => (int) $values['feedback']));
$SESSION->add_ok_msg(get_string('feedbackchangedtoprivate', 'view'));
redirect(get_config('wwwroot') . 'view/artefact.php?view=' . $view->get('id') . '&artefact=' . $artefact->get('id'));
}
update_record('view_feedback', (object) array('public' => 0, 'id' => (int) $values['feedback']));
$SESSION->add_ok_msg(get_string('feedbackchangedtoprivate', 'view'));
redirect(get_config('wwwroot') . 'view/view.php?id=' . $view->get('id'));
}
function objection_form() { function objection_form() {
$form = array( $form = array(
'name' => 'objection_form', 'name' => 'objection_form',
......
...@@ -797,16 +797,6 @@ function jsstrings() { ...@@ -797,16 +797,6 @@ function jsstrings() {
'cancel', 'cancel',
), ),
), ),
'feedbacklist' => array(
'view' => array(
'feedbackattachmessage',
'makeprivate',
'thisfeedbackisprivate',
'thisfeedbackispublic',
'attachment',
'nopublicfeedback',
),
),
); );
} }
...@@ -2736,6 +2726,9 @@ function build_pagination($params) { ...@@ -2736,6 +2726,9 @@ function build_pagination($params) {
$page = $params['offset'] / $params['limit']; $page = $params['offset'] / $params['limit'];
$last = $pages - 1; $last = $pages - 1;
if (!empty($params['lastpage'])) {
$page = $last;
}
$next = min($last, $page + 1); $next = min($last, $page + 1);
$prev = max(0, $page - 1); $prev = max(0, $page - 1);
......
...@@ -100,6 +100,10 @@ body:last-child:not(:root:root) .newblockhere { ...@@ -100,6 +100,10 @@ body:last-child:not(:root:root) .newblockhere {
padding: 1em; padding: 1em;
border: 1px solid #eee; border: 1px solid #eee;
} }
#feedbacktable form.makeprivate,
#feedbacktable form.makeprivate div {
display: inline;
}
#viewmenu a { #viewmenu a {
margin: 0 .5em; margin: 0 .5em;
} }
......
...@@ -15,17 +15,19 @@ ...@@ -15,17 +15,19 @@
</div> </div>
</div> </div>
<div id="publicfeedback"> <div class="viewfooter">
<table id="feedbacktable" class="fullwidth"> <table id="feedbacktable" class="fullwidth table">
<thead> <thead><tr><th>{str tag="feedback" section="view"}</th></tr></thead>
<tr><th>{str tag="feedback" section="view"}</th></tr> <tbody>
</thead> {$feedback->tablerows}
</tbody>
</table> </table>
</div> {$feedback->pagination}
<div id="viewmenu"> <div id="viewmenu">
{include file="view/viewmenu.tpl"} {include file="view/viewmenu.tpl"}
</div> </div>
<div>{$addfeedbackform}</div> <div>{$addfeedbackform}</div>
<div>{$objectionform}</div> <div>{$objectionform}</div>
</div>
{include file="footer.tpl"} {include file="footer.tpl"}
{foreach from=$data item=item}
<tr class="{cycle name=rows values='r0,r1'}">
<td>
{$item->message}
{if $item->attachmessage}<div>{$item->attachmessage}</div>{/if}
<div class="details">
{if $item->author}
<div class="icon"><a href="{$WWWROOT}user/view.php?id={$item->author|escape}">
<img src="{$WWWROOT}thumb.php?type=profileicon&id={$item->author|escape}&maxsize=20" valign="middle" alt="{$item->author|display_name}">
</a></div>
<a href="{$WWWROOT}user/view.php?id={$item->author|escape}">{$item->author|display_name}</a>
{else}
{$item->authorname|escape}
{/if}
| {$item->date|escape}
{if $item->pubmessage}
| {$item->pubmessage|escape}{if $item->makeprivateform}{$item->makeprivateform}{/if}
{/if}
{if $item->attachid}
| {str tag=attachment section=view}: <a href="{$WWWROOT}artefact/file/download.php?file={$item->attachid}">{$item->attachtitle|escape}</a> ({$item->attachsize|escape})
{/if}
</div>
</td>
</tr>
{/foreach}
...@@ -17,7 +17,11 @@ ...@@ -17,7 +17,11 @@
<div>{$releaseform}</div> <div>{$releaseform}</div>
<table id="feedbacktable" class="fullwidth table"> <table id="feedbacktable" class="fullwidth table">
<thead><tr><th>{str tag="feedback" section="view"}</th></tr></thead> <thead><tr><th>{str tag="feedback" section="view"}</th></tr></thead>
<tbody>
{$feedback->tablerows}
</tbody>
</table> </table>
{$feedback->pagination}
<div id="viewmenu"> <div id="viewmenu">
{include file="view/viewmenu.tpl"} {include file="view/viewmenu.tpl"}
</div> </div>
......
...@@ -47,9 +47,18 @@ if (!artefact_in_view($artefactid, $viewid)) { ...@@ -47,9 +47,18 @@ if (!artefact_in_view($artefactid, $viewid)) {
throw new AccessDeniedException("Artefact $artefactid not in View $viewid"); throw new AccessDeniedException("Artefact $artefactid not in View $viewid");
} }
// Feedback list pagination requires limit/offset params
$limit = param_integer('limit', 10);
$offset = param_integer('offset', 0);
require_once(get_config('docroot') . 'artefact/lib.php'); require_once(get_config('docroot') . 'artefact/lib.php');
$artefact = artefact_instance_from_id($artefactid); $artefact = artefact_instance_from_id($artefactid);
// Create the "make feedback private form" now if it's been submitted
if (param_variable('make_private_submit', null)) {
pieform(make_private_form(param_integer('feedback')));
}
if (!$artefact->in_view_list()) { if (!$artefact->in_view_list()) {
throw new AccessDeniedException("Artefacts of this type are only viewable within a View"); throw new AccessDeniedException("Artefacts of this type are only viewable within a View");
} }
...@@ -90,18 +99,21 @@ $artefactpath[] = array( ...@@ -90,18 +99,21 @@ $artefactpath[] = array(
// Feedback // Feedback
$feedback = $artefact->get_feedback($limit, $offset, $viewid);
build_feedback_html($feedback);
$javascript = <<<EOF $javascript = <<<EOF
feedbacklist.view = {$viewid}; var viewid = {$viewid};
feedbacklist.artefact = {$artefactid}; addLoadEvent(function () {
feedbacklist.statevars.push('view', 'artefact'); paginator = {$feedback->pagination_js}
feedbacklist.updateOnLoad(); });
EOF; EOF;
$feedbackform = pieform(add_feedback_form(false)); $feedbackform = pieform(add_feedback_form(false));
$objectionform = pieform(objection_form()); $objectionform = pieform(objection_form());
$smarty = smarty( $smarty = smarty(
array('mahara', 'tablerenderer', 'feedbacklist'), array('paginator', 'feedbacklist'),
array('<link rel="stylesheet" type="text/css" href="' . get_config('wwwroot') . 'theme/views.css">'), array('<link rel="stylesheet" type="text/css" href="' . get_config('wwwroot') . 'theme/views.css">'),
array(), array(),
array( array(
...@@ -116,6 +128,7 @@ $smarty->assign('INLINEJAVASCRIPT', $javascript); ...@@ -116,6 +128,7 @@ $smarty->assign('INLINEJAVASCRIPT', $javascript);
$smarty->assign('viewid', $viewid); $smarty->assign('viewid', $viewid);
$smarty->assign('viewtitle', $view->get('title')); $smarty->assign('viewtitle', $view->get('title'));
$smarty->assign('feedback', $feedback);
$viewowner = $view->get('owner'); $viewowner = $view->get('owner');
if ($viewowner) { if ($viewowner) {
......
...@@ -26,36 +26,27 @@ ...@@ -26,36 +26,27 @@
*/ */
define('INTERNAL', 1); define('INTERNAL', 1);
define('PUBLIC', 1);
define('JSON', 1); define('JSON', 1);
require(dirname(dirname(__FILE__)) . '/init.php'); require(dirname(dirname(__FILE__)) . '/init.php');
$extradata = json_decode(param_variable('extradata'));
json_headers(); if (!can_view_view($extradata->view)) {
json_reply('local', get_string('noaccesstoview', 'view'));
$data = new StdClass;
$data->view = param_integer('view');
$data->artefact = param_integer('artefact', null);
$data->message = param_variable('message');
$data->public = param_boolean('public') ? 1 : 0;
$data->attachment = param_integer('attachment', null);
$data->author = $USER->get('id');
$data->ctime = db_format_timestamp(time());
if ($data->artefact) {
$table = 'artefact_feedback';
} }
else { if (!artefact_in_view($extradata->artefact, $extradata->view)) {
$table = 'view_feedback'; json_reply('local', get_string('accessdenied', 'error'));
} }
if (!insert_record($table, $data, 'id', true)) { $limit = param_integer('limit', 10);
json_reply('local', get_string('addfeedbackfailed', 'view')); $offset = param_integer('offset', 0);
}