Commit e55fbbae by gradyward

Nearing the end of code review and testing.

parent a73a0638
{% load i18n %}
<div id="openassessment-editor" class="editor-with-buttons editor-with-tabs">
<div class="openassessment-editor-content-and-tabs">
<div class="openassessment_editor_content_and_tabs">
<div class="openassessment-editor-header">
<h6 id="oa-editor-window-title" class="title modal-window-title" >{% trans "Component: Open Response Problem" %}</h6>
<ul class="editor-modes action-list action-modes editor-tabs">
<li class="view-button oa-editor-tab"><a href="#oa-settings-editor-wrapper">{% trans "Settings" %}</a></li>
<li class="view-button oa-editor-tab"><a href="#oa-rubric-editor-wrapper">{% trans "Rubric" %}</a></li>
<li class="view-button oa-editor-tab"><a href="#oa-prompt-editor-wrapper">{% trans "Prompt" %}</a></li>
<div id="openassessment_editor_header">
<h6 id="oa_editor_window_title" class="title modal_window_title" >{% trans "Component: Open Response Problem" %}</h6>
<ul class="editor_modes action_list action_modes editor_tabs">
<li class="view-button oa_editor_tab"><a href="#oa_settings_editor_wrapper">{% trans "Settings" %}</a></li>
<li class="view-button oa_editor_tab"><a href="#oa_rubric_editor_wrapper">{% trans "Rubric" %}</a></li>
<li class="view-button oa_editor_tab"><a href="#oa_prompt_editor_wrapper">{% trans "Prompt" %}</a></li>
</ul>
</div>
<div id = "oa-prompt-editor-wrapper" class="oa-editor-content-wrapper">
<textarea class="openassessment-prompt-editor"></textarea>
<div id = "oa_prompt_editor_wrapper" class="oa_editor_content_wrapper">
<textarea id="openassessment_prompt_editor"></textarea>
</div>
<div id="oa-rubric-editor-wrapper" class="oa-editor-content-wrapper">
<div id="rubric-editor-wrapper">
<textarea class="openassessment-rubric-editor"></textarea>
</div>
<div id="oa_rubric_editor_wrapper" class="oa_editor_content_wrapper">
<textarea id="openassessment_rubric_editor"></textarea>
</div>
<div id="oa-settings-editor-wrapper" class="oa-editor-content-wrapper">
<div id="oa_settings_editor_wrapper" class="oa_editor_content_wrapper">
<div id="oa-base-settings-editor" >
<div>
<label for="openassessment-title-editor">{% trans "Display Name "%}</label>
<input type="text" name="title" class="openassessment-title-editor" id="openassessment-title-editor">
<div id="oa_basic_settings_editor">
<div id="openassessment_title_editor_wrapper">
<label for="openassessment_title_editor">{% trans "Display Name "%}</label>
<input type="text" id="openassessment_title_editor">
</div>
<p class="openassessment-description">{% trans "This name appears in the horizontal navigation at the top of the page." %}</p>
<div class="openassessment-due-date-editor">
<div class="openassessment-text-field-wrapper left-text-field-wrapper">
<label for="openassessment-submission-start-editor">{% trans "Submission Start Date"%} </label>
<input type="text" name="start_date" class="openassessment-submission-start-editor openassessment-date-field" id="openassessment-submission-start-editor">
<p class="openassessment_description">{% trans "This name appears when you hover over the unit in the course ribbon at the top of the page." %}</p>
<hr>
<div class="openassessment_due_date_editor">
<div class="openassessment_left_text_field_wrapper">
<label for="openassessment_submission_start_editor">{% trans "Response Submission Start Date"%} </label>
<input type="text" class="openassessment_date_field" id="openassessment_submission_start_editor">
</div>
<div class="openassessment-text-field-wrapper right-text-field-wrapper">
<label for="openassessment-submission-due-editor">{% trans "Submission Due Date" %}</label>
<input type="text" name="due_date" class="openassessment-submission-due-editor openassessment-date-field" id="openassessment-submission-due-editor">
<div class="openassessment_right_text_field_wrapper">
<label for="openassessment_submission_due_editor">{% trans "Response Submission Due Date" %}</label>
<input type="text" class="openassessment_date_field" id="openassessment_submission_due_editor">
</div>
</div>
<hr>
</div>
<div class="openassessment-assessment-module-settings-editor" id="oa-student-training-editor">
<div class = "openassessment-inclusion-wrapper">
<input type="checkbox" name="has_training" id="include-student-training">
<label for="include-student-training">{% trans "Step: Learn to Assess Peers" %}</label>
<p class="openassessment_description" id="openassessment_step_select_description">
{% trans "Select the steps that students must complete. All steps are optional, but every assignment must include at least one step." %}
</p>
<div class="openassessment_assessment_module_settings_editor" id="oa_student_training_editor">
<div class = "openassessment_inclusion_wrapper">
<input type="checkbox" id="include_student_training">
<label for="include_student_training">{% trans "Step: Student Training" %}</label>
</div>
<p id="student-training-description-closed" class="openassessment-description openassessment-description-closed">
{% trans "When enabled, a step is added where students must read and store instructor provided responses with the goal of matching the instructor's score." %}
<p id="student_training_description_closed" class="openassessment_description_closed">
{% trans "Students learn to assess responses by scoring pre-assessed sample responses that the instructor provides. Students move to the next step when the scores they give match the instructor's scores." %}
</p>
<div id="student-training-settings-editor" class="assessment-settings-wrapper">
<p id="student-training-description-open" class="openassessment-description">
{% trans "Please insert the XML definition of the examples that you would like students to see and train against in the editor below." %}
<div id="student_training_settings_editor" class="assessment_settings_wrapper">
<p class="openassessment_description">
{% trans "Enter one or more sample responses that you've created, together with the scores you would give those responses. Be sure to format the responses and scores according to the placeholder text below." %}
</p>
<label for="student-training-examples">{% trans "Student Training Examples" %}</label>
<textarea name="student-training-examples" id="student-training-examples"></textarea>
<label for="student_training_examples">{% trans "Student Training Responses" %}</label>
<textarea id="student_training_examples"></textarea>
</div>
<hr>
</div>
<div class="openassessment-assessment-module-settings-editor" id="oa-peer-assessment-editor">
<div class="openassessment-inclusion-wrapper">
<input type="checkbox" name="has-peer" id="include-peer-assessment">
<label for="include-peer-assessment">{% trans "Step: Include Peer Assessment" %}</label>
<div class="openassessment_assessment_module_settings_editor" id="oa_peer_assessment_editor">
<div class="openassessment_inclusion_wrapper">
<input type="checkbox" id="include_peer_assessment">
<label for="include_peer_assessment">{% trans "Step: Peer Assessment" %}</label>
</div>
<p id="peer-assessment-description-closed" class="openassessment-description openassessment-description-closed">
{% trans "When enabled, students peer review and score some number of responses using the problem's rubric." %}
<p id="peer_assessment_description_closed" class="openassessment_description_closed">
{% trans "Students assess a specified number of other students' responses using the rubric for the assignment." %}
</p>
<div id="peer-assessment-settings-editor" class="assessment-settings-wrapper">
<p id="peer-assessment-description-open" class="openassessment-description">
{% trans "Some instructional text here that guides them on how to complete this section." %}
<div id="peer_assessment_settings_editor" class="assessment_settings_wrapper">
<p class="openassessment_description">
{% trans "Specify the following values for the peer assessment step. The numeric grading requirements must be given a value." %}
</p>
<div class="peer-number-constraints">
<label for="peer-assessment-must-grade">{% trans "Each student must grade" %}</label>
<input id="peer-assessment-must-grade" class="openassessment-number-field" type="text">
<label for="peer-assessment-graded-by"> {% trans "peer(s), and must be graded by at least" %}</label>
<input id="peer-assessment-graded-by" class="openassessment-number-field" type="text">
<label>of their peers.</label>
<div class="openassessment_indent_line_input">
<label for="peer_assessment_must_grade">{% trans "Each student must assess X peer responses" %}</label>
<input id="peer_assessment_must_grade" class="openassessment_number_field" type="text">
</div>
<div class="openassessment-due-date-editor">
<div class="openassessment-text-field-wrapper left-text-field-wrapper">
<label for="peer-assessment-start-date">{% trans "Start Date" %}</label>
<input id="peer-assessment-start-date" type="text" class="openassessment-date-field">
<div class="openassessment_indent_line_input">
<label for="peer_assessment_graded_by"> {% trans "Each response must be assessed by at least X students" %}</label>
<input id="peer_assessment_graded_by" class="openassessment_number_field" type="text">
</div>
<div class="openassessment_due_date_editor">
<div class="openassessment_left_text_field_wrapper">
<label for="peer_assessment_start_date">{% trans "Start Date" %}</label>
<input id="peer_assessment_start_date" type="text" class="openassessment_date_field">
</div>
<div class="openassessment-text-field-wrapper right-text-field-wrapper">
<label for="peer-assessment-due-date">{% trans "Due Date" %}</label>
<input id="peer-assessment-due-date" type="text" class="openassessment-date-field">
<div class="openassessment_right_text_field_wrapper">
<label for="peer_assessment_due_date">{% trans "Due Date" %}</label>
<input id="peer_assessment_due_date" type="text" class="openassessment_date_field">
</div>
</div>
</div>
<hr>
</div>
<div class="openassessment-assessment-module-settings-editor" id="oa-self-assessment-editor">
<div class = "openassessment-inclusion-wrapper">
<input id="include-self-assessment" type="checkbox" checked="0">
<label for="include-self-assessment">{% trans "Step: Include Self Assessment" %}</label>
<div class="openassessment_assessment_module_settings_editor" id="oa_self_assessment_editor">
<div class = "openassessment_inclusion_wrapper">
<input id="include_self_assessment" type="checkbox">
<label for="include_self_assessment">{% trans "Step: Self Assessment" %}</label>
</div>
<p id="self-assessment-description-closed" class="openassessment-description openassessment-description-closed">
{% trans "When enabled, students are asked to self assess their own response using the problem's rubric." %}
<p id="self_assessment_description_closed" class="openassessment_description_closed">
{% trans "Students assess their own responses using the rubric for the assignment." %}
</p>
<div id="self-assessment-settings-editor" class="assessment-settings-wrapper">
<p id="self-assessment-description-open" class="openassessment-description">
{% trans "Add start and/or due dates for the self assessment period, or leave blank to allow self assessment any time after submission." %}
<div id="self_assessment_settings_editor" class="assessment_settings_wrapper">
<p class="openassessment_description">
{% trans "Specify start and due dates for the self assessment step. To allow self assessment to run as long as the assignment is open, leave both fields blank." %}
</p>
<div class="openassessment-due-date-editor">
<div class="openassessment-text-field-wrapper left-text-field-wrapper">
<label for="self-assessment-start-date">{% trans "Start Date" %}</label>
<input id="self-assessment-start-date" type="text" class="openassessment-date-field">
<div class="openassessment_due_date_editor">
<div class="openassessment_left_text_field_wrapper">
<label for="self_assessment_start_date">{% trans "Start Date" %}</label>
<input id="self_assessment_start_date" type="text" class="openassessment_date_field">
</div>
<div class="openassessment-text-field-wrapper left-text-field-wrapper">
<label for="self-assessment-due-date">{% trans "Due Date" %}</label>
<input id="self-assessment-due-date" type="text" class="openassessment-date-field">
<div class="openassessment_right_text_field_wrapper">
<label for="self_assessment_due_date">{% trans "Due Date" %}</label>
<input id="self_assessment_due_date" type="text" class="openassessment_date_field">
</div>
</div>
</div>
<hr>
</div>
<div class="openassessment-assessment-module-settings-editor" id="oa-ai-assessment-editor">
<div class = "openassessment-inclusion-wrapper">
<input id="include-ai-assessment" type="checkbox" checked="0">
<label for="include-ai-assessment">{% trans "Step: Include Example Based Assessment" %}</label>
<div class="openassessment_assessment_module_settings_editor" id="oa_ai_assessment_editor">
<div class = "openassessment_inclusion_wrapper">
<input id="include_ai_assessment" type="checkbox">
<label for="include_ai_assessment">{% trans "Step: Example-Based Assessment" %}</label>
</div>
<p id="ai-assessment-description-closed" class="openassessment-description openassessment-description-closed">
{% trans "When enabled, an algorithm will determine scores by comparing essays to instructor defined example essays."%}
<p id="ai_assessment_description_closed" class="openassessment_description_closed">
{% trans "An algorithm assesses students' responses by comparing the responses to pre-assessed sample responses that the instructor provides."%}
</p>
<div id="ai-assessment-settings-editor" class="assessment-settings-wrapper">
<p id="ai-assessment-description-open" class="openassessment-description">
{% trans "Instructional text. Instructional text here. Much instructional test. Wow."%}
<div id="ai_assessment_settings_editor" class="assessment_settings_wrapper">
<p class="openassessment_description">
{% trans "Enter one or more sample responses that you've created, together with the scores you would give those responses. Be sure to format the responses and scores according to the placeholder text below. The algorithm assesses students' responses by comparing them to the sample responses and scores that you provide."%}
</p>
<label for="ai-training-examples">{% trans "Training Examples" %}</label>
<textarea id="ai-training-examples"></textarea>
<label for="ai_training_examples">{% trans "Sample Responses" %}</label>
<textarea id="ai_training_examples"></textarea>
</div>
<hr>
</div>
</div>
</div>
<div class="xblock-actions">
<div class="openassessment_editor_buttons xblock-actions">
<h3 class="sr">Actions</h3>
<ul>
<li class="action-item">
<a href="#" class="button action-primary openassessment-save-button">{% trans "Save" %}</a>
<a href="#" class="button action-primary openassessment_save_button">{% trans "Save" %}</a>
</li>
<li class="action-item">
<a href="#" class="button openassessment-cancel-button">{% trans "Cancel" %}</a>
<a href="#" class="button openassessment_cancel_button">{% trans "Cancel" %}</a>
</li>
</ul>
</div>
......
......@@ -2135,73 +2135,99 @@ hr.divider,
#openassessment-editor {
margin-bottom: 0; }
#openassessment-editor .openassessment-editor-content-and-tabs {
#openassessment-editor .openassessment_editor_content_and_tabs {
width: 100%;
height: 370px; }
#openassessment-editor .openassessment-editor-header {
#openassessment-editor #openassessment_editor_header {
background-color: #e5e5e5;
width: 100%;
top: 0; }
#openassessment-editor #oa-editor-window-title {
#openassessment-editor #oa_editor_window_title {
float: left; }
#openassessment-editor .oa-editor-tab {
#openassessment-editor .oa_editor_tab {
float: right;
padding: 2.5px 5px;
margin: 2.5px 5px;
border-radius: 2.5px;
border-radius: 5px;
box-shadow: none;
border: 0; }
#openassessment-editor .oa-editor-content-wrapper {
#openassessment-editor .oa_editor_content_wrapper {
height: 100%;
width: 100%;
padding: 5px 10px; }
#openassessment-editor .openassessment-prompt-editor {
#openassessment-editor #openassessment_prompt_editor {
width: 100%;
height: 100%;
resize: none; }
#openassessment-editor .openassessment-rubric-editor {
resize: none;
border: none; }
#openassessment-editor #openassessment_rubric_editor {
width: 100%;
height: 100%; }
#openassessment-editor .openassessment-assessments-editor {
width: 100%; }
#openassessment-editor #oa-settings-editor-wrapper {
#openassessment-editor #oa_basic_settings_editor {
padding: 20px 20px;
border-bottom: 1px solid #414243; }
#openassessment-editor #oa_basic_settings_editor #openassessment_title_editor_wrapper label {
width: 25%;
text-align: left; }
#openassessment-editor #oa_basic_settings_editor #openassessment_title_editor_wrapper input {
width: 45%;
min-width: 100px; }
#openassessment-editor #openassessment_step_select_description {
margin: 10px 0; }
#openassessment-editor .openassessment_assessment_module_settings_editor {
margin-bottom: 10px;
padding-bottom: 10px;
border-bottom: 1px solid #dadbdc; }
#openassessment-editor .openassessment_indent_line_input {
padding: 5px 20px; }
#openassessment-editor #oa_settings_editor_wrapper {
overflow-y: scroll; }
#openassessment-editor #openassessment-title-editor {
#openassessment-editor #openassessment_title_editor {
width: 300px;
margin-left: 50px; }
#openassessment-editor .openassessment-number-field {
width: 25px; }
#openassessment-editor .openassessment-date-field {
#openassessment-editor .openassessment_description, #openassessment-editor .openassessment_description_closed {
font-size: 75%;
margin: 0; }
#openassessment-editor .openassessment_date_field {
width: 130px; }
#openassessment-editor .openassessment-description {
font-size: 75%; }
#openassessment-editor .openassessment-text-field-wrapper {
#openassessment-editor .openassessment_number_field {
width: 25px; }
#openassessment-editor .openassessment_text_field_wrapper, #openassessment-editor .openassessment_right_text_field_wrapper, #openassessment-editor .openassessment_left_text_field_wrapper {
width: 50%;
text-align: center; }
#openassessment-editor .right-text-field-wrapper {
#openassessment-editor .openassessment_right_text_field_wrapper {
float: right; }
#openassessment-editor .left-text-field-wrapper {
#openassessment-editor .openassessment_left_text_field_wrapper {
float: left; }
#openassessment-editor .openassessment-due-date-editor {
#openassessment-editor .openassessment_due_date_editor {
height: 30px; }
#openassessment-editor .openassessment-inclusion-wrapper {
#openassessment-editor .openassessment_inclusion_wrapper {
background-color: #dadbdc;
padding: 2.5px 5px;
margin: 2.5px 5px;
border-radius: 2.5px; }
#openassessment-editor .openassessment_inclusion_wrapper input[type="checkbox"] {
display: none; }
#openassessment-editor .openassessment_inclusion_wrapper input[type="checkbox"] + label:before {
font-family: "FontAwesome";
display: inline-block;
margin-right: 10px;
width: auto;
height: auto;
content: "\f096"; }
#openassessment-editor .openassessment_inclusion_wrapper input[type="checkbox"]:checked + label:before {
content: "\f046"; }
#openassessment-editor label {
padding-right: 10px; }
#openassessment-editor .xblock-actions {
background-color: #e5e5e5;
#openassessment-editor .xblock_actions {
background-color: #c8c9ca;
position: absolute;
width: 100%;
bottom: 0; }
#openassessment-editor .peer-number-constraints {
margin-bottom: 10px; }
#openassessment-editor .ui-widget-header .ui-state-default {
background: #e5e5e5; }
#openassessment-editor .ui-widget-header .ui-state-default a {
color: #202021;
color: #414243;
text-transform: uppercase;
outline-color: transparent; }
#openassessment-editor .ui-widget-header .ui-state-active {
......@@ -2211,19 +2237,8 @@ hr.divider,
color: whitesmoke;
text-transform: uppercase;
outline-color: transparent; }
#openassessment-editor input[type="checkbox"] {
display: none; }
#openassessment-editor input[type="checkbox"] + label:before {
font-family: "FontAwesome";
display: inline-block;
margin-right: 10px;
width: auto;
height: auto;
content: "\f096"; }
#openassessment-editor input[type="checkbox"]:checked + label:before {
content: "\f046"; }
#openassessment-editor hr {
background-color: #d4d4d4;
background-color: transparent;
color: #414243;
height: 1px;
border: 0px;
......
if(typeof OpenAssessment=="undefined"||!OpenAssessment){OpenAssessment={}}if(typeof window.gettext==="undefined"){window.gettext=function(text){return text}}OpenAssessment.BaseView=function(runtime,element,server){this.runtime=runtime;this.element=element;this.server=server;this.responseView=new OpenAssessment.ResponseView(this.element,this.server,this);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.gradeView=new OpenAssessment.GradeView(this.element,this.server,this);this.messageView=new OpenAssessment.MessageView(this.element,this.server,this);this.staffInfoView=new OpenAssessment.StaffInfoView(this.element,this.server,this)};OpenAssessment.BaseView.prototype={scrollToTop:function(){if($.scrollTo instanceof Function){$(window).scrollTo($("#openassessment__steps"),800,{offset:-50})}},setUpCollapseExpand:function(parentSel,onExpand){parentSel.find(".ui-toggle-visibility__control").click(function(eventData){var sel=$(eventData.target).closest(".ui-toggle-visibility");if(sel.hasClass("is--collapsed")&&onExpand!==undefined){onExpand()}sel.toggleClass("is--collapsed")})},load:function(){this.responseView.load();this.loadAssessmentModules();this.staffInfoView.load()},loadAssessmentModules:function(){this.trainingView.load();this.peerView.load();this.selfView.load();this.gradeView.load()},loadMessageView:function(){this.messageView.load()},toggleActionError:function(type,msg){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"}if(container===null){if(msg!==null){console.log(msg)}}else{var msgHtml=msg===null?"":msg;$(container+" .message__content",element).html("<p>"+msgHtml+"</p>");$(container,element).toggleClass("has--error",msg!==null)}},showLoadError:function(step){var container="#openassessment__"+step;$(container).toggleClass("has--error",true);$(container+" .step__status__value i").removeClass().addClass("ico icon-warning-sign");$(container+" .step__status__value .copy").html(gettext("Unable to Load"))}};function OpenAssessmentBlock(runtime,element){var server=new OpenAssessment.Server(runtime,element);var view=new OpenAssessment.BaseView(runtime,element,server);view.load()}OpenAssessment.StudioView=function(runtime,element,server){this.runtime=runtime;this.server=server;live_element=$(element);this.promptBox=live_element.find(".openassessment-prompt-editor").first().get(0);this.rubricXmlBox=CodeMirror.fromTextArea(live_element.find(".openassessment-rubric-editor").first().get(0),{mode:"xml",lineNumbers:true,lineWrapping:true});this.titleField=live_element.find(".openassessment-title-editor").first().get(0);this.submissionStartField=live_element.find(".openassessment-submission-start-editor").first().get(0);this.submissionDueField=live_element.find(".openassessment-submission-due-editor").first().get(0);this.hasPeer=live_element.find("#include-peer-assessment");this.hasSelf=live_element.find("#include-self-assessment");this.hasAI=live_element.find("#include-ai-assessment");this.hasTraining=live_element.find("#include-student-training");this.peerMustGrade=live_element.find("#peer-assessment-must-grade");this.peerGradedBy=live_element.find("#peer-assessment-graded-by");this.peerStart=live_element.find("#peer-assessment-start-date");this.peerDue=live_element.find("#peer-assessment-due-date");this.selfStart=live_element.find("#self-assessment-start-date");this.selfDue=live_element.find("#self-assessment-due-date");this.aiTrainingExamplesCodeBox=CodeMirror.fromTextArea(live_element.find("#ai-training-examples").get(0),{mode:"xml",lineNumbers:true,lineWrapping:true});this.studentTrainingExamplesCodeBox=CodeMirror.fromTextArea(live_element.find("#student-training-examples").get(0),{mode:"xml",lineNumbers:true,lineWrapping:true});var view=this;live_element.find(".openassessment-save-button").click(function(eventData){view.save()});live_element.find(".openassessment-cancel-button").click(function(eventData){view.cancel()});live_element.find(".openassessment-editor-content-and-tabs").tabs({activate:function(event,ui){view.rubricXmlBox.refresh()}});live_element.find("#include-peer-assessment").change(function(){if(this.checked){$("#peer-assessment-description-closed",live_element).fadeOut("fast");$("#peer-assessment-settings-editor",live_element).fadeIn()}else{$("#peer-assessment-settings-editor",live_element).fadeOut("fast");$("#peer-assessment-description-closed",live_element).fadeIn()}});live_element.find("#include-self-assessment").change(function(){if(this.checked){$("#self-assessment-description-closed",live_element).fadeOut("fast");$("#self-assessment-settings-editor",live_element).fadeIn()}else{$("#self-assessment-settings-editor",live_element).fadeOut("fast");$("#self-assessment-description-closed",live_element).fadeIn()}});live_element.find("#include-ai-assessment").change(function(){if(this.checked){$("#ai-assessment-description-closed",live_element).fadeOut("fast");$("#ai-assessment-settings-editor",live_element).fadeIn()}else{$("#ai-assessment-settings-editor",live_element).fadeOut("fast");$("#ai-assessment-description-closed",live_element).fadeIn()}});live_element.find("#include-student-training").change(function(){if(this.checked){$("#student-training-description-closed",live_element).fadeOut("fast");$("#student-training-settings-editor",live_element).fadeIn()}else{$("#student-training-settings-editor",live_element).fadeOut("fast");$("#student-training-description-closed",live_element).fadeIn()}})};OpenAssessment.StudioView.prototype={load:function(){var view=this;this.server.loadEditorContext().done(function(prompt,rubricXml,title,sub_start,sub_due,assessments){view.rubricXmlBox.setValue(rubricXml);view.submissionStartField.value=sub_start;view.submissionDueField.value=sub_due;view.promptBox.value=prompt;view.titleField.value=title;view.hasPeer.prop("checked",false).change();view.hasSelf.prop("checked",false).change();view.hasTraining.prop("checked",false).change();view.hasAI.prop("checked",false).change();for(var i=0;i<assessments.length;i++){var assessment=assessments[i];if(assessment.name=="peer-assessment"){view.hasPeer.prop("checked",true).change();view.peerMustGrade.prop("value",assessment.must_grade);view.peerGradedBy.prop("value",assessment.must_be_graded_by);view.peerStart.prop("value",assessment.start);view.peerDue.prop("value",assessment.due)}else if(assessment.name=="self-assessment"){view.hasSelf.prop("checked",true).change();view.selfStart.prop("value",assessment.start);view.selfDue.prop("value",assessment.due)}else if(assessment.name=="example-based-assessment"){view.hasAI.prop("checked",true).change();view.aiTrainingExamplesCodeBox.setValue(assessment.examples)}else if(assessment.name=="student-training"){view.hasTraining.prop("checked",true).change();view.studentTrainingExamplesCodeBox.setValue(assessment.examples)}else{}}}).fail(function(msg){view.showError(msg)})},save:function(){var view=this;this.server.checkReleased().done(function(isReleased){if(isReleased){view.confirmPostReleaseUpdate($.proxy(view.updateEditorContext,view))}else{view.updateEditorContext()}}).fail(function(errMsg){view.showError(msg)})},confirmPostReleaseUpdate:function(onConfirm){var msg=gettext("This problem has already been released. Any changes will apply only to future assessments.");if(confirm(msg)){onConfirm()}},updateEditorContext:function(){this.runtime.notify("save",{state:"start"});var prompt=this.promptBox.value;var rubricXml=this.rubricXmlBox.getValue();var title=this.titleField.value;var sub_start=this.submissionStartField.value;var sub_due=this.submissionDueField.value;var assessments=[];if(this.hasTraining.prop("checked")){assessments[assessments.length]={name:"student-training",examples:this.studentTrainingExamplesCodeBox.getValue()}}if(this.hasPeer.prop("checked")){var assessment={name:"peer-assessment",must_grade:parseInt(this.peerMustGrade.prop("value")),must_be_graded_by:parseInt(this.peerGradedBy.prop("value"))};var start_str=this.peerStart.prop("value");var due_str=this.peerDue.prop("value");if(start_str){assessment=$.extend(assessment,{start:start_str})}if(due_str){assessment=$.extend(assessment,{due:due_str})}assessments[assessments.length]=assessment}if(this.hasSelf.prop("checked")){assessment={name:"self-assessment"};start_str=this.selfStart.prop("value");due_str=this.selfDue.prop("value");if(start_str){assessment=$.extend(assessment,{start:start_str})}if(due_str){assessment=$.extend(assessment,{due:due_str})}assessments[assessments.length]=assessment}if(this.hasAI.prop("checked")){assessments[assessments.length]={name:"example-based-assessment",algorithm_id:"ease",examples:this.aiTrainingExamplesCodeBox.getValue()}}var view=this;this.server.updateEditorContext(prompt,rubricXml,title,sub_start,sub_due,assessments).done(function(){view.runtime.notify("save",{state:"end"});view.load()}).fail(function(msg){view.showError(msg)})},cancel:function(){this.runtime.notify("cancel",{})},showError:function(errorMsg){this.runtime.notify("error",{msg:errorMsg})}};function OpenAssessmentEditor(runtime,element){var server=new OpenAssessment.Server(runtime,element);var view=new OpenAssessment.StudioView(runtime,element,server);view.load()}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.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,index){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(sel,hidden){sel.toggleClass("is--hidden",hidden);sel.attr("aria-hidden",hidden?"true":"false")},isHidden:function(sel){return sel.hasClass("is--hidden")&&sel.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.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)}).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={load:function(){var view=this;this.server.render("peer_assessment").done(function(html){$("#openassessment__peer-assessment",view.element).replaceWith(html);view.installHandlers(false)}).fail(function(errMsg){view.baseView.showLoadError("peer-assessment")});view.baseView.loadMessageView()},loadContinuedAssessment:function(){var view=this;this.server.renderContinuedPeer().done(function(html){$("#openassessment__peer-assessment",view.element).replaceWith(html);view.installHandlers(true)}).fail(function(errMsg){view.baseView.showLoadError("peer-assessment")})},installHandlers:function(isContinuedAssessment){var sel=$("#openassessment__peer-assessment",this.element);var view=this;this.baseView.setUpCollapseExpand(sel,$.proxy(view.loadContinuedAssessment,view));var rubricSelector=$("#peer-assessment--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(view.peerSubmitEnabled,view))}sel.find("#peer-assessment--001__assessment__submit").click(function(eventObject){eventObject.preventDefault();if(!isContinuedAssessment){view.peerAssess()}else{view.continuedPeerAssess()}})},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)}},peerAssess:function(){var view=this;var baseView=view.baseView;this.peerAssessRequest(function(){view.load();baseView.loadAssessmentModules();baseView.scrollToTop()})},continuedPeerAssess:function(){var view=this;var gradeView=this.baseView.gradeView;var baseView=view.baseView;view.peerAssessRequest(function(){view.loadContinuedAssessment();gradeView.load();baseView.scrollToTop()})},peerAssessRequest:function(successFunction){var view=this;view.baseView.toggleActionError("peer",null);view.peerSubmitEnabled(false);this.server.peerAssess(this.rubric.optionsSelected(),this.rubric.criterionFeedback(),this.overallFeedback()).done(successFunction).fail(function(errMsg){view.baseView.toggleActionError("peer",errMsg);view.peerSubmitEnabled(true)})},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)}}};OpenAssessment.ResponseView=function(element,server,baseView){this.element=element;this.server=server;this.baseView=baseView;this.savedResponse="";this.lastChangeTime=Date.now();this.errorOnLastSave=false;this.autoSaveTimerId=null};OpenAssessment.ResponseView.prototype={AUTO_SAVE_POLL_INTERVAL:2e3,AUTO_SAVE_WAIT:3e4,load:function(){var view=this;this.server.render("submission").done(function(html){$("#openassessment__response",view.element).replaceWith(html);view.installHandlers();view.setAutoSaveEnabled(true)}).fail(function(errMsg){view.baseView.showLoadError("response")})},installHandlers:function(){var sel=$("#openassessment__response",this.element);var view=this;this.baseView.setUpCollapseExpand(sel);this.savedResponse=this.response();var handleChange=function(eventData){view.handleResponseChanged()};sel.find("#submission__answer__value").on("change keyup drop paste",handleChange);sel.find("#step--response__submit").click(function(eventObject){eventObject.preventDefault();view.submit()});sel.find("#submission__save").click(function(eventObject){eventObject.preventDefault();view.save()})},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)}},saveEnabled:function(enabled){var sel=$("#submission__save",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">'+label+":"+"</span>\n"+msg)}},unsavedWarningEnabled:function(enabled){if(typeof enabled==="undefined"){return window.onbeforeunload!==null}else{if(enabled){window.onbeforeunload=function(){return gettext("If you leave this page without saving or submitting your response, you'll lose any work you've done on the response.")}}else{window.onbeforeunload=null}}},response:function(text){var sel=$("#submission__answer__value",this.element);if(typeof text==="undefined"){return sel.val()}else{sel.val(text)}},responseChanged:function(){var currentResponse=$.trim(this.response());var savedResponse=$.trim(this.savedResponse);return savedResponse!==currentResponse},autoSave:function(){var timeSinceLastChange=Date.now()-this.lastChangeTime;if(this.responseChanged()&&timeSinceLastChange>this.AUTO_SAVE_WAIT&&!this.errorOnLastSave){this.save()}},handleResponseChanged:function(){var isBlank=$.trim(this.response())!=="";this.submitEnabled(isBlank);if(this.responseChanged()){this.saveEnabled(isBlank);this.saveStatus(gettext("This response has not been saved."));this.unsavedWarningEnabled(true)}this.lastChangeTime=Date.now()},save:function(){this.errorOnLastSave=false;this.saveStatus(gettext("Saving..."));this.baseView.toggleActionError("save",null);this.unsavedWarningEnabled(false);var view=this;var savedResponse=this.response();this.server.save(savedResponse).done(function(){view.savedResponse=savedResponse;var currentResponse=view.response();view.submitEnabled(currentResponse!=="");if(currentResponse==savedResponse){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;this.confirmSubmission().pipe(function(){var submission=$("#submission__answer__value",view.element).val();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.unsavedWarningEnabled(false)},confirmSubmission:function(){var msg="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()}})}};OpenAssessment.Rubric=function(element){this.element=element};OpenAssessment.Rubric.prototype={criterionFeedback:function(criterionFeedback){var selector="textarea.answer__value";var feedback={};$(selector,this.element).each(function(index,sel){if(typeof criterionFeedback!=="undefined"){$(sel).val(criterionFeedback[sel.name]);feedback[sel.name]=criterionFeedback[sel.name]}else{feedback[sel.name]=$(sel).val()}});return feedback},optionsSelected:function(optionsSelected){var selector="input[type=radio]";if(typeof optionsSelected==="undefined"){var options={};$(selector+":checked",this.element).each(function(index,sel){options[sel.name]=sel.value});return options}else{$(selector,this.element).prop("checked",false);$(selector,this.element).each(function(index,sel){if(optionsSelected.hasOwnProperty(sel.name)){if(sel.value==optionsSelected[sel.name]){$(sel).prop("checked",true)}}})}},canSubmitCallback:function(callback){$(this.element).change(function(){var numChecked=$("input[type=radio]:checked",this).length;var numAvailable=$(".field--radio.assessment__rubric__question",this).length;var canSubmit=numChecked==numAvailable;callback(canSubmit)})},showCorrections:function(corrections){var selector="input[type=radio]";var hasErrors=false;$(selector,this.element).each(function(index,sel){var listItem=$(sel).parents(".assessment__rubric__question");if(corrections.hasOwnProperty(sel.name)){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}};OpenAssessment.SelfView=function(element,server,baseView){this.element=element;this.server=server;this.baseView=baseView;this.rubric=null};OpenAssessment.SelfView.prototype={load:function(){var view=this;this.server.render("self_assessment").done(function(html){$("#openassessment__self-assessment",view.element).replaceWith(html);view.installHandlers()}).fail(function(errMsg){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)}if(this.rubric!==null){this.rubric.canSubmitCallback($.proxy(this.selfSubmitEnabled,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)}},selfAssess:function(){var view=this;var baseView=this.baseView;baseView.toggleActionError("self",null);view.selfSubmitEnabled(false);var options=this.rubric.optionsSelected();this.server.selfAssess(options).done(function(){baseView.loadAssessmentModules();baseView.scrollToTop()}).fail(function(errMsg){baseView.toggleActionError("self",errMsg);view.selfSubmitEnabled(true)})}};OpenAssessment.Server=function(runtime,element){this.runtime=runtime;this.element=element};OpenAssessment.Server.prototype={url:function(handler){return this.runtime.handlerUrl(this.element,handler)},render:function(component){var url=this.url("render_"+component);return $.Deferred(function(defer){$.ajax({url:url,type:"POST",dataType:"html"}).done(function(data){defer.resolveWith(this,[data])}).fail(function(data){defer.rejectWith(this,[gettext("This section could not be loaded.")])})}).promise()},renderContinuedPeer:function(){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(this,[data])}).fail(function(data){defer.rejectWith(this,[gettext("This section could not be loaded.")])})}).promise()},studentInfo:function(student_id){var url=this.url("render_student_info");return $.Deferred(function(defer){$.ajax({url:url,type:"POST",dataType:"html",data:{student_id:student_id}}).done(function(data){defer.resolveWith(this,[data])}).fail(function(data){defer.rejectWith(this,[gettext("This section 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})}).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(data){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})}).done(function(data){if(data.success){defer.resolve()}else{defer.rejectWith(this,[data.msg])}}).fail(function(data){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}).done(function(data){if(data.success){defer.resolve()}else{defer.rejectWith(this,[data.msg])}}).fail(function(data){defer.rejectWith(this,[gettext("This feedback could not be submitted.")])})}).promise()},peerAssess:function(optionsSelected,criterionFeedback,overallFeedback){var url=this.url("peer_assess");var payload=JSON.stringify({options_selected:optionsSelected,criterion_feedback:criterionFeedback,overall_feedback:overallFeedback});return $.Deferred(function(defer){$.ajax({type:"POST",url:url,data:payload}).done(function(data){if(data.success){defer.resolve()}else{defer.rejectWith(this,[data.msg])}}).fail(function(data){defer.rejectWith(this,[gettext("This assessment could not be submitted.")])})}).promise()},selfAssess:function(optionsSelected){var url=this.url("self_assess");var payload=JSON.stringify({options_selected:optionsSelected});return $.Deferred(function(defer){$.ajax({type:"POST",url:url,data:payload}).done(function(data){if(data.success){defer.resolve()}else{defer.rejectWith(this,[data.msg])}}).fail(function(data){defer.rejectWith(this,[gettext("This assessment could not be submitted.")])})})},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}).done(function(data){if(data.success){defer.resolveWith(this,[data.corrections])}else{defer.rejectWith(this,[data.msg])}}).fail(function(data){defer.rejectWith(this,[gettext("This assessment could not be submitted.")])})})},loadEditorContext:function(){var url=this.url("editor_context");return $.Deferred(function(defer){$.ajax({type:"POST",url:url,data:'""'}).done(function(data){if(data.success){defer.resolveWith(this,[data.prompt,data.rubric,data.title,data.submission_start,data.submission_due,data.assessments])}else{defer.rejectWith(this,[data.msg])}}).fail(function(data){defer.rejectWith(this,[gettext("This problem could not be loaded.")])})}).promise()},updateEditorContext:function(prompt,rubricXml,title,sub_start,sub_due,assessments){var url=this.url("update_editor_context");var payload=JSON.stringify({prompt:prompt,rubric:rubricXml,title:title,submission_start:sub_start,submission_due:sub_due,assessments:assessments});return $.Deferred(function(defer){$.ajax({type:"POST",url:url,data:payload}).done(function(data){if(data.success){defer.resolve()}else{defer.rejectWith(this,[data.msg])}}).fail(function(data){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}).done(function(data){if(data.success){defer.resolveWith(this,[data.is_released])}else{defer.rejectWith(this,[data.msg])}}).fail(function(data){defer.rejectWith(this,[gettext("The server could not be contacted.")])})}).promise()}};if(typeof OpenAssessment=="undefined"||!OpenAssessment){OpenAssessment={}}if(typeof window.gettext==="undefined"){window.gettext=function(text){return text}}OpenAssessment.StaffInfoView=function(element,server,baseView){this.element=element;this.server=server;this.baseView=baseView};OpenAssessment.StaffInfoView.prototype={load:function(){var view=this;if($("#openassessment__staff-info",view.element).length>0){this.server.render("staff_info").done(function(html){$("#openassessment__staff-info",view.element).replaceWith(html);view.installHandlers()}).fail(function(errMsg){view.baseView.showLoadError("staff_info")})}},loadStudentInfo:function(){var view=this;var sel=$("#openassessment__staff-info",this.element);var student_id=sel.find("#openassessment__student_id").val();this.server.studentInfo(student_id).done(function(html){$("#openassessment__student-info",view.element).replaceWith(html)}).fail(function(errMsg){view.showLoadError("student_info")})},installHandlers:function(){var sel=$("#openassessment__staff-info",this.element);var view=this;if(sel.length<=0){return}this.baseView.setUpCollapseExpand(sel,function(){});sel.find("#openassessment_student_info_form").submit(function(eventObject){eventObject.preventDefault();view.loadStudentInfo()});sel.find("#submit_student_id").click(function(eventObject){eventObject.preventDefault();view.loadStudentInfo()})}};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.installHandlers()}).fail(function(errMsg){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",this.element);var instructions=$("#openassessment__student-training--instructions",this.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 OpenAssessment == "undefined" || !OpenAssessment) {
OpenAssessment = {};
}
if (typeof window.gettext === "undefined") {
window.gettext = function(text) {
return text;
};
}
OpenAssessment.BaseView = function(runtime, element, server) {
this.runtime = runtime;
this.element = element;
this.server = server;
this.responseView = new OpenAssessment.ResponseView(this.element, this.server, this);
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.gradeView = new OpenAssessment.GradeView(this.element, this.server, this);
this.messageView = new OpenAssessment.MessageView(this.element, this.server, this);
this.staffInfoView = new OpenAssessment.StaffInfoView(this.element, this.server, this);
};
OpenAssessment.BaseView.prototype = {
scrollToTop: function() {
if ($.scrollTo instanceof Function) {
$(window).scrollTo($("#openassessment__steps"), 800, {
offset: -50
});
}
},
setUpCollapseExpand: function(parentSel, onExpand) {
parentSel.find(".ui-toggle-visibility__control").click(function(eventData) {
var sel = $(eventData.target).closest(".ui-toggle-visibility");
if (sel.hasClass("is--collapsed") && onExpand !== undefined) {
onExpand();
}
sel.toggleClass("is--collapsed");
});
},
load: function() {
this.responseView.load();
this.loadAssessmentModules();
this.staffInfoView.load();
},
loadAssessmentModules: function() {
this.trainingView.load();
this.peerView.load();
this.selfView.load();
this.gradeView.load();
},
loadMessageView: function() {
this.messageView.load();
},
toggleActionError: function(type, msg) {
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";
}
if (container === null) {
if (msg !== null) {
console.log(msg);
}
} else {
var msgHtml = msg === null ? "" : msg;
$(container + " .message__content", element).html("<p>" + msgHtml + "</p>");
$(container, element).toggleClass("has--error", msg !== null);
}
},
showLoadError: function(step) {
var container = "#openassessment__" + step;
$(container).toggleClass("has--error", true);
$(container + " .step__status__value i").removeClass().addClass("ico icon-warning-sign");
$(container + " .step__status__value .copy").html(gettext("Unable to Load"));
}
};
function OpenAssessmentBlock(runtime, element) {
var server = new OpenAssessment.Server(runtime, element);
var view = new OpenAssessment.BaseView(runtime, element, server);
view.load();
}
OpenAssessment.StudioView = function(runtime, element, server) {
this.runtime = runtime;
this.server = server;
var liveElement = $(element);
this.promptBox = $("#openassessment_prompt_editor", liveElement).get(0);
this.titleField = $("#openassessment_title_editor", liveElement).first().get(0);
this.submissionStartField = $("#openassessment_submission_start_editor", liveElement).first().get(0);
this.submissionDueField = $("#openassessment_submission_due_editor", liveElement).first().get(0);
this.hasPeer = $("#include_peer_assessment", liveElement);
this.hasSelf = $("#include_self_assessment", liveElement);
this.hasAI = $("#include_ai_assessment", liveElement);
this.hasTraining = $("#include_student_training", liveElement);
this.peerMustGrade = $("#peer_assessment_must_grade", liveElement);
this.peerGradedBy = $("#peer_assessment_graded_by", liveElement);
this.peerStart = $("#peer_assessment_start_date", liveElement);
this.peerDue = $("#peer_assessment_due_date", liveElement);
this.selfStart = $("#self_assessment_start_date", liveElement);
this.selfDue = $("#self_assessment_due_date", liveElement);
this.rubricXmlBox = CodeMirror.fromTextArea($("#openassessment_rubric_editor", liveElement).first().get(0), {
mode: "xml",
lineNumbers: true,
lineWrapping: true
});
this.aiTrainingExamplesCodeBox = CodeMirror.fromTextArea($("#ai_training_examples", liveElement).first().get(0), {
mode: "xml",
lineNumbers: true,
lineWrapping: true
});
this.studentTrainingExamplesCodeBox = CodeMirror.fromTextArea($("#student_training_examples", liveElement).first().get(0), {
mode: "xml",
lineNumbers: true,
lineWrapping: true
});
var view = this;
$(".openassessment_save_button", liveElement).click(function(eventData) {
view.save();
});
$(".openassessment_cancel_button", liveElement).click(function(eventData) {
view.cancel();
});
$(".openassessment_editor_content_and_tabs", liveElement).tabs({
activate: function(event, ui) {
view.rubricXmlBox.refresh();
}
});
$("#include_peer_assessment", liveElement).change(function() {
if (this.checked) {
$("#peer_assessment_description_closed", liveElement).fadeOut("fast");
$("#peer_assessment_settings_editor", liveElement).fadeIn();
} else {
$("#peer_assessment_settings_editor", liveElement).fadeOut("fast");
$("#peer_assessment_description_closed", liveElement).fadeIn();
}
});
$("#include_self_assessment", liveElement).change(function() {
if (this.checked) {
$("#self_assessment_description_closed", liveElement).fadeOut("fast");
$("#self_assessment_settings_editor", liveElement).fadeIn();
} else {
$("#self_assessment_settings_editor", liveElement).fadeOut("fast");
$("#self_assessment_description_closed", liveElement).fadeIn();
}
});
$("#include_ai_assessment", liveElement).change(function() {
if (this.checked) {
$("#ai_assessment_description_closed", liveElement).fadeOut("fast");
$("#ai_assessment_settings_editor", liveElement).fadeIn();
} else {
$("#ai_assessment_settings_editor", liveElement).fadeOut("fast");
$("#ai_assessment_description_closed", liveElement).fadeIn();
}
});
$("#include_student_training", liveElement).change(function() {
if (this.checked) {
$("#student_training_description_closed", liveElement).fadeOut("fast");
$("#student_training_settings_editor", liveElement).fadeIn();
} else {
$("#student_training_settings_editor", liveElement).fadeOut("fast");
$("#student_training_description_closed", liveElement).fadeIn();
}
});
};
OpenAssessment.StudioView.prototype = {
load: function() {
var view = this;
this.server.loadEditorContext().done(function(prompt, rubricXml, title, subStart, subDue, assessments) {
view.rubricXmlBox.setValue(rubricXml);
view.submissionStartField.value = subStart;
view.submissionDueField.value = subDue;
view.promptBox.value = prompt;
view.titleField.value = title;
view.hasTraining.prop("checked", false).change();
view.hasPeer.prop("checked", false).change();
view.hasSelf.prop("checked", false).change();
view.hasAI.prop("checked", false).change();
for (var i = 0; i < assessments.length; i++) {
var assessment = assessments[i];
if (assessment.name == "peer-assessment") {
view.peerMustGrade.prop("value", assessment.must_grade);
view.peerGradedBy.prop("value", assessment.must_be_graded_by);
view.peerStart.prop("value", assessment.start);
view.peerDue.prop("value", assessment.due);
view.hasPeer.prop("checked", true).change();
} else if (assessment.name == "self-assessment") {
view.selfStart.prop("value", assessment.start);
view.selfDue.prop("value", assessment.due);
view.hasSelf.prop("checked", true).change();
} else if (assessment.name == "example-based-assessment") {
view.aiTrainingExamplesCodeBox.setValue(assessment.examples);
view.hasAI.prop("checked", true).change();
} else if (assessment.name == "student-training") {
view.studentTrainingExamplesCodeBox.setValue(assessment.examples);
view.hasTraining.prop("checked", true).change();
}
}
}).fail(function(msg) {
view.showError(msg);
});
},
save: function() {
var view = this;
this.server.checkReleased().done(function(isReleased) {
if (isReleased) {
view.confirmPostReleaseUpdate($.proxy(view.updateEditorContext, view));
} else {
view.updateEditorContext();
}
}).fail(function(errMsg) {
view.showError(msg);
});
},
confirmPostReleaseUpdate: function(onConfirm) {
var msg = gettext("This problem has already been released. Any changes will apply only to future assessments.");
if (confirm(msg)) {
onConfirm();
}
},
updateEditorContext: function() {
this.runtime.notify("save", {
state: "start"
});
var prompt = this.promptBox.value;
var rubricXml = this.rubricXmlBox.getValue();
var title = this.titleField.value;
var subStart = this.submissionStartField.value;
var subDue = this.submissionDueField.value;
var assessments = [];
if (this.hasTraining.prop("checked")) {
assessments[assessments.length] = {
name: "student-training",
examples: this.studentTrainingExamplesCodeBox.getValue()
};
}
if (this.hasPeer.prop("checked")) {
var assessment = {
name: "peer-assessment",
must_grade: parseInt(this.peerMustGrade.prop("value")),
must_be_graded_by: parseInt(this.peerGradedBy.prop("value"))
};
var startStr = this.peerStart.prop("value");
var dueStr = this.peerDue.prop("value");
if (startStr) {
assessment = $.extend(assessment, {
start: startStr
});
}
if (dueStr) {
assessment = $.extend(assessment, {
due: dueStr
});
}
assessments[assessments.length] = assessment;
}
if (this.hasSelf.prop("checked")) {
assessment = {
name: "self-assessment"
};
startStr = this.selfStart.prop("value");
dueStr = this.selfDue.prop("value");
if (startStr) {
assessment = $.extend(assessment, {
start: startStr
});
}
if (dueStr) {
assessment = $.extend(assessment, {
due: dueStr
});
}
assessments[assessments.length] = assessment;
}
if (this.hasAI.prop("checked")) {
assessments[assessments.length] = {
name: "example-based-assessment",
examples: this.aiTrainingExamplesCodeBox.getValue()
};
}
var view = this;
this.server.updateEditorContext(prompt, rubricXml, title, subStart, subDue, assessments).done(function() {
view.runtime.notify("save", {
state: "end"
});
view.load();
}).fail(function(msg) {
view.showError(msg);
});
},
cancel: function() {
this.runtime.notify("cancel", {});
},
showError: function(errorMsg) {
this.runtime.notify("error", {
msg: errorMsg
});
}
};
function OpenAssessmentEditor(runtime, element) {
var server = new OpenAssessment.Server(runtime, element);
var view = new OpenAssessment.StudioView(runtime, element, server);
view.load();
}
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.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, index) {
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(sel, hidden) {
sel.toggleClass("is--hidden", hidden);
sel.attr("aria-hidden", hidden ? "true" : "false");
},
isHidden: function(sel) {
return sel.hasClass("is--hidden") && sel.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.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);
}).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 = {
load: function() {
var view = this;
this.server.render("peer_assessment").done(function(html) {
$("#openassessment__peer-assessment", view.element).replaceWith(html);
view.installHandlers(false);
}).fail(function(errMsg) {
view.baseView.showLoadError("peer-assessment");
});
view.baseView.loadMessageView();
},
loadContinuedAssessment: function() {
var view = this;
this.server.renderContinuedPeer().done(function(html) {
$("#openassessment__peer-assessment", view.element).replaceWith(html);
view.installHandlers(true);
}).fail(function(errMsg) {
view.baseView.showLoadError("peer-assessment");
});
},
installHandlers: function(isContinuedAssessment) {
var sel = $("#openassessment__peer-assessment", this.element);
var view = this;
this.baseView.setUpCollapseExpand(sel, $.proxy(view.loadContinuedAssessment, view));
var rubricSelector = $("#peer-assessment--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(view.peerSubmitEnabled, view));
}
sel.find("#peer-assessment--001__assessment__submit").click(function(eventObject) {
eventObject.preventDefault();
if (!isContinuedAssessment) {
view.peerAssess();
} else {
view.continuedPeerAssess();
}
});
},
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);
}
},
peerAssess: function() {
var view = this;
var baseView = view.baseView;
this.peerAssessRequest(function() {
view.load();
baseView.loadAssessmentModules();
baseView.scrollToTop();
});
},
continuedPeerAssess: function() {
var view = this;
var gradeView = this.baseView.gradeView;
var baseView = view.baseView;
view.peerAssessRequest(function() {
view.loadContinuedAssessment();
gradeView.load();
baseView.scrollToTop();
});
},
peerAssessRequest: function(successFunction) {
var view = this;
view.baseView.toggleActionError("peer", null);
view.peerSubmitEnabled(false);
this.server.peerAssess(this.rubric.optionsSelected(), this.rubric.criterionFeedback(), this.overallFeedback()).done(successFunction).fail(function(errMsg) {
view.baseView.toggleActionError("peer", errMsg);
view.peerSubmitEnabled(true);
});
},
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);
}
}
};
OpenAssessment.ResponseView = function(element, server, baseView) {
this.element = element;
this.server = server;
this.baseView = baseView;
this.savedResponse = "";
this.lastChangeTime = Date.now();
this.errorOnLastSave = false;
this.autoSaveTimerId = null;
};
OpenAssessment.ResponseView.prototype = {
AUTO_SAVE_POLL_INTERVAL: 2e3,
AUTO_SAVE_WAIT: 3e4,
load: function() {
var view = this;
this.server.render("submission").done(function(html) {
$("#openassessment__response", view.element).replaceWith(html);
view.installHandlers();
view.setAutoSaveEnabled(true);
}).fail(function(errMsg) {
view.baseView.showLoadError("response");
});
},
installHandlers: function() {
var sel = $("#openassessment__response", this.element);
var view = this;
this.baseView.setUpCollapseExpand(sel);
this.savedResponse = this.response();
var handleChange = function(eventData) {
view.handleResponseChanged();
};
sel.find("#submission__answer__value").on("change keyup drop paste", handleChange);
sel.find("#step--response__submit").click(function(eventObject) {
eventObject.preventDefault();
view.submit();
});
sel.find("#submission__save").click(function(eventObject) {
eventObject.preventDefault();
view.save();
});
},
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);
}
},
saveEnabled: function(enabled) {
var sel = $("#submission__save", 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">' + label + ":" + "</span>\n" + msg);
}
},
unsavedWarningEnabled: function(enabled) {
if (typeof enabled === "undefined") {
return window.onbeforeunload !== null;
} else {
if (enabled) {
window.onbeforeunload = function() {
return gettext("If you leave this page without saving or submitting your response, you'll lose any work you've done on the response.");
};
} else {
window.onbeforeunload = null;
}
}
},
response: function(text) {
var sel = $("#submission__answer__value", this.element);
if (typeof text === "undefined") {
return sel.val();
} else {
sel.val(text);
}
},
responseChanged: function() {
var currentResponse = $.trim(this.response());
var savedResponse = $.trim(this.savedResponse);
return savedResponse !== currentResponse;
},
autoSave: function() {
var timeSinceLastChange = Date.now() - this.lastChangeTime;
if (this.responseChanged() && timeSinceLastChange > this.AUTO_SAVE_WAIT && !this.errorOnLastSave) {
this.save();
}
},
handleResponseChanged: function() {
var isBlank = $.trim(this.response()) !== "";
this.submitEnabled(isBlank);
if (this.responseChanged()) {
this.saveEnabled(isBlank);
this.saveStatus(gettext("This response has not been saved."));
this.unsavedWarningEnabled(true);
}
this.lastChangeTime = Date.now();
},
save: function() {
this.errorOnLastSave = false;
this.saveStatus(gettext("Saving..."));
this.baseView.toggleActionError("save", null);
this.unsavedWarningEnabled(false);
var view = this;
var savedResponse = this.response();
this.server.save(savedResponse).done(function() {
view.savedResponse = savedResponse;
var currentResponse = view.response();
view.submitEnabled(currentResponse !== "");
if (currentResponse == savedResponse) {
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;
this.confirmSubmission().pipe(function() {
var submission = $("#submission__answer__value", view.element).val();
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.unsavedWarningEnabled(false);
},
confirmSubmission: function() {
var msg = "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();
}
});
}
};
OpenAssessment.Rubric = function(element) {
this.element = element;
};
OpenAssessment.Rubric.prototype = {
criterionFeedback: function(criterionFeedback) {
var selector = "textarea.answer__value";
var feedback = {};
$(selector, this.element).each(function(index, sel) {
if (typeof criterionFeedback !== "undefined") {
$(sel).val(criterionFeedback[sel.name]);
feedback[sel.name] = criterionFeedback[sel.name];
} else {
feedback[sel.name] = $(sel).val();
}
});
return feedback;
},
optionsSelected: function(optionsSelected) {
var selector = "input[type=radio]";
if (typeof optionsSelected === "undefined") {
var options = {};
$(selector + ":checked", this.element).each(function(index, sel) {
options[sel.name] = sel.value;
});
return options;
} else {
$(selector, this.element).prop("checked", false);
$(selector, this.element).each(function(index, sel) {
if (optionsSelected.hasOwnProperty(sel.name)) {
if (sel.value == optionsSelected[sel.name]) {
$(sel).prop("checked", true);
}
}
});
}
},
canSubmitCallback: function(callback) {
$(this.element).change(function() {
var numChecked = $("input[type=radio]:checked", this).length;
var numAvailable = $(".field--radio.assessment__rubric__question", this).length;
var canSubmit = numChecked == numAvailable;
callback(canSubmit);
});
},
showCorrections: function(corrections) {
var selector = "input[type=radio]";
var hasErrors = false;
$(selector, this.element).each(function(index, sel) {
var listItem = $(sel).parents(".assessment__rubric__question");
if (corrections.hasOwnProperty(sel.name)) {
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;
}
};
OpenAssessment.SelfView = function(element, server, baseView) {
this.element = element;
this.server = server;
this.baseView = baseView;
this.rubric = null;
};
OpenAssessment.SelfView.prototype = {
load: function() {
var view = this;
this.server.render("self_assessment").done(function(html) {
$("#openassessment__self-assessment", view.element).replaceWith(html);
view.installHandlers();
}).fail(function(errMsg) {
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);
}
if (this.rubric !== null) {
this.rubric.canSubmitCallback($.proxy(this.selfSubmitEnabled, 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);
}
},
selfAssess: function() {
var view = this;
var baseView = this.baseView;
baseView.toggleActionError("self", null);
view.selfSubmitEnabled(false);
var options = this.rubric.optionsSelected();
this.server.selfAssess(options).done(function() {
baseView.loadAssessmentModules();
baseView.scrollToTop();
}).fail(function(errMsg) {
baseView.toggleActionError("self", errMsg);
view.selfSubmitEnabled(true);
});
}
};
OpenAssessment.Server = function(runtime, element) {
this.runtime = runtime;
this.element = element;
};
OpenAssessment.Server.prototype = {
url: function(handler) {
return this.runtime.handlerUrl(this.element, handler);
},
render: function(component) {
var url = this.url("render_" + component);
return $.Deferred(function(defer) {
$.ajax({
url: url,
type: "POST",
dataType: "html"
}).done(function(data) {
defer.resolveWith(this, [ data ]);
}).fail(function(data) {
defer.rejectWith(this, [ gettext("This section could not be loaded.") ]);
});
}).promise();
},
renderContinuedPeer: function() {
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(this, [ data ]);
}).fail(function(data) {
defer.rejectWith(this, [ gettext("This section could not be loaded.") ]);
});
}).promise();
},
studentInfo: function(student_id) {
var url = this.url("render_student_info");
return $.Deferred(function(defer) {
$.ajax({
url: url,
type: "POST",
dataType: "html",
data: {
student_id: student_id
}
}).done(function(data) {
defer.resolveWith(this, [ data ]);
}).fail(function(data) {
defer.rejectWith(this, [ gettext("This section 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
})
}).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(data) {
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
})
}).done(function(data) {
if (data.success) {
defer.resolve();
} else {
defer.rejectWith(this, [ data.msg ]);
}
}).fail(function(data) {
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
}).done(function(data) {
if (data.success) {
defer.resolve();
} else {
defer.rejectWith(this, [ data.msg ]);
}
}).fail(function(data) {
defer.rejectWith(this, [ gettext("This feedback could not be submitted.") ]);
});
}).promise();
},
peerAssess: function(optionsSelected, criterionFeedback, overallFeedback) {
var url = this.url("peer_assess");
var payload = JSON.stringify({
options_selected: optionsSelected,
criterion_feedback: criterionFeedback,
overall_feedback: overallFeedback
});
return $.Deferred(function(defer) {
$.ajax({
type: "POST",
url: url,
data: payload
}).done(function(data) {
if (data.success) {
defer.resolve();
} else {
defer.rejectWith(this, [ data.msg ]);
}
}).fail(function(data) {
defer.rejectWith(this, [ gettext("This assessment could not be submitted.") ]);
});
}).promise();
},
selfAssess: function(optionsSelected) {
var url = this.url("self_assess");
var payload = JSON.stringify({
options_selected: optionsSelected
});
return $.Deferred(function(defer) {
$.ajax({
type: "POST",
url: url,
data: payload
}).done(function(data) {
if (data.success) {
defer.resolve();
} else {
defer.rejectWith(this, [ data.msg ]);
}
}).fail(function(data) {
defer.rejectWith(this, [ gettext("This assessment could not be submitted.") ]);
});
});
},
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
}).done(function(data) {
if (data.success) {
defer.resolveWith(this, [ data.corrections ]);
} else {
defer.rejectWith(this, [ data.msg ]);
}
}).fail(function(data) {
defer.rejectWith(this, [ gettext("This assessment could not be submitted.") ]);
});
});
},
loadEditorContext: function() {
var url = this.url("editor_context");
return $.Deferred(function(defer) {
$.ajax({
type: "POST",
url: url,
data: '""'
}).done(function(data) {
if (data.success) {
defer.resolveWith(this, [ data.prompt, data.rubric, data.title, data.submission_start, data.submission_due, data.assessments ]);
} else {
defer.rejectWith(this, [ data.msg ]);
}
}).fail(function(data) {
defer.rejectWith(this, [ gettext("This problem could not be loaded.") ]);
});
}).promise();
},
updateEditorContext: function(prompt, rubricXml, title, sub_start, sub_due, assessments) {
var url = this.url("update_editor_context");
var payload = JSON.stringify({
prompt: prompt,
rubric: rubricXml,
title: title,
submission_start: sub_start,
submission_due: sub_due,
assessments: assessments
});
return $.Deferred(function(defer) {
$.ajax({
type: "POST",
url: url,
data: payload
}).done(function(data) {
if (data.success) {
defer.resolve();
} else {
defer.rejectWith(this, [ data.msg ]);
}
}).fail(function(data) {
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
}).done(function(data) {
if (data.success) {
defer.resolveWith(this, [ data.is_released ]);
} else {
defer.rejectWith(this, [ data.msg ]);
}
}).fail(function(data) {
defer.rejectWith(this, [ gettext("The server could not be contacted.") ]);
});
}).promise();
}
};
if (typeof OpenAssessment == "undefined" || !OpenAssessment) {
OpenAssessment = {};
}
if (typeof window.gettext === "undefined") {
window.gettext = function(text) {
return text;
};
}
OpenAssessment.StaffInfoView = function(element, server, baseView) {
this.element = element;
this.server = server;
this.baseView = baseView;
};
OpenAssessment.StaffInfoView.prototype = {
load: function() {
var view = this;
if ($("#openassessment__staff-info", view.element).length > 0) {
this.server.render("staff_info").done(function(html) {
$("#openassessment__staff-info", view.element).replaceWith(html);
view.installHandlers();
}).fail(function(errMsg) {
view.baseView.showLoadError("staff_info");
});
}
},
loadStudentInfo: function() {
var view = this;
var sel = $("#openassessment__staff-info", this.element);
var student_id = sel.find("#openassessment__student_id").val();
this.server.studentInfo(student_id).done(function(html) {
$("#openassessment__student-info", view.element).replaceWith(html);
}).fail(function(errMsg) {
view.showLoadError("student_info");
});
},
installHandlers: function() {
var sel = $("#openassessment__staff-info", this.element);
var view = this;
if (sel.length <= 0) {
return;
}
this.baseView.setUpCollapseExpand(sel, function() {});
sel.find("#openassessment_student_info_form").submit(function(eventObject) {
eventObject.preventDefault();
view.loadStudentInfo();
});
sel.find("#submit_student_id").click(function(eventObject) {
eventObject.preventDefault();
view.loadStudentInfo();
});
}
};
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.installHandlers();
}).fail(function(errMsg) {
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", this.element);
var instructions = $("#openassessment__student-training--instructions", this.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
......@@ -17,9 +17,10 @@ describe("OpenAssessment.StudioView", function() {
this.titleField = "";
this.submissionStartField = "";
this.submissionDueField = "";
this.hasPeer = true;
this.hasSelf = true;
this.hasTraining = true;
this.hasTraining = false;
this.hasAI = false;
this.peerMustGrade = 2;
......@@ -45,20 +46,35 @@ describe("OpenAssessment.StudioView", function() {
var title = this.titleField;
var submission_start = this.submissionStartField;
var submission_due = this.submissionDueField;
var assessments = [
{
name: "peer",
must_grade: this.peerMustGrade,
must_be_graded_by: this.peerGradedBy,
start: this.peerStart,
due: this.peerDue
},
{
name: "self",
start: this.selfStart,
due: this.selfDue
}
];
var assessments = [];
if (this.hasTraining){
assessments = assessments.concat({
"name": "student-training",
"examples": this.studentTrainingExamplesCodeBox
});
}
if (this.hasPeer){
assessments = assessments.concat({
"name": "peer-assessment",
"start": this.peerStart,
"due": this.peerDue,
"must_grade": this.peerMustGrade,
"must_be_graded_by": this.peerGradedBy
});
}
if (this.hasSelf){
assessments = assessments.concat({
"name": "self-assessment",
"start": this.selfStart,
"due": this.selfDue
});
}
if (this.hasAI){
assessments = assessments.concat({
"name": "example-based-assessment",
"examples": this.aiTrainingExamplesCodeBox
});
}
if (!this.loadError) {
return $.Deferred(function(defer) {
......@@ -123,6 +139,52 @@ describe("OpenAssessment.StudioView", function() {
var server = null;
var view = null;
var prompt = "How much do you like waffles?";
var rubric =
"<rubric>" +
"<criterion>"+
"<name>Proper Appreciation of Gravity</name>"+
"<prompt>How much respect did the person give waffles?</prompt>"+
"<option points=\"0\"><name>No</name><explanation>Not enough</explanation></option>"+
"<option points=\"2\"><name>Yes</name><explanation>An appropriate Amount</explanation></option>"+
"</criterion>"+
"</rubric>";
var title = "The most important of all questions.";
var subStart = "";
var subDue = "2014-10-1T10:00:00";
var assessments = [
{
"name": "student-training",
"examples":
"<examples>"+
"<example>" +
"<answer>ẗëṡẗ äṅṡẅëṛ</answer>" +
"<select criterion=\"Test criterion\" option=\"Yes\" />" +
"<select criterion=\"Another test criterion\" option=\"No\" />" +
"</example>" +
"<example>" +
"<answer>äṅöẗḧëṛ ẗëṡẗ äṅṡẅëṛ</answer>" +
"<select criterion=\"Another test criterion\" option=\"Yes\" />" +
"<select criterion=\"Test criterion\" option=\"No\" />" +
"</example>"+
"</examples>",
"start": "",
"due": ""
},
{
"name": "peer-assessment",
"must_grade": 5,
"must_be_graded_by": 3,
"start": "2014-10-04T00:00:00",
"due": ""
},
{
"name": "self-assessment",
"start": "",
"due": ""
}
];
beforeEach(function() {
// Load the DOM fixture
......@@ -183,6 +245,34 @@ describe("OpenAssessment.StudioView", function() {
expect(view.confirmPostReleaseUpdate).toHaveBeenCalled();
});
it("full integration test for load and update_editor_context", function() {
server.updateEditorContext(prompt, rubric, title, subStart, subDue, assessments);
view.load();
expect(view.promptBox.value).toEqual(prompt);
expect(view.rubricXmlBox.getValue()).toEqual(rubric);
expect(view.titleField.value).toEqual(title);
expect(view.submissionStartField.value).toEqual(subStart);
expect(view.submissionDueField.value).toEqual(subDue);
expect(view.hasPeer.prop('checked')).toEqual(true);
expect(view.hasSelf.prop('checked')).toEqual(true);
expect(view.hasAI.prop('checked')).toEqual(false);
expect(view.hasTraining.prop('checked')).toEqual(true);
expect(view.peerMustGrade.prop('value')).toEqual('5');
expect(view.peerGradedBy.prop('value')).toEqual('3');
expect(view.peerDue.prop('value')).toEqual("");
expect(view.selfStart.prop('value')).toEqual("");
expect(view.selfDue.prop('value')).toEqual("");
expect(view.aiTrainingExamplesCodeBox.getValue()).toEqual("");
expect(view.studentTrainingExamplesCodeBox.getValue()).toEqual(assessments[0].examples);
expect(view.peerStart.prop('value')).toEqual("2014-10-04T00:00:00");
view.titleField.value = "This is the new title.";
view.updateEditorContext();
expect(server.titleField).toEqual("This is the new title.");
});
it("cancels editing", function() {
view.cancel();
expect(runtime.notify).toHaveBeenCalledWith('cancel', {});
......
......@@ -15,102 +15,103 @@ OpenAssessment.StudioView = function(runtime, element, server) {
this.runtime = runtime;
this.server = server;
// Initialize the code box
//Instantiates JQuery variables which will allow manipulation and display controls.
live_element = $(element)
var liveElement = $(element);
this.promptBox = live_element.find('.openassessment-prompt-editor').first().get(0);
this.promptBox = $('#openassessment_prompt_editor', liveElement).get(0);
this.rubricXmlBox = CodeMirror.fromTextArea(
live_element.find('.openassessment-rubric-editor').first().get(0),
{mode: "xml", lineNumbers: true, lineWrapping: true}
);
this.titleField = $('#openassessment_title_editor', liveElement).first().get(0);
this.titleField = live_element.find('.openassessment-title-editor').first().get(0);
this.submissionStartField = $('#openassessment_submission_start_editor', liveElement).first().get(0);
this.submissionStartField = live_element.find('.openassessment-submission-start-editor').first().get(0);
this.submissionDueField = live_element.find('.openassessment-submission-due-editor').first().get(0);
this.submissionDueField = $('#openassessment_submission_due_editor', liveElement).first().get(0);
// Finds our boolean checkboxes that indicate the assessment definition
this.hasPeer = live_element.find('#include-peer-assessment');
this.hasSelf = live_element.find('#include-self-assessment');
this.hasAI = live_element.find('#include-ai-assessment');
this.hasTraining = live_element.find('#include-student-training');
this.hasPeer = $('#include_peer_assessment', liveElement);
this.hasSelf = $('#include_self_assessment', liveElement);
this.hasAI = $('#include_ai_assessment', liveElement);
this.hasTraining = $('#include_student_training', liveElement);
this.peerMustGrade = live_element.find('#peer-assessment-must-grade');
this.peerGradedBy = live_element.find('#peer-assessment-graded-by');
this.peerStart = live_element.find('#peer-assessment-start-date');
this.peerDue = live_element.find('#peer-assessment-due-date');
this.peerMustGrade = $('#peer_assessment_must_grade', liveElement);
this.peerGradedBy = $('#peer_assessment_graded_by', liveElement);
this.peerStart = $('#peer_assessment_start_date', liveElement);
this.peerDue = $('#peer_assessment_due_date', liveElement);
this.selfStart = live_element.find('#self-assessment-start-date');
this.selfDue = live_element.find('#self-assessment-due-date');
this.selfStart = $('#self_assessment_start_date', liveElement);
this.selfDue = $('#self_assessment_due_date', liveElement);
//Instantiates our codemirror codeboxes
this.rubricXmlBox = CodeMirror.fromTextArea(
$('#openassessment_rubric_editor', liveElement).first().get(0),
{mode: "xml", lineNumbers: true, lineWrapping: true}
);
this.aiTrainingExamplesCodeBox = CodeMirror.fromTextArea(
live_element.find('#ai-training-examples').get(0),
$('#ai_training_examples', liveElement).first().get(0),
{mode: "xml", lineNumbers: true, lineWrapping: true}
);
this.studentTrainingExamplesCodeBox = CodeMirror.fromTextArea(
live_element.find('#student-training-examples').get(0),
$('#student_training_examples', liveElement).first().get(0),
{mode: "xml", lineNumbers: true, lineWrapping: true}
);
// Install click handlers
var view = this;
live_element.find('.openassessment-save-button').click(
$('.openassessment_save_button', liveElement) .click(
function (eventData) {
view.save();
});
live_element.find('.openassessment-cancel-button').click(
$('.openassessment_cancel_button', liveElement) .click(
function (eventData) {
view.cancel();
});
live_element.find('.openassessment-editor-content-and-tabs').tabs({
$('.openassessment_editor_content_and_tabs', liveElement) .tabs({
activate: function (event, ui){
view.rubricXmlBox.refresh();
}
});
live_element.find('#include-peer-assessment').change(function () {
$('#include_peer_assessment', liveElement) .change(function () {
if (this.checked){
$("#peer-assessment-description-closed", live_element).fadeOut('fast');
$("#peer-assessment-settings-editor", live_element).fadeIn();
$("#peer_assessment_description_closed", liveElement).fadeOut('fast');
$("#peer_assessment_settings_editor", liveElement).fadeIn();
} else {
$("#peer-assessment-settings-editor", live_element).fadeOut('fast');
$("#peer-assessment-description-closed", live_element).fadeIn();
$("#peer_assessment_settings_editor", liveElement).fadeOut('fast');
$("#peer_assessment_description_closed", liveElement).fadeIn();
}
});
live_element.find('#include-self-assessment').change(function () {
$('#include_self_assessment', liveElement) .change(function () {
if (this.checked){
$("#self-assessment-description-closed", live_element).fadeOut('fast');
$("#self-assessment-settings-editor", live_element).fadeIn();
$("#self_assessment_description_closed", liveElement).fadeOut('fast');
$("#self_assessment_settings_editor", liveElement).fadeIn();
} else {
$("#self-assessment-settings-editor", live_element).fadeOut('fast');
$("#self-assessment-description-closed", live_element).fadeIn();
$("#self_assessment_settings_editor", liveElement).fadeOut('fast');
$("#self_assessment_description_closed", liveElement).fadeIn();
}
});
live_element.find('#include-ai-assessment').change(function () {
$('#include_ai_assessment', liveElement) .change(function () {
if (this.checked){
$("#ai-assessment-description-closed", live_element).fadeOut('fast');
$("#ai-assessment-settings-editor", live_element).fadeIn();
$("#ai_assessment_description_closed", liveElement).fadeOut('fast');
$("#ai_assessment_settings_editor", liveElement).fadeIn();
} else {
$("#ai-assessment-settings-editor", live_element).fadeOut('fast');
$("#ai-assessment-description-closed", live_element).fadeIn();
$("#ai_assessment_settings_editor", liveElement).fadeOut('fast');
$("#ai_assessment_description_closed", liveElement).fadeIn();
}
});
live_element.find('#include-student-training').change(function () {
$('#include_student_training', liveElement) .change(function () {
if (this.checked){
$("#student-training-description-closed", live_element).fadeOut('fast');
$("#student-training-settings-editor", live_element).fadeIn();
$("#student_training_description_closed", liveElement).fadeOut('fast');
$("#student_training_settings_editor", liveElement).fadeIn();
} else {
$("#student-training-settings-editor", live_element).fadeOut('fast');
$("#student-training-description-closed", live_element).fadeIn();
$("#student_training_settings_editor", liveElement).fadeOut('fast');
$("#student_training_description_closed", liveElement).fadeIn();
}
});
......@@ -124,36 +125,34 @@ OpenAssessment.StudioView.prototype = {
load: function () {
var view = this;
this.server.loadEditorContext().done(
function (prompt, rubricXml, title, sub_start, sub_due, assessments) {
function (prompt, rubricXml, title, subStart, subDue, assessments) {
view.rubricXmlBox.setValue(rubricXml);
view.submissionStartField.value = sub_start;
view.submissionDueField.value = sub_due;
view.submissionStartField.value = subStart;
view.submissionDueField.value = subDue;
view.promptBox.value = prompt;
view.titleField.value = title;
view.hasPeer.prop('checked',false).change();
view.hasSelf.prop('checked',false).change();
view.hasTraining.prop('checked',false).change();
view.hasAI.prop('checked',false).change();
view.hasTraining.prop('checked', false).change();
view.hasPeer.prop('checked', false).change();
view.hasSelf.prop('checked', false).change();
view.hasAI.prop('checked', false).change();
for (var i = 0; i < assessments.length; i++) {
var assessment = assessments[i];
if (assessment.name == 'peer-assessment') {
view.hasPeer.prop('checked', true).change();
view.peerMustGrade.prop('value', assessment.must_grade);
view.peerGradedBy.prop('value', assessment.must_be_graded_by);
view.peerStart.prop('value', assessment.start);
view.peerDue.prop('value', assessment.due);
view.hasPeer.prop('checked', true).change();
} else if (assessment.name == 'self-assessment') {
view.hasSelf.prop('checked', true).change();
view.selfStart.prop('value', assessment.start);
view.selfDue.prop('value', assessment.due);
view.hasSelf.prop('checked', true).change();
} else if (assessment.name == 'example-based-assessment') {
view.hasAI.prop('checked', true).change();
view.aiTrainingExamplesCodeBox.setValue(assessment.examples);
view.hasAI.prop('checked', true).change();
} else if (assessment.name == 'student-training') {
view.hasTraining.prop('checked', true).change();
view.studentTrainingExamplesCodeBox.setValue(assessment.examples);
} else {
view.hasTraining.prop('checked', true).change();
}
}
}).fail(function (msg) {
......@@ -213,8 +212,8 @@ OpenAssessment.StudioView.prototype = {
var prompt = this.promptBox.value;
var rubricXml = this.rubricXmlBox.getValue();
var title = this.titleField.value;
var sub_start = this.submissionStartField.value;
var sub_due = this.submissionDueField.value;
var subStart = this.submissionStartField.value;
var subDue = this.submissionDueField.value;
var assessments = [];
......@@ -231,13 +230,13 @@ OpenAssessment.StudioView.prototype = {
"must_grade": parseInt(this.peerMustGrade.prop('value')),
"must_be_graded_by": parseInt(this.peerGradedBy.prop('value'))
};
var start_str = this.peerStart.prop('value');
var due_str = this.peerDue.prop('value');
if (start_str){
assessment = $.extend(assessment, {"start": start_str})
var startStr = this.peerStart.prop('value');
var dueStr = this.peerDue.prop('value');
if (startStr){
assessment = $.extend(assessment, {"start": startStr})
}
if (due_str){
assessment = $.extend(assessment, {"due": due_str})
if (dueStr){
assessment = $.extend(assessment, {"due": dueStr})
}
assessments[assessments.length] = assessment;
}
......@@ -246,13 +245,13 @@ OpenAssessment.StudioView.prototype = {
assessment = {
"name": "self-assessment"
};
start_str = this.selfStart.prop('value');
due_str = this.selfDue.prop('value');
if (start_str){
assessment = $.extend(assessment, {"start": start_str})
startStr = this.selfStart.prop('value');
dueStr = this.selfDue.prop('value');
if (startStr){
assessment = $.extend(assessment, {"start": startStr})
}
if (due_str){
assessment = $.extend(assessment, {"due": due_str})
if (dueStr){
assessment = $.extend(assessment, {"due": dueStr})
}
assessments[assessments.length] = assessment;
}
......@@ -260,13 +259,12 @@ OpenAssessment.StudioView.prototype = {
if (this.hasAI.prop('checked')) {
assessments[assessments.length] = {
"name": "example-based-assessment",
"algorithm_id": "ease",
"examples": this.aiTrainingExamplesCodeBox.getValue()
};
}
var view = this;
this.server.updateEditorContext(prompt, rubricXml, title, sub_start, sub_due, assessments).done(function () {
this.server.updateEditorContext(prompt, rubricXml, title, subStart, subDue, assessments).done(function () {
// Notify the client-side runtime that we finished saving
// so it can hide the "Saving..." notification.
view.runtime.notify('save', {state: 'end'});
......
......@@ -173,120 +173,160 @@
#openassessment-editor {
margin-bottom: 0;
.openassessment-editor-content-and-tabs {
.openassessment_editor_content_and_tabs {
width: 100%;
height: 370px;
}
.openassessment-editor-header{
#openassessment_editor_header{
background-color: #e5e5e5;
width: 100%;
top: 0;
}
#oa-editor-window-title{
#oa_editor_window_title{
float: left;
}
.oa-editor-tab{
.oa_editor_tab{
float: right;
padding: ($baseline-v/8) ($baseline-h/8);
margin: ($baseline-v/8) ($baseline-h/8);
border-radius: ($baseline-v/8);
border-radius: ($baseline-v/4);
box-shadow: none;
border: 0;
}
.oa-editor-content-wrapper {
.oa_editor_content_wrapper {
height: 100%;
width: 100%;
padding: ($baseline-v/4) ($baseline-h/4);
}
.openassessment-prompt-editor {
#openassessment_prompt_editor {
width: 100%;
height: 100%;
resize: none;
border: none;
}
.openassessment-rubric-editor {
#openassessment_rubric_editor {
width: 100%;
height: 100%;
}
.openassessment-assessments-editor {
width: 100%;
#oa_basic_settings_editor {
padding: 20px 20px;
border-bottom: 1px solid $edx-gray-d3;
#openassessment_title_editor_wrapper{
label{
width: 25%;
text-align: left;
}
input{
width: 45%;
min-width: 100px;
}
}
}
#oa-settings-editor-text-fields {
#openassessment_step_select_description{
margin: 10px 0;
}
#oa-settings-editor-wrapper {
.openassessment_assessment_module_settings_editor{
margin-bottom: 10px;
padding-bottom: 10px;
border-bottom: 1px solid $edx-gray-l3;
}
.openassessment_indent_line_input{
padding: 5px 20px;
}
#oa_settings_editor_wrapper {
overflow-y: scroll;
}
#openassessment-title-editor {
#openassessment_title_editor {
width: 300px;
margin-left: 50px;
}
.openassessment-number-field{
width: 25px;
.openassessment_description{
font-size: 75%;
margin: 0;
}
.openassessment-date-field{
.openassessment_date_field{
width: 130px;
}
.openassessment_number_field{
width: 25px;
}
.openassessment-description{
font-size: 75%;
.openassessment_description_closed{
@extend .openassessment_description;
}
.openassessment-text-field-wrapper{
.openassessment_text_field_wrapper{
width: 50%;
text-align: center;
}
.right-text-field-wrapper {
.openassessment_right_text_field_wrapper {
@extend .openassessment_text_field_wrapper;
float: right;
}
.left-text-field-wrapper {
.openassessment_left_text_field_wrapper {
@extend .openassessment_text_field_wrapper;
float: left;
}
.openassessment-due-date-editor{
.openassessment_due_date_editor{
height: 30px;
}
.openassessment-inclusion-wrapper{
.openassessment_inclusion_wrapper{
background-color: $edx-gray-l3;
input[type="checkbox"] {
}
padding: ($baseline-v/8) ($baseline-h/8);
margin: ($baseline-v/8) ($baseline-h/8);
border-radius: ($baseline-v)/8;
input[type="checkbox"]{
display: none;
}
input[type="checkbox"] + label:before {
font-family: "FontAwesome";
display: inline-block;
margin-right: ($baseline-h/4);
width: auto;
height: auto;
content: "\f096";
}
input[type="checkbox"]:checked + label:before{
content: "\f046";
}
}
label{
padding-right: 10px;
}
.xblock-actions {
background-color: #e5e5e5;
.xblock_actions {
background-color: $edx-gray-l2;
position: absolute;
width: 100%;
bottom: 0;
}
.peer-number-constraints{
margin-bottom: 10px;
}
.ui-widget-header .ui-state-default{
background: #e5e5e5;
a{
color: $edx-gray-d4;
color: $edx-gray-d3;
text-transform: uppercase;
outline-color: transparent;
}
......@@ -302,25 +342,8 @@
}
}
input[type="checkbox"]{
display: none;
}
input[type="checkbox"] + label:before {
font-family: "FontAwesome";
display: inline-block;
margin-right: ($baseline-h/4);
width: auto;
height: auto;
content: "\f096";
}
input[type="checkbox"]:checked + label:before{
content: "\f046";
}
hr {
background-color: #d4d4d4;
background-color: transparent;
color: $edx-gray-d3;
height: 1px;
border: 0px;
......
......@@ -6,11 +6,12 @@ import copy
import logging
from django.template.context import Context
from django.template.loader import get_template
from django.utils.translation import ugettext as _
from django.utils.translation import ugettext as _, ugettext
from xblock.core import XBlock
from xblock.fragment import Fragment
from openassessment.xblock import xml
from openassessment.xblock.validation import validator
from openassessment.xblock.xml import UpdateFromXmlError, parse_date, parse_examples_xml_str
logger = logging.getLogger(__name__)
......@@ -48,7 +49,7 @@ class StudioMixin(object):
-- The 'rubric' should be an XML representation of the new rubric.
-- The 'prompt' and 'title' should be plain text.
-- The dates 'submission_start' and 'submission_due' are both ISO strings
-- The 'assessments' is a list of asessment dictionaries (much like self.rubric_assessments)
-- The 'assessments' is a list of assessment dictionaries (much like self.rubric_assessments)
with the notable exception that all examples (for Student Training and eventually AI)
are in XML string format and need to be parsed into dictionaries.
......@@ -69,9 +70,9 @@ class StudioMixin(object):
try:
rubric = xml.parse_rubric_xml_str(data["rubric"])
submission_due = xml.parse_date(data["submission_due"])
submission_start = xml.parse_date(data["submission_start"])
assessments = xml.parse_assessment_dictionaries(data["assessments"])
submission_due = xml.parse_date(data["submission_due"], name="submission due date")
submission_start = xml.parse_date(data["submission_start"], name="submission start date")
assessments = parse_assessment_dictionaries(data["assessments"])
except xml.UpdateFromXmlError as ex:
return {'success': False, 'msg': _('An error occurred while saving: {error}').format(error=ex)}
......@@ -171,3 +172,72 @@ class StudioMixin(object):
'is_released': self.is_released()
}
def parse_assessment_dictionaries(input_assessments):
"""
Parses the elements of assessment dictionaries returned by the Studio UI into storable rubric_assessments
Args:
input_assessments (list of dict): A list of the dictionaries that are assembled in Javascript to
represent their modules. Some changes need to be made between this and the result:
-- Parse the XML examples from the Student Training and or AI
-- Parse all dates (including the assessment dates) correctly
Returns:
(list of dict): Can be directly assigned/stored in an openassessmentblock.rubric_assessments
"""
assessments_list = []
for assessment in input_assessments:
assessment_dict = dict()
# Assessment name
if 'name' in assessment:
assessment_dict['name'] = assessment.get('name')
else:
raise UpdateFromXmlError(_('All "assessment" elements must contain a "name" element.'))
# Assessment start
if 'start' in assessment:
parsed_start = parse_date(assessment.get('start'), name="{} start date".format(assessment.get('name')))
assessment_dict['start'] = parsed_start
else:
assessment_dict['start'] = None
# Assessment due
if 'due' in assessment:
parsed_due = parse_date(assessment.get('due'), name="{} due date".format(assessment.get('name')))
assessment_dict['due'] = parsed_due
else:
assessment_dict['due'] = None
# Assessment must_grade
if 'must_grade' in assessment:
try:
assessment_dict['must_grade'] = int(assessment.get('must_grade'))
except (ValueError, TypeError):
raise UpdateFromXmlError(_('The "must_grade" value must be a positive integer.'))
# Assessment must_be_graded_by
if 'must_be_graded_by' in assessment:
try:
assessment_dict['must_be_graded_by'] = int(assessment.get('must_be_graded_by'))
except (ValueError, TypeError):
raise UpdateFromXmlError(_('The "must_be_graded_by" value must be a positive integer.'))
# Training examples (can be for AI OR for Student Training)
if 'examples' in assessment:
try:
assessment_dict['examples'] = parse_examples_xml_str(assessment.get('examples'))
except UpdateFromXmlError as ex:
raise UpdateFromXmlError(_("There was an error in parsing the {name} examples: {ex}").format(
name=assessment_dict['name'], ex=ex
))
# Update the list of assessments
assessments_list.append(assessment_dict)
return assessments_list
\ No newline at end of file
......@@ -36,7 +36,7 @@ class StudioViewTest(XBlockHandlerTestCase):
# Verify that every assessment in the list of assessments has a name.
for assessment_dict in resp['assessments']:
self.assertTrue(assessment_dict.get('name', False))
if assessment_dict.get('name') == 'studnet-training':
if assessment_dict.get('name') == 'student-training':
examples = etree.fromstring(assessment_dict['examples'])
self.assertEqual(examples.tag, 'examples')
......
......@@ -11,11 +11,12 @@ import dateutil.parser
from django.test import TestCase
import ddt
from openassessment.xblock.openassessmentblock import OpenAssessmentBlock
from openassessment.xblock.studio_mixin import parse_assessment_dictionaries
from openassessment.xblock.xml import (
serialize_content, parse_from_xml_str, parse_rubric_xml_str,
parse_examples_xml_str, parse_assessments_xml_str,
serialize_rubric_to_xml_str, serialize_examples_to_xml_str,
serialize_assessments_to_xml_str, UpdateFromXmlError, parse_assessment_dictionaries
serialize_assessments_to_xml_str, UpdateFromXmlError
)
......@@ -366,8 +367,12 @@ class TestParseAssessmentsFromDictionaries(TestCase):
config = parse_assessment_dictionaries(data['assessments_list'])
for i in range(0, len(config)):
self.assertEqual(config[i], data['results'][i])
if len(config) == 0:
# Prevents this test from passing benignly if parse_assessment_dictionaries returns []
self.assertTrue(False)
for config_assessment, correct_assessment in zip(config, data['results']):
self.assertEqual(config_assessment, correct_assessment)
@ddt.file_data('data/parse_assessment_dicts_error.json')
def test_parse_assessments_dictionary_error(self, data):
......
......@@ -160,7 +160,7 @@ def serialize_rubric(rubric_root, oa_block, include_prompt=True):
feedback_prompt.text = unicode(oa_block.rubric_feedback_prompt)
def parse_date(date_str):
def parse_date(date_str, name=""):
"""
Attempt to parse a date string into ISO format (without milliseconds)
Returns `None` if this cannot be done.
......@@ -168,6 +168,9 @@ def parse_date(date_str):
Args:
date_str (str): The date string to parse.
Kwargs:
name (str): the name to return in an error to the origin of the call if an error occurs.
Returns:
unicode in ISO format (without milliseconds) if the date string is
parse-able. None if parsing fails.
......@@ -184,8 +187,9 @@ def parse_date(date_str):
return unicode(formatted_date)
except (ValueError, TypeError):
msg = (
'The format for the given date ({}) is invalid. Make sure the date is formatted as YYYY-MM-DDTHH:MM:SS.'
).format(date_str)
'The format of the given date ({date}) for the {name} is invalid. '
'Make sure the date is formatted as YYYY-MM-DDTHH:MM:SS.'
).format(date=date_str, name=name)
raise UpdateFromXmlError(_(msg))
......@@ -374,68 +378,6 @@ def parse_examples_xml(examples):
return examples_list
def parse_assessment_dictionaries(input_assessments):
assessments_list = []
for assessment in input_assessments:
assessment_dict = dict()
# Assessment name
if assessment.get('name'):
assessment_dict['name'] = unicode(assessment.get('name'))
else:
raise UpdateFromXmlError(_('All "assessment" elements must contain a "name" element.'))
# Assessment start
if assessment.get('start'):
try:
parsed_start = parse_date(assessment.get('start'))
assessment_dict['start'] = parsed_start
except UpdateFromXmlError:
raise UpdateFromXmlError(_('The date format in the "start" attribute is invalid. Make sure the date is formatted as YYYY-MM-DDTHH:MM:SS.'))
else:
assessment_dict['start'] = None
# Assessment due
if assessment.get('due'):
try:
parsed_due = parse_date(assessment.get('due'))
assessment_dict['due'] = parsed_due
except UpdateFromXmlError:
raise UpdateFromXmlError(_('The date format in the "due" attribute is invalid. Make sure the date is formatted as YYYY-MM-DDTHH:MM:SS.'))
else:
assessment_dict['due'] = None
# Assessment must_grade
if assessment.get('must_grade'):
try:
assessment_dict['must_grade'] = int(assessment.get('must_grade'))
except ValueError:
raise UpdateFromXmlError(_('The "must_grade" value must be a positive integer.'))
# Assessment must_be_graded_by
if assessment.get('must_be_graded_by'):
try:
assessment_dict['must_be_graded_by'] = int(assessment.get('must_be_graded_by'))
except ValueError:
raise UpdateFromXmlError(_('The "must_be_graded_by" value must be a positive integer.'))
# Training examples (can be for AI or for Student Training)
if assessment.get('examples'):
try:
assessment_dict['examples'] = parse_examples_xml_str(assessment.get('examples'))
except (UpdateFromXmlError, UnicodeError) as ex:
raise UpdateFromXmlError(_(
"There was an error in parsing the {0} examples: {1}".format(assessment.get('name'), ex)
))
# Update the list of assessments
assessments_list.append(assessment_dict)
return assessments_list
def parse_assessments_xml(assessments_root):
"""
Parse the <assessments> element in the OpenAssessment XBlock's content XML.
......@@ -464,21 +406,17 @@ def parse_assessments_xml(assessments_root):
# Assessment start
if 'start' in assessment.attrib:
parsed_start = parse_date(assessment.get('start'))
parsed_start = parse_date(assessment.get('start'), name="{} start date".format(assessment_dict['name']))
if parsed_start is not None:
assessment_dict['start'] = parsed_start
else:
raise UpdateFromXmlError(_('The date format in the "start" attribute is invalid. Make sure the date is formatted as YYYY-MM-DDTHH:MM:SS.'))
else:
assessment_dict['start'] = None
# Assessment due
if 'due' in assessment.attrib:
parsed_start = parse_date(assessment.get('due'))
parsed_start = parse_date(assessment.get('due'), name="{} due date".format(assessment_dict['name']))
if parsed_start is not None:
assessment_dict['due'] = parsed_start
else:
raise UpdateFromXmlError(_('The date format in the "due" attribute is invalid. Make sure the date is formatted as YYYY-MM-DDTHH:MM:SS.'))
else:
assessment_dict['due'] = None
......@@ -711,13 +649,13 @@ def parse_from_xml(root):
# Set it to None by default; we will update it to the latest start date later on
submission_start = None
if 'submission_start' in root.attrib:
submission_start = parse_date(unicode(root.attrib['submission_start']))
submission_start = parse_date(unicode(root.attrib['submission_start']), name="submission start date")
# Retrieve the due date for the submission
# Set it to None by default; we will update it to the earliest deadline later on
submission_due = None
if 'submission_due' in root.attrib:
submission_due = parse_date(unicode(root.attrib['submission_due']))
submission_due = parse_date(unicode(root.attrib['submission_due']), name="submission due date")
# Retrieve the title
title_el = root.find('title')
......@@ -827,10 +765,10 @@ def parse_examples_xml_str(xml):
"""
# This should work for both wrapped and unwrapped examples. Based on our final configuration (and tests)
# we should handle both cases gracefully.
if "<examples>" not in xml:
xml = u"<data>" + xml + u"</data>"
else:
xml = unicode(xml)
xml = u"<examples>" + xml + u"</examples>"
return parse_examples_xml(list(_unicode_to_xml(xml).findall('example')))
......
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