Commit e0ef8d40 authored by mathieso's avatar mathieso

FiB give up button, confirm suggestion cancel, other things.

parent 3ebaacc7
......@@ -12631,6 +12631,12 @@ Object.defineProperty(__webpack_exports__, "__esModule", { value: true });
//
//
//
//
//
//
//
//
//
var rowClickedOn;
......@@ -12721,8 +12727,7 @@ __WEBPACK_IMPORTED_MODULE_0_vue__["a" /* default */].use(__WEBPACK_IMPORTED_MODU
graderTypedKey: false
};
},
// computed: {
// },
computed: {},
methods: {
graderTypedKeyboardKey() {
......@@ -12797,18 +12802,36 @@ __WEBPACK_IMPORTED_MODULE_0_vue__["a" /* default */].use(__WEBPACK_IMPORTED_MODU
* @param submissionId Submission id the send is for.
*/
appSendMessageClicked(submissionId) {
// console.log("appSendMessageClicked run");
let submissionRow = $('td#submission' + submissionId).closest('tr');
this.$nextTick(() => {
this.$forceUpdate();
});
// this.$forceUpdate();
},
submissionGraded(submissionId) {
// console.log("submissionGraded start, sub id:", submissionId);
let result;
if (submissionId === 0) {
//Initial state. Grader hasn't begun work.
return false;
result = false;
} else {
result = window.submissions[submissionId].feedbackDate !== '';
}
// console.log('submissionGraded result: ', result);
return result;
},
submissionRowClass(submissionId) {
// console.log("submissionRowClass run");
if (submissionId === 0) {
//Initial state. Grader hasn't begun work.
return '';
}
// console.log('submissionGraded: submissionId', submissionId);
return window.submissions[submissionId].feedbackDate !== '';
const graded = window.submissions[submissionId].feedbackDate !== '';
// console.log('submissionRowClass: ', graded);
const classToUse = graded ? "submission-graded" : "rosie";
// console.log("classToUse ", classToUse);
return classToUse;
}
},
mounted() {
......@@ -12993,12 +13016,16 @@ Object.defineProperty(__webpack_exports__, "__esModule", { value: true });
},
methods: {
setEnabledStateCK() {
//If submission is graded, CK instance is read-only.
let ckInstance = this.$refs.cycoFeedbackContent.instance;
//Prevent errors first time through.
if (!ckInstance || ckInstance === undefined) {
if (this.$refs.cycoFeedbackContent === undefined || this.$refs.cycoFeedbackContent.instance === undefined) {
return;
}
//If submission is graded, CK instance is read-only.
let ckInstance = this.$refs.cycoFeedbackContent.instance;
//Prevent errors first time through.
// if (!ckInstance || ckInstance === undefined ) {
// return;
// }
//Delayed execution - ckeditor must be properly initialized before setting readonly
//https://stackoverflow.com/questions/18391556/setreadonly-causes-error-when-called-on-instanceready-of-ckeditor
//Yes - this is slimy, but it works.
......@@ -13971,9 +13998,6 @@ Object.defineProperty(__webpack_exports__, "__esModule", { value: true });
//
//
//
//
//
//
// var thisOverallEvalClicked = '';
// var thisCreateMessage = '';
......@@ -30934,17 +30958,17 @@ module.exports={render:function (){var _vm=this;var _h=_vm.$createElement;var _c
scopedSlots: _vm._u([{
key: "table-row",
fn: function(props) {
return [_c('td', {
class: {
'submission-graded': _vm.submissionGraded(props.row.submissionId)
},
return [(_vm.submissionGraded(props.row.submissionId)) ? _c('td', {
staticClass: "submission-graded",
attrs: {
"id": 'submission' + props.row.submissionId
}
}, [_vm._v(_vm._s(props.row.when))]), _vm._v(" "), _c('td', {
class: {
'submission-graded': _vm.submissionGraded(props.row.submissionId)
}, [_vm._v(_vm._s(props.row.when))]) : _c('td', {
attrs: {
"id": 'submission' + props.row.submissionId
}
}, [_vm._v(_vm._s(props.row.when))]), _vm._v(" "), _c('td', {
class: _vm.submissionRowClass(props.row.submissionId)
}, [_vm._v(_vm._s(props.row.name))]), _vm._v(" "), _c('td', {
class: {
'submission-graded': _vm.submissionGraded(props.row.submissionId)
......
This diff is collapsed.
......@@ -11,10 +11,16 @@
<template slot="table-row"
scope="props">
<!--<td>{{ props.row.submissionId }}</td>-->
<td :id="'submission' + props.row.submissionId"
:class="{ 'submission-graded': submissionGraded(props.row.submissionId) }"
<td v-if="submissionGraded(props.row.submissionId)" :id="'submission' + props.row.submissionId"
class="submission-graded"
>{{ props.row.when }}</td>
<td v-else :id="'submission' + props.row.submissionId"
>{{ props.row.when }}</td>
<td :class="{ 'submission-graded': submissionGraded(props.row.submissionId) }"
<!-- <td :id="'submission' + props.row.submissionId"-->
<!-- :class="`${submissionGraded(props.row.submissionId) ? 'submission-graded' : 'buttz'}`"-->
<!-- >{{ props.row.when }}</td>-->
<td :class="submissionRowClass(props.row.submissionId)"
>{{ props.row.name }}</td>
<td :data-exercise-id="props.row.eid"
:class="{ 'submission-graded': submissionGraded(props.row.submissionId) }"
......@@ -177,8 +183,8 @@
graderTypedKey:false,
};
},
// computed: {
// },
computed: {
},
methods: {
graderTypedKeyboardKey(){
......@@ -257,18 +263,37 @@
* @param submissionId Submission id the send is for.
*/
appSendMessageClicked(submissionId) {
// console.log("appSendMessageClicked run");
let submissionRow = $('td#submission' + submissionId).closest('tr');
this.$nextTick( () => {
this.$forceUpdate();
});
// this.$forceUpdate();
},
submissionGraded(submissionId){
// console.log("submissionGraded start, sub id:", submissionId);
let result;
if ( submissionId === 0 ) {
//Initial state. Grader hasn't begun work.
result = false;
}
else {
result = (window.submissions[submissionId].feedbackDate !== '');
}
// console.log('submissionGraded result: ', result);
return result;
},
submissionRowClass(submissionId){
// console.log("submissionRowClass run");
if ( submissionId === 0 ) {
//Initial state. Grader hasn't begun work.
return false;
return '';
}
// console.log('submissionGraded: submissionId', submissionId);
return (window.submissions[submissionId].feedbackDate !== '');
const graded = (window.submissions[submissionId].feedbackDate !== '');
// console.log('submissionRowClass: ', graded);
const classToUse = graded ? "submission-graded" : "rosie";
// console.log("classToUse ", classToUse);
return classToUse;
},
},
mounted() {
......
......@@ -84,12 +84,16 @@
},
methods: {
setEnabledStateCK(){
//If submission is graded, CK instance is read-only.
let ckInstance = this.$refs.cycoFeedbackContent.instance;
//Prevent errors first time through.
if (!ckInstance || ckInstance === undefined ) {
if (this.$refs.cycoFeedbackContent === undefined || this.$refs.cycoFeedbackContent.instance === undefined) {
return;
}
//If submission is graded, CK instance is read-only.
let ckInstance = this.$refs.cycoFeedbackContent.instance;
//Prevent errors first time through.
// if (!ckInstance || ckInstance === undefined ) {
// return;
// }
//Delayed execution - ckeditor must be properly initialized before setting readonly
//https://stackoverflow.com/questions/18391556/setreadonly-causes-error-when-called-on-instanceready-of-ckeditor
//Yes - this is slimy, but it works.
......
......@@ -67,9 +67,6 @@
>Override
</button>
</div>
</div>
<div class="cp-row feedback-button-row"> <!-- CP third line -->
......@@ -98,7 +95,7 @@
style="position: absolute; right: 8px; display: none;"
>
</div> <!-- End CP line 2 -->
</div> <!-- End CP line 3 -->
</div> <!-- End CP -->
<div class="section-fluid" id="anchor-jump-list-targets" style="overflow-y:auto;"> <!-- Start rubric item list -->
<!--<div class="row"> &lt;!&ndash; CP line 1 &ndash;&gt;-->
......
......@@ -5,7 +5,7 @@
"use strict";
Drupal.skillingSettings.setupFibs = false;
// Flag to show when saving, used to disable processing another click.
Drupal.skillingSettings.savingFibResponse = false;
Drupal.skillingSettings.interactingWithServer = false;
Drupal.behaviors.skillingFibCheckAnswer = {
/**
* What is checked? text, number, or none.
......@@ -17,10 +17,14 @@
}
Drupal.skillingSettings.setupFibs = true;
$(document).ready(function () {
$(".skilling-insert-fib-response-container button").click(function (event) {
$(".skilling-insert-fib-check-button").click(function (event) {
let $fibQuestionContainer = $($(event.target).closest(".skilling-insert-fib"));
Drupal.behaviors.skillingFibCheckAnswer.checkAnswer($fibQuestionContainer);
});
$(".skilling-insert-fib-give-up-button").click(function (event) {
let $fibQuestionContainer = $($(event.target).closest(".skilling-insert-fib"));
Drupal.behaviors.skillingFibCheckAnswer.giveUp($fibQuestionContainer);
});
$(".skilling-insert-fib-response-container input").keypress(function (event) {
if (event.which === 13) {
event.preventDefault();
......@@ -37,17 +41,17 @@
* The fib element.
*/
checkAnswer: function ($fibQuestionContainer) {
if ( Drupal.skillingSettings.savingFibResponse ) {
if ( Drupal.skillingSettings.interactingWithServer ) {
return;
}
Drupal.skillingSettings.savingFibResponse = true;
Drupal.skillingSettings.interactingWithServer = true;
// Get the answer.
// DOM element the user types his/her answer into.
let answerControl = $fibQuestionContainer.find("input");
let answer = answerControl.val().trim();
// Stop if MT.
if (answer === "") {
Drupal.skillingSettings.savingFibResponse = false;
Drupal.skillingSettings.interactingWithServer = false;
swal(Drupal.t("Sorry, please type an answer."));
$(answerControl).focus().select();
return;
......@@ -104,7 +108,52 @@
swal(message);
})
});
Drupal.skillingSettings.savingFibResponse = false;
Drupal.skillingSettings.interactingWithServer = false;
},
/**
* Give up.
*/
giveUp: function ($fibQuestionContainer) {
if ( Drupal.skillingSettings.interactingWithServer ) {
return;
}
Drupal.skillingSettings.interactingWithServer = true;
// Ask the server for the answer.
let internalName = $fibQuestionContainer.attr("id");
let throbber = $fibQuestionContainer.find(".skilling-throbber");
$(throbber).show();
// Disable the buttons.
$("button.skilling-insert-fib-check-button").attr('disabled',true);
$("button.skilling-insert-fib-give-up-button").attr('disabled',true);
$.ajax({
url: Drupal.url("skilling/fib-give-up"),
type: 'POST',
dataType: 'json',
data: {
"csrfToken": drupalSettings.csrfToken,
"sessionId": drupalSettings.sessionId,
"internalName": internalName
},
success: function (result) {
$(throbber).hide();
if (result.status.toLowerCase() === "error") {
swal(result.errorMessage);
return;
}
// Show it.
$("input.skilling-insert-fib-response").val(result.answer);
},
fail: (function (jqXHR, textStatus) {
$(throbber).hide();
let message = Drupal.t(
"Skilling history FIB give up fail @text. Please send a screen shot of your "
+ "entire browser window, including URL, to someone.",
{'@text': textStatus}
);
swal(message);
})
});
Drupal.skillingSettings.interactingWithServer = false;
}
};
}(jQuery, Drupal));
......@@ -28,7 +28,7 @@ CKEDITOR.addTemplates( 'default', {
{
title: 'Character',
image: 'character.png',
description: 'A face with emotion. <a href="/admin/skilling/characters/choose_grid_character" target="_blank">List</a>',
description: 'A face with emotion. <a href="/admin/skilling/characters-grid" target="_blank">List</a>',
html: 'character.<br>' +
'&nbsp;&nbsp;internal_name=<br>' +
'<br>' +
......
......@@ -24,6 +24,11 @@
textarea.val("");
textarea.focus();
});
$("#cancel-button").click(function(){
if (confirm(Drupal.t("Are you sure you want to forghedaboudit?"))) {
$("#suggestion-modal").modal("hide");
}
});
$("#suggestion-save").click(function() {
let dataToSave = $(textarea).val();
dataToSave = dataToSave.trim();
......
......@@ -11,18 +11,6 @@ X - initial valuies of new config flags and shit.
Module updates
# History
All records owned by nobody?
Submission feedback - put JSON of eval and other things in history record.
Remove JSON field from submission content type.
Need a filter to remove students not in own classes.
Date range filter on reports.
# Permission
......@@ -32,15 +20,6 @@ What do graders see when there is no admin toolbar?
- search in admin toolbar.
# Suggestion
Confirm cancel
# Submission delays - user confidence
When submit, can be slow, tell user that something is happening.
......@@ -48,29 +27,10 @@ When submit, can be slow, tell user that something is happening.
Same for showing the exercise in the first place.
# FiB
Give-up option.
# Subm
Show submit new button when should not abe able to.
Also add check when showing new window.
Give perm to submissions admin view?
Edit submissions.
Does the instructor views access plugin work? Make one for graders and admin too
Add record selection thing?
# FiB
color change after shrink
# Exercises
......@@ -133,6 +93,8 @@ Check progress score computation, and reports for instructor.
# Grading interface
Missing linethrough. CAN'T FIGURE OUT. GIVE UP.
When grader can't see names, what happens generate message containing names?
- Maybe turn off the names thing for now.
......
No preview for this file type
......@@ -618,6 +618,7 @@ views.view.patterns.yml so
views.view.patterns_administration.yml so
views.view.principles.yml so
views.view.principles_administration.yml so
views.view.reflect_notes_for_authors.yml so
views.view.reflect_notes_for_students.yml so
views.view.rubric_items.yml so
views.view.rubric_item_categories.yml so
......@@ -625,6 +626,7 @@ views.view.rubric_items_with_no_categories.yml so
views.view.submissions.yml so
views.view.submissions_administration.yml so
views.view.submissions_administration_for_class.yml so
views.view.submissions_admin_for_class_header.yml so
views.view.suggestions_administration.yml so
views.view.user_details_header_contextual_filter_.yml so
......
......@@ -509,6 +509,15 @@ skilling.check_fib_response:
requirements:
_permission: 'access content'
# Give up on FiB question.
skilling.fib_give_up:
path: '/skilling/fib-give-up'
defaults:
_controller: '\Drupal\skilling\Controller\FibController::giveUp'
methods: [POST]
requirements:
_permission: 'access content'
skilling.save_suggestion:
path: '/skilling/save-suggestion'
defaults:
......
......@@ -1223,6 +1223,8 @@ class AssessmentController extends ControllerBase {
}
} //End for each response option for a rubric item.
}
// What the grader chose on each rubric item.
$rubricItemChoices = json_encode($feedbackData['rubricItemChoices']);
// Filter.
$feedback = $this->filterInputService->filterUserContent($feedback);
// Update the submission.
......@@ -1239,6 +1241,7 @@ class AssessmentController extends ControllerBase {
/* @noinspection PhpUndefinedFieldInspection */
$submissionNode->field_when_feedback_given->value
= $this->dateFormatter->format(time(), 'custom', 'Y-m-d\TH:i:s', 'UTC');
$submissionNode->field_feedback_responses->value = $rubricItemChoices;
$submissionNode->save();
// Add notice.
/** @var \Drupal\node\NodeInterface $exercise */
......
......@@ -285,4 +285,145 @@ class FibController extends ControllerBase {
return new JsonResponse($result);
}
/**
* Check student response.
*
* Expect in request:
* internalName: internal name of the item.
* response: What the user typed.
*
* Return JSON object:
* status: "OK" or "error"
* errorMessage: message to show if there was a problem.
* match: Was there a match?
* responseMessage: Message to show about the response.
*
* @param \Symfony\Component\HttpFoundation\Request $request
* HTTP request.
*
* @return \Symfony\Component\HttpFoundation\JsonResponse
* The JSON response to the client.
*
* @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
* @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
* @throws \Drupal\skilling\Exception\SkillingException
* @throws \Drupal\skilling\Exception\SkillingParserException
* @throws \Drupal\Core\TypedData\Exception\MissingDataException
*/
public function giveUp(Request $request) {
$passedBasicSecurity = $this->ajaxSecurityService->securityCheckAjaxRequest(
$request,
['POST'],
['/skilling/fib-give-up'],
TRUE
);
if (!$passedBasicSecurity) {
throw new AccessDeniedException('Access denied, sec fail in FiB::giveUp');
}
// Get the internal name of the MCQ.
$internalName = $request->get('internalName');
// Filter with Stripping.
$internalName = $this->filterInputService->filterUserContent($internalName);
// Check that FiB with that name exists.
$fibIds = $this->entityTypeManager->getStorage('node')
->getQuery()
// Is FiB.
->condition('type', SkillingConstants::FILL_IN_THE_BLANK_CONTENT_TYPE)
// Has the right internal name.
->condition(SkillingConstants::FIELD_INTERNAL_NAME, $internalName)
->execute();
if (!$fibIds) {
$message = 'Bad internal name: ' . Html::escape($internalName);
return $this->skillingUtilities->formatJsonErrorReport($message);
}
// Have the id of the FiB.
$fibId = reset($fibIds);
// Load the FiB.
/** @var \Drupal\node\NodeInterface $fib */
$fib = $this->entityTypeManager->getStorage('node')->load($fibId);
// Get the user who owns the data.
if (!$fib) {
$message = 'Bad node in FiB::giveUp';
return $this->skillingUtilities->formatJsonErrorReport($message);
}
// Check the user's response.
/* @noinspection PhpUndefinedFieldInspection */
$responses = $fib->field_fib_responses;
/** @var bool $matched Whether found a correct response. */
$matched = FALSE;
$answer = $this->t('Could not find the correct answer.');
foreach ($responses as $response) {
if ($matched) {
break;
}
$responseParagraph = $response->entity;
$responseType = $responseParagraph->field_response_type->value;
// Skip incorrect responses.
$correct = $responseParagraph->field_correct->value ? TRUE : FALSE;
if (!$correct) {
continue;
}
if ($responseType === 'number') {
$minMatchResponse = $responseParagraph->field_lowest_number->value;
// Was a min specified?
if (!$minMatchResponse === '0' && !$minMatchResponse) {
$message = 'Bad min in FiB::checkResponse, fib id:' . Html::escape($fib->id());
return $this->skillingUtilities->formatJsonErrorReport($message);
}
$maxMatchResponse = $responseParagraph->field_highest_number->value;
if (!$maxMatchResponse === '0' && !$maxMatchResponse) {
$message = 'Bad max in FiB::checkResponse, fib id:' . Html::escape($fib->id());
return $this->skillingUtilities->formatJsonErrorReport($message);
}
$answer = $this->t(
'Between @min and @max would be correct',
[
'@min' => $minMatchResponse,
'@max' => $maxMatchResponse,
]
);
// Flag to show answer found.
$matched = TRUE;
} // End responseType is number.
elseif ($responseType === 'text') {
/** @var \Drupal\Core\Field\FieldItemList $matchTextItems */
$matchTextItems = $responseParagraph->field_matching_text_responses;
if ($matchTextItems->count() > 0) {
$answer = $matchTextItems->get(0)->value;
// Flag to show answer found.
$matched = TRUE;
}
}
else {
$message = 'Bad type in FiB::checkResponse: ' . Html::escape($responseType);
return $this->skillingUtilities->formatJsonErrorReport($message);
}
} // End for each response.
if ($this->skillingCurrentUser->isStudent()) {
// Check whether the history module is active.
$isHistoryModuleActive =
$this->moduleHandler->moduleExists(SkillingConstants::HISTORY_MODULE_NAME);
if ($isHistoryModuleActive) {
/** @var \Drupal\skilling_history\History $historyService */
$historyService = \Drupal::service(SkillingConstants::HISTORY_SERVICE_NAME);
// Record the response in history.
try {
$historyService->recordFibAnswer($fibId, $internalName, $this->t('Gave up'));
}
catch (\Exception $e) {
$message = 'Exception FIB history call, FIB nid: ' . Html::escape($fibId)
. $e->getMessage();
return $this->skillingUtilities->formatJsonErrorReport($message);
}
}
}
// Send result of response check to user.
// Response is escaped, maybe should not be, since it comes from authors.
$result = [
'status' => 'OK',
'answer' => $answer,
];
return new JsonResponse($result);
}
}
......@@ -33,10 +33,10 @@ class ContainerTag extends SkillingCustomTagBase {
* HTML.
*/
public function processTag($content = '', array $options = NULL, Node $nodeWithTag = NULL) {
// Is it floatable?
$floatable = $this->findOption(
$options, [SkillingConstants::FLOATABLE]
);
// // Is it floatable?
// $floatable = $this->findOption(
// $options, [SkillingConstants::FLOATABLE]
// );
// Extra spaces before HTML tags are needed so that Textile does not wrap
// them in p tags.
......
......@@ -15,7 +15,8 @@
{{ 'Your answer:'|t }}
<input class="skilling-insert-fib-response form-control" type="text" size="20">
</div>
<button type="button" class="skilling-insert-fib-check-button btn btn-primary">{{ 'Check'|t }}</button>
<button type="button" class="skilling-insert-fib-check-button btn btn-primary" title="{{ 'See if your answer is correct.'|t }}">{{ 'Check'|t }}</button>
<button type="button" class="skilling-insert-fib-give-up-button btn btn-secondary" title="{{ 'Give up, and show the right answer.'|t }}">{{ 'Give up'|t }}</button>
<img class="skilling-throbber"
src="{{ url('<front>') }}/core/misc/throbber-active.gif" alt="Saving">
</form>
......
......@@ -28,7 +28,7 @@
</div>
<div class="modal-footer">
<button id="suggestion-save" type="button" class="btn btn-primary">{{ 'Save'|t }}</button>
<button type="button" class="btn btn-secondary" data-dismiss="modal">{{ 'Cancel'|t }}</button>
<button id="cancel-button" type="button" class="btn btn-secondary">{{ 'Forghedaboudit'|t }}</button>
</div>
</div>
</div>
......
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