Commit 093f298d authored by Robert Lyon's avatar Robert Lyon

Bug 1409546: Add annotation to view via click on matrix point

When clicking on the 'dot' on the Smart evidence frame work we can add
an annotation to the view relating to the standard

Change-Id: Iab2f55c325c4e4d0dea52c915eb04da9933bd7df
Signed-off-by: Robert Lyon's avatarRobert Lyon <robertl@catalyst.net.nz>
parent d2bcc198
......@@ -21,3 +21,5 @@ $string['errorbadmatrixname'] = 'Unable to find the matrix file';
$string['changeframeworkproblems'] = 'You cannot change the framework. The following pages have evidence connected with them:';
$string['accessdeniednoviews'] = 'You need to add some pages to your collection.';
$string['noframeworkselected'] = 'None';
$string['matrixpointupdated'] = "SmartEvidence updated";
$string['matrixpointinserted'] = "SmartEvidence added";
......@@ -193,7 +193,7 @@ class Framework {
$standards = get_column('framework_standard', 'id', 'framework', $this->id);
db_begin();
delete_records('framework_evidence', 'framework', $this->id);
delete_records_sql('DELETE FROM {framework_standard_element} WHERE standard IN (' . join(',', array_map('intval', $standards)) . ')');
delete_records('framework_standard', 'framework', $this->id);
delete_records('framework', 'id', $this->id);
......@@ -435,6 +435,84 @@ class Framework {
return $outcomes;
}
public static function annotation_config_form($data) {
require_once(get_config('docroot') . 'blocktype/lib.php');
if (empty($data->annotation)) {
// Find out how many blocks already exist for the view.
$maxorder = get_field_sql(
'SELECT MAX("order") FROM {block_instance} WHERE "view"=? AND "row"=? AND "column"=?',
array($data->view, 1, 1)
);
// Create the block at the end of the cell.
$annotation = new BlockInstance(0, array(
'blocktype' => 'annotation',
'title' => get_string('Annotation', 'artefact.annotation'),
'view' => $data->view,
'row' => 1,
'column' => 1,
'order' => $maxorder + 1,
));
$annotation->commit();
$new = true;
}
else {
$annotation = new BlockInstance($data->annotation);
$new = false;
}
$title = $annotation->get_title();
list($content, $js, $css) = array_values($annotation->build_configure_form($new));
$return = array(
'content' => $content,
'js' => $js,
'css' => $css,
'title' => $title,
'isnew' => $new
);
return $return;
}
/**
* Save evidence
* @param string $id Framework_evidence id
* @param string $framework Framework id }
* @param string $element Framework_standard_element id } A unique grouping
* @param string $view View id }
* @param string $annotation Annotation block id (not artefact id)
* @param string $state Either 'begun', 'ready', 'completed'
* @param string $reviewer The user marking the evidence as completed
*/
public static function save_evidence($id = null, $framework = null, $element = null, $view = null, $annotation = null, $state = Self::EVIDENCE_BEGUN, $reviewer = null) {
// need to check we have at least one indicator of uniqueness
$uniqueness = false;
if (!empty($id)) {
$uniqueness = true;
}
else if (!empty($framework) && !empty($element) && !empty($view)) {
$uniqueness = true;
}
if (!$uniqueness) {
throw new SQLException('No unique identifier supplied');
}
$fordb = array('mtime' => db_format_timestamp(time()),
'annotation' => $annotation,
'state' => $state);
if ($id) {
// update row
update_record('framework_evidence', (object) $fordb, (object) array('id' => $id));
}
else {
// insert
$fordb['view'] = $view;
$fordb['element'] = $element;
$fordb['framework'] = $framework;
$fordb['ctime'] = db_format_timestamp(time());
$id = insert_record('framework_evidence', (object) $fordb, 'id', true);
}
return $id;
}
}
class FrameworkNotFoundException extends NotFoundException {}
......@@ -51,13 +51,13 @@ if (!can_view_view($view->get('id'))) {
$errorstr = get_string('accessdenied', 'error');
throw new AccessDeniedException($errorstr);
}
$framework = new Framework($collection->get('framework'));
$frameworkid = $collection->get('framework');
$framework = new Framework($frameworkid);
$standards = $framework->standards();
define('TITLE', $collection->get('name'));
$javascript = array('js/collection-navigation.js');
$javascript = array('js/collection-navigation.js', 'tinymce');
// Set up theme
$viewtheme = $view->get('theme');
......@@ -164,6 +164,89 @@ jQuery(function($) {
carousel_matrix();
}
});
var cellx = celly = 0;
$('#tablematrix td.mid span').on('click', function(e) {
e.preventDefault();
cellx = $(this).closest('td').index();
celly = $(this).closest('tr').index();
var params = {};
params.framework = $frameworkid;
params.view = $(this).data("view");
params.option = $(this).data("option");
sendjsonrequest('matrixpoint.json.php', params, 'POST', function(data) {
dock.show($('#configureblock'), true, false);
var newpagemodal = $('#configureblock');
newpagemodal.find('.blockinstance-header').html(data.data.form.title);
newpagemodal.find('.blockinstance-content').html(data.data.form.content);
deletebutton = newpagemodal.find('.deletebutton');
// Lock focus to the newly opened dialog
deletebutton.focus();
deletebutton.on('click', function(e) {
e.stopPropagation();
e.preventDefault();
if (data.data.form.isnew) {
// need to delete empty annotation on cancel
params.action = 'delete';
params.blockconfig = $('#instconf_blockconfig').val();
editmatrix_update(params);
}
tinyMCE.execCommand('mceRemoveEditor', false, "instconf_text");
dock.hide();
});
cancelbutton = newpagemodal.find('.submitcancel.cancel');
cancelbutton.on('click', function(e) {
e.stopPropagation();
e.preventDefault();
if (data.data.form.isnew) {
params.action = 'delete';
params.blockconfig = $('#instconf_blockconfig').val();
editmatrix_update(params);
}
tinyMCE.execCommand('mceRemoveEditor', false, "instconf_text");
dock.hide();
});
tinyMCE.idCounter=0;
tinyMCE.execCommand('mceAddEditor', false, "instconf_text");
$('#instconf').on('submit', function(se) {
se.preventDefault();
var sdata = $("#instconf :input").serializeArray();
var values = {};
var tags = new Array();
sdata.forEach(function(item, index) {
if (item.name == 'tags[]') {
tags.push(item.value);
}
else {
values[item.name] = item.value;
}
});
values['tags'] = tags.join();
values['framework'] = params.framework;
values['view'] = params.view;
values['option'] = params.option;
values['action'] = 'update';
editmatrix_update(values);
tinyMCE.execCommand('mceRemoveEditor', false, "instconf_text");
dock.hide();
});
});
});
function editmatrix_update(data) {
params = data;
sendjsonrequest('matrixpoint.json.php', params, 'POST', function(results) {
if (results.data.class) {
$('#tablematrix tr:eq(' + celly + ') td:eq(' + cellx + ') span')
.attr('class', results.data.class)
.data('option', results.data.option)
.data('view', results.data.view).empty();
}
});
}
// Setup
carousel_matrix();
......@@ -191,6 +274,5 @@ $smarty->assign('standardscount', $standards['count']);
$smarty->assign('framework', $collection->get('framework'));
$smarty->assign('views', $views['views']);
$smarty->assign('viewcount', $views['count']);
$smarty->assign('totalcompleted', array_sum($completed));
$smarty->display('module:framework:matrix.tpl');
<?php
/**
*
* @package mahara
* @subpackage module-framework
* @author Catalyst IT Ltd
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL version 3 or later
* @copyright For copyright information on Mahara, please see the README file distributed with this software.
*
*/
define('INTERNAL', 1);
define('JSON', 1);
require(dirname(dirname(dirname(__FILE__))) . '/init.php');
safe_require('module', 'framework');
safe_require('artefact', 'annotation');
safe_require('blocktype', 'annotation');
global $USER;
$framework = param_integer('framework');
$option = param_integer('option');
$view = param_integer('view');
$action = param_alphanum('action', 'form');
$evidence = get_record('framework_evidence', 'framework', $framework, 'element', $option, 'view', $view);
if ($action == 'update') {
require_once(get_config('docroot') . 'blocktype/lib.php');
$title = param_alphanumext('title', 'Annotation');
$text = param_variable('text', '');
$allowfeedback = param_boolean('allowfeedback');
$retractable = param_integer('retractable', 0);
$blockid = param_integer('blockconfig', 0);
$tags = param_variable('tags', '');
$tags = explode(',', $tags);
$values = array('title' => $title,
'text' => $text,
'tags' => $tags,
'retractable' => $retractable,
'retractedonload' => 0,
);
$bi = new BlockInstance($blockid);
$values = call_static_method(generate_class_name('blocktype', $bi->get('blocktype')), 'instance_config_save', $values, $bi);
$title = (isset($values['title'])) ? $values['title'] : '';
unset($values['title']);
unset($values['_redrawblocks']);
$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');
}
else {
$id = Framework::save_evidence(null, $framework, $option, $view, $bi->get('id'));
$message = get_string('matrixpointinserted', 'module.framework');
}
$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));
}
if ($action == 'delete') {
// Clean up partial annotation block instance
require_once(get_config('docroot') . 'blocktype/lib.php');
$blockid = param_integer('blockconfig', 0);
$bi = new BlockInstance($blockid);
$bi->delete();
$data = (object) array('class' => false,
'view' => $view,
'option' => $option
);
json_reply(false, array('message' => '', 'data' => $data));
}
else {
$message = null;
$state = ($evidence) ? $evidence->state : -1;
$states = Framework::get_state_array($state);
$params = (object) array(
'framework' => $framework,
'option' => $option,
'view' => $view,
'id' => ($evidence) ? $evidence->id : null,
'annotation' => ($evidence) ? $evidence->annotation : null,
'begun' => $states['begun'],
'incomplete' => $states['incomplete'],
'partialcomplete' => $states['partialcomplete'],
'completed' => $states['completed'],
);
$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
......@@ -426,6 +426,34 @@ class BehatGeneral extends BehatBase {
$this->getSession()->executeScript($jscode);
}
/**
* Click a matrix point by being given a column,row pair
*
* @When I click on the matrix point :matrix_point
* @param string $matrix_point a column,row value
* @throws ElementNotFoundException
* @throws ExpectationException
*/
public function i_click_matrix_point($matrix_point) {
// Check that we have a valid matrix point
$point = explode(',', $matrix_point);
if (empty($point[0]) || empty($point[1]) ||
!is_numeric($point[0]) || !is_numeric($point[1])) {
throw new ExpectationException('"' . $matrix_point . '" is not valid. Needs to be like "3,5"', $this->getSession());
}
// The table container.
$exception = new ElementNotFoundException($this->getSession(), 'text', null, 'Unable to find the point "(' . $matrix_point . ')" in a table with class "tablematrix"');
$xpath = "//table[(contains(concat(' ', normalize-space(@class), ' '), ' tablematrix '))]" .
"/tbody/tr[" . $point[1] . "]/td[" . $point[0] . "]";
$pointnode = $this->find('xpath', $xpath, $exception);
// For some reasons, the Mink function click() and check() do not work
// Using jQuery as a workaround
$jscode = "jQuery(\".tablematrix tr:eq('" . $point[1] . "') td:eq('" . $point[0] . "') span\").click();";
$this->getSession()->executeScript($jscode);
}
/**
* Click on the delete button inside a list/table row containing the specified text.
*
......
......@@ -40,27 +40,41 @@
<td class="code"><div>{$option->shortname} <span class="hidden matrixtooltip">{$option->name}<br>{$option->description}</span></div></td>
<td>{if $completed[$option->id]}{$completed[$option->id]}{else}0{/if}</td>
{foreach from=$views key=vk item=view}
<td class="mid">{if $evidence[$framework][$option->id][$view->id].completed}
<span class="icon icon-circle completed"></span>
<td class="mid"><span data-view="{$view->id}" data-option="{$option->id}"
{if $evidence[$framework][$option->id][$view->id].completed}
class="icon icon-circle completed">
{elseif $evidence[$framework][$option->id][$view->id].partialcomplete}
<span class="icon icon-adjust partial"></span>
class="icon icon-adjust partial">
{elseif $evidence[$framework][$option->id][$view->id].incomplete}
<span class="icon icon-circle-o incomplete"></span>
class="icon icon-circle-o incomplete">
{elseif $evidence[$framework][$option->id][$view->id].begun}
<span class="icon icon-circle-o begun"></span>
class="icon icon-circle-o begun">
{else}
<span>&bull;</span>
>&bull;
{/if}
</span>
</td>
{/foreach}
</tr>
{/foreach}
{/if}
{/foreach}
<tr>
<td>{str tag="taskscompleted" section="module.framework"}</td>
<td>{$totalcompleted}</td>
<td colspan="{$viewcount}">&nbsp;</td>
</tr>
</table>
<div role="dialog" id="configureblock" class="modal modal-shown modal-docked-right modal-docked closed blockinstance configure">
<div class="modal-dialog modal-lg">
<div data-height=".modal-body" class="modal-content">
<div class="modal-header">
<button name="close_configuration" class="deletebutton close">
<span class="times">×</span>
<span class="sr-only">Close configuration</span>
</button>
<h4 class="modal-title blockinstance-header text-inline"></h4>
<span aria-hidden="true" role="presentation" class="icon icon-cogs icon-2x pull-right"></span>
</div>
<div class="modal-body blockinstance-content">
</div>
</div>
</div>
</div>
{include file="footer.tpl"}
\ No newline at end of file
......@@ -17,6 +17,7 @@
vertical-align: middle;
span {
cursor: pointer;
&.begun {
color: #5b9aa9;
}
......
......@@ -59,3 +59,12 @@ Scenario: Installing framework module and activating for an institution
Then I should see "PageF"
And I press "Prev" in the "table#tablematrix" "css_element"
Then I should not see "PageF"
# Click on a matrix point to add an annotation
And I click on the matrix point "3,5"
And I wait "1" seconds
And I set the following fields to these values:
| Annotation | My two cents |
And I press "Save"
And I go to portfolio page "PageB"
Then I should see "Annotation"
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