Commit eb3ec9c1 authored by Robert Lyon's avatar Robert Lyon

Bug 1409546: Annotation feedback on form

When you click on the hollow circle (rather than dot) on the matrix
screen you will get an annotation feedback form in the modal dock
rather than the create annotation form.

Change-Id: Id9c73a2a3a379b2700c4196726a50179be81974f
Signed-off-by: Robert Lyon's avatarRobert Lyon <robertl@catalyst.net.nz>
parent bc2ad0c5
......@@ -112,3 +112,4 @@ $string['private'] = 'Private';
$string['public'] = 'Public';
$string['enteredon'] = 'entered on';
$string['noreflectionentryfound'] = "Cannot find reflection entry for annotation.";
$string['nofeedback'] = "There is no feedback for this annotation yet.";
\ No newline at end of file
This diff is collapsed.
......@@ -27,3 +27,9 @@ $string['standard'] = 'Standard';
$string['standarddesc'] = 'Select the standard this evidence addresses. You can type into the box to search the standards.';
$string['annotationclash'] = 'There is already an annotation block on the page for this standard';
$string['needtoactivate'] = 'The annotation plugin needs activation. Please ask your site administrator to activate it.';
$string['studentannotation'] = "Annotation:";
$string['assessment'] = 'Assessment';
$string['begun'] = 'Ready for assessment';
$string['incomplete'] = 'Doesn\'t meet the standard';
$string['partialcomplete'] = 'Partially meets the standard';
$string['completed'] = 'Meets the standard';
......@@ -383,10 +383,10 @@ class Framework {
*/
public static function get_state_array($state) {
return array(
'begun' => ((int) $state === Self::EVIDENCE_BEGUN),
'incomplete' => ((int) $state === Self::EVIDENCE_INCOMPLETE),
'partialcomplete' => ((int) $state === Self::EVIDENCE_PARTIALCOMPLETE),
'completed' => ((int) $state === Self::EVIDENCE_COMPLETED),
'begun' => ((int) $state === Self::EVIDENCE_BEGUN ? 1 : 0),
'incomplete' => ((int) $state === Self::EVIDENCE_INCOMPLETE ? 1 : 0),
'partialcomplete' => ((int) $state === Self::EVIDENCE_PARTIALCOMPLETE ? 1 : 0),
'completed' => ((int) $state === Self::EVIDENCE_COMPLETED ? 1 : 0),
);
}
......@@ -424,7 +424,8 @@ class Framework {
}
/**
* Get the evidence state for the framework
* Add/update an annotation block on a view via the framework matrix page.
* This hooks into using the annotation block's config form.
*
* @param int $annotationid
*
......@@ -514,6 +515,7 @@ class Framework {
if (!empty($element)) {
$fordb['element'] = $element;
}
$fordb['reviewer'] = ($completed === 1) ? $reviewer : null;
update_record('framework_evidence', (object) $fordb, (object) array('id' => $id));
}
else {
......@@ -569,6 +571,77 @@ class Framework {
}
}
}
/**
* Add/update an annotation status form on the framework matrix page.
* This uses a feedback style config form with some extra bits.
*/
public function annotation_feedback_form($data) {
require_once(get_config('docroot') . 'blocktype/lib.php');
$annotation = new BlockInstance($data->annotation);
$configdata = $annotation->get('configdata');
if (empty($configdata['artefactid'])) {
return false;
}
safe_require('artefact', 'file');
$artefactid = $configdata['artefactid'];
$artefact = $annotation->get_artefact_instance($artefactid);
$view = $annotation->get_view();
$text = $artefact->get('description');
$collection = $view->get('collection');
$evidence = get_record('framework_evidence', 'annotation', $annotation->get('id'));
if (!is_object($collection) || !$collection->get('framework')) {
return false;
}
$form = array(
'name' => 'annotationfeedback',
'jsform' => true,
'renderer' => 'div',
'plugintype' => 'module',
'pluginname' => 'framework',
'jssuccesscallback' => 'updateAnnotation',
'elements' => array(
'annotation' => array(
'type' => 'html',
'title' => get_string('studentannotation', 'module.framework'),
'value' => $text,
),
'assessment' => array(
'type' => 'select',
'title' => get_string('assessment', 'module.framework'),
'options' => array(
'0' => get_string('begun','module.framework'),
'1' => get_string('incomplete','module.framework'),
'2' => get_string('partialcomplete','module.framework'),
'3' => get_string('completed','module.framework'),
),
'defaultvalue' => $evidence->state,
'width' => '280px',
'class' => 'top-line',
),
'submitcancel' => array(
'type' => 'submitcancel',
'class' => 'btn-default',
'value' => array(get_string('save'), get_string('cancel')),
'goto' => get_string('docroot') . 'module/framework/matrix.php?id=' . $collection->get('id'),
),
),
);
$content = pieform($form);
list($feedbackcount, $annotationfeedback) = ArtefactTypeAnnotationfeedback::get_annotation_feedback_for_matrix($artefact, $view, $annotation->get('id'));
$content .= $annotationfeedback;
$return = array(
'content' => $content,
'js' => 'function updateAnnotation(form, data) { formSuccess(form, data); }',
'css' => '',
'title' => $annotation->get_title(),
);
return $return;
}
}
class FrameworkNotFoundException extends NotFoundException {}
......@@ -194,6 +194,10 @@ jQuery(function($) {
editmatrix_update(params);
}
tinyMCE.execCommand('mceRemoveEditor', false, "instconf_text");
feedbacktextarea = $("#addfeedbackmatrix textarea");
if (feedbacktextarea.length) {
tinyMCE.execCommand('mceRemoveEditor', false, feedbacktextarea.attr('id'));
}
dock.hide();
});
cancelbutton = newpagemodal.find('.submitcancel.cancel');
......@@ -206,10 +210,20 @@ jQuery(function($) {
editmatrix_update(params);
}
tinyMCE.execCommand('mceRemoveEditor', false, "instconf_text");
feedbacktextarea = $("#addfeedbackmatrix textarea");
if (feedbacktextarea.length) {
tinyMCE.execCommand('mceRemoveEditor', false, feedbacktextarea.attr('id'));
}
dock.hide();
});
tinyMCE.idCounter=0;
tinyMCE.execCommand('mceAddEditor', false, "instconf_text");
if ($("#instconf_text").length) {
tinyMCE.execCommand('mceAddEditor', false, "instconf_text");
}
if ($("#addfeedbackmatrix").length) {
textareaid = $("#addfeedbackmatrix textarea").attr('id');
tinyMCE.execCommand('mceAddEditor', false, textareaid);
}
// Only allow the point selected to be active in the 'Standard' dropdown
$("#instconf_smartevidence option:not(:selected)").prop('disabled', true);
$("#instconf_smartevidence").select2();
......@@ -223,7 +237,7 @@ jQuery(function($) {
$("#instconf_smartevidence").on('change', function() {
show_se_desc($(this).val());
});
// When we are saving the annotation block config form
$('#instconf').on('submit', function(se) {
se.preventDefault();
var sdata = $("#instconf :input").serializeArray();
......@@ -243,9 +257,48 @@ jQuery(function($) {
values['option'] = params.option;
values['action'] = 'update';
editmatrix_update(values);
dock.hide();
});
// When we are saving the annotation feedback form - changing the evidence status
$('#annotationfeedback').on('submit', function(se) {
se.preventDefault();
var sdata = $("#annotationfeedback :input").serializeArray();
var values = {};
sdata.forEach(function(item, index) {
values[item.name] = item.value;
});
values['framework'] = params.framework;
values['view'] = params.view;
values['option'] = params.option;
values['action'] = 'evidence';
editmatrix_update(values);
tinyMCE.execCommand('mceRemoveEditor', false, "instconf_text");
dock.hide();
});
// When we are saving the annotation feedback form - adding new feedback
$('#addfeedbackmatrix').on('submit', function(se) {
se.preventDefault();
var sdata = $("#addfeedbackmatrix :input").serializeArray();
var values = {};
sdata.forEach(function(item, index) {
values[item.name] = item.value;
});
textareaid = $("#addfeedbackmatrix textarea").attr('id');
if (values['message'].length == 0) {
// add error message
$("#" + textareaid).parent().append('<div class="errmsg"><span>' +
get_string_ajax('annotationfeedbackempty', 'artefact.annotation') +
'</span></div>');
}
else {
values['framework'] = params.framework;
values['view'] = params.view;
values['option'] = params.option;
values['action'] = 'feedback';
editmatrix_update(values);
}
});
});
});
......@@ -258,6 +311,14 @@ jQuery(function($) {
.data('option', results.data.option)
.data('view', results.data.view).empty();
}
if (results.data.tablerows) {
if ($("#matrixfeedbacklist").has(".annotationfeedbacktable").length == 0) {
$("#matrixfeedbacklist").html('<ul class="annotationfeedbacktable list-group list-group-lite list-unstyled"></div>');
}
$("#matrixfeedbacklist .annotationfeedbacktable").html(results.data.tablerows);
textareaid = $("#addfeedbackmatrix textarea").attr('id');
tinyMCE.get(textareaid).setContent('');
}
});
}
// Setup
......
......@@ -31,6 +31,7 @@ $action = param_alphanum('action', 'form');
$evidence = get_record('framework_evidence', 'framework', $framework, 'element', $option, 'view', $view);
if ($action == 'update') {
// When we click a dot on the matrix and add an annotation
require_once(get_config('docroot') . 'blocktype/lib.php');
$title = param_alphanumext('title', 'Annotation');
$text = param_variable('text', '');
......@@ -42,6 +43,7 @@ if ($action == 'update') {
$values = array('title' => $title,
'text' => $text,
'tags' => $tags,
'allowfeedback' => $allowfeedback,
'retractable' => $retractable,
'retractedonload' => 0,
);
......@@ -55,6 +57,7 @@ if ($action == 'update') {
$bi->set('configdata', $values);
$bi->set('title', $title);
$bi->commit();
if ($evidence) {
$id = Framework::save_evidence($evidence->id, null, null, null, $bi->get('id'));
$message = get_string('matrixpointupdated', 'module.framework');
......@@ -65,6 +68,46 @@ if ($action == 'update') {
}
$class = 'icon icon-circle-o danger';
$data = (object) array('id' => $id,
'class' => $class,
'view' => $view,
'option' => $option
);
json_reply(false, array('message' => $message, 'data' => $data));
}
else if ($action == 'evidence') {
global $USER;
// When we click on one of the begun/ready/completed symbols and submit that form
if (!$evidence->id) {
// problem need to return error
}
$begun = $ready = $completed = 0;
$reviewer = null;
$assessment = param_alpha('assessment', 'begun');
switch ($assessment) {
case 'completed':
$begun = $ready = $completed = 1;
$reviewer = $USER->get('id');
break;
case 'ready':
$begun = $ready = 1;
break;
default:
$begun = 1;
}
$id = Framework::save_evidence($evidence->id, null, null, null, $evidence->annotation, $assessment, $USER->get('id'));
$message = get_string('matrixpointupdated', 'module.framework');
if ($completed) {
$class = 'icon icon-circle success';
}
else if ($ready) {
$class = 'icon icon-adjust warning';
}
else {
$class = 'icon icon-circle-o danger';
}
$data = (object) array('id' => $id,
'class' => $class,
......@@ -73,7 +116,20 @@ if ($action == 'update') {
);
json_reply(false, array('message' => $message, 'data' => $data));
}
if ($action == 'delete') {
else if ($action == 'feedback') {
$annotationid = param_integer('annotationid');
$annotation = new ArtefactTypeAnnotation((int) $annotationid);
$blockid = param_integer('blockid');
$message = param_variable('message');
$ispublic = param_boolean('ispublic');
require_once(get_config('libroot') . 'view.php');
$view = new View($view);
$newlist = ArtefactTypeAnnotationfeedback::save_matrix_feedback($annotation, $view, $blockid, $message, $ispublic);
$message = get_string('annotationfeedbacksubmitted', 'artefact.annotation');
$data = (object) array('id' => $evidence->id, 'tablerows' => $newlist);
json_reply(false, array('message' => $message, 'data' => $data));
}
else if ($action == 'delete') {
// Clean up partial annotation block instance
require_once(get_config('docroot') . 'blocktype/lib.php');
$blockid = param_integer('blockconfig', 0);
......@@ -100,7 +156,13 @@ else {
'partialcomplete' => $states['partialcomplete'],
'completed' => $states['completed'],
);
$form = Framework::annotation_config_form($params);
if ($evidence && !empty($params->begun)) {
// There is an annotation in play
$form = Framework::annotation_feedback_form($params);
}
else {
$form = Framework::annotation_config_form($params);
}
$data = (object) array('form' => $form);
json_reply(false, (object) array('message' => $message, 'data' => $data));
}
\ No newline at end of file
<div id="annotationfeedback_{$blockid}" class="annotation-feedback matrix">
<div class="modal-header modal-section">
{str tag="Annotationfeedback" section="artefact.annotation"}
</div>
{if $addannotationfeedbackform}
<div id="addfeedbackmatrix">
{str tag="placeannotationfeedback" section="artefact.annotation"}
{$addannotationfeedbackform|safe}
</div>
{/if}
<div id="matrixfeedbacklist">
{if $annotationfeedbackcount}
<ul id="annotationfeedbacktable_{$blockid}" class="annotationfeedbacktable list-group list-group-lite list-unstyled">
{$annotationfeedback->tablerows|safe}
</ul>
{else}
<div class="form-group"><span class="description">{str tag='nofeedback' section='artefact.annotation'}</span></div>
{/if}
</div>
</div>
......@@ -48,6 +48,11 @@ $width-sm: 90%;
.list-group.flush {
margin: -15px;
}
.matrix {
.list-group {
margin: 0 -15px;
}
}
&.blockinstance-content {
padding: 0 15px;
}
......@@ -151,6 +156,9 @@ $width-sm: 90%;
h4, a {
color: #fff;
}
&.modal-section {
margin: 10px -15px;
}
.close {
@include box-shadow(-2px 0px 2px rgba(0,0,0,0.3));
border-radius:3px 0 0 3px;
......
......@@ -546,6 +546,10 @@
}
}
}
&.top-line {
border-top: 1px solid #f0f0f0;
}
}
.panel .form-group-nested {
......
......@@ -79,3 +79,15 @@ Scenario: Installing framework module and activating for an institution
| Annotation | My three cents |
And I set the select2 value "1.1 one point one" for "instconf_smartevidence"
And I press "Save"
# Re-click a matrix point to add some feedback
And I choose "Collections" in "Portfolio"
And I follow "CollA"
And I click on the matrix point "3,5"
And I wait "1" seconds
And I set the following fields to these values:
| Feedback | This is annotation feedback |
And I press "Place feedback"
# And change assessment status
And I select "Partially meets the standard" from "Assessment"
And I press "Save"
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