Commit ddb627ba by cahrens

Make collapsible features accessible.

TNL-4002
parent 76e560e8
......@@ -3,14 +3,14 @@
<div class="openassessment__staff-area wrapper--staff-area">
<div class="wrapper--staff-toolbar">
<button class="ui-staff__button button-staff-tools" data-panel="openassessment__staff-tools">{% trans "Manage Individual Learners" %}</button>
<button class="ui-staff__button button-staff-info" data-panel="openassessment__staff-info">{% trans "View Assignment Statistics" %}</button>
<button class="ui-staff__button button-staff-tools" aria-expanded="false" data-panel="openassessment__staff-tools">{% trans "Manage Individual Learners" %}</button>
<button class="ui-staff__button button-staff-info" aria-expanded="false" data-panel="openassessment__staff-info">{% trans "View Assignment Statistics" %}</button>
{% if staff_assessment_required %}
<button class="ui-staff__button button-staff-grading" data-panel="openassessment__staff-grading">{% trans "Grade Available Responses" %}</button>
<button class="ui-staff__button button-staff-grading" aria-expanded="false" data-panel="openassessment__staff-grading">{% trans "Grade Available Responses" %}</button>
{% endif %}
</div>
<div class="openassessment__staff-tools wrapper--staff-tools wrapper--ui-staff is--hidden">
<div class="openassessment__staff-tools wrapper--staff-tools wrapper--ui-staff">
<div class="staff-info ui-staff">
<h2 class="staff-info__title ui-staff__title">
<span class="staff-info__title__copy">{% trans "Manage Individual Learners" %}</span>
......@@ -22,7 +22,7 @@
<div class="staff-info__student">
<div class="wrapper--input" class="staff-info__student__form">
<form class="openassessment_student_info_form">
<div class="form--error"></div>
<div class="form--error" tabindex="-1"></div>
<label class="label">{% trans "Enter an individual learner's username or email" %}
<input type="text" class="openassessment__student_username value" maxlength="255">
</label>
......@@ -82,7 +82,7 @@
</div>
</div>
<div class="openassessment__staff-info wrapper--staff-info wrapper--ui-staff is--hidden">
<div class="openassessment__staff-info wrapper--staff-info wrapper--ui-staff">
<div class="staff-info ui-staff">
<h2 class="staff-info__title ui-staff__title">
<span class="staff-info__title__copy">{% trans "View Assignment Statistics" %}</span>
......@@ -164,7 +164,7 @@
</div>
{% if staff_assessment_required %}
<div class="openassessment__staff-grading wrapper--staff-grading wrapper--ui-staff is--hidden">
<div class="openassessment__staff-grading wrapper--staff-grading wrapper--ui-staff">
<div class="staff-grading ui-staff">
<h2 class="staff-grading__title ui-staff__title">
<span class="staff-info__title__copy">{% trans "Grade Available Responses" %}</span>
......
{% load i18n %}
<div class="staff__grade__control ui-toggle-visibility is--collapsed">
<header class="staff__grade__header ui-toggle-visibility__control">
<div class="staff__grade__control">
<header class="staff__grade__header ui-slidable__control">
<h3 class="staff__grade__title">
<span class="wrapper--copy">
<button class="staff__grade__show-form">{% trans "Staff Assessment" %}</button>
<button class="staff__grade__show-form ui-slidable" aria-expanded="false">{% trans "Staff Assessment" %}</button>
</span>
</h3>
{% include "openassessmentblock/staff_area/oa_staff_grade_learners_count.html" with staff_assessment_ungraded=staff_assessment_ungraded staff_assessment_in_progress=staff_assessment_in_progress %}
</header>
<div class="ui-staff__content__section staff__grade__content ui-toggle-visibility__content">
<div class="ui-staff__content__section staff__grade__content ui-slidable__content">
<div class="wrapper--input">
<div class="staff__grade__form--error"></div>
<div class="staff__grade__form--error" tabindex="-1"></div>
<div class="staff__grade__form"></div>
</div>
</div>
......
{% load i18n %}
{% spaceless %}
<div class="staff__grade__form ui-toggle-visibility__content" data-submission-uuid="{{ submission.uuid }}">
<div class="staff__grade__form" data-submission-uuid="{{ submission.uuid }}">
<div class="wrapper--staff-assessment">
<div>
<p>{% trans "Give this learner a grade using the problem's rubric." %}</p>
......
......@@ -5,7 +5,7 @@
data-submission-uuid="{{ submission.uuid }}">
{% if submission %}
<h2 class="title">
<span class="label">
<span class="label staff-info__student__report__summary" tabindex="-1">
{% blocktrans with learner=student_username %}
Viewing learner: {{ learner }}
{% endblocktrans %}
......@@ -13,40 +13,40 @@
</h2>
<div class="staff-info__status ui-staff__content__section wrapper--ui--collapse staff-info__student__response">
<div class="ui-staff ui-toggle-visibility is--collapsed">
<h2 class="staff-info__title ui-staff__subtitle ui-toggle-visibility__control">
<button class="ui-staff ui-slidable" aria-expanded="false" id="learner_response_{{ submission.uuid }}">
<h2 class="staff-info__title ui-staff__subtitle">
<i class="icon fa fa-caret-right" aria-hidden="true"></i>
<span>{% trans "Learner's Response" %}</span>
</h2>
<div class="ui-toggle-visibility__content">
{% if workflow_cancellation %}
<p>
{% if workflow_cancellation.cancelled_by %}
{% blocktrans with removed_by_username=workflow_cancellation.cancelled_by removed_datetime=workflow_cancellation.cancelled_at|utc|date:"F j, Y H:i e" %}
Learner submission removed by {{ removed_by_username }} on {{ removed_datetime }}
{% endblocktrans %}
{% else %}
{% blocktrans with removed_datetime=workflow_cancellation.cancelled_at|utc|date:"F j, Y H:i e" %}
Learner submission removed on {{ removed_datetime }}
{% endblocktrans %}
{% endif %}
</p>
<!-- Comments: Reason for Cancellation-->
<p>
{% blocktrans with comments=workflow_cancellation.comments %}
Comments: {{ comments }}
</button>
<div class="ui-slidable__content" aria-labelledby="learner_response_{{ submission.uuid }}">
{% if workflow_cancellation %}
<p>
{% if workflow_cancellation.cancelled_by %}
{% blocktrans with removed_by_username=workflow_cancellation.cancelled_by removed_datetime=workflow_cancellation.cancelled_at|utc|date:"F j, Y H:i e" %}
Learner submission removed by {{ removed_by_username }} on {{ removed_datetime }}
{% endblocktrans %}
</p>
{% else %}
<div class="wrapper--content">
{% trans "The learner's response to the question above:" as translated_label %}
{% include "openassessmentblock/oa_submission_answer.html" with answer=submission.answer answer_text_label=translated_label %}
{% trans "Associated File" as translated_header %}
{% include "openassessmentblock/oa_uploaded_file.html" with file_upload_type=file_upload_type file_url=staff_file_url header=translated_header class_prefix="staff-assessment" show_warning="true" %}
</div>
{% endif %}
</div>
{% else %}
{% blocktrans with removed_datetime=workflow_cancellation.cancelled_at|utc|date:"F j, Y H:i e" %}
Learner submission removed on {{ removed_datetime }}
{% endblocktrans %}
{% endif %}
</p>
<!-- Comments: Reason for Cancellation-->
<p>
{% blocktrans with comments=workflow_cancellation.comments %}
Comments: {{ comments }}
{% endblocktrans %}
</p>
{% else %}
<div class="wrapper--content">
{% trans "The learner's response to the question above:" as translated_label %}
{% include "openassessmentblock/oa_submission_answer.html" with answer=submission.answer answer_text_label=translated_label %}
{% trans "Associated File" as translated_header %}
{% include "openassessmentblock/oa_uploaded_file.html" with file_upload_type=file_upload_type file_url=staff_file_url header=translated_header class_prefix="staff-assessment" show_warning="true" %}
</div>
{% endif %}
</div>
</div>
......@@ -76,124 +76,123 @@
{% endif %}
<div class="staff-info__status ui-staff__content__section wrapper--ui--collapse staff-info__student__grade">
<div class="ui-staff ui-toggle-visibility {% if expanded_view != 'final-grade' %}is--collapsed {% endif %}">
<h2 class="staff-info__title ui-staff__subtitle ui-toggle-visibility__control">
<button class="ui-staff ui-slidable" aria-expanded="false" id="final_grade_{{ submission.uuid }}">
<h2 class="staff-info__title ui-staff__subtitle">
<i class="icon fa fa-caret-right" aria-hidden="true"></i>
<span>{% trans "Learner's Final Grade" %}</span>
</h2>
<div class="ui-toggle-visibility__content">
{% if workflow_status == "done" %}
<p class="staff-info__final__grade__score">
{% with points_earned_string=score.points_earned|stringformat:"s" points_possible_string=score.points_possible|stringformat:"s" %}
{% blocktrans with points_earned='<span class="grade__value__earned">'|safe|add:points_earned_string|add:'</span>'|safe points_possible='<span class="grade__value__potential">'|safe|add:points_possible_string|add:'</span>'|safe %}
Final grade: {{ points_earned }} out of {{ points_possible }}
{% endblocktrans %}
{% endwith %}
</p>
<table class="staff-info__status__table staff-info__final__grade__table" summary="{% trans "Final Grade Details" %}">
<thead>
</button>
<div class="ui-slidable__content" aria-labelledby="final_grade_{{ submission.uuid }}">
{% if workflow_status == "done" %}
<div class="staff-info__final__grade__score">
{% with points_earned_string=score.points_earned|stringformat:"s" points_possible_string=score.points_possible|stringformat:"s" %}
{% blocktrans with points_earned='<span class="grade__value__earned">'|safe|add:points_earned_string|add:'</span>'|safe points_possible='<span class="grade__value__potential">'|safe|add:points_possible_string|add:'</span>'|safe %}
Final grade: {{ points_earned }} out of {{ points_possible }}
{% endblocktrans %}
{% endwith %}
</div>
<table class="staff-info__status__table staff-info__final__grade__table">
<caption class="sr">{% trans "Final Grade Details" %}</caption>
<thead>
<tr>
<th abbr="{% trans 'Criterion' %}" scope="col">{% trans "Criterion" %}</th>
{% with criterion=grade_details.criteria.0 %}
{% for assessment in criterion.assessments %}
<th abbr="{{ assessment.title }}" scope="col">{{ assessment.title }}</th>
{% endfor %}
{% endwith %}
</tr>
</thead>
<tbody>
{% for criterion in grade_details.criteria %}
<tr>
<th abbr="{% trans 'Criterion' %}" scope="col">{% trans "Criterion" %}</th>
{% with criterion=grade_details.criteria.0 %}
{% for assessment in criterion.assessments %}
<th abbr="{{ assessment.title }}" scope="col">{{ assessment.title }}</th>
{% endfor %}
{% endwith %}
<td class="label">{{ criterion.label }}</td>
{% for assessment in criterion.assessments %}
<td class="value">
{% if assessment.points != None %}
<div>
{% blocktrans with assessment_label=assessment.option.label count points=assessment.points %}
{{ assessment_label }} - {{ points }} point
{% plural %}
{{ assessment_label }} - {{ points }} points
{% endblocktrans %}
</div>
{% endif %}
{% if assessment.individual_assessments %}
{% for individual_assessment in assessment.individual_assessments %}
<div>{{ individual_assessment.title }} - {{ individual_assessment.option.label}}</div>
{% endfor %}
{% elif assessment.points == None %}
<div>{{ assessment.option.label }}</div>
{% endif %}
</td>
{% endfor %}
</tr>
</thead>
<tbody>
{% for criterion in grade_details.criteria %}
<tr>
<td class="label">{{ criterion.label }}</td>
{% for assessment in criterion.assessments %}
<td class="value">
{% if assessment.points != None %}
<div>
{% blocktrans with assessment_label=assessment.option.label count points=assessment.points %}
{{ assessment_label }} - {{ points }} point
{% plural %}
{{ assessment_label }} - {{ points }} points
{% endblocktrans %}
</div>
{% endif %}
{% if assessment.individual_assessments %}
{% for individual_assessment in assessment.individual_assessments %}
<div>{{ individual_assessment.title }} - {{ individual_assessment.option.label}}</div>
{% endfor %}
{% elif assessment.points == None %}
<div>{{ assessment.option.label }}</div>
{% endif %}
</td>
{% endfor %}
</tr>
{% endfor %}
</tbody>
</table>
{% elif workflow_status == "waiting" %}
<p class="staff-info__final__grade__score">{% trans "The submission is waiting for assessments." %}</p>
{% elif workflow_status == "cancelled" %}
<p class="staff-info__final__grade__score">{% trans "The learner's submission has been removed from peer assessment. The learner receives a grade of zero unless you delete the learner's state for the problem to allow them to resubmit a response." %}</p>
{% elif workflow_status == None %}
<p class="staff-info__final__grade__score">{% trans "The problem has not been started." %}</p>
{% else %}
<p class="staff-info__final__grade__score">{% trans "The problem has not been completed." %}</p>
{% endif %}
</div>
{% endfor %}
</tbody>
</table>
{% elif workflow_status == "waiting" %}
<div class="staff-info__final__grade__score">{% trans "The submission is waiting for assessments." %}</div>
{% elif workflow_status == "cancelled" %}
<div class="staff-info__final__grade__score">{% trans "The learner's submission has been removed from peer assessment. The learner receives a grade of zero unless you delete the learner's state for the problem to allow them to resubmit a response." %}</div>
{% elif workflow_status == None %}
<div class="staff-info__final__grade__score">{% trans "The problem has not been started." %}</div>
{% else %}
<div class="staff-info__final__grade__score">{% trans "The problem has not been completed." %}</div>
{% endif %}
</div>
</div>
{% if not workflow_cancellation %}
<div class="staff-info__staff-override ui-staff__content__section wrapper--ui--collapse">
<div class="ui-staff ui-toggle-visibility {% if expanded_view != 'staff-override' %}is--collapsed {% endif %}">
<h2 class="staff-info__title ui-staff__subtitle ui-toggle-visibility__control">
<button class="ui-staff ui-slidable" aria-expanded="false" id="grade_override_{{ submission.uuid }}">
<h2 class="staff-info__title ui-staff__subtitle">
<i class="icon fa fa-caret-right" aria-hidden="true"></i>
<span>{% trans "Submit Assessment Grade Override" %}</span>
</h2>
<div class="staff-info__staff-override__content ui-toggle-visibility__content">
<div class="wrapper--input">
{% include "openassessmentblock/staff_area/oa_staff_override_assessment.html" %}
</div>
</button>
<div class="staff-info__staff-override__content ui-slidable__content" aria-labelledby="grade_override_{{ submission.uuid }}">
<div class="wrapper--input">
{% include "openassessmentblock/staff_area/oa_staff_override_assessment.html" %}
</div>
</div>
</div>
<div class="staff-info__workflow-cancellation ui-staff__content__section wrapper--ui--collapse">
<div class="ui-staff ui-toggle-visibility is--collapsed">
<h2 class="staff-info__title ui-staff__subtitle ui-toggle-visibility__control">
<button class="ui-staff ui-slidable" aria-expanded="false" id="remove_submission_{{ submission.uuid }}">
<h2 class="staff-info__title ui-staff__subtitle">
<i class="icon fa fa-caret-right" aria-hidden="true"></i>
<span>{% trans "Remove Submission From Peer Grading" %}</span>
</h2>
<div class="staff-info__cancel-submission__content ui-toggle-visibility__content">
<div class="wrapper--input">
<form data-submission-uuid="{{ submission.uuid }}">
<div class="step__message message message--warning">
<h3 class="message__title">{% trans "Caution: This Action Cannot Be Undone" %}</h3>
<div class="message__content">{% trans "Removing a learner's submission cannot be undone and should be done with caution." %}</div>
</div>
<ul class="list list--actions">
<li>
<label class="label comments__label">{% trans "Comments:" %}
<textarea class="cancel_submission_comments" value="" maxlength="10000"></textarea>
</label>
</li>
</ul>
<ul class="list list--actions">
<li class="list--actions__item">
<button data-submission-uuid="{{ submission.uuid }}"
class="action--submit action--submit-cancel-submission is--disabled">
<span class="copy">{% trans "Remove submission" %}</span>
</button>
<div class="cancel-submission-error"></div>
</li>
</ul>
</form>
</div>
</button>
<div class="staff-info__cancel-submission__content ui-slidable__content" aria-labelledby="remove_submission_{{ submission.uuid }}">
<div class="wrapper--input">
<form data-submission-uuid="{{ submission.uuid }}">
<div class="step__message message message--warning">
<h3 class="message__title">{% trans "Caution: This Action Cannot Be Undone" %}</h3>
<div class="message__content">{% trans "Removing a learner's submission cannot be undone and should be done with caution." %}</div>
</div>
<ul class="list list--actions">
<li>
<label class="label comments__label">{% trans "Comments:" %}
<textarea class="cancel_submission_comments" value="" maxlength="10000"></textarea>
</label>
</li>
</ul>
<ul class="list list--actions">
<li class="list--actions__item">
<button data-submission-uuid="{{ submission.uuid }}"
class="action--submit action--submit-cancel-submission is--disabled">
<span class="copy">{% trans "Remove submission" %}</span>
</button>
<div class="cancel-submission-error"></div>
</li>
</ul>
</form>
</div>
</div>
</div>
......@@ -201,6 +200,8 @@
</div>
{% else %}
{% trans "A response was not found for this learner." %}
<span class="staff-info__student__report__summary" tabindex="-1">
{% trans "A response was not found for this learner." %}
</span>
{% endif %}
</div>
{% load i18n %}
<div class="staff-info__status ui-staff__content__section wrapper--ui--collapse staff-info__{{ class_type }}__assessments">
<div class="ui-staff ui-toggle-visibility is--collapsed">
<h2 class="staff-info__title ui-staff__subtitle ui-toggle-visibility__control">
<button class="ui-staff ui-slidable" aria-expanded="false" id="{{ class_type }}_{{ submission.uuid }}">
<h2 class="staff-info__title ui-staff__subtitle">
<i class="icon fa fa-caret-right" aria-hidden="true"></i>
<span>{{ translated_title }}</span>
</h2>
<div class="ui-toggle-visibility__content">
{% for assessment in assessments %}
{% with assessment_num=forloop.counter %}
{% if assessments|length > 1 %}
<h4 class="title--sub">
{% blocktrans %}
Assessment {{ assessment_num }}:
{% endblocktrans %}
</h4>
{% endif %}
<table class="staff-info__status__table" summary="{% trans "Assessment" %}">
<thead>
<tr>
<th abbr="{% trans "Criterion" %}" scope="col">{% trans "Criterion" %}</th>
<th abbr="{% trans "Selected Option" %}" scope="col">{% trans "Selected Option" %}</th>
<th abbr="{% trans "Feedback" %}" scope="col">{% trans "Feedback" %}</th>
<th abbr="{% trans "Points" %}" scope="col">{% trans "Points" %}</th>
<th abbr="{% trans "Points Possible" %}" scope="col">{% trans "Points Possible" %}</th>
</tr>
</thead>
</button>
<div class="ui-slidable__content" aria-labelledby="{{ class_type }}_{{ submission.uuid }}">
{% for assessment in assessments %}
{% with assessment_num=forloop.counter %}
{% if assessments|length > 1 %}
<h4 class="title--sub">
{% blocktrans %}
Assessment {{ assessment_num }}:
{% endblocktrans %}
</h4>
{% endif %}
<table class="staff-info__status__table">
<caption class="sr">{% trans "Assessment Details" %}</caption>
<thead>
<tr>
<th abbr="{% trans "Criterion" %}" scope="col">{% trans "Criterion" %}</th>
<th abbr="{% trans "Selected Option" %}" scope="col">{% trans "Selected Option" %}</th>
<th abbr="{% trans "Feedback" %}" scope="col">{% trans "Feedback" %}</th>
<th abbr="{% trans "Points" %}" scope="col">{% trans "Points" %}</th>
<th abbr="{% trans "Points Possible" %}" scope="col">{% trans "Points Possible" %}</th>
</tr>
</thead>
<tbody>
{% for criterion in rubric_criteria %}
{% for part in assessment.parts %}
{% if part.option.criterion.name == criterion.name %}
<tr>
<td class="label">{{ criterion.label }}</td>
<td class="value">{{ part.option.label }}</td>
<td class="value">{{ part.feedback }}</td>
<td class="value">{{ part.option.points }}</td>
<td class="value">{{ criterion.total_value }}</td>
</tr>
{% endif %}
{% endfor %}
<tbody>
{% for criterion in rubric_criteria %}
{% for part in assessment.parts %}
{% if part.option.criterion.name == criterion.name %}
<tr>
<td class="label">{{ criterion.label }}</td>
<td class="value">{{ part.option.label }}</td>
<td class="value">{{ part.feedback }}</td>
<td class="value">{{ part.option.points }}</td>
<td class="value">{{ criterion.total_value }}</td>
</tr>
{% endif %}
{% endfor %}
</tbody>
</table>
{% if assessment.feedback %}
<h4 class="title--sub">{% trans "Overall Feedback" %}</h4>
<div class="student__answer__display__content">
{{ assessment.feedback|linebreaks }}
</div>
{% endif %}
{% endwith %}
{% endfor %}
</div>
{% endfor %}
</tbody>
</table>
{% if assessment.feedback %}
<h4 class="title--sub">{% trans "Overall Feedback" %}</h4>
<div class="student__answer__display__content">
{{ assessment.feedback|linebreaks }}
</div>
{% endif %}
{% endwith %}
{% endfor %}
</div>
</div>
......@@ -236,8 +236,6 @@ class StaffAreaMixin(object):
try:
student_username = data.params.get('student_username', '')
path, context = self.get_student_info_path_and_context(student_username)
expanded_view = data.params.get('expanded_view', [])
context.update({'expanded_view': expanded_view})
return self.render_assessment(path, context)
except PeerAssessmentInternalError:
......
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -953,8 +953,7 @@
"points_earned": 1,
"points_possible": 2
},
"workflow_status": "done",
"expanded_view": "final-grade"
"workflow_status": "done"
},
"output": "oa_staff_graded_submission.html"
},
......
if(typeof OpenAssessment=="undefined"||!OpenAssessment){OpenAssessment={}}if(typeof window.gettext==="undefined"){window.gettext=function(text){return text}}if(typeof window.ngetgext==="undefined"){window.ngettext=function(singularText,pluralText,n){if(n>1){return pluralText}else{return singularText}}}if(typeof window.Logger==="undefined"){window.Logger={log:function(){}}}if(typeof window.MathJax==="undefined"){window.MathJax={Hub:{Typeset:function(){},Queue:function(){}}}}if(typeof OpenAssessment.Server==="undefined"||!OpenAssessment.Server){OpenAssessment.Server=function(runtime,element){this.runtime=runtime;this.element=element};var jsonContentType="application/json; charset=utf-8";OpenAssessment.Server.prototype={url:function(handler){return this.runtime.handlerUrl(this.element,handler)},render:function(component){var view=this;var url=this.url("render_"+component);return $.Deferred(function(defer){$.ajax({url:url,type:"POST",dataType:"html"}).done(function(data){defer.resolveWith(view,[data])}).fail(function(){defer.rejectWith(view,[gettext("This section could not be loaded.")])})}).promise()},renderLatex:function(element){element.filter(".allow--latex").each(function(){MathJax.Hub.Queue(["Typeset",MathJax.Hub,this])})},renderContinuedPeer:function(){var view=this;var url=this.url("render_peer_assessment");return $.Deferred(function(defer){$.ajax({url:url,type:"POST",dataType:"html",data:{continue_grading:true}}).done(function(data){defer.resolveWith(view,[data])}).fail(function(){defer.rejectWith(view,[gettext("This section could not be loaded.")])})}).promise()},studentInfo:function(studentUsername,options){var url=this.url("render_student_info");return $.Deferred(function(defer){$.ajax({url:url,type:"POST",dataType:"html",data:_.extend({student_username:studentUsername},options)}).done(function(data){defer.resolveWith(this,[data])}).fail(function(){defer.rejectWith(this,[gettext("This section could not be loaded.")])})}).promise()},staffGradeForm:function(){var url=this.url("render_staff_grade_form");return $.Deferred(function(defer){$.ajax({url:url,type:"POST",dataType:"html"}).done(function(data){defer.resolveWith(this,[data])}).fail(function(){defer.rejectWith(this,[gettext("The staff assessment form could not be loaded.")])})}).promise()},staffGradeCounts:function(){var url=this.url("render_staff_grade_counts");return $.Deferred(function(defer){$.ajax({url:url,type:"POST",dataType:"html"}).done(function(data){defer.resolveWith(this,[data])}).fail(function(){defer.rejectWith(this,[gettext("The display of ungraded and checked out responses could not be loaded.")])})}).promise()},submit:function(submission){var url=this.url("submit");return $.Deferred(function(defer){$.ajax({type:"POST",url:url,data:JSON.stringify({submission:submission}),contentType:jsonContentType}).done(function(data){var success=data[0];if(success){var studentId=data[1];var attemptNum=data[2];defer.resolveWith(this,[studentId,attemptNum])}else{var errorNum=data[1];var errorMsg=data[2];defer.rejectWith(this,[errorNum,errorMsg])}}).fail(function(){defer.rejectWith(this,["AJAX",gettext("This response could not be submitted.")])})}).promise()},save:function(submission){var url=this.url("save_submission");return $.Deferred(function(defer){$.ajax({type:"POST",url:url,data:JSON.stringify({submission:submission}),contentType:jsonContentType}).done(function(data){if(data.success){defer.resolve()}else{defer.rejectWith(this,[data.msg])}}).fail(function(){defer.rejectWith(this,[gettext("This response could not be saved.")])})}).promise()},submitFeedbackOnAssessment:function(text,options){var url=this.url("submit_feedback");var payload=JSON.stringify({feedback_text:text,feedback_options:options});return $.Deferred(function(defer){$.ajax({type:"POST",url:url,data:payload,contentType:jsonContentType}).done(function(data){if(data.success){defer.resolve()}else{defer.rejectWith(this,[data.msg])}}).fail(function(){defer.rejectWith(this,[gettext("This feedback could not be submitted.")])})}).promise()},submitAssessment:function(assessmentType,payload){var url=this.url(assessmentType);return $.Deferred(function(defer){$.ajax({type:"POST",url:url,data:JSON.stringify(payload),contentType:jsonContentType}).done(function(data){if(data.success){defer.resolve()}else{defer.rejectWith(this,[data.msg])}}).fail(function(){defer.rejectWith(this,[gettext("This assessment could not be submitted.")])})}).promise()},peerAssess:function(optionsSelected,criterionFeedback,overallFeedback,submissionID){return this.submitAssessment("peer_assess",{options_selected:optionsSelected,criterion_feedback:criterionFeedback,overall_feedback:overallFeedback,submission_uuid:submissionID})},selfAssess:function(optionsSelected,criterionFeedback,overallFeedback){return this.submitAssessment("self_assess",{options_selected:optionsSelected,criterion_feedback:criterionFeedback,overall_feedback:overallFeedback})},staffAssess:function(optionsSelected,criterionFeedback,overallFeedback,submissionID,assessType){return this.submitAssessment("staff_assess",{options_selected:optionsSelected,criterion_feedback:criterionFeedback,overall_feedback:overallFeedback,submission_uuid:submissionID,assess_type:assessType})},trainingAssess:function(optionsSelected){var url=this.url("training_assess");var payload=JSON.stringify({options_selected:optionsSelected});return $.Deferred(function(defer){$.ajax({type:"POST",url:url,data:payload,contentType:jsonContentType}).done(function(data){if(data.success){defer.resolveWith(this,[data.corrections])}else{defer.rejectWith(this,[data.msg])}}).fail(function(){defer.rejectWith(this,[gettext("This assessment could not be submitted.")])})})},scheduleTraining:function(){var url=this.url("schedule_training");return $.Deferred(function(defer){$.ajax({type:"POST",url:url,data:'""',contentType:jsonContentType}).done(function(data){if(data.success){defer.resolveWith(this,[data.msg])}else{defer.rejectWith(this,[data.msg])}}).fail(function(){defer.rejectWith(this,[gettext("This assessment could not be submitted.")])})})},rescheduleUnfinishedTasks:function(){var url=this.url("reschedule_unfinished_tasks");return $.Deferred(function(defer){$.ajax({type:"POST",url:url,data:'""',contentType:jsonContentType}).done(function(data){if(data.success){defer.resolveWith(this,[data.msg])}else{defer.rejectWith(this,[data.msg])}}).fail(function(){defer.rejectWith(this,[gettext("One or more rescheduling tasks failed.")])})})},updateEditorContext:function(options){var url=this.url("update_editor_context");var payload=JSON.stringify({prompts:options.prompts,feedback_prompt:options.feedbackPrompt,feedback_default_text:options.feedback_default_text,title:options.title,submission_start:options.submissionStart,submission_due:options.submissionDue,criteria:options.criteria,assessments:options.assessments,editor_assessments_order:options.editorAssessmentsOrder,file_upload_type:options.fileUploadType,white_listed_file_types:options.fileTypeWhiteList,allow_latex:options.latexEnabled,leaderboard_show:options.leaderboardNum});return $.Deferred(function(defer){$.ajax({type:"POST",url:url,data:payload,contentType:jsonContentType}).done(function(data){if(data.success){defer.resolve()}else{defer.rejectWith(this,[data.msg])}}).fail(function(){defer.rejectWith(this,[gettext("This problem could not be saved.")])})}).promise()},checkReleased:function(){var url=this.url("check_released");var payload='""';return $.Deferred(function(defer){$.ajax({type:"POST",url:url,data:payload,contentType:jsonContentType}).done(function(data){if(data.success){defer.resolveWith(this,[data.is_released])}else{defer.rejectWith(this,[data.msg])}}).fail(function(){defer.rejectWith(this,[gettext("The server could not be contacted.")])})}).promise()},getUploadUrl:function(contentType,filename){var url=this.url("upload_url");return $.Deferred(function(defer){$.ajax({type:"POST",url:url,data:JSON.stringify({contentType:contentType,filename:filename}),contentType:jsonContentType}).done(function(data){if(data.success){defer.resolve(data.url)}else{defer.rejectWith(this,[data.msg])}}).fail(function(){defer.rejectWith(this,[gettext("Could not retrieve upload url.")])})}).promise()},getDownloadUrl:function(){var url=this.url("download_url");return $.Deferred(function(defer){$.ajax({type:"POST",url:url,data:JSON.stringify({}),contentType:jsonContentType}).done(function(data){if(data.success){defer.resolve(data.url)}else{defer.rejectWith(this,[data.msg])}}).fail(function(){defer.rejectWith(this,[gettext("Could not retrieve download url.")])})}).promise()},cancelSubmission:function(submissionID,comments){var url=this.url("cancel_submission");var payload=JSON.stringify({submission_uuid:submissionID,comments:comments});return $.Deferred(function(defer){$.ajax({type:"POST",url:url,data:payload,contentType:jsonContentType}).done(function(data){if(data.success){defer.resolveWith(this,[data.msg])}}).fail(function(){defer.rejectWith(this,[gettext("The submission could not be removed from the grading pool.")])})}).promise()},publishEvent:function(eventName,eventData){eventData.event_name=eventName;var url=this.url("publish_event");var payload=JSON.stringify(eventData);$.ajax({type:"POST",url:url,data:payload,contentType:jsonContentType})}}}if(typeof OpenAssessment=="undefined"||!OpenAssessment){OpenAssessment={}}if(typeof window.gettext==="undefined"){window.gettext=function(text){return text}}if(typeof window.ngetgext==="undefined"){window.ngettext=function(singularText,pluralText,n){if(n>1){return pluralText}else{return singularText}}}if(typeof window.Logger==="undefined"){window.Logger={log:function(){}}}if(typeof window.MathJax==="undefined"){window.MathJax={Hub:{Typeset:function(){},Queue:function(){}}}}OpenAssessment.BaseView=function(runtime,element,server,data){this.runtime=runtime;this.element=element;this.server=server;this.fileUploader=new OpenAssessment.FileUploader;this.responseView=new OpenAssessment.ResponseView(this.element,this.server,this.fileUploader,this,data);this.trainingView=new OpenAssessment.StudentTrainingView(this.element,this.server,this);this.selfView=new OpenAssessment.SelfView(this.element,this.server,this);this.peerView=new OpenAssessment.PeerView(this.element,this.server,this);this.staffView=new OpenAssessment.StaffView(this.element,this.server,this);this.gradeView=new OpenAssessment.GradeView(this.element,this.server,this);this.leaderboardView=new OpenAssessment.LeaderboardView(this.element,this.server,this);this.messageView=new OpenAssessment.MessageView(this.element,this.server,this);this.staffAreaView=new OpenAssessment.StaffAreaView(this.element,this.server,this)};if(typeof OpenAssessment.unsavedChanges==="undefined"||!OpenAssessment.unsavedChanges){OpenAssessment.unsavedChanges={}}OpenAssessment.clearUnsavedChanges=function(){OpenAssessment.unsavedChanges={};window.onbeforeunload=null};OpenAssessment.BaseView.prototype={scrollToTop:function(selector){if(!selector){selector="#openassessment__steps"}if($.scrollTo instanceof Function){$(window).scrollTo($(selector,this.element),800,{offset:-50})}},setUpCollapseExpand:function(parentElement){parentElement.on("click",".ui-toggle-visibility__control",function(eventData){var sel=$(eventData.target).closest(".ui-toggle-visibility");sel.toggleClass("is--collapsed")})},load:function(){this.responseView.load();this.loadAssessmentModules();this.staffAreaView.load()},loadAssessmentModules:function(){this.trainingView.load();this.peerView.load();this.staffView.load();this.selfView.load();this.gradeView.load();this.leaderboardView.load()},loadMessageView:function(){this.messageView.load()},toggleActionError:function(type,message){var element=this.element;var container=null;if(type==="save"){container=".response__submission__actions"}else if(type==="submit"||type==="peer"||type==="self"||type==="student-training"){container=".step__actions"}else if(type==="feedback_assess"){container=".submission__feedback__actions"}else if(type==="upload"){container="#upload__error"}if(container===null){if(message!==null){console.log(message)}}else{$(container+" .message__content",element).html("<p>"+(message?_.escape(message):"")+"</p>");$(container,element).toggleClass("has--error",message!==null)}},showLoadError:function(stepName,errorMessage){if(!errorMessage){errorMessage=gettext("Unable to load")}var $container=$("#openassessment__"+stepName);$container.toggleClass("has--error",true);$container.find(".step__status__value i").removeClass().addClass("icon fa fa-exclamation-triangle");$container.find(".step__status__value .copy").html(_.escape(errorMessage))},unsavedWarningEnabled:function(enabled,key,message){if(typeof enabled==="undefined"){return window.onbeforeunload!==null}else{var usageID=$(this.element).data("usage-id");if(enabled){if(typeof OpenAssessment.unsavedChanges[usageID]==="undefined"||!OpenAssessment.unsavedChanges[usageID]){OpenAssessment.unsavedChanges[usageID]={}}OpenAssessment.unsavedChanges[usageID][key]=message;window.onbeforeunload=function(){for(var xblockUsageID in OpenAssessment.unsavedChanges){if(OpenAssessment.unsavedChanges.hasOwnProperty(xblockUsageID)){for(var key in OpenAssessment.unsavedChanges[xblockUsageID]){if(OpenAssessment.unsavedChanges[xblockUsageID].hasOwnProperty(key)){return OpenAssessment.unsavedChanges[xblockUsageID][key]}}}}}}else{if(typeof OpenAssessment.unsavedChanges[usageID]!=="undefined"){delete OpenAssessment.unsavedChanges[usageID][key];if($.isEmptyObject(OpenAssessment.unsavedChanges[usageID])){delete OpenAssessment.unsavedChanges[usageID]}if($.isEmptyObject(OpenAssessment.unsavedChanges)){window.onbeforeunload=null}}}}}};function OpenAssessmentBlock(runtime,element,data){var server=new OpenAssessment.Server(runtime,element);var view=new OpenAssessment.BaseView(runtime,element,server,data);view.load()}OpenAssessment.FileUploader=function(){this.upload=function(url,file){return $.Deferred(function(defer){$.ajax({url:url,type:"PUT",data:file,async:false,processData:false,contentType:file.type}).done(function(){Logger.log("openassessment.upload_file",{fileName:file.name,fileSize:file.size,fileType:file.type});defer.resolve()}).fail(function(data,textStatus){defer.rejectWith(this,[textStatus])})}).promise()}};OpenAssessment.GradeView=function(element,server,baseView){this.element=element;this.server=server;this.baseView=baseView};OpenAssessment.GradeView.prototype={load:function(){var view=this;var baseView=this.baseView;this.server.render("grade").done(function(html){$("#openassessment__grade",view.element).replaceWith(html);view.server.renderLatex($("#openassessment__grade",view.element));view.installHandlers()}).fail(function(errMsg){baseView.showLoadError("grade",errMsg)})},installHandlers:function(){var sel=$("#openassessment__grade",this.element);this.baseView.setUpCollapseExpand(sel);var view=this;sel.find(".feedback__submit").click(function(eventObject){eventObject.preventDefault();view.submitFeedbackOnAssessment()})},feedbackText:function(text){if(typeof text==="undefined"){return $("#feedback__remarks__value",this.element).val()}else{$("#feedback__remarks__value",this.element).val(text)}},feedbackOptions:function(options){var view=this;if(typeof options==="undefined"){return $.map($(".feedback__overall__value:checked",view.element),function(element){return $(element).val()})}else{$(".feedback__overall__value",this.element).prop("checked",false);$.each(options,function(index,opt){$("#feedback__overall__value--"+opt,view.element).prop("checked",true)})}},setHidden:function(selector,hidden){selector.toggleClass("is--hidden",hidden);selector.attr("aria-hidden",hidden?"true":"false")},isHidden:function(selector){return selector.hasClass("is--hidden")&&selector.attr("aria-hidden")==="true"},feedbackState:function(newState){var containerSel=$(".submission__feedback__content",this.element);var instructionsSel=containerSel.find(".submission__feedback__instructions");var fieldsSel=containerSel.find(".submission__feedback__fields");var actionsSel=containerSel.find(".submission__feedback__actions");var transitionSel=containerSel.find(".transition__status");var messageSel=containerSel.find(".message--complete");if(typeof newState==="undefined"){var isSubmitting=containerSel.hasClass("is--transitioning")&&containerSel.hasClass("is--submitting")&&!this.isHidden(transitionSel)&&this.isHidden(messageSel)&&this.isHidden(instructionsSel)&&this.isHidden(fieldsSel)&&this.isHidden(actionsSel);var hasSubmitted=containerSel.hasClass("is--submitted")&&this.isHidden(transitionSel)&&!this.isHidden(messageSel)&&this.isHidden(instructionsSel)&&this.isHidden(fieldsSel)&&this.isHidden(actionsSel);var isOpen=!containerSel.hasClass("is--submitted")&&!containerSel.hasClass("is--transitioning")&&!containerSel.hasClass("is--submitting")&&this.isHidden(transitionSel)&&this.isHidden(messageSel)&&!this.isHidden(instructionsSel)&&!this.isHidden(fieldsSel)&&!this.isHidden(actionsSel);if(isOpen){return"open"}else if(isSubmitting){return"submitting"}else if(hasSubmitted){return"submitted"}else{throw"Invalid feedback state"}}else{if(newState==="open"){containerSel.toggleClass("is--transitioning",false);containerSel.toggleClass("is--submitting",false);containerSel.toggleClass("is--submitted",false);this.setHidden(instructionsSel,false);this.setHidden(fieldsSel,false);this.setHidden(actionsSel,false);this.setHidden(transitionSel,true);this.setHidden(messageSel,true)}else if(newState==="submitting"){containerSel.toggleClass("is--transitioning",true);containerSel.toggleClass("is--submitting",true);containerSel.toggleClass("is--submitted",false);this.setHidden(instructionsSel,true);this.setHidden(fieldsSel,true);this.setHidden(actionsSel,true);this.setHidden(transitionSel,false);this.setHidden(messageSel,true)}else if(newState==="submitted"){containerSel.toggleClass("is--transitioning",false);containerSel.toggleClass("is--submitting",false);containerSel.toggleClass("is--submitted",true);this.setHidden(instructionsSel,true);this.setHidden(fieldsSel,true);this.setHidden(actionsSel,true);this.setHidden(transitionSel,true);this.setHidden(messageSel,false)}}},submitFeedbackOnAssessment:function(){var view=this;var baseView=this.baseView;$(".feedback__submit",this.element).toggleClass("is--disabled",true);view.feedbackState("submitting");this.server.submitFeedbackOnAssessment(this.feedbackText(),this.feedbackOptions()).done(function(){view.feedbackState("submitted")}).fail(function(errMsg){baseView.toggleActionError("feedback_assess",errMsg)})}};OpenAssessment.LeaderboardView=function(element,server,baseView){this.element=element;this.server=server;this.baseView=baseView};OpenAssessment.LeaderboardView.prototype={load:function(){var view=this;var baseView=this.baseView;this.server.render("leaderboard").done(function(html){$("#openassessment__leaderboard",view.element).replaceWith(html);view.server.renderLatex($("#openassessment__leaderboard",view.element))}).fail(function(errMsg){baseView.showLoadError("leaderboard",errMsg)})}};OpenAssessment.MessageView=function(element,server,baseView){this.element=element;this.server=server;this.baseView=baseView};OpenAssessment.MessageView.prototype={load:function(){var view=this;var baseView=this.baseView;this.server.render("message").done(function(html){$("#openassessment__message",view.element).replaceWith(html);view.server.renderLatex($("#openassessment__message",view.element))}).fail(function(errMsg){baseView.showLoadError("message",errMsg)})}};OpenAssessment.PeerView=function(element,server,baseView){this.element=element;this.server=server;this.baseView=baseView;this.rubric=null};OpenAssessment.PeerView.prototype={UNSAVED_WARNING_KEY:"peer-assessment",load:function(){var view=this;this.server.render("peer_assessment").done(function(html){$("#openassessment__peer-assessment",view.element).replaceWith(html);view.server.renderLatex($("#openassessment__peer-assessment",view.element));view.installHandlers(false)}).fail(function(){view.baseView.showLoadError("peer-assessment")});view.baseView.loadMessageView()},loadContinuedAssessment:function(){var view=this;view.continueAssessmentEnabled(false);this.server.renderContinuedPeer().done(function(html){$("#openassessment__peer-assessment",view.element).replaceWith(html);view.server.renderLatex($("#openassessment__peer-assessment",view.element));view.installHandlers(true)}).fail(function(){view.baseView.showLoadError("peer-assessment");view.continueAssessmentEnabled(true)})},continueAssessmentEnabled:function(enabled){var button=$(".action--continue--grading",this.element);if(typeof enabled==="undefined"){return!button.hasClass("is--disabled")}else{button.toggleClass("is--disabled",!enabled)}},installHandlers:function(isContinuedAssessment){var sel=$("#openassessment__peer-assessment",this.element);var view=this;this.baseView.setUpCollapseExpand(sel);var rubricSelector=$("#peer-assessment--001__assessment",this.element);if(rubricSelector.size()>0){var rubricElement=rubricSelector.get(0);this.rubric=new OpenAssessment.Rubric(rubricElement)}else{this.rubric=null}if(this.rubric!==null){this.rubric.canSubmitCallback($.proxy(view.peerSubmitEnabled,view));this.rubric.changesExistCallback($.proxy(view.assessmentRubricChanges,view))}sel.find("#peer-assessment--001__assessment__submit").click(function(eventObject){eventObject.preventDefault();if(!isContinuedAssessment){view.peerAssess()}else{view.continuedPeerAssess()}});sel.find(".action--continue--grading").click(function(eventObject){eventObject.preventDefault();view.loadContinuedAssessment()})},peerSubmitEnabled:function(enabled){var button=$("#peer-assessment--001__assessment__submit",this.element);if(typeof enabled==="undefined"){return!button.hasClass("is--disabled")}else{button.toggleClass("is--disabled",!enabled);return enabled}},assessmentRubricChanges:function(changesExist){if(changesExist){this.baseView.unsavedWarningEnabled(true,this.UNSAVED_WARNING_KEY,gettext("If you leave this page without submitting your peer assessment, you will lose any work you have done."))}},peerAssess:function(){var view=this;var baseView=view.baseView;this.peerAssessRequest(function(){baseView.unsavedWarningEnabled(false,view.UNSAVED_WARNING_KEY);baseView.loadAssessmentModules();baseView.scrollToTop()})},continuedPeerAssess:function(){var view=this;var gradeView=this.baseView.gradeView;var baseView=view.baseView;view.peerAssessRequest(function(){baseView.unsavedWarningEnabled(false,view.UNSAVED_WARNING_KEY);view.loadContinuedAssessment();gradeView.load();baseView.scrollToTop()})},peerAssessRequest:function(successFunction){var view=this;var uuid=$("#openassessment__peer-assessment").data("submission-uuid");view.baseView.toggleActionError("peer",null);view.peerSubmitEnabled(false);this.server.peerAssess(this.rubric.optionsSelected(),this.rubric.criterionFeedback(),this.rubric.overallFeedback(),uuid).done(successFunction).fail(function(errMsg){view.baseView.toggleActionError("peer",errMsg);view.peerSubmitEnabled(true)})}};OpenAssessment.ResponseView=function(element,server,fileUploader,baseView,data){this.element=element;this.server=server;this.fileUploader=fileUploader;this.baseView=baseView;this.savedResponse=[];this.files=null;this.fileType=null;this.lastChangeTime=Date.now();this.errorOnLastSave=false;this.autoSaveTimerId=null;this.data=data;this.fileUploaded=false};OpenAssessment.ResponseView.prototype={AUTO_SAVE_POLL_INTERVAL:2e3,AUTO_SAVE_WAIT:3e4,MAX_FILE_SIZE:5242880,UNSAVED_WARNING_KEY:"learner-response",load:function(){var view=this;this.server.render("submission").done(function(html){$("#openassessment__response",view.element).replaceWith(html);view.server.renderLatex($("#openassessment__response",view.element));view.installHandlers();view.setAutoSaveEnabled(true)}).fail(function(){view.baseView.showLoadError("response")})},installHandlers:function(){var sel=$("#openassessment__response",this.element);var view=this;var uploadType="";if(sel.find(".submission__answer__display__file").length){uploadType=sel.find(".submission__answer__display__file").data("upload-type")}this.baseView.setUpCollapseExpand(sel);this.savedResponse=this.response();var handleChange=function(){view.handleResponseChanged()};sel.find(".submission__answer__part__text__value").on("change keyup drop paste",handleChange);var handlePrepareUpload=function(eventData){view.prepareUpload(eventData.target.files,uploadType)};sel.find("input[type=file]").on("change",handlePrepareUpload);sel.find("#submission__preview__item").hide();sel.find("#step--response__submit").click(function(eventObject){eventObject.preventDefault();view.submit()});sel.find("#submission__save").click(function(eventObject){eventObject.preventDefault();view.save()});sel.find("#submission__preview").click(function(eventObject){eventObject.preventDefault();var previewText=sel.find(".submission__answer__part__text__value").val();var previewContainer=sel.find("#preview_content");previewContainer.html(previewText.replace(/\r\n|\r|\n/g,"<br />"));sel.find("#submission__preview__item").show();MathJax.Hub.Queue(["Typeset",MathJax.Hub,previewContainer[0]])});sel.find("#file__upload").click(function(eventObject){eventObject.preventDefault();$(".submission__answer__display__file",view.element).removeClass("is--hidden");view.fileUpload()})},setAutoSaveEnabled:function(enabled){if(enabled){if(this.autoSaveTimerId===null){this.autoSaveTimerId=setInterval($.proxy(this.autoSave,this),this.AUTO_SAVE_POLL_INTERVAL)}}else{if(this.autoSaveTimerId!==null){clearInterval(this.autoSaveTimerId)}}},submitEnabled:function(enabled){var sel=$("#step--response__submit",this.element);if(typeof enabled==="undefined"){return!sel.hasClass("is--disabled")}else{sel.toggleClass("is--disabled",!enabled);return enabled}},saveEnabled:function(enabled){var sel=$("#submission__save",this.element);if(typeof enabled==="undefined"){return!sel.hasClass("is--disabled")}else{sel.toggleClass("is--disabled",!enabled)}},previewEnabled:function(enabled){var sel=$("#submission__preview",this.element);if(typeof enabled==="undefined"){return!sel.hasClass("is--disabled")}else{sel.toggleClass("is--disabled",!enabled)}},saveStatus:function(msg){var sel=$("#response__save_status h3",this.element);if(typeof msg==="undefined"){return sel.text()}else{var label=gettext("Status of Your Response");sel.html('<span class="sr">'+_.escape(label)+":"+"</span>\n"+msg)}},response:function(texts){var sel=$(".response__submission .submission__answer__part__text__value",this.element);if(typeof texts==="undefined"){return sel.map(function(){return $.trim($(this).val())}).get()}else{sel.map(function(index){$(this).val(texts[index])})}},responseChanged:function(){var savedResponse=this.savedResponse;return this.response().some(function(element,index){return element!==savedResponse[index]})},autoSave:function(){var timeSinceLastChange=Date.now()-this.lastChangeTime;if(this.responseChanged()&&timeSinceLastChange>this.AUTO_SAVE_WAIT&&!this.errorOnLastSave){this.save()}},handleResponseChanged:function(){var isNotBlank=!this.response().every(function(element){return $.trim(element)===""});this.submitEnabled(isNotBlank);if(this.responseChanged()){this.saveEnabled(isNotBlank);this.previewEnabled(isNotBlank);this.saveStatus(gettext("This response has not been saved."));this.baseView.unsavedWarningEnabled(true,this.UNSAVED_WARNING_KEY,gettext("If you leave this page without saving or submitting your response, you will lose any work you have done on the response."))}this.lastChangeTime=Date.now()},save:function(){this.errorOnLastSave=false;this.saveStatus(gettext("Saving..."));this.baseView.toggleActionError("save",null);this.baseView.unsavedWarningEnabled(false,this.UNSAVED_WARNING_KEY);var view=this;var savedResponse=this.response();this.server.save(savedResponse).done(function(){view.savedResponse=savedResponse;var currentResponse=view.response();var currentResponseIsEmpty=currentResponse.every(function(element){return element===""});view.submitEnabled(!currentResponseIsEmpty);var currentResponseEqualsSaved=currentResponse.every(function(element,index){return element===savedResponse[index]});if(currentResponseEqualsSaved){view.saveEnabled(false);view.saveStatus(gettext("This response has been saved but not submitted."))}}).fail(function(errMsg){view.saveStatus(gettext("Error"));view.baseView.toggleActionError("save",errMsg);view.errorOnLastSave=true})},submit:function(){this.submitEnabled(false);var view=this;var baseView=this.baseView;var fileDefer=$.Deferred();if(view.files!==null&&!view.fileUploaded){var msg=gettext("Do you want to upload your file before submitting?");if(confirm(msg)){fileDefer=view.fileUpload()}else{view.submitEnabled(true);return}}else{fileDefer.resolve()}fileDefer.pipe(function(){return view.confirmSubmission().pipe(function(){var submission=view.response();baseView.toggleActionError("response",null);return view.server.submit(submission)})}).done($.proxy(view.moveToNextStep,view)).fail(function(errCode,errMsg){if(errCode==="ENOMULTI"){view.moveToNextStep()}else{if(errMsg){baseView.toggleActionError("submit",errMsg)}view.submitEnabled(true)}})},moveToNextStep:function(){this.load();this.baseView.loadAssessmentModules();this.baseView.unsavedWarningEnabled(false,this.UNSAVED_WARNING_KEY)},confirmSubmission:function(){var msg=gettext("You're about to submit your response for this assignment. After you submit this response, you can't change it or submit a new response.");return $.Deferred(function(defer){if(confirm(msg)){defer.resolve()}else{defer.reject()}})},prepareUpload:function(files,uploadType){this.files=null;this.fileType=files[0].type;var ext=files[0].name.split(".").pop().toLowerCase();if(files[0].size>this.MAX_FILE_SIZE){this.baseView.toggleActionError("upload",gettext("File size must be 5MB or less."))}else if(uploadType==="image"&&this.data.ALLOWED_IMAGE_MIME_TYPES.indexOf(this.fileType)===-1){this.baseView.toggleActionError("upload",gettext("You can upload files with these file types: ")+"JPG, PNG or GIF")}else if(uploadType==="pdf-and-image"&&this.data.ALLOWED_FILE_MIME_TYPES.indexOf(this.fileType)===-1){this.baseView.toggleActionError("upload",gettext("You can upload files with these file types: ")+"JPG, PNG, GIF or PDF")}else if(uploadType==="custom"&&this.data.FILE_TYPE_WHITE_LIST.indexOf(ext)===-1){this.baseView.toggleActionError("upload",gettext("You can upload files with these file types: ")+this.data.FILE_TYPE_WHITE_LIST.join(", "))}else if(this.data.FILE_EXT_BLACK_LIST.indexOf(ext)!==-1){this.baseView.toggleActionError("upload",gettext("File type is not allowed."))}else{this.baseView.toggleActionError("upload",null);this.files=files}$("#file__upload").toggleClass("is--disabled",this.files===null)},fileUpload:function(){var view=this;var fileUpload=$("#file__upload");fileUpload.addClass("is--disabled");var handleError=function(errMsg){view.baseView.toggleActionError("upload",errMsg);fileUpload.removeClass("is--disabled")};return this.server.getUploadUrl(view.fileType,view.files[0].name).done(function(url){var file=view.files[0];view.fileUploader.upload(url,file).done(function(){view.fileUrl();view.baseView.toggleActionError("upload",null);view.fileUploaded=true}).fail(handleError)}).fail(handleError)},fileUrl:function(){var view=this;var file=$("#submission__answer__file",view.element);view.server.getDownloadUrl().done(function(url){if(file.prop("tagName")==="IMG"){file.attr("src",url)}else{file.attr("href",url)}return url})}};OpenAssessment.Rubric=function(element){this.element=element};OpenAssessment.Rubric.prototype={criterionFeedback:function(criterionFeedback){var selector="textarea.answer__value";var feedback={};var rubric=this;$(selector,this.element).each(function(index,sel){var criterionName=rubric.getCriterionName(sel);if(typeof criterionFeedback!=="undefined"){$(sel).val(criterionFeedback[criterionName]);feedback[criterionName]=criterionFeedback[criterionName]}else{feedback[criterionName]=$(sel).val()}});return feedback},overallFeedback:function(overallFeedback){var selector=".assessment__rubric__question--feedback__value";
if(typeof overallFeedback==="undefined"){return $(selector,this.element).val()}else{$(selector,this.element).val(overallFeedback)}},optionsSelected:function(optionsSelected){var selector="input[type=radio]";var rubric=this;if(typeof optionsSelected==="undefined"){var options={};$(selector+":checked",this.element).each(function(index,sel){options[rubric.getCriterionName(sel)]=sel.value});return options}else{$(selector,this.element).prop("checked",false);$(selector,this.element).each(function(index,sel){var criterionName=rubric.getCriterionName(sel);if(optionsSelected.hasOwnProperty(criterionName)){if(sel.value===optionsSelected[criterionName]){$(sel).prop("checked",true)}}})}},canSubmitCallback:function(callback){var rubric=this;callback(rubric.canSubmit());$(this.element).on("change keyup drop paste",function(){callback(rubric.canSubmit())})},canSubmit:function(){var numChecked=$("input[type=radio]:checked",this.element).length;var numAvailable=$(".field--radio.assessment__rubric__question.has--options",this.element).length;var completedRequiredComments=true;$("textarea[required]",this.element).each(function(){var trimmedText=$.trim($(this).val());if(trimmedText===""){completedRequiredComments=false}});return numChecked===numAvailable&&completedRequiredComments},changesExistCallback:function(callback){var rubric=this;callback(rubric.changesExist());$(this.element).on("change keyup drop paste",function(){callback(rubric.changesExist())})},changesExist:function(){var numChecked=$("input[type=radio]:checked",this.element).length;var textExists=false;$("textarea",this.element).each(function(){var trimmedText=$.trim($(this).val());if(trimmedText!==""){textExists=true}});return numChecked>0||textExists},showCorrections:function(corrections){var selector="input[type=radio]";var hasErrors=false;var rubric=this;$(selector,this.element).each(function(index,sel){var listItem=$(sel).parents(".assessment__rubric__question");if(corrections.hasOwnProperty(rubric.getCriterionName(sel))){hasErrors=true;listItem.find(".message--incorrect").removeClass("is--hidden");listItem.find(".message--correct").addClass("is--hidden")}else{listItem.find(".message--correct").removeClass("is--hidden");listItem.find(".message--incorrect").addClass("is--hidden")}});return hasErrors},getCriterionName:function(element){return $(element).data("criterion-name")}};OpenAssessment.SelfView=function(element,server,baseView){this.element=element;this.server=server;this.baseView=baseView;this.rubric=null};OpenAssessment.SelfView.prototype={UNSAVED_WARNING_KEY:"self-assessment",load:function(){var view=this;this.server.render("self_assessment").done(function(html){$("#openassessment__self-assessment",view.element).replaceWith(html);view.server.renderLatex($("#openassessment__self-assessment",view.element));view.installHandlers()}).fail(function(){view.showLoadError("self-assessment")})},installHandlers:function(){var view=this;var sel=$("#openassessment__self-assessment",view.element);this.baseView.setUpCollapseExpand(sel);var rubricSelector=$("#self-assessment--001__assessment",this.element);if(rubricSelector.size()>0){var rubricElement=rubricSelector.get(0);this.rubric=new OpenAssessment.Rubric(rubricElement)}else{this.rubric=null}if(this.rubric!==null){this.rubric.canSubmitCallback($.proxy(this.selfSubmitEnabled,this));this.rubric.changesExistCallback($.proxy(this.assessmentRubricChanges,this))}sel.find("#self-assessment--001__assessment__submit").click(function(eventObject){eventObject.preventDefault();view.selfAssess()})},selfSubmitEnabled:function(enabled){var button=$("#self-assessment--001__assessment__submit",this.element);if(typeof enabled==="undefined"){return!button.hasClass("is--disabled")}else{button.toggleClass("is--disabled",!enabled);return enabled}},assessmentRubricChanges:function(changesExist){if(changesExist){this.baseView.unsavedWarningEnabled(true,this.UNSAVED_WARNING_KEY,gettext("If you leave this page without submitting your self assessment, you will lose any work you have done."))}},selfAssess:function(){var view=this;var baseView=this.baseView;baseView.toggleActionError("self",null);view.selfSubmitEnabled(false);this.server.selfAssess(this.rubric.optionsSelected(),this.rubric.criterionFeedback(),this.rubric.overallFeedback()).done(function(){baseView.unsavedWarningEnabled(false,view.UNSAVED_WARNING_KEY);baseView.loadAssessmentModules();baseView.scrollToTop()}).fail(function(errMsg){baseView.toggleActionError("self",errMsg);view.selfSubmitEnabled(true)})}};OpenAssessment.StaffView=function(element,server,baseView){this.element=element;this.server=server;this.baseView=baseView};OpenAssessment.StaffView.prototype={load:function(){var view=this;this.server.render("staff_assessment").done(function(html){$("#openassessment__staff-assessment",view.element).replaceWith(html)}).fail(function(){view.baseView.showLoadError("staff-assessment")})}};!function(OpenAssessment){"use strict";OpenAssessment.StaffAreaView=function(element,server,baseView){this.element=element;this.server=server;this.baseView=baseView};OpenAssessment.StaffAreaView.prototype={FULL_GRADE_UNSAVED_WARNING_KEY:"staff-grade",OVERRIDE_UNSAVED_WARNING_KEY:"staff-override",load:function(){var view=this;if($(".openassessment__staff-area",view.element).length>0){this.server.render("staff_area").done(function(html){$(".openassessment__staff-area",view.element).replaceWith(html);view.server.renderLatex($(".openassessment__staff-area",view.element));view.installHandlers()}).fail(function(){view.baseView.showLoadError("staff_area")})}},loadStudentInfo:function(options){var view=this;var $manageLearnersTab=$(".openassessment__staff-tools",this.element);var $form=$manageLearnersTab.find(".openassessment_student_info_form");var studentUsername=$manageLearnersTab.find(".openassessment__student_username").val();var showFormError=function(errorMessage){$form.find(".form--error").text(errorMessage)};var deferred=$.Deferred();$(".openassessment__student-info",view.element).text("");if(studentUsername.trim()){this.server.studentInfo(studentUsername,options).done(function(html){showFormError("");$(".openassessment__student-info",view.element).replaceWith(html);$manageLearnersTab.on("click",".action--submit-cancel-submission",function(eventObject){eventObject.preventDefault();view.cancelSubmission($(this).data("submission-uuid"))});var handleChange=function(eventData){view.handleCommentChanged(eventData)};$manageLearnersTab.find(".cancel_submission_comments").on("change keyup drop paste",handleChange);var $rubric=$manageLearnersTab.find(".staff-assessment__assessment");if($rubric.size()>0){var rubricElement=$rubric.get(0);var rubric=new OpenAssessment.Rubric(rubricElement);rubric.canSubmitCallback($.proxy(view.staffSubmitEnabled,view,$manageLearnersTab));rubric.changesExistCallback($.proxy(view.assessmentRubricChanges,view,view.OVERRIDE_UNSAVED_WARNING_KEY));$manageLearnersTab.find(".wrapper--staff-assessment .action--submit",view.element).click(function(eventObject){var target=$(eventObject.currentTarget),rootElement=target.closest(".openassessment__student-info"),submissionID=rootElement.data("submission-uuid");eventObject.preventDefault();view.submitStaffOverride(submissionID,rubric,$manageLearnersTab)})}deferred.resolve()}).fail(function(){showFormError(gettext("Unexpected server error."));deferred.reject()})}else{showFormError(gettext("You must provide a learner name."));deferred.reject()}return deferred.promise()},loadStaffGradeForm:function(clearAndCollapse){var view=this;var $staffGradeTab=$(".openassessment__staff-grading",this.element);var deferred=$.Deferred();var showFormError=function(errorMessage){$staffGradeTab.find(".staff__grade__form--error").text(errorMessage)};if(clearAndCollapse){$staffGradeTab.find(".staff__grade__control").toggleClass("is--collapsed",true);$staffGradeTab.find(".staff__grade__form").replaceWith('<div class="staff__grade__form"></div>');view.updateStaffGradeCounts();deferred.resolve()}else if(!this.staffGradeFormLoaded){this.staffGradeFormLoaded=true;this.server.staffGradeForm().done(function(html){showFormError("");$staffGradeTab.find(".staff__grade__form").replaceWith(html);view.updateStaffGradeCounts();var $rubric=$staffGradeTab.find(".staff-assessment__assessment");if($rubric.size()>0){var rubricElement=$rubric.get(0);var rubric=new OpenAssessment.Rubric(rubricElement);rubric.canSubmitCallback($.proxy(view.staffSubmitEnabled,view,$staffGradeTab));rubric.changesExistCallback($.proxy(view.assessmentRubricChanges,view,view.FULL_GRADE_UNSAVED_WARNING_KEY));$staffGradeTab.find(".wrapper--staff-assessment .action--submit").click(function(eventObject){var submissionID=$staffGradeTab.find(".staff__grade__form").data("submission-uuid");eventObject.preventDefault();view.submitStaffGrade(submissionID,rubric,$staffGradeTab,$(eventObject.currentTarget).hasClass("continue_grading--action"))})}deferred.resolve()}).fail(function(){showFormError(gettext("Unexpected server error."));view.staffGradeFormLoaded=false;deferred.reject()})}return deferred.promise()},updateStaffGradeCounts:function(){var view=this;var $staffGradeTab=$(".openassessment__staff-grading",this.element);view.server.staffGradeCounts().done(function(html){$staffGradeTab.find(".staff__grade__status").replaceWith(html)}).fail(function(){$staffGradeTab.find(".staff__grade__status").replaceWith('<span class="staff__grade__status"><span class="staff__grade__value"><span class="copy">'+gettext("Error getting the number of ungraded responses")+"</span></span></span>")})},installHandlers:function(){var view=this;var $staffArea=$(".openassessment__staff-area",this.element);var $staffTools=$(".openassessment__staff-tools",$staffArea);var $staffInfo=$(".openassessment__student-info",$staffArea);var $staffGradeTool=$(".openassessment__staff-grading",$staffArea);if($staffArea.length<=0){return}this.baseView.setUpCollapseExpand($staffTools,function(){});this.baseView.setUpCollapseExpand($staffInfo,function(){});this.baseView.setUpCollapseExpand($staffGradeTool,function(){});$staffArea.find(".ui-staff__button").click(function(eventObject){var $button=$(eventObject.currentTarget),panelClass=$button.data("panel"),$panel=$staffArea.find("."+panelClass).first();if($button.hasClass("is--active")){$button.removeClass("is--active");$panel.addClass("is--hidden")}else{$staffArea.find(".ui-staff__button").removeClass("is--active");$button.addClass("is--active");$staffArea.find(".wrapper--ui-staff").addClass("is--hidden");$panel.removeClass("is--hidden")}$panel.find(".ui-staff_close_button").focus()});$staffArea.find(".ui-staff_close_button").click(function(eventObject){var $button=$(eventObject.currentTarget),$panel=$button.closest(".wrapper--ui-staff");$staffArea.find(".ui-staff__button").removeClass("is--active");$panel.addClass("is--hidden");$staffArea.find(".ui-staff__button").each(function(index,button){var $staffPanel=$staffArea.find("."+$(button).data("panel")).first();if($staffPanel[0]===$panel[0]){$(button).focus()}})});$staffTools.find(".openassessment_student_info_form").submit(function(eventObject){eventObject.preventDefault();view.loadStudentInfo()});$staffTools.find(".action--submit-username").click(function(eventObject){eventObject.preventDefault();view.loadStudentInfo()});$staffTools.find(".action--submit-training").click(function(eventObject){eventObject.preventDefault();view.scheduleTraining()});$staffTools.find(".action--submit-unfinished-tasks").click(function(eventObject){eventObject.preventDefault();view.rescheduleUnfinishedTasks()});$staffGradeTool.find(".staff__grade__show-form").click(function(){var wasCollapsed=$staffGradeTool.find(".staff__grade__control").hasClass("is--collapsed");if(wasCollapsed){view.loadStaffGradeForm()}})},scheduleTraining:function(){var view=this;this.server.scheduleTraining().done(function(msg){$(".schedule_training_message",view.element).text(msg)}).fail(function(errMsg){$(".schedule_training_message",view.element).text(errMsg)})},rescheduleUnfinishedTasks:function(){var view=this;this.server.rescheduleUnfinishedTasks().done(function(msg){$(".reschedule_unfinished_tasks_message",view.element).text(msg)}).fail(function(errMsg){$(".reschedule_unfinished_tasks_message",view.element).text(errMsg)})},cancelSubmission:function(submissionUUID){this.cancelSubmissionEnabled(false);var view=this;var comments=$(".cancel_submission_comments",this.element).val();this.server.cancelSubmission(submissionUUID,comments).done(function(){view.loadStudentInfo({expanded_view:"final-grade"})}).fail(function(errorMessage){$(".cancel-submission-error").html(_.escape(errorMessage))})},cancelSubmissionEnabled:function(enabled){var $cancelButton=$(".action--submit-cancel-submission",this.element);if(typeof enabled==="undefined"){return!$cancelButton.hasClass("is--disabled")}else{$cancelButton.toggleClass("is--disabled",!enabled)}},comment:function(text){var $submissionComments=$(".cancel_submission_comments",this.element);if(typeof text==="undefined"){return $submissionComments.val()}else{$submissionComments.val(text)}},handleCommentChanged:function(){var isBlank=$.trim(this.comment())!=="";this.cancelSubmissionEnabled(isBlank)},staffSubmitEnabled:function(scope,enabled){var button=scope.find(".wrapper--staff-assessment .action--submit");if(typeof enabled==="undefined"){return!button.hasClass("is--disabled")}else{button.toggleClass("is--disabled",!enabled);return enabled}},assessmentRubricChanges:function(key,changesExist){if(changesExist){this.baseView.unsavedWarningEnabled(true,key,gettext("If you leave this page without submitting your staff assessment, you will lose any work you have done."))}},submitStaffOverride:function(submissionID,rubric,scope){var view=this;var successCallback=function(){view.baseView.unsavedWarningEnabled(false,view.OVERRIDE_UNSAVED_WARNING_KEY);view.loadStudentInfo({expanded_view:"final-grade"})};this.callStaffAssess(submissionID,rubric,scope,successCallback,".staff-override-error","regrade")},submitStaffGrade:function(submissionID,rubric,scope,continueGrading){var view=this;var successCallback=function(){view.baseView.unsavedWarningEnabled(false,view.FULL_GRADE_UNSAVED_WARNING_KEY);view.staffGradeFormLoaded=false;view.loadStaffGradeForm(!continueGrading);if(continueGrading){view.baseView.scrollToTop(".openassessment__staff-area")}};this.callStaffAssess(submissionID,rubric,scope,successCallback,".staff-grade-error","full-grade")},callStaffAssess:function(submissionID,rubric,scope,successCallback,errorSelector,assessType){var view=this;view.staffSubmitEnabled(scope,false);this.server.staffAssess(rubric.optionsSelected(),rubric.criterionFeedback(),rubric.overallFeedback(),submissionID,assessType).done(successCallback).fail(function(errorMessage){scope.find(errorSelector).html(_.escape(errorMessage));view.staffSubmitEnabled(scope,true)})}}}(OpenAssessment);OpenAssessment.StudentTrainingView=function(element,server,baseView){this.element=element;this.server=server;this.baseView=baseView;this.rubric=null};OpenAssessment.StudentTrainingView.prototype={load:function(){var view=this;this.server.render("student_training").done(function(html){$("#openassessment__student-training",view.element).replaceWith(html);view.server.renderLatex($("#openassessment__student-training",view.element));view.installHandlers()}).fail(function(){view.baseView.showLoadError("student-training")})},installHandlers:function(){var sel=$("#openassessment__student-training",this.element);var view=this;this.baseView.setUpCollapseExpand(sel);var rubricSelector=$("#student-training--001__assessment",this.element);if(rubricSelector.size()>0){var rubricElement=rubricSelector.get(0);this.rubric=new OpenAssessment.Rubric(rubricElement)}if(this.rubric!==null){this.rubric.canSubmitCallback($.proxy(this.assessButtonEnabled,this))}sel.find("#student-training--001__assessment__submit").click(function(eventObject){eventObject.preventDefault();view.assess()})},assess:function(){this.assessButtonEnabled(false);var options={};if(this.rubric!==null){options=this.rubric.optionsSelected()}var view=this;var baseView=this.baseView;this.server.trainingAssess(options).done(function(corrections){var incorrect=$("#openassessment__student-training--incorrect",view.element);var instructions=$("#openassessment__student-training--instructions",view.element);if(!view.rubric.showCorrections(corrections)){view.load();baseView.loadAssessmentModules();incorrect.addClass("is--hidden");instructions.removeClass("is--hidden")}else{instructions.addClass("is--hidden");incorrect.removeClass("is--hidden")}baseView.scrollToTop()}).fail(function(errMsg){baseView.toggleActionError("student-training",errMsg);view.assessButtonEnabled(true)})},assessButtonEnabled:function(isEnabled){var button=$("#student-training--001__assessment__submit",this.element);if(typeof isEnabled==="undefined"){return!button.hasClass("is--disabled")}else{button.toggleClass("is--disabled",!isEnabled)}}};
\ No newline at end of file
if(typeof overallFeedback==="undefined"){return $(selector,this.element).val()}else{$(selector,this.element).val(overallFeedback)}},optionsSelected:function(optionsSelected){var selector="input[type=radio]";var rubric=this;if(typeof optionsSelected==="undefined"){var options={};$(selector+":checked",this.element).each(function(index,sel){options[rubric.getCriterionName(sel)]=sel.value});return options}else{$(selector,this.element).prop("checked",false);$(selector,this.element).each(function(index,sel){var criterionName=rubric.getCriterionName(sel);if(optionsSelected.hasOwnProperty(criterionName)){if(sel.value===optionsSelected[criterionName]){$(sel).prop("checked",true)}}})}},canSubmitCallback:function(callback){var rubric=this;callback(rubric.canSubmit());$(this.element).on("change keyup drop paste",function(){callback(rubric.canSubmit())})},canSubmit:function(){var numChecked=$("input[type=radio]:checked",this.element).length;var numAvailable=$(".field--radio.assessment__rubric__question.has--options",this.element).length;var completedRequiredComments=true;$("textarea[required]",this.element).each(function(){var trimmedText=$.trim($(this).val());if(trimmedText===""){completedRequiredComments=false}});return numChecked===numAvailable&&completedRequiredComments},changesExistCallback:function(callback){var rubric=this;callback(rubric.changesExist());$(this.element).on("change keyup drop paste",function(){callback(rubric.changesExist())})},changesExist:function(){var numChecked=$("input[type=radio]:checked",this.element).length;var textExists=false;$("textarea",this.element).each(function(){var trimmedText=$.trim($(this).val());if(trimmedText!==""){textExists=true}});return numChecked>0||textExists},showCorrections:function(corrections){var selector="input[type=radio]";var hasErrors=false;var rubric=this;$(selector,this.element).each(function(index,sel){var listItem=$(sel).parents(".assessment__rubric__question");if(corrections.hasOwnProperty(rubric.getCriterionName(sel))){hasErrors=true;listItem.find(".message--incorrect").removeClass("is--hidden");listItem.find(".message--correct").addClass("is--hidden")}else{listItem.find(".message--correct").removeClass("is--hidden");listItem.find(".message--incorrect").addClass("is--hidden")}});return hasErrors},getCriterionName:function(element){return $(element).data("criterion-name")}};OpenAssessment.SelfView=function(element,server,baseView){this.element=element;this.server=server;this.baseView=baseView;this.rubric=null};OpenAssessment.SelfView.prototype={UNSAVED_WARNING_KEY:"self-assessment",load:function(){var view=this;this.server.render("self_assessment").done(function(html){$("#openassessment__self-assessment",view.element).replaceWith(html);view.server.renderLatex($("#openassessment__self-assessment",view.element));view.installHandlers()}).fail(function(){view.showLoadError("self-assessment")})},installHandlers:function(){var view=this;var sel=$("#openassessment__self-assessment",view.element);this.baseView.setUpCollapseExpand(sel);var rubricSelector=$("#self-assessment--001__assessment",this.element);if(rubricSelector.size()>0){var rubricElement=rubricSelector.get(0);this.rubric=new OpenAssessment.Rubric(rubricElement)}else{this.rubric=null}if(this.rubric!==null){this.rubric.canSubmitCallback($.proxy(this.selfSubmitEnabled,this));this.rubric.changesExistCallback($.proxy(this.assessmentRubricChanges,this))}sel.find("#self-assessment--001__assessment__submit").click(function(eventObject){eventObject.preventDefault();view.selfAssess()})},selfSubmitEnabled:function(enabled){var button=$("#self-assessment--001__assessment__submit",this.element);if(typeof enabled==="undefined"){return!button.hasClass("is--disabled")}else{button.toggleClass("is--disabled",!enabled);return enabled}},assessmentRubricChanges:function(changesExist){if(changesExist){this.baseView.unsavedWarningEnabled(true,this.UNSAVED_WARNING_KEY,gettext("If you leave this page without submitting your self assessment, you will lose any work you have done."))}},selfAssess:function(){var view=this;var baseView=this.baseView;baseView.toggleActionError("self",null);view.selfSubmitEnabled(false);this.server.selfAssess(this.rubric.optionsSelected(),this.rubric.criterionFeedback(),this.rubric.overallFeedback()).done(function(){baseView.unsavedWarningEnabled(false,view.UNSAVED_WARNING_KEY);baseView.loadAssessmentModules();baseView.scrollToTop()}).fail(function(errMsg){baseView.toggleActionError("self",errMsg);view.selfSubmitEnabled(true)})}};OpenAssessment.StaffView=function(element,server,baseView){this.element=element;this.server=server;this.baseView=baseView};OpenAssessment.StaffView.prototype={load:function(){var view=this;this.server.render("staff_assessment").done(function(html){$("#openassessment__staff-assessment",view.element).replaceWith(html)}).fail(function(){view.baseView.showLoadError("staff-assessment")})}};!function(OpenAssessment){"use strict";OpenAssessment.StaffAreaView=function(element,server,baseView){this.element=element;this.server=server;this.baseView=baseView};OpenAssessment.StaffAreaView.prototype={FULL_GRADE_UNSAVED_WARNING_KEY:"staff-grade",OVERRIDE_UNSAVED_WARNING_KEY:"staff-override",IS_SHOWING_CLASS:"is--showing",SLIDABLE_CLASS:"ui-slidable",SLIDABLE_CONTENT_CLASS:"ui-slidable__content",load:function(){var view=this;if($(".openassessment__staff-area",view.element).length>0){this.server.render("staff_area").done(function(html){$(".openassessment__staff-area",view.element).replaceWith(html);view.server.renderLatex($(".openassessment__staff-area",view.element));view.installHandlers()}).fail(function(){view.baseView.showLoadError("staff_area")})}},loadStudentInfo:function(classToExpand){var view=this;var $manageLearnersTab=$(".openassessment__staff-tools",this.element);var $form=$manageLearnersTab.find(".openassessment_student_info_form");var studentUsername=$manageLearnersTab.find(".openassessment__student_username").val();var showFormError=function(errorMessage){$form.find(".form--error").text(errorMessage).focus()};var deferred=$.Deferred();$(".openassessment__student-info",view.element).text("");if(studentUsername.trim()){this.server.studentInfo(studentUsername).done(function(html){showFormError("");$(".openassessment__student-info",view.element).replaceWith(html);$manageLearnersTab.on("click",".action--submit-cancel-submission",function(eventObject){eventObject.preventDefault();view.cancelSubmission($(this).data("submission-uuid"))});var handleChange=function(eventData){view.handleCommentChanged(eventData)};$manageLearnersTab.find(".cancel_submission_comments").on("change keyup drop paste",handleChange);var $rubric=$manageLearnersTab.find(".staff-assessment__assessment");if($rubric.size()>0){var rubricElement=$rubric.get(0);var rubric=new OpenAssessment.Rubric(rubricElement);rubric.canSubmitCallback($.proxy(view.staffSubmitEnabled,view,$manageLearnersTab));rubric.changesExistCallback($.proxy(view.assessmentRubricChanges,view,view.OVERRIDE_UNSAVED_WARNING_KEY));$manageLearnersTab.find(".wrapper--staff-assessment .action--submit",view.element).click(function(eventObject){var target=$(eventObject.currentTarget),rootElement=target.closest(".openassessment__student-info"),submissionID=rootElement.data("submission-uuid");eventObject.preventDefault();view.submitStaffOverride(submissionID,rubric,$manageLearnersTab)})}$manageLearnersTab.find("."+view.SLIDABLE_CLASS).click(function(event){var $toggle=$(event.currentTarget),$content=$toggle.next("."+view.SLIDABLE_CONTENT_CLASS);if($toggle.hasClass(view.IS_SHOWING_CLASS)){$toggle.removeClass(view.IS_SHOWING_CLASS).attr("aria-expanded","false");$content.slideUp()}else{$toggle.addClass(view.IS_SHOWING_CLASS).attr("aria-expanded","true");$content.slideDown()}});$manageLearnersTab.find(".staff-info__student__report__summary").focus();if(classToExpand){$manageLearnersTab.find("."+classToExpand+" ."+view.SLIDABLE_CONTENT_CLASS).slideDown();$manageLearnersTab.find("."+classToExpand+" ."+view.SLIDABLE_CLASS).addClass(view.IS_SHOWING_CLASS).attr("aria-expanded","true").focus()}deferred.resolve()}).fail(function(){showFormError(gettext("Unexpected server error."));deferred.reject()})}else{showFormError(gettext("You must provide a learner name."));deferred.reject()}return deferred.promise()},loadStaffGradeForm:function(){var view=this;var $staffGradeTab=$(".openassessment__staff-grading",this.element);var $staffGradeControl=$staffGradeTab.find("."+view.SLIDABLE_CLASS);var $staffGradeContent=$staffGradeTab.find("."+view.SLIDABLE_CONTENT_CLASS);var deferred=$.Deferred();var showFormError=function(errorMessage){$staffGradeTab.find(".staff__grade__form--error").text(errorMessage).focus()};$staffGradeControl.toggleClass(view.IS_SHOWING_CLASS,true).attr("aria-expanded","true");if(this.staffGradeFormLoaded){$staffGradeContent.slideDown();deferred.resolve()}else{this.staffGradeFormLoaded=true;this.server.staffGradeForm().done(function(html){showFormError("");$staffGradeTab.find(".staff__grade__form").replaceWith(html);view.updateStaffGradeCounts();var $rubric=$staffGradeTab.find(".staff-assessment__assessment");if($rubric.size()>0){var rubricElement=$rubric.get(0);var rubric=new OpenAssessment.Rubric(rubricElement);rubric.canSubmitCallback($.proxy(view.staffSubmitEnabled,view,$staffGradeTab));rubric.changesExistCallback($.proxy(view.assessmentRubricChanges,view,view.FULL_GRADE_UNSAVED_WARNING_KEY));$staffGradeTab.find(".wrapper--staff-assessment .action--submit").click(function(eventObject){var submissionID=$staffGradeTab.find(".staff__grade__form").data("submission-uuid");eventObject.preventDefault();view.submitStaffGrade(submissionID,rubric,$staffGradeTab,$(eventObject.currentTarget).hasClass("continue_grading--action"))})}$staffGradeContent.slideDown(function(){$staffGradeControl.focus()});deferred.resolve()}).fail(function(){showFormError(gettext("Unexpected server error."));view.staffGradeFormLoaded=false;deferred.reject()})}return deferred.promise()},closeStaffGradeForm:function(clear){var $staffGradeTab=$(".openassessment__staff-grading",this.element);var $staffGradeControl=$staffGradeTab.find("."+this.SLIDABLE_CLASS);var $staffGradeContent=$staffGradeTab.find("."+this.SLIDABLE_CONTENT_CLASS);$staffGradeControl.toggleClass(this.IS_SHOWING_CLASS,false).attr("aria-expanded","false");if(clear){$staffGradeTab.find(".staff__grade__form").replaceWith('<div class="staff__grade__form"></div>');this.updateStaffGradeCounts()}else{$staffGradeContent.slideUp()}$staffGradeControl.focus()},updateStaffGradeCounts:function(){var view=this;var $staffGradeTab=$(".openassessment__staff-grading",this.element);view.server.staffGradeCounts().done(function(html){$staffGradeTab.find(".staff__grade__status").replaceWith(html)}).fail(function(){$staffGradeTab.find(".staff__grade__status").replaceWith('<span class="staff__grade__status"><span class="staff__grade__value"><span class="copy">'+gettext("Error getting the number of ungraded responses")+"</span></span></span>")})},installHandlers:function(){var view=this;var $staffArea=$(".openassessment__staff-area",this.element);var $manageLearnersTab=$(".openassessment__staff-tools",$staffArea);var $staffGradeTool=$(".openassessment__staff-grading",$staffArea);if($staffArea.length<=0){return}$staffArea.find(".ui-staff__button").click(function(eventObject){$staffArea.find(".ui-staff__button").each(function(index,button){if(button!==eventObject.currentTarget){var $panel=$staffArea.find("."+$(button).data("panel")).first();$panel.slideUp(0)}});var $button=$(eventObject.currentTarget),$panel=$staffArea.find("."+$button.data("panel")).first();if($button.hasClass("is--active")){$button.removeClass("is--active").attr("aria-expanded","false");$panel.slideUp()}else{$staffArea.find(".ui-staff__button").removeClass("is--active").attr("aria-expanded","false");$button.addClass("is--active").attr("aria-expanded","true");$panel.slideDown()}$panel.find(".ui-staff_close_button").focus()});$staffArea.find(".ui-staff_close_button").click(function(eventObject){var $button=$(eventObject.currentTarget),$panel=$button.closest(".wrapper--ui-staff");$staffArea.find(".ui-staff__button").removeClass("is--active").attr("aria-expanded","false");$panel.slideUp();$staffArea.find(".ui-staff__button").each(function(index,button){var $staffPanel=$staffArea.find("."+$(button).data("panel")).first();if($staffPanel[0]===$panel[0]){$(button).focus()}})});$manageLearnersTab.find(".openassessment_student_info_form").submit(function(eventObject){eventObject.preventDefault();view.loadStudentInfo()});$manageLearnersTab.find(".action--submit-username").click(function(eventObject){eventObject.preventDefault();view.loadStudentInfo()});$manageLearnersTab.find(".action--submit-training").click(function(eventObject){eventObject.preventDefault();view.scheduleTraining()});$manageLearnersTab.find(".action--submit-unfinished-tasks").click(function(eventObject){eventObject.preventDefault();view.rescheduleUnfinishedTasks()});$staffGradeTool.find(".staff__grade__show-form").click(function(event){var wasShowing=$(event.currentTarget).hasClass(view.IS_SHOWING_CLASS);if(wasShowing){view.closeStaffGradeForm(false)}else{view.loadStaffGradeForm()}})},scheduleTraining:function(){var view=this;this.server.scheduleTraining().done(function(msg){$(".schedule_training_message",view.element).text(msg)}).fail(function(errMsg){$(".schedule_training_message",view.element).text(errMsg)})},rescheduleUnfinishedTasks:function(){var view=this;this.server.rescheduleUnfinishedTasks().done(function(msg){$(".reschedule_unfinished_tasks_message",view.element).text(msg)}).fail(function(errMsg){$(".reschedule_unfinished_tasks_message",view.element).text(errMsg)})},cancelSubmission:function(submissionUUID){this.cancelSubmissionEnabled(false);var view=this;var comments=$(".cancel_submission_comments",this.element).val();this.server.cancelSubmission(submissionUUID,comments).done(function(){view.loadStudentInfo("staff-info__student__grade")}).fail(function(errorMessage){$(".cancel-submission-error").html(_.escape(errorMessage))})},cancelSubmissionEnabled:function(enabled){var $cancelButton=$(".action--submit-cancel-submission",this.element);if(typeof enabled==="undefined"){return!$cancelButton.hasClass("is--disabled")}else{$cancelButton.toggleClass("is--disabled",!enabled)}},comment:function(text){var $submissionComments=$(".cancel_submission_comments",this.element);if(typeof text==="undefined"){return $submissionComments.val()}else{$submissionComments.val(text)}},handleCommentChanged:function(){var isBlank=$.trim(this.comment())!=="";this.cancelSubmissionEnabled(isBlank)},staffSubmitEnabled:function(scope,enabled){var button=scope.find(".wrapper--staff-assessment .action--submit");if(typeof enabled==="undefined"){return!button.hasClass("is--disabled")}else{button.toggleClass("is--disabled",!enabled);return enabled}},assessmentRubricChanges:function(key,changesExist){if(changesExist){this.baseView.unsavedWarningEnabled(true,key,gettext("If you leave this page without submitting your staff assessment, you will lose any work you have done."))}},submitStaffOverride:function(submissionID,rubric,scope){var view=this;var successCallback=function(){view.baseView.unsavedWarningEnabled(false,view.OVERRIDE_UNSAVED_WARNING_KEY);view.loadStudentInfo("staff-info__student__grade")};this.callStaffAssess(submissionID,rubric,scope,successCallback,".staff-override-error","regrade")},submitStaffGrade:function(submissionID,rubric,scope,continueGrading){var view=this;var successCallback=function(){view.baseView.unsavedWarningEnabled(false,view.FULL_GRADE_UNSAVED_WARNING_KEY);view.staffGradeFormLoaded=false;if(continueGrading){view.loadStaffGradeForm();view.baseView.scrollToTop(".openassessment__staff-area")}else{view.closeStaffGradeForm(true)}};this.callStaffAssess(submissionID,rubric,scope,successCallback,".staff-grade-error","full-grade")},callStaffAssess:function(submissionID,rubric,scope,successCallback,errorSelector,assessType){var view=this;view.staffSubmitEnabled(scope,false);this.server.staffAssess(rubric.optionsSelected(),rubric.criterionFeedback(),rubric.overallFeedback(),submissionID,assessType).done(successCallback).fail(function(errorMessage){scope.find(errorSelector).html(_.escape(errorMessage));view.staffSubmitEnabled(scope,true)})}}}(OpenAssessment);OpenAssessment.StudentTrainingView=function(element,server,baseView){this.element=element;this.server=server;this.baseView=baseView;this.rubric=null};OpenAssessment.StudentTrainingView.prototype={load:function(){var view=this;this.server.render("student_training").done(function(html){$("#openassessment__student-training",view.element).replaceWith(html);view.server.renderLatex($("#openassessment__student-training",view.element));view.installHandlers()}).fail(function(){view.baseView.showLoadError("student-training")})},installHandlers:function(){var sel=$("#openassessment__student-training",this.element);var view=this;this.baseView.setUpCollapseExpand(sel);var rubricSelector=$("#student-training--001__assessment",this.element);if(rubricSelector.size()>0){var rubricElement=rubricSelector.get(0);this.rubric=new OpenAssessment.Rubric(rubricElement)}if(this.rubric!==null){this.rubric.canSubmitCallback($.proxy(this.assessButtonEnabled,this))}sel.find("#student-training--001__assessment__submit").click(function(eventObject){eventObject.preventDefault();view.assess()})},assess:function(){this.assessButtonEnabled(false);var options={};if(this.rubric!==null){options=this.rubric.optionsSelected()}var view=this;var baseView=this.baseView;this.server.trainingAssess(options).done(function(corrections){var incorrect=$("#openassessment__student-training--incorrect",view.element);var instructions=$("#openassessment__student-training--instructions",view.element);if(!view.rubric.showCorrections(corrections)){view.load();baseView.loadAssessmentModules();incorrect.addClass("is--hidden");instructions.removeClass("is--hidden")}else{instructions.addClass("is--hidden");incorrect.removeClass("is--hidden")}baseView.scrollToTop()}).fail(function(errMsg){baseView.toggleActionError("student-training",errMsg);view.assessButtonEnabled(true)})},assessButtonEnabled:function(isEnabled){var button=$("#student-training--001__assessment__submit",this.element);if(typeof isEnabled==="undefined"){return!button.hasClass("is--disabled")}else{button.toggleClass("is--disabled",!isEnabled)}}};
\ No newline at end of file
......@@ -160,6 +160,9 @@ describe('OpenAssessment.StaffAreaView', function() {
// Create a new stub server
server = new StubServer();
server.renderLatex = jasmine.createSpy('renderLatex');
// Disable animations for slideUp and slideDown.
jQuery.fx.off = true;
});
describe('Initial rendering', function() {
......@@ -293,15 +296,17 @@ describe('OpenAssessment.StaffAreaView', function() {
};
var getVisibleStaffPanels = function(view) {
return $('.wrapper--ui-staff', view.element).not('.is--hidden');
return $('.wrapper--ui-staff:visible, view.element');
};
var verifyStaffButtonBehavior = function(view, buttonName) {
var $staffInfoButton = getStaffButton(view, buttonName),
$visiblePanels;
expect($staffInfoButton).not.toHaveClass('is--active');
expect($staffInfoButton).toHaveAttr('aria-expanded', 'false');
$staffInfoButton[0].click();
expect($staffInfoButton).toHaveClass('is--active');
expect($staffInfoButton).toHaveAttr('aria-expanded', 'true');
$visiblePanels = getVisibleStaffPanels(view);
expect($visiblePanels.length).toBe(1);
expect($visiblePanels.first()).toHaveClass('wrapper--' + buttonName);
......@@ -310,23 +315,23 @@ describe('OpenAssessment.StaffAreaView', function() {
verifyFocused(closeButton);
};
it('shows the correct buttons with no panels initially', function() {
it('shows the correct buttons when full grading is not enabled', function() {
var view = createStaffArea(),
$buttons = $('.ui-staff__button', view.element);
expect($buttons.length).toBe(2);
expect($buttons).toHaveAttr('aria-expanded', 'false');
expect($($buttons[0]).text().trim()).toEqual('Manage Individual Learners');
expect($($buttons[1]).text().trim()).toEqual('View Assignment Statistics');
expect(getVisibleStaffPanels(view).length).toBe(0);
});
it('shows the correct buttons for full grading with no panels initially', function() {
it('shows the correct buttons for full grading', function() {
var view = createStaffArea({}, 'oa_staff_area_full_grading.html'),
$buttons = $('.ui-staff__button', view.element);
expect($buttons.length).toBe(3);
expect($buttons).toHaveAttr('aria-expanded', 'false');
expect($($buttons[0]).text().trim()).toEqual('Manage Individual Learners');
expect($($buttons[1]).text().trim()).toEqual('View Assignment Statistics');
expect($($buttons[2]).text().trim()).toEqual('Grade Available Responses');
expect(getVisibleStaffPanels(view).length).toBe(0);
});
it('shows the "Manage Individual Learners" panel when the button is clicked', function() {
......@@ -365,30 +370,60 @@ describe('OpenAssessment.StaffAreaView', function() {
expect($staffToolsButton.length).toBe(1);
$staffToolsButton[0].click();
expect($staffToolsButton).toHaveClass('is--active');
expect($staffToolsPanel).toBeVisible();
closeButton = $('.ui-staff_close_button', $staffToolsPanel)[0];
verifyFocused(closeButton);
// Now click the close button.
closeButton.click();
expect($staffToolsButton).not.toHaveClass('is--active');
expect($staffToolsPanel).toHaveClass('is--hidden');
expect($staffToolsPanel).toBeHidden();
verifyFocused($staffToolsButton[0]);
});
it('shows an error when clicking "Submit" with no student name chosen', function() {
var staffArea = createStaffArea();
var staffArea = createStaffArea(), $error;
chooseStudent(staffArea, '');
expect($('.openassessment_student_info_form .form--error', staffArea.element).text().trim())
.toBe('You must provide a learner name.');
$error = $('.openassessment_student_info_form .form--error', staffArea.element);
expect($error.text().trim()).toBe('You must provide a learner name.');
verifyFocused($error[0]);
});
it('shows an error message when failing to load the student info', function() {
var staffArea = createStaffArea();
var staffArea = createStaffArea(), $error;
server.studentInfo = failWith(server);
chooseStudent(staffArea, 'testStudent');
expect($('.openassessment_student_info_form .form--error', staffArea.element).first().text().trim()).toBe(
'Unexpected server error.'
);
$error = $('.openassessment_student_info_form .form--error', staffArea.element);
expect($error.text().trim()).toBe('Unexpected server error.');
verifyFocused($error[0]);
});
it('moves focus to learner report when successfully loading the student info', function() {
var staffArea = createStaffArea(), $reportHeader;
chooseStudent(staffArea, 'testStudent');
$reportHeader = $('.staff-info__student__report__summary', staffArea.element);
expect($reportHeader.text().trim()).toContain('Viewing learner:');
verifyFocused($reportHeader[0]);
});
it('updates aria-expanded when toggling slidable sections', function() {
var staffArea = createStaffArea(), $slidableControls;
chooseStudent(staffArea, 'testStudent');
$slidableControls = $('.ui-slidable', staffArea.element);
expect($slidableControls.length).toBe(5);
expect($slidableControls).toHaveAttr('aria-expanded', 'false');
$slidableControls.click();
expect($slidableControls).toHaveAttr('aria-expanded', 'true');
});
it('links slidable controls with content', function() {
var staffArea = createStaffArea();
chooseStudent(staffArea, 'testStudent');
$('.ui-slidable', staffArea.element).each(function(index, slidable) {
var id = slidable.id;
var content = $(slidable).next('.ui-slidable__content');
expect(content).toHaveAttr('aria-labelledby', id);
});
});
describe('Submission Management', function() {
......@@ -475,13 +510,13 @@ describe('OpenAssessment.StaffAreaView', function() {
it('can submit a staff grade override', function() {
var staffArea = createStaffArea(),
$assessment, $gradeSection;
$assessment, $gradeSection, $gradeSectionButton;
chooseStudent(staffArea, 'testStudent');
// Verify that the student info section is hidden but shows the original score
$gradeSection = $('.staff-info__student__grade', staffArea.element);
expect($('.ui-toggle-visibility', $gradeSection)).toHaveClass('is--collapsed');
expect($('p', $gradeSection).first().text().trim()).toBe(
expect($('.ui-slidable', $gradeSection)).not.toHaveClass('is--showing');
expect($('.staff-info__final__grade__score').text().trim()).toBe(
'The problem has not been started.'
);
......@@ -495,8 +530,12 @@ describe('OpenAssessment.StaffAreaView', function() {
// Verify that the student info is visible and shows the correct score
$gradeSection = $('.staff-info__student__grade', staffArea.element);
expect($('.ui-toggle-visibility', $gradeSection)).not.toHaveClass('is--collapsed');
expect($('p', $gradeSection).first().text().trim()).toBe(
$gradeSectionButton = $('.ui-slidable', $gradeSection);
expect($gradeSectionButton).toHaveClass('is--showing');
expect($gradeSectionButton).toHaveAttr('aria-expanded', 'true');
verifyFocused($gradeSectionButton[0]);
expect($('.ui-slidable__content', $gradeSection)).toBeVisible();
expect($('.staff-info__final__grade__score').text().trim()).toBe(
'Final grade: 1 out of 2'
);
});
......@@ -552,13 +591,14 @@ describe('OpenAssessment.StaffAreaView', function() {
expect($staffInfoButton.length).toBe(1);
$staffInfoButton[0].click();
expect($staffInfoButton).toHaveClass('is--active');
expect($staffInfoPanel).toBeVisible();
closeButton = $('.ui-staff_close_button', $staffInfoPanel)[0];
verifyFocused(closeButton);
// Now click the close button.
closeButton.click();
expect($staffInfoButton).not.toHaveClass('is--active');
expect($staffInfoPanel).toHaveClass('is--hidden');
expect($staffInfoPanel).toBeHidden();
verifyFocused($staffInfoButton[0]);
});
});
......@@ -584,13 +624,14 @@ describe('OpenAssessment.StaffAreaView', function() {
expect($staffGradingButton.length).toBe(1);
$staffGradingButton[0].click();
expect($staffGradingButton).toHaveClass('is--active');
expect($staffGradingPanel).toBeVisible();
closeButton = $('.ui-staff_close_button', $staffGradingPanel)[0];
verifyFocused(closeButton);
// Now click the close button.
closeButton.click();
expect($staffGradingButton).not.toHaveClass('is--active');
expect($staffGradingPanel).toHaveClass('is--hidden');
expect($staffGradingPanel).toBeHidden();
verifyFocused($staffGradingButton[0]);
});
......@@ -608,8 +649,11 @@ describe('OpenAssessment.StaffAreaView', function() {
it('can submit a staff grade', function() {
var staffArea = createStaffArea({}, 'oa_staff_area_full_grading.html'),
$assessment, $gradeSection;
$assessment, $staffGradeButton;
$staffGradeButton = $('.staff__grade__show-form', staffArea.element);
expect($staffGradeButton).toHaveAttr('aria-expanded', 'false');
showInstructorAssessmentForm(staffArea);
expect($staffGradeButton).toHaveAttr('aria-expanded', 'true');
$assessment = getAssessment(staffArea, staffAreaTab);
// Verify that the submission is shown for the first user
......@@ -625,12 +669,15 @@ describe('OpenAssessment.StaffAreaView', function() {
// Verify that the assessment form has been removed
expect($('.staff__grade__form', staffArea.element).html().trim()).toBe('');
expect($staffGradeButton).toHaveAttr('aria-expanded', 'false');
verifyFocused($staffGradeButton[0]);
});
it('can submit a staff grade and receive another submission', function() {
var staffArea = createStaffArea({}, 'oa_staff_area_full_grading.html'),
$assessment;
$assessment, $staffGradeButton;
showInstructorAssessmentForm(staffArea);
$staffGradeButton = $('.staff__grade__show-form', staffArea.element);
// Verify that the submission is shown for the first user
expect($('.staff-assessment__display__title', staffArea.element).text().trim()).toBe(
......@@ -647,16 +694,16 @@ describe('OpenAssessment.StaffAreaView', function() {
expect($('.staff-assessment__display__title', staffArea.element).text().trim()).toBe(
'Response for: mock_user_2'
);
verifyFocused($staffGradeButton[0]);
});
it('shows an error message when failing to load the staff grade form', function() {
var staffArea = createStaffArea({}, 'oa_staff_area_full_grading.html'),
$assessment, $submitButtons;
var staffArea = createStaffArea({}, 'oa_staff_area_full_grading.html'), $error;
server.staffGradeForm = failWith(server);
showInstructorAssessmentForm(staffArea);
expect($('.staff__grade__form--error', staffArea.element).first().text().trim()).toBe(
'Unexpected server error.'
);
$error = $('.staff__grade__form--error', staffArea.element);
expect($error.text().trim()).toBe('Unexpected server error.');
verifyFocused($error[0]);
});
it('shows an error message when a staff grade request fails', function() {
......
......@@ -22,6 +22,9 @@
FULL_GRADE_UNSAVED_WARNING_KEY: "staff-grade",
OVERRIDE_UNSAVED_WARNING_KEY: "staff-override",
IS_SHOWING_CLASS: "is--showing",
SLIDABLE_CLASS: "ui-slidable",
SLIDABLE_CONTENT_CLASS: "ui-slidable__content",
/**
* Load the staff area.
......@@ -49,17 +52,19 @@
* This allows viewing all the submissions and assessments associated
* to the given student's current workflow.
*
* @param {object} options An optional set of options to render the section.
* @param {string} classToExpand An optional CSS class. If present, the "slidable content"
* within the element with this class will be expanded after rendering the student
* info section.
* @returns {promise} A promise representing the successful loading
* of the student info section.
* of the student info section.
*/
loadStudentInfo: function(options) {
loadStudentInfo: function(classToExpand) {
var view = this;
var $manageLearnersTab = $('.openassessment__staff-tools', this.element);
var $form = $manageLearnersTab.find('.openassessment_student_info_form');
var studentUsername = $manageLearnersTab.find('.openassessment__student_username').val();
var showFormError = function(errorMessage) {
$form.find('.form--error').text(errorMessage);
$form.find('.form--error').text(errorMessage).focus();
};
var deferred = $.Deferred();
......@@ -67,7 +72,7 @@
$('.openassessment__student-info', view.element).text('');
if (studentUsername.trim()) {
this.server.studentInfo(studentUsername, options).done(function(html) {
this.server.studentInfo(studentUsername).done(function(html) {
// Clear any error message
showFormError('');
......@@ -109,6 +114,33 @@
}
);
}
$manageLearnersTab.find('.' + view.SLIDABLE_CLASS).click(
function(event) {
var $toggle = $(event.currentTarget),
$content = $toggle.next('.' + view.SLIDABLE_CONTENT_CLASS);
if ($toggle.hasClass(view.IS_SHOWING_CLASS)) {
$toggle.removeClass(view.IS_SHOWING_CLASS).attr('aria-expanded', 'false');
$content.slideUp();
}
else {
$toggle.addClass(view.IS_SHOWING_CLASS).attr('aria-expanded', 'true');
$content.slideDown();
}
}
);
// By default, focus is put on the summary.
$manageLearnersTab.find('.staff-info__student__report__summary').focus();
if (classToExpand) {
$manageLearnersTab.find('.' + classToExpand + ' .' + view.SLIDABLE_CONTENT_CLASS)
.slideDown();
$manageLearnersTab.find('.' + classToExpand + ' .' + view.SLIDABLE_CLASS)
.addClass(view.IS_SHOWING_CLASS).attr('aria-expanded', 'true').focus();
}
deferred.resolve();
}).fail(function() {
showFormError(gettext('Unexpected server error.'));
......@@ -125,27 +157,25 @@
* Upon request, loads the staff grade/assessment section of the staff area.
* This allows staff grading when staff assessment is a required step.
*
* @param {boolean} clearAndCollapse if true, clear the staff grade form and collapse it. Otherwise
* render the staff grade form if is not already loaded.
* @returns {promise} A promise representing the successful loading
* of the staff grade (assessment) section.
*/
loadStaffGradeForm: function(clearAndCollapse) {
loadStaffGradeForm: function() {
var view = this;
var $staffGradeTab = $('.openassessment__staff-grading', this.element);
var $staffGradeControl = $staffGradeTab.find('.' + view.SLIDABLE_CLASS);
var $staffGradeContent = $staffGradeTab.find('.' + view.SLIDABLE_CONTENT_CLASS);
var deferred = $.Deferred();
var showFormError = function(errorMessage) {
$staffGradeTab.find('.staff__grade__form--error').text(errorMessage);
$staffGradeTab.find('.staff__grade__form--error').text(errorMessage).focus();
};
if (clearAndCollapse) {
// Collapse the editor and update the counts.
$staffGradeTab.find('.staff__grade__control').toggleClass('is--collapsed', true);
$staffGradeTab.find('.staff__grade__form').replaceWith('<div class="staff__grade__form"></div>');
view.updateStaffGradeCounts();
$staffGradeControl.toggleClass(view.IS_SHOWING_CLASS, true).attr('aria-expanded', 'true');
if (this.staffGradeFormLoaded) {
$staffGradeContent.slideDown();
deferred.resolve();
}
else if (!this.staffGradeFormLoaded) {
else {
this.staffGradeFormLoaded = true;
this.server.staffGradeForm().done(function(html) {
showFormError('');
......@@ -179,6 +209,15 @@
}
);
}
$staffGradeContent.slideDown(
function() {
// For accessibility, move focus to the staff grade form control
// (since this code may have executed as part of "Submit and Grade Next...").
$staffGradeControl.focus();
}
);
deferred.resolve();
}).fail(function() {
showFormError(gettext('Unexpected server error.'));
......@@ -191,6 +230,34 @@
},
/**
* Closes the staff grade/assessment section of the staff area.
*
* @param {boolean} clear if true, remove the staff grade form and collapse it. Otherwise
* the staff grade form is collapsed but not removed (meaning that the same
* form will be presented if the user later expands the staff grade section again).
*/
closeStaffGradeForm: function(clear) {
var $staffGradeTab = $('.openassessment__staff-grading', this.element);
var $staffGradeControl = $staffGradeTab.find('.' + this.SLIDABLE_CLASS);
var $staffGradeContent = $staffGradeTab.find('.' + this.SLIDABLE_CONTENT_CLASS);
$staffGradeControl.toggleClass(this.IS_SHOWING_CLASS, false).attr('aria-expanded', 'false');
if (clear) {
// Collapse the editor and update the counts.
// This is the case of submitting an assessment and NOT continuing with grading.
$staffGradeTab.find('.staff__grade__form').replaceWith('<div class="staff__grade__form"></div>');
this.updateStaffGradeCounts();
}
else {
// Just hide the form currently being shown (no need to update counts).
$staffGradeContent.slideUp();
}
// For accessibility, move focus to the staff grade form control.
$staffGradeControl.focus();
},
/**
* Update the counts of ungraded and checked out assessments.
*/
updateStaffGradeCounts: function() {
......@@ -214,32 +281,36 @@
installHandlers: function() {
var view = this;
var $staffArea = $('.openassessment__staff-area', this.element);
var $staffTools = $('.openassessment__staff-tools', $staffArea);
var $staffInfo = $('.openassessment__student-info', $staffArea);
var $manageLearnersTab = $('.openassessment__staff-tools', $staffArea);
var $staffGradeTool = $('.openassessment__staff-grading', $staffArea);
if ($staffArea.length <= 0) {
return;
}
this.baseView.setUpCollapseExpand($staffTools, function() {});
this.baseView.setUpCollapseExpand($staffInfo, function() {});
this.baseView.setUpCollapseExpand($staffGradeTool, function() {});
// Install a click handler for the staff button panel
$staffArea.find('.ui-staff__button').click(
function(eventObject) {
// Close all other panels first. Classes and aria attributes will be updated below.
$staffArea.find('.ui-staff__button').each(function(index, button) {
if (button !== eventObject.currentTarget) {
var $panel = $staffArea.find('.' + $(button).data('panel')).first();
$panel.slideUp(0);
}
});
var $button = $(eventObject.currentTarget),
panelClass = $button.data('panel'),
$panel = $staffArea.find('.' + panelClass).first();
$panel = $staffArea.find('.' + $button.data('panel')).first();
if ($button.hasClass('is--active')) {
$button.removeClass('is--active');
$panel.addClass('is--hidden');
$button.removeClass('is--active').attr('aria-expanded', 'false');
$panel.slideUp();
} else {
$staffArea.find('.ui-staff__button').removeClass('is--active');
$button.addClass('is--active');
$staffArea.find('.wrapper--ui-staff').addClass('is--hidden');
$panel.removeClass('is--hidden');
// Remove "is--active" and the aria-expanded state from all buttons.
$staffArea.find('.ui-staff__button').removeClass('is--active').attr('aria-expanded', 'false');
// Set "is--active" and aria-expanded state on the toggled button.
$button.addClass('is--active').attr('aria-expanded', 'true');
$panel.slideDown();
}
// For accessibility, move focus to the first focusable component.
$panel.find('.ui-staff_close_button').focus();
......@@ -251,8 +322,8 @@
function(eventObject) {
var $button = $(eventObject.currentTarget),
$panel = $button.closest('.wrapper--ui-staff');
$staffArea.find('.ui-staff__button').removeClass('is--active');
$panel.addClass('is--hidden');
$staffArea.find('.ui-staff__button').removeClass('is--active').attr('aria-expanded', 'false');
$panel.slideUp();
// For accessibility, move focus back to the tab associated with the closed panel.
$staffArea.find('.ui-staff__button').each(function(index, button) {
......@@ -266,7 +337,7 @@
);
// Install key handler for student id field
$staffTools.find('.openassessment_student_info_form').submit(
$manageLearnersTab.find('.openassessment_student_info_form').submit(
function(eventObject) {
eventObject.preventDefault();
view.loadStudentInfo();
......@@ -274,7 +345,7 @@
);
// Install a click handler for requesting student info
$staffTools.find('.action--submit-username').click(
$manageLearnersTab.find('.action--submit-username').click(
function(eventObject) {
eventObject.preventDefault();
view.loadStudentInfo();
......@@ -282,7 +353,7 @@
);
// Install a click handler for scheduling AI classifier training
$staffTools.find('.action--submit-training').click(
$manageLearnersTab.find('.action--submit-training').click(
function(eventObject) {
eventObject.preventDefault();
view.scheduleTraining();
......@@ -290,7 +361,7 @@
);
// Install a click handler for rescheduling unfinished AI tasks for this problem
$staffTools.find('.action--submit-unfinished-tasks').click(
$manageLearnersTab.find('.action--submit-unfinished-tasks').click(
function(eventObject) {
eventObject.preventDefault();
view.rescheduleUnfinishedTasks();
......@@ -299,9 +370,12 @@
// Install a click handler for showing the staff grading form.
$staffGradeTool.find('.staff__grade__show-form').click(
function() {
var wasCollapsed = $staffGradeTool.find('.staff__grade__control').hasClass("is--collapsed");
if (wasCollapsed) {
function(event) {
var wasShowing = $(event.currentTarget).hasClass(view.IS_SHOWING_CLASS);
if (wasShowing) {
view.closeStaffGradeForm(false);
}
else {
view.loadStaffGradeForm();
}
}
......@@ -348,7 +422,7 @@
// re-render the student info with the "Learner's Final Grade"
// section expanded. This section will show that the learner's
// submission was cancelled.
view.loadStudentInfo({expanded_view: 'final-grade'});
view.loadStudentInfo('staff-info__student__grade');
}).fail(function(errorMessage) {
$('.cancel-submission-error').html(_.escape(errorMessage));
});
......@@ -461,7 +535,7 @@
// section expanded. This section will show the learner's
// final grade and in the future should include details of
// the staff override itself.
view.loadStudentInfo({expanded_view: 'final-grade'});
view.loadStudentInfo('staff-info__student__grade');
};
this.callStaffAssess(submissionID, rubric, scope, successCallback, '.staff-override-error', 'regrade');
},
......@@ -481,10 +555,13 @@
var successCallback = function() {
view.baseView.unsavedWarningEnabled(false, view.FULL_GRADE_UNSAVED_WARNING_KEY);
view.staffGradeFormLoaded = false;
view.loadStaffGradeForm(!continueGrading);
if (continueGrading) {
view.loadStaffGradeForm();
view.baseView.scrollToTop(".openassessment__staff-area");
}
else {
view.closeStaffGradeForm(true);
}
};
this.callStaffAssess(submissionID, rubric, scope, successCallback, '.staff-grade-error', 'full-grade');
},
......
......@@ -17,34 +17,31 @@
border-top: ($baseline-v/4) solid $color-decorative-staff;
padding: $baseline-v ($baseline-h/2);
background: $staff-bg;
display: none;
}
.ui-staff {
// CASE: area is collapse/expand friendly
&.ui-toggle-visibility {
.ui-slidable {
.staff-info__title__copy {
@include margin-left(($baseline-h/4));
.icon {
@include transition(all $tmg-f2 ease-in-out 0s);
@include transform(rotate(bidi-rotate-angle(0deg)));
}
// STATE: is collapsed
&.is--collapsed {
.ui-staff__content {
margin-top: 0;
}
.staff-info__cancel-submission__content,
.staff-info__staff-override__content {
padding: 0;
&.is--showing {
.icon {
@include transform(rotate(bidi-rotate-angle(90deg)));
@include transform-origin(50% 50%);
}
}
}
.ui-toggle-visibility__content {
@include margin-left(($baseline-h/4));
margin-bottom: ($baseline-v/2);
}
.ui-slidable__content {
padding: ($baseline-v/2) ($baseline-h/4);
// Display as initially collapsed.
display: none;
}
}
......@@ -241,11 +238,16 @@
// Styling for staff grade tab ("Grade Available Responses").
.ui-staff {
.staff__grade__control {
border-top: ($baseline-v/4) solid $color-decorative-tertiary;
background: $bg-content;
background-color: $bg-content;
.staff__grade__header {
margin-bottom: 0;
}
.staff__grade__title {
@include text-align(left);
@include float(none);
......@@ -324,13 +326,13 @@
display: inline;
}
.wrapper--input {
padding-top: 0;
.staff__grade__content {
padding: 0;
}
}
// Override the default color for h3 (for elements that can be toggled).
.ui-toggle-visibility .ui-toggle-visibility__control .staff__grade__title {
.ui-slidable__control .staff__grade__title {
color: $action-primary-color;
}
}
......@@ -351,4 +353,19 @@
}
}
}
// Learner info section
.staff-info__student__report {
// Override default button styling.
.ui-slidable {
@extend %btn-reset;
background-color: $staff-bg;
padding: 0;
}
.staff-info__final__grade__table {
margin-top: ($baseline-v/2);
}
}
}
......@@ -193,10 +193,6 @@
color: $copy-staff-color !important;
}
.staff-info__workflow-cancellation {
margin-bottom: ($baseline-v) !important;
}
.wrapper--staff-assessment {
// 'p' elements in LMS have a color set on them.
.student__answer__display__content p {
......
......@@ -465,7 +465,7 @@ class StaffAreaPage(OpenAssessmentPage, AssessmentMixin):
Returns the classes of the visible staff panels
"""
panels = self.q(css=self._bounded_selector(".wrapper--ui-staff"))
return [panel.get_attribute('class') for panel in panels if u'is--hidden' not in panel.get_attribute('class')]
return [panel.get_attribute('class') for panel in panels if panel.is_displayed()]
def is_button_visible(self, button_name):
"""
......@@ -479,6 +479,8 @@ class StaffAreaPage(OpenAssessmentPage, AssessmentMixin):
Presses the button to show the panel with the specified name.
:return:
"""
# Disable JQuery animations (for slideUp/slideDown).
self.browser.execute_script("jQuery.fx.off = true;")
buttons = self.q(css=self._bounded_selector(".button-{button_name}".format(button_name=button_name)))
buttons.first.click()
......@@ -617,7 +619,7 @@ class StaffAreaPage(OpenAssessmentPage, AssessmentMixin):
@property
def learner_response(self):
return self.q(
css=self._bounded_selector(".staff-info__student__response .ui-toggle-visibility__content")
css=self._bounded_selector(".staff-info__student__response .ui-slidable__content")
).text[0]
def staff_assess(self, options_selected, grading_type, continue_after=False):
......
......@@ -500,10 +500,9 @@ class StaffAreaTest(OpenAssessmentTest):
# Click on the button and verify that the panel has opened
self.staff_area_page.click_staff_toolbar_button(panel_name)
self.assertEqual(self.staff_area_page.selected_button_names, [button_label])
self.assertIn(
u'openassessment__{button_name}'.format(button_name=panel_name),
self.staff_area_page.visible_staff_panels[0]
)
visible_panels = self.staff_area_page.visible_staff_panels
self.assertEqual(1, len(visible_panels))
self.assertIn(u'openassessment__{button_name}'.format(button_name=panel_name), visible_panels[0])
# Click 'Close' and verify that the panel has been closed
self.staff_area_page.click_staff_panel_close_button(panel_name)
......
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