Commit 6a28da14 by Will Daly

Merge pull request #538 from edx/will/student-training-refactor-and-tests

Student training dynamic update refactor and tests
parents a05d51fd 2232813d
...@@ -27,6 +27,7 @@ module.exports = function(config) { ...@@ -27,6 +27,7 @@ module.exports = function(config) {
'src/*.js', 'src/*.js',
'src/lms/*.js', 'src/lms/*.js',
'src/studio/*.js', 'src/studio/*.js',
'spec/test_shared.js',
'spec/*.js', 'spec/*.js',
'spec/lms/*.js', 'spec/lms/*.js',
'spec/studio/*.js', 'spec/studio/*.js',
......
...@@ -391,7 +391,7 @@ ...@@ -391,7 +391,7 @@
"submission_due": "2014-10-1T10:00:00", "submission_due": "2014-10-1T10:00:00",
"criteria": [ "criteria": [
{ {
"name": "52bfbd0eb3044212b809564866e77079", "name": "criterion_1",
"label": "Criterion with two options", "label": "Criterion with two options",
"prompt": "Prompt for criterion with two options", "prompt": "Prompt for criterion with two options",
"order_num": 0, "order_num": 0,
...@@ -400,14 +400,14 @@ ...@@ -400,14 +400,14 @@
{ {
"order_num": 0, "order_num": 0,
"points": 1, "points": 1,
"name": "85bbbecbb6a343f8a2146cde0e609ad0", "name": "option_1",
"label": "Fair", "label": "Fair",
"explanation": "Fair explanation" "explanation": "Fair explanation"
}, },
{ {
"order_num": 1, "order_num": 1,
"points": 2, "points": 2,
"name": "5936d5b9e281403ca123964055d4719a", "name": "option_2",
"label": "Good", "label": "Good",
"explanation": "Good explanation" "explanation": "Good explanation"
} }
...@@ -415,7 +415,7 @@ ...@@ -415,7 +415,7 @@
"points_possible": 2 "points_possible": 2
}, },
{ {
"name": "d96bb68a69ee4ccb8f86c753b6924f75", "name": "criterion_2",
"label": "Criterion with no options", "label": "Criterion with no options",
"prompt": "Prompt for criterion with no options", "prompt": "Prompt for criterion with no options",
"order_num": 0, "order_num": 0,
...@@ -424,7 +424,7 @@ ...@@ -424,7 +424,7 @@
"points_possible": 0 "points_possible": 0
}, },
{ {
"name": "2ca052403b06424da714f7a80dfb954d", "name": "criterion_3",
"label": "Criterion with optional feedback", "label": "Criterion with optional feedback",
"prompt": "Prompt for criterion with optional feedback", "prompt": "Prompt for criterion with optional feedback",
"order_num": 2, "order_num": 2,
...@@ -433,7 +433,7 @@ ...@@ -433,7 +433,7 @@
{ {
"order_num": 0, "order_num": 0,
"points": 2, "points": 2,
"name": "d7445661a89b4b339b9788cb7225a603", "name": "option_1",
"label": "Good", "label": "Good",
"explanation": "Good explanation" "explanation": "Good explanation"
} }
...@@ -462,6 +462,148 @@ ...@@ -462,6 +462,148 @@
"output": "oa_edit.html" "output": "oa_edit.html"
}, },
{ {
"template": "openassessmentblock/edit/oa_edit.html",
"context": {
"prompt": "Test prompt",
"title": "Test title",
"submission_due": "2014-10-1T10:00:00",
"criteria": [
{
"name": "criterion_with_two_options",
"label": "Criterion with two options",
"prompt": "Criterion with two options prompt",
"order_num": 0,
"feedback": "disabled",
"options": [
{
"order_num": 0,
"points": 1,
"name": "option_1",
"label": "Fair",
"explanation": "Fair explanation"
},
{
"order_num": 1,
"points": 2,
"name": "option_2",
"label": "Good",
"explanation": "Good explanation"
}
],
"points_possible": 2
},
{
"name": "criterion_no_options",
"label": "Criterion with no options",
"prompt": "Criterion with no options prompt",
"order_num": 0,
"options": [],
"feedback": "required",
"points_possible": 0
}
],
"assessments": {
"training": {
"examples": [
{
"answer": "Test answer",
"criteria": [
{
"name": "criterion_with_two_options",
"label": "Criterion with two options",
"prompt": "Criterion with two options prompt",
"order_num": 0,
"feedback": "disabled",
"options": [
{
"order_num": 0,
"points": 1,
"name": "option_1",
"label": "Fair",
"explanation": "Fair explanation"
},
{
"order_num": 1,
"points": 2,
"name": "option_2",
"label": "Good",
"explanation": "Good explanation"
}
],
"points_possible": 2,
"option_selected": "option_1"
},
{
"name": "criterion_no_options",
"label": "Criterion with no options",
"prompt": "Criterion with no options prompt",
"order_num": 0,
"options": [],
"feedback": "required",
"points_possible": 0,
"option_selected": ""
}
]
}
],
"template": {
"answer": "",
"criteria": [
{
"name": "criterion_with_two_options",
"label": "Criterion with two options",
"prompt": "Criterion with two options prompt",
"order_num": 0,
"feedback": "disabled",
"options": [
{
"order_num": 0,
"points": 1,
"name": "option_1",
"label": "Fair",
"explanation": "Fair explanation"
},
{
"order_num": 1,
"points": 2,
"name": "option_2",
"label": "Good",
"explanation": "Good explanation"
}
],
"points_possible": 2,
"option_selected": ""
},
{
"name": "criterion_no_options",
"label": "Criterion with no options",
"prompt": "Criterion with no options prompt",
"order_num": 0,
"options": [],
"feedback": "required",
"points_possible": 0,
"option_selected": ""
}
]
}
},
"peer_assessment": {
"start": "",
"due": "",
"must_grade": 5,
"must_be_graded_by": 3
}
},
"editor_assessments_order": [
"student_training",
"peer_assessment",
"self_assessment",
"example_based_assessment"
]
},
"output": "oa_edit_student_training.html"
},
{
"template": "openassessmentblock/staff_debug/staff_debug.html", "template": "openassessmentblock/staff_debug/staff_debug.html",
"context": { "context": {
"status_counts": { "status_counts": {
......
if(typeof OpenAssessment=="undefined"||!OpenAssessment){OpenAssessment={}}if(typeof window.gettext==="undefined"){window.gettext=function(text){return text}}OpenAssessment.FileUploader=function(){this.upload=function(url,data,contentType){return $.Deferred(function(defer){$.ajax({url:url,type:"PUT",data:data,async:false,processData:false,contentType:contentType}).done(function(data,textStatus,jqXHR){defer.resolve()}).fail(function(data,textStatus,jqXHR){defer.rejectWith(this,[textStatus])})}).promise()}};if(typeof OpenAssessment.Server=="undefined"||!OpenAssessment.Server){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.")])})})},scheduleTraining:function(){var url=this.url("schedule_training");return $.Deferred(function(defer){$.ajax({type:"POST",url:url,data:'""'}).done(function(data){if(data.success){defer.resolveWith(this,[data.msg])}else{defer.rejectWith(this,[data.msg])}}).fail(function(data){defer.rejectWith(this,[gettext("This assessment could not be submitted.")])})})},rescheduleUnfinishedTasks:function(){var url=this.url("reschedule_unfinished_tasks");return $.Deferred(function(defer){$.ajax({type:"POST",url:url,data:'""'}).done(function(data){if(data.success){defer.resolveWith(this,[data.msg])}else{defer.rejectWith(this,[data.msg])}}).fail(function(data){defer.rejectWith(this,[gettext("One or more rescheduling tasks failed.")])})})},updateEditorContext:function(kwargs){var url=this.url("update_editor_context");var payload=JSON.stringify({prompt:kwargs.prompt,feedback_prompt:kwargs.feedbackPrompt,title:kwargs.title,submission_start:kwargs.submissionStart,submission_due:kwargs.submissionDue,criteria:kwargs.criteria,assessments:kwargs.assessments,editor_assessments_order:kwargs.editorAssessmentsOrder,allow_file_upload:kwargs.imageSubmissionEnabled});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()},getUploadUrl:function(contentType){var url=this.url("upload_url");return $.Deferred(function(defer){$.ajax({type:"POST",url:url,data:JSON.stringify({contentType:contentType})}).done(function(data){if(data.success){defer.resolve(data.url)}else{defer.rejectWith(this,[data.msg])}}).fail(function(data){defer.rejectWith(this,[gettext("Could not retrieve upload url.")])})}).promise()},getDownloadUrl:function(){var url=this.url("download_url");return $.Deferred(function(defer){$.ajax({type:"POST",url:url,data:JSON.stringify({})}).done(function(data){if(data.success){defer.resolve(data.url)}else{defer.rejectWith(this,[data.msg])}}).fail(function(data){defer.rejectWith(this,[gettext("Could not retrieve download url.")])})}).promise()}}}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.fileUploader=new OpenAssessment.FileUploader;this.responseView=new OpenAssessment.ResponseView(this.element,this.server,this.fileUploader,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){parentSel.find(".ui-toggle-visibility__control").click(function(eventData){var sel=$(eventData.target).closest(".ui-toggle-visibility");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"}else if(type=="upload"){container="#upload__error"}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.Container=function(containerItem,kwargs){this.containerItem=containerItem;this.containerElement=kwargs.containerElement;this.templateElement=kwargs.templateElement;this.addButtonElement=kwargs.addButtonElement;this.removeButtonClass=kwargs.removeButtonClass;this.containerItemClass=kwargs.containerItemClass;$(this.addButtonElement).click($.proxy(this.add,this));var container=this;$("."+this.removeButtonClass,this.containerElement).click(function(eventData){var item=new container.containerItem(eventData.target);container.remove(item)});$("."+this.containerItemClass,this.containerElement).each(function(index,element){new container.containerItem(element)})};OpenAssessment.Container.prototype={add:function(){$(this.templateElement).children().first().clone().removeAttr("id").toggleClass("is--hidden",false).toggleClass(this.containerItemClass,true).appendTo($(this.containerElement));var container=this;var containerItem=$("."+this.containerItemClass,this.containerElement).last();containerItem.find("."+this.removeButtonClass).click(function(eventData){var containerItem=new container.containerItem(eventData.target);container.remove(containerItem)});var handlerItem=new this.containerItem(containerItem);handlerItem.addHandler()},remove:function(item){var itemElement=$(item.element).closest("."+this.containerItemClass);var containerItem=new this.containerItem(itemElement);containerItem.removeHandler();itemElement.remove()},getItemValues:function(){var values=[];var container=this;$("."+this.containerItemClass,this.containerElement).each(function(index,element){var containerItem=new container.containerItem(element);var fieldValues=containerItem.getFieldValues();values.push(fieldValues)});return values},getItem:function(index){var element=$("."+this.containerItemClass,this.containerElement).get(index);return element!==undefined?new this.containerItem(element):null},getAllItems:function(){var container=this;return $("."+this.containerItemClass,this.containerElement).map(function(){return new container.containerItem(this)})}};OpenAssessment.ItemUtilities={createUniqueName:function(selector,nameAttribute){var index=0;while(index<=selector.length){if(selector.parent().find("*["+nameAttribute+"='"+index+"']").length==0){return index.toString()}index++}return null}};OpenAssessment.RubricOption=function(element){this.element=element;this.modificationHandler=new OpenAssessment.RubricEventHandler;$(this.element).focusout($.proxy(this.updateHandler,this))};OpenAssessment.RubricOption.prototype={getFieldValues:function(){var fields={label:OpenAssessment.Fields.stringField($(".openassessment_criterion_option_label",this.element)),points:OpenAssessment.Fields.intField($(".openassessment_criterion_option_points",this.element)),explanation:OpenAssessment.Fields.stringField($(".openassessment_criterion_option_explanation",this.element))};var nameString=OpenAssessment.Fields.stringField($(".openassessment_criterion_option_name",this.element));if(nameString!==""){fields.name=nameString}return fields},addHandler:function(){var criterionElement=$(this.element).closest(".openassessment_criterion");var criterionName=$(criterionElement).data("criterion");var criterionLabel=$(".openassessment_criterion_label",criterionElement).val();var options=$(".openassessment_criterion_option",this.element.parent());var name=OpenAssessment.ItemUtilities.createUniqueName(options,"data-option");$(this.element).attr("data-criterion",criterionName).attr("data-option",name);$(".openassessment_criterion_option_name",this.element).attr("value",name);var fields=this.getFieldValues();this.modificationHandler.notificationFired("optionAdd",{criterionName:criterionName,criterionLabel:criterionLabel,name:name,label:fields.label,points:fields.points})},removeHandler:function(){var criterionName=$(this.element).data("criterion");var optionName=$(this.element).data("option");this.modificationHandler.notificationFired("optionRemove",{criterionName:criterionName,name:optionName})},updateHandler:function(){var fields=this.getFieldValues();var criterionName=$(this.element).data("criterion");var optionName=$(this.element).data("option");var optionLabel=fields.label;var optionPoints=fields.points;this.modificationHandler.notificationFired("optionUpdated",{criterionName:criterionName,name:optionName,label:optionLabel,points:optionPoints})}};OpenAssessment.RubricCriterion=function(element){this.element=element;this.modificationHandler=new OpenAssessment.RubricEventHandler;this.optionContainer=new OpenAssessment.Container(OpenAssessment.RubricOption,{containerElement:$(".openassessment_criterion_option_list",this.element).get(0),templateElement:$("#openassessment_option_template").get(0),addButtonElement:$(".openassessment_criterion_add_option",this.element).get(0),removeButtonClass:"openassessment_criterion_option_remove_button",containerItemClass:"openassessment_criterion_option"});$(this.element).focusout($.proxy(this.updateHandler,this))};OpenAssessment.RubricCriterion.prototype={getFieldValues:function(){var fields={label:OpenAssessment.Fields.stringField($(".openassessment_criterion_label",this.element)),prompt:OpenAssessment.Fields.stringField($(".openassessment_criterion_prompt",this.element)),feedback:OpenAssessment.Fields.stringField($(".openassessment_criterion_feedback",this.element)),options:this.optionContainer.getItemValues()};var nameString=OpenAssessment.Fields.stringField($(".openassessment_criterion_name",this.element));if(nameString!==""){fields.name=nameString}return fields},addOption:function(){this.optionContainer.add()},addHandler:function(){var criteria=$(".openassessment_criterion",this.element.parent());var name=OpenAssessment.ItemUtilities.createUniqueName(criteria,"data-criterion");$(this.element).attr("data-criterion",name);$(".openassessment_criterion_name",this.element).attr("value",name)},removeHandler:function(){var criterionName=$(this.element).data("criterion");this.modificationHandler.notificationFired("criterionRemove",{criterionName:criterionName})},updateHandler:function(){var fields=this.getFieldValues();var criterionName=fields.name;var criterionLabel=fields.label;this.modificationHandler.notificationFired("criterionUpdated",{criterionName:criterionName,criterionLabel:criterionLabel})}};OpenAssessment.TrainingExample=function(element){this.element=element};OpenAssessment.TrainingExample.prototype={getFieldValues:function(){var optionsSelected=[];$(".openassessment_training_example_criterion_option",this.element).each(function(){optionsSelected.push({criterion:$(this).data("criterion"),option:$(this).prop("value")})});return{answer:$(".openassessment_training_example_essay",this.element).first().prop("value"),options_selected:optionsSelected}},addHandler:function(){},removeHandler:function(){},updateHandler:function(){}};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;view.continueAssessmentEnabled(false);this.server.renderContinuedPeer().done(function(html){$("#openassessment__peer-assessment",view.element).replaceWith(html);view.installHandlers(true)}).fail(function(errMsg){view.baseView.showLoadError("peer-assessment");view.continueAssessmentEnabled(true)})},continueAssessmentEnabled:function(enabled){var button=$("#peer-assessment__continue__grading",this.element);if(typeof enabled==="undefined"){return!button.hasClass("is--disabled")}else{button.toggleClass("is--disabled",!enabled)}},installHandlers:function(isContinuedAssessment){var sel=$("#openassessment__peer-assessment",this.element);var view=this;this.baseView.setUpCollapseExpand(sel);var rubricSelector=$("#peer-assessment--001__assessment",this.element);if(rubricSelector.size()>0){var rubricElement=rubricSelector.get(0);this.rubric=new OpenAssessment.Rubric(rubricElement)}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()}});sel.find("#peer-assessment__continue__grading").click(function(eventObject){eventObject.preventDefault();view.loadContinuedAssessment()})},peerSubmitEnabled:function(enabled){var button=$("#peer-assessment--001__assessment__submit",this.element);if(typeof enabled==="undefined"){return!button.hasClass("is--disabled")}else{button.toggleClass("is--disabled",!enabled)}},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,fileUploader,baseView){this.element=element;this.server=server;this.fileUploader=fileUploader;this.baseView=baseView;this.savedResponse="";this.files=null;this.imageType=null;this.lastChangeTime=Date.now();this.errorOnLastSave=false;this.autoSaveTimerId=null};OpenAssessment.ResponseView.prototype={AUTO_SAVE_POLL_INTERVAL:2e3,AUTO_SAVE_WAIT:3e4,MAX_FILE_SIZE:5242880,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);var handlePrepareUpload=function(eventData){view.prepareUpload(eventData.target.files)};sel.find("input[type=file]").on("change",handlePrepareUpload);sel.find("#step--response__submit").click(function(eventObject){eventObject.preventDefault();view.submit()});sel.find("#submission__save").click(function(eventObject){eventObject.preventDefault();view.save()});sel.find("#file__upload").click(function(eventObject){eventObject.preventDefault();view.fileUpload()})},setAutoSaveEnabled:function(enabled){if(enabled){if(this.autoSaveTimerId===null){this.autoSaveTimerId=setInterval($.proxy(this.autoSave,this),this.AUTO_SAVE_POLL_INTERVAL)}}else{if(this.autoSaveTimerId!==null){clearInterval(this.autoSaveTimerId)}}},submitEnabled:function(enabled){var sel=$("#step--response__submit",this.element);if(typeof enabled==="undefined"){return!sel.hasClass("is--disabled")}else{sel.toggleClass("is--disabled",!enabled)}},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()}})},prepareUpload:function(files){this.files=null;this.imageType=files[0].type;if(files[0].size>this.MAX_FILE_SIZE){this.baseView.toggleActionError("upload",gettext("File size must be 5MB or less."))}else if(this.imageType.substring(0,6)!="image/"){this.baseView.toggleActionError("upload",gettext("File must be an image."))}else{this.baseView.toggleActionError("upload",null);this.files=files}$("#file__upload").toggleClass("is--disabled",this.files===null)},fileUpload:function(){var view=this;var fileUpload=$("#file__upload");fileUpload.addClass("is--disabled");var handleError=function(errMsg){view.baseView.toggleActionError("upload",errMsg);fileUpload.removeClass("is--disabled")};this.server.getUploadUrl(view.imageType).done(function(url){var image=view.files[0];view.fileUploader.upload(url,image,view.imageType).done(function(){view.imageUrl();view.baseView.toggleActionError("upload",null)}).fail(handleError)}).fail(handleError)},imageUrl:function(){var view=this;var image=$("#submission__answer__image",view.element);view.server.getDownloadUrl().done(function(url){image.attr("src",url);return url})}};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){var rubric=this;callback(rubric.canSubmit());$(this.element).on("change keyup drop paste",function(){callback(rubric.canSubmit())})},canSubmit:function(){var numChecked=$("input[type=radio]:checked",this.element).length;var numAvailable=$(".field--radio.assessment__rubric__question.has--options",this.element).length;var completedRequiredComments=true;$("textarea[required]",this.element).each(function(){var trimmedText=$.trim($(this).val());if(trimmedText===""){completedRequiredComments=false}});return numChecked==numAvailable&&completedRequiredComments},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"); if(typeof OpenAssessment=="undefined"||!OpenAssessment){OpenAssessment={}}if(typeof window.gettext==="undefined"){window.gettext=function(text){return text}}if(typeof OpenAssessment.Server=="undefined"||!OpenAssessment.Server){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.")])})})},scheduleTraining:function(){var url=this.url("schedule_training");return $.Deferred(function(defer){$.ajax({type:"POST",url:url,data:'""'}).done(function(data){if(data.success){defer.resolveWith(this,[data.msg])}else{defer.rejectWith(this,[data.msg])}}).fail(function(data){defer.rejectWith(this,[gettext("This assessment could not be submitted.")])})})},rescheduleUnfinishedTasks:function(){var url=this.url("reschedule_unfinished_tasks");return $.Deferred(function(defer){$.ajax({type:"POST",url:url,data:'""'}).done(function(data){if(data.success){defer.resolveWith(this,[data.msg])}else{defer.rejectWith(this,[data.msg])}}).fail(function(data){defer.rejectWith(this,[gettext("One or more rescheduling tasks failed.")])})})},updateEditorContext:function(kwargs){var url=this.url("update_editor_context");var payload=JSON.stringify({prompt:kwargs.prompt,feedback_prompt:kwargs.feedbackPrompt,title:kwargs.title,submission_start:kwargs.submissionStart,submission_due:kwargs.submissionDue,criteria:kwargs.criteria,assessments:kwargs.assessments,editor_assessments_order:kwargs.editorAssessmentsOrder,allow_file_upload:kwargs.imageSubmissionEnabled});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()},getUploadUrl:function(contentType){var url=this.url("upload_url");return $.Deferred(function(defer){$.ajax({type:"POST",url:url,data:JSON.stringify({contentType:contentType})}).done(function(data){if(data.success){defer.resolve(data.url)}else{defer.rejectWith(this,[data.msg])}}).fail(function(data){defer.rejectWith(this,[gettext("Could not retrieve upload url.")])})}).promise()},getDownloadUrl:function(){var url=this.url("download_url");return $.Deferred(function(defer){$.ajax({type:"POST",url:url,data:JSON.stringify({})}).done(function(data){if(data.success){defer.resolve(data.url)}else{defer.rejectWith(this,[data.msg])}}).fail(function(data){defer.rejectWith(this,[gettext("Could not retrieve download url.")])})}).promise()}}}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.fileUploader=new OpenAssessment.FileUploader;this.responseView=new OpenAssessment.ResponseView(this.element,this.server,this.fileUploader,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){parentSel.find(".ui-toggle-visibility__control").click(function(eventData){var sel=$(eventData.target).closest(".ui-toggle-visibility");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"}else if(type=="upload"){container="#upload__error"}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.FileUploader=function(){this.upload=function(url,data,contentType){return $.Deferred(function(defer){$.ajax({url:url,type:"PUT",data:data,async:false,processData:false,contentType:contentType}).done(function(data,textStatus,jqXHR){defer.resolve()}).fail(function(data,textStatus,jqXHR){defer.rejectWith(this,[textStatus])})}).promise()}};OpenAssessment.GradeView=function(element,server,baseView){this.element=element;this.server=server;this.baseView=baseView};OpenAssessment.GradeView.prototype={load:function(){var view=this;var baseView=this.baseView;this.server.render("grade").done(function(html){$("#openassessment__grade",view.element).replaceWith(html);view.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;view.continueAssessmentEnabled(false);this.server.renderContinuedPeer().done(function(html){$("#openassessment__peer-assessment",view.element).replaceWith(html);view.installHandlers(true)}).fail(function(errMsg){view.baseView.showLoadError("peer-assessment");view.continueAssessmentEnabled(true)})},continueAssessmentEnabled:function(enabled){var button=$("#peer-assessment__continue__grading",this.element);if(typeof enabled==="undefined"){return!button.hasClass("is--disabled")}else{button.toggleClass("is--disabled",!enabled)}},installHandlers:function(isContinuedAssessment){var sel=$("#openassessment__peer-assessment",this.element);var view=this;this.baseView.setUpCollapseExpand(sel);var rubricSelector=$("#peer-assessment--001__assessment",this.element);if(rubricSelector.size()>0){var rubricElement=rubricSelector.get(0);this.rubric=new OpenAssessment.Rubric(rubricElement)}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()}});sel.find("#peer-assessment__continue__grading").click(function(eventObject){eventObject.preventDefault();view.loadContinuedAssessment()})},peerSubmitEnabled:function(enabled){var button=$("#peer-assessment--001__assessment__submit",this.element);if(typeof enabled==="undefined"){return!button.hasClass("is--disabled")}else{button.toggleClass("is--disabled",!enabled)}},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,fileUploader,baseView){this.element=element;this.server=server;this.fileUploader=fileUploader;this.baseView=baseView;this.savedResponse="";this.files=null;this.imageType=null;this.lastChangeTime=Date.now();this.errorOnLastSave=false;this.autoSaveTimerId=null};OpenAssessment.ResponseView.prototype={AUTO_SAVE_POLL_INTERVAL:2e3,AUTO_SAVE_WAIT:3e4,MAX_FILE_SIZE:5242880,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);var handlePrepareUpload=function(eventData){view.prepareUpload(eventData.target.files)};sel.find("input[type=file]").on("change",handlePrepareUpload);sel.find("#step--response__submit").click(function(eventObject){eventObject.preventDefault();view.submit()});sel.find("#submission__save").click(function(eventObject){eventObject.preventDefault();view.save()});sel.find("#file__upload").click(function(eventObject){eventObject.preventDefault();view.fileUpload()})},setAutoSaveEnabled:function(enabled){if(enabled){if(this.autoSaveTimerId===null){this.autoSaveTimerId=setInterval($.proxy(this.autoSave,this),this.AUTO_SAVE_POLL_INTERVAL)}}else{if(this.autoSaveTimerId!==null){clearInterval(this.autoSaveTimerId)}}},submitEnabled:function(enabled){var sel=$("#step--response__submit",this.element);if(typeof enabled==="undefined"){return!sel.hasClass("is--disabled")}else{sel.toggleClass("is--disabled",!enabled)}},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()}})},prepareUpload:function(files){this.files=null;this.imageType=files[0].type;if(files[0].size>this.MAX_FILE_SIZE){this.baseView.toggleActionError("upload",gettext("File size must be 5MB or less."))}else if(this.imageType.substring(0,6)!="image/"){this.baseView.toggleActionError("upload",gettext("File must be an image."))}else{this.baseView.toggleActionError("upload",null);this.files=files}$("#file__upload").toggleClass("is--disabled",this.files===null)},fileUpload:function(){var view=this;var fileUpload=$("#file__upload");fileUpload.addClass("is--disabled");var handleError=function(errMsg){view.baseView.toggleActionError("upload",errMsg);fileUpload.removeClass("is--disabled")};this.server.getUploadUrl(view.imageType).done(function(url){var image=view.files[0];view.fileUploader.upload(url,image,view.imageType).done(function(){view.imageUrl();view.baseView.toggleActionError("upload",null)}).fail(handleError)}).fail(handleError)},imageUrl:function(){var view=this;var image=$("#submission__answer__image",view.element);view.server.getDownloadUrl().done(function(url){image.attr("src",url);return url})}};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){var rubric=this;callback(rubric.canSubmit());$(this.element).on("change keyup drop paste",function(){callback(rubric.canSubmit())})},canSubmit:function(){var numChecked=$("input[type=radio]:checked",this.element).length;var numAvailable=$(".field--radio.assessment__rubric__question.has--options",this.element).length;var completedRequiredComments=true;$("textarea[required]",this.element).each(function(){var trimmedText=$.trim($(this).val());if(trimmedText===""){completedRequiredComments=false}});return numChecked==numAvailable&&completedRequiredComments},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.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()});sel.find("#schedule_training").click(function(eventObject){eventObject.preventDefault();view.scheduleTraining()});sel.find("#reschedule_unfinished_tasks").click(function(eventObject){eventObject.preventDefault();view.rescheduleUnfinishedTasks()})},scheduleTraining:function(){var view=this;this.server.scheduleTraining().done(function(msg){$("#schedule_training_message",this.element).text(msg)}).fail(function(errMsg){$("#schedule_training_message",this.element).text(errMsg)})},rescheduleUnfinishedTasks:function(){var view=this;this.server.rescheduleUnfinishedTasks().done(function(msg){$("#reschedule_unfinished_tasks_message",this.element).text(msg)}).fail(function(errMsg){$("#reschedule_unfinished_tasks_message",this.element).text(errMsg)})}};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)}}};
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.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()});sel.find("#schedule_training").click(function(eventObject){eventObject.preventDefault();view.scheduleTraining()});sel.find("#reschedule_unfinished_tasks").click(function(eventObject){eventObject.preventDefault();view.rescheduleUnfinishedTasks()})},scheduleTraining:function(){var view=this;this.server.scheduleTraining().done(function(msg){$("#schedule_training_message",this.element).text(msg)}).fail(function(errMsg){$("#schedule_training_message",this.element).text(errMsg)})},rescheduleUnfinishedTasks:function(){var view=this;this.server.rescheduleUnfinishedTasks().done(function(msg){$("#reschedule_unfinished_tasks_message",this.element).text(msg)}).fail(function(errMsg){$("#reschedule_unfinished_tasks_message",this.element).text(errMsg)})}};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
\ No newline at end of file
if(typeof OpenAssessment=="undefined"||!OpenAssessment){OpenAssessment={}}if(typeof window.gettext==="undefined"){window.gettext=function(text){return text}}OpenAssessment.FileUploader=function(){this.upload=function(url,data,contentType){return $.Deferred(function(defer){$.ajax({url:url,type:"PUT",data:data,async:false,processData:false,contentType:contentType}).done(function(data,textStatus,jqXHR){defer.resolve()}).fail(function(data,textStatus,jqXHR){defer.rejectWith(this,[textStatus])})}).promise()}};if(typeof OpenAssessment.Server=="undefined"||!OpenAssessment.Server){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.")])})})},scheduleTraining:function(){var url=this.url("schedule_training");return $.Deferred(function(defer){$.ajax({type:"POST",url:url,data:'""'}).done(function(data){if(data.success){defer.resolveWith(this,[data.msg])}else{defer.rejectWith(this,[data.msg])}}).fail(function(data){defer.rejectWith(this,[gettext("This assessment could not be submitted.")])})})},rescheduleUnfinishedTasks:function(){var url=this.url("reschedule_unfinished_tasks");return $.Deferred(function(defer){$.ajax({type:"POST",url:url,data:'""'}).done(function(data){if(data.success){defer.resolveWith(this,[data.msg])}else{defer.rejectWith(this,[data.msg])}}).fail(function(data){defer.rejectWith(this,[gettext("One or more rescheduling tasks failed.")])})})},updateEditorContext:function(kwargs){var url=this.url("update_editor_context");var payload=JSON.stringify({prompt:kwargs.prompt,feedback_prompt:kwargs.feedbackPrompt,title:kwargs.title,submission_start:kwargs.submissionStart,submission_due:kwargs.submissionDue,criteria:kwargs.criteria,assessments:kwargs.assessments,editor_assessments_order:kwargs.editorAssessmentsOrder,allow_file_upload:kwargs.imageSubmissionEnabled});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()},getUploadUrl:function(contentType){var url=this.url("upload_url");return $.Deferred(function(defer){$.ajax({type:"POST",url:url,data:JSON.stringify({contentType:contentType})}).done(function(data){if(data.success){defer.resolve(data.url)}else{defer.rejectWith(this,[data.msg])}}).fail(function(data){defer.rejectWith(this,[gettext("Could not retrieve upload url.")])})}).promise()},getDownloadUrl:function(){var url=this.url("download_url");return $.Deferred(function(defer){$.ajax({type:"POST",url:url,data:JSON.stringify({})}).done(function(data){if(data.success){defer.resolve(data.url)}else{defer.rejectWith(this,[data.msg])}}).fail(function(data){defer.rejectWith(this,[gettext("Could not retrieve download url.")])})}).promise()}}}if(typeof OpenAssessment=="undefined"||!OpenAssessment){OpenAssessment={}}if(typeof window.gettext==="undefined"){window.gettext=function(text){return text}}OpenAssessment.StudioView=function(runtime,element,server){this.element=element;this.runtime=runtime;this.server=server;this.fixModalHeight();this.initializeTabs();this.promptView=new OpenAssessment.EditPromptView($("#oa_prompt_editor_wrapper",this.element).get(0));var studentTrainingView=new OpenAssessment.EditStudentTrainingView($("#oa_student_training_editor",this.element).get(0));var peerAssessmentView=new OpenAssessment.EditPeerAssessmentView($("#oa_peer_assessment_editor",this.element).get(0));var selfAssessmentView=new OpenAssessment.EditSelfAssessmentView($("#oa_self_assessment_editor",this.element).get(0));var exampleBasedAssessmentView=new OpenAssessment.EditExampleBasedAssessmentView($("#oa_ai_assessment_editor",this.element).get(0));var assessmentLookupDictionary={};assessmentLookupDictionary[studentTrainingView.getID()]=studentTrainingView;assessmentLookupDictionary[peerAssessmentView.getID()]=peerAssessmentView;assessmentLookupDictionary[selfAssessmentView.getID()]=selfAssessmentView;assessmentLookupDictionary[exampleBasedAssessmentView.getID()]=exampleBasedAssessmentView;this.settingsView=new OpenAssessment.EditSettingsView($("#oa_basic_settings_editor",this.element).get(0),assessmentLookupDictionary);this.rubricView=new OpenAssessment.EditRubricView($("#oa_rubric_editor_wrapper",this.element).get(0));$(".openassessment_save_button",this.element).click($.proxy(this.save,this));$(".openassessment_cancel_button",this.element).click($.proxy(this.cancel,this))};OpenAssessment.StudioView.prototype={fixModalHeight:function(){$(this.element).addClass("openassessment_full_height").parentsUntil(".modal-window").addClass("openassessment_full_height");$(this.element).closest(".modal-window").addClass("openassessment_modal_window")},initializeTabs:function(){if(typeof OpenAssessment.lastOpenEditingTab==="undefined"){OpenAssessment.lastOpenEditingTab=2}$(".openassessment_editor_content_and_tabs",this.element).tabs({active:OpenAssessment.lastOpenEditingTab})},saveTabState:function(){var tabElement=$(".openassessment_editor_content_and_tabs",this.element);OpenAssessment.lastOpenEditingTab=tabElement.tabs("option","active")},save:function(){var view=this;this.saveTabState();this.server.checkReleased().done(function(isReleased){if(isReleased){view.confirmPostReleaseUpdate($.proxy(view.updateEditorContext,view))}else{view.updateEditorContext()}}).fail(function(errMsg){view.showError(errMsg)})},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 view=this;this.server.updateEditorContext({prompt:view.promptView.promptText(),feedbackPrompt:view.rubricView.feedbackPrompt(),criteria:view.rubricView.criteriaDefinition(),title:view.settingsView.displayName(),submissionStart:view.settingsView.submissionStart(),submissionDue:view.settingsView.submissionDue(),assessments:view.settingsView.assessmentsDescription(),imageSubmissionEnabled:view.settingsView.imageSubmissionEnabled(),editorAssessmentsOrder:view.settingsView.editorAssessmentsOrder()}).done(function(){view.runtime.notify("save",{state:"end"})}).fail(function(msg){view.showError(msg)})},cancel:function(){this.saveTabState();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)}OpenAssessment.EditPeerAssessmentView=function(element){this.element=element;this.name="peer-assessment";new OpenAssessment.ToggleControl(this.element,"#peer_assessment_description_closed","#peer_assessment_settings_editor").install("#include_peer_assessment");this.startDatetimeControl=new OpenAssessment.DatetimeControl(this.element,"#peer_assessment_start_date","#peer_assessment_start_time").install();this.dueDatetimeControl=new OpenAssessment.DatetimeControl(this.element,"#peer_assessment_due_date","#peer_assessment_due_time").install()};OpenAssessment.EditPeerAssessmentView.prototype={description:function(){return{must_grade:this.mustGradeNum(),must_be_graded_by:this.mustBeGradedByNum(),start:this.startDatetime(),due:this.dueDatetime()}},isEnabled:function(isEnabled){var sel=$("#include_peer_assessment",this.element);return OpenAssessment.Fields.booleanField(sel,isEnabled)},mustGradeNum:function(num){var sel=$("#peer_assessment_must_grade",this.element);return OpenAssessment.Fields.intField(sel,num)},mustBeGradedByNum:function(num){var sel=$("#peer_assessment_graded_by",this.element);return OpenAssessment.Fields.intField(sel,num)},startDatetime:function(dateString,timeString){return this.startDatetimeControl.datetime(dateString,timeString)},dueDatetime:function(dateString,timeString){return this.dueDatetimeControl.datetime(dateString,timeString)},getID:function(){return $(this.element).attr("id")}};OpenAssessment.EditSelfAssessmentView=function(element){this.element=element;this.name="self-assessment";new OpenAssessment.ToggleControl(this.element,"#self_assessment_description_closed","#self_assessment_settings_editor").install("#include_self_assessment");this.startDatetimeControl=new OpenAssessment.DatetimeControl(this.element,"#self_assessment_start_date","#self_assessment_start_time").install();this.dueDatetimeControl=new OpenAssessment.DatetimeControl(this.element,"#self_assessment_due_date","#self_assessment_due_time").install()};OpenAssessment.EditSelfAssessmentView.prototype={description:function(){return{start:this.startDatetime(),due:this.dueDatetime()}},isEnabled:function(isEnabled){var sel=$("#include_self_assessment",this.element);return OpenAssessment.Fields.booleanField(sel,isEnabled)},startDatetime:function(dateString,timeString){return this.startDatetimeControl.datetime(dateString,timeString)},dueDatetime:function(dateString,timeString){return this.dueDatetimeControl.datetime(dateString,timeString)},getID:function(){return $(this.element).attr("id")}};OpenAssessment.EditStudentTrainingView=function(element){this.element=element;this.name="student-training";new OpenAssessment.ToggleControl(this.element,"#student_training_description_closed","#student_training_settings_editor").install("#include_student_training");this.exampleContainer=new OpenAssessment.Container(OpenAssessment.TrainingExample,{containerElement:$("#openassessment_training_example_list",this.element).get(0),templateElement:$("#openassessment_training_example_template",this.element).get(0),addButtonElement:$(".openassessment_add_training_example",this.element).get(0),removeButtonClass:"openassessment_training_example_remove",containerItemClass:"openassessment_training_example"})};OpenAssessment.EditStudentTrainingView.prototype={description:function(){return{examples:this.exampleContainer.getItemValues()}},isEnabled:function(isEnabled){var sel=$("#include_student_training",this.element);return OpenAssessment.Fields.booleanField(sel,isEnabled)},exampleDefinitions:function(xml){var sel=$("#student_training_examples",this.element);return OpenAssessment.Fields.stringField(sel,xml)},getID:function(){return $(this.element).attr("id")}};OpenAssessment.EditExampleBasedAssessmentView=function(element){this.element=element;this.name="example-based-assessment";new OpenAssessment.ToggleControl(this.element,"#ai_assessment_description_closed","#ai_assessment_settings_editor").install("#include_ai_assessment")};OpenAssessment.EditExampleBasedAssessmentView.prototype={description:function(){return{examples_xml:this.exampleDefinitions()}},isEnabled:function(isEnabled){var sel=$("#include_ai_assessment",this.element);return OpenAssessment.Fields.booleanField(sel,isEnabled)},exampleDefinitions:function(xml){var sel=$("#ai_training_examples",this.element);return OpenAssessment.Fields.stringField(sel,xml)},getID:function(){return $(this.element).attr("id")}};OpenAssessment.Fields={stringField:function(sel,value){if(typeof value!=="undefined"){sel.val(value)}return sel.val()},intField:function(sel,value){if(typeof value!=="undefined"){sel.val(value)}return parseInt(sel.val(),10)},booleanField:function(sel,value){if(typeof value!=="undefined"){sel.prop("checked",value)}return sel.prop("checked")}};OpenAssessment.ToggleControl=function(element,hiddenSelector,shownSelector){this.element=element;this.hiddenSelector=hiddenSelector;this.shownSelector=shownSelector};OpenAssessment.ToggleControl.prototype={install:function(checkboxSelector){$(checkboxSelector,this.element).change(this,function(event){var control=event.data;if(this.checked){control.show()}else{control.hide()}});return this},show:function(){$(this.hiddenSelector,this.element).addClass("is--hidden");$(this.shownSelector,this.element).removeClass("is--hidden")},hide:function(){$(this.hiddenSelector,this.element).removeClass("is--hidden");$(this.shownSelector,this.element).addClass("is--hidden")}};OpenAssessment.DatetimeControl=function(element,datePicker,timePicker){this.element=element;this.datePicker=datePicker;this.timePicker=timePicker};OpenAssessment.DatetimeControl.prototype={install:function(){var dateString=$(this.datePicker,this.element).val();$(this.datePicker,this.element).datepicker({showButtonPanel:true}).datepicker("option","dateFormat","yy-mm-dd").datepicker("setDate",dateString);$(this.timePicker,this.element).timepicker({timeFormat:"H:i",step:60});return this},datetime:function(dateString,timeString){var datePickerSel=$(this.datePicker,this.element);var timePickerSel=$(this.timePicker,this.element);if(typeof dateString!=="undefined"){datePickerSel.datepicker("setDate",dateString)}if(typeof timeString!=="undefined"){timePickerSel.val(timeString)}if(datePickerSel.val()===""&&timePickerSel.val()===""){return null}return datePickerSel.val()+"T"+timePickerSel.val()}};OpenAssessment.EditPromptView=function(element){this.element=element};OpenAssessment.EditPromptView.prototype={promptText:function(text){var sel=$("#openassessment_prompt_editor",this.element);return OpenAssessment.Fields.stringField(sel,text)}};OpenAssessment.EditRubricView=function(element){this.element=element;this.criteriaContainer=new OpenAssessment.Container(OpenAssessment.RubricCriterion,{containerElement:$("#openassessment_criterion_list",this.element).get(0),templateElement:$("#openassessment_criterion_template",this.element).get(0),addButtonElement:$("#openassessment_rubric_add_criterion",this.element).get(0),removeButtonClass:"openassessment_criterion_remove_button",containerItemClass:"openassessment_criterion"});this.alert=new OpenAssessment.ValidationAlert($("#openassessment_rubric_validation_alert",this.element))};OpenAssessment.EditRubricView.prototype={criteriaDefinition:function(){var criteria=this.criteriaContainer.getItemValues();for(var criterion_idx=0;criterion_idx<criteria.length;criterion_idx++){var criterion=criteria[criterion_idx];criterion.order_num=criterion_idx;for(var option_idx=0;option_idx<criterion.options.length;option_idx++){var option=criterion.options[option_idx];option.order_num=option_idx}}return criteria},feedbackPrompt:function(text){var sel=$("#openassessment_rubric_feedback",this.element);return OpenAssessment.Fields.stringField(sel,text)},removeAllCriteria:function(){var items=this.criteriaContainer.getAllItems();var view=this;$.each(items,function(){view.criteriaContainer.remove(this)})},addCriterion:function(){this.criteriaContainer.add()},getCriterionItem:function(index){return this.criteriaContainer.getItem(index)}};OpenAssessment.ValidationAlert=function(element){this.element=element;this.title=$(".openassessment_alert_title",this.element);this.message=$(".openassessment_alert_message",this.element)};OpenAssessment.ValidationAlert.prototype={hide:function(){this.element.addClass("is--hidden")},show:function(){this.element.removeClass("is--hidden")},setMessage:function(newTitle,newMessage){this.title.text(newTitle);this.message.text(newMessage)}};OpenAssessment.EditSettingsView=function(element,assessmentViews){this.settingsElement=element;this.assessmentsElement=$(element).siblings("#openassessment_assessment_module_settings_editors").get(0);this.assessmentViews=assessmentViews;this.startDatetimeControl=new OpenAssessment.DatetimeControl(this.element,"#openassessment_submission_start_date","#openassessment_submission_start_time").install();this.dueDatetimeControl=new OpenAssessment.DatetimeControl(this.element,"#openassessment_submission_due_date","#openassessment_submission_due_time").install();this.initializeSortableAssessments()};OpenAssessment.EditSettingsView.prototype={initializeSortableAssessments:function(){var view=this;$("#openassessment_assessment_module_settings_editors",view.element).sortable({start:function(event,ui){$(".openassessment_assessment_module_editor",view.element).hide();var targetHeight="auto";ui.placeholder.height(targetHeight);ui.helper.height(targetHeight);$("#openassessment_assessment_module_settings_editors",view.element).sortable("refresh").sortable("refreshPositions")},stop:function(event,ui){$(".openassessment_assessment_module_editor",view.element).show()},snap:true,axis:"y",handle:".drag-handle",cursorAt:{top:20}});$("#openassessment_assessment_module_settings_editors .drag-handle",view.element).disableSelection()},displayName:function(name){var sel=$("#openassessment_title_editor",this.settingsElement);return OpenAssessment.Fields.stringField(sel,name)},submissionStart:function(dateString,timeString){return this.startDatetimeControl.datetime(dateString,timeString)},submissionDue:function(dateString,timeString){return this.dueDatetimeControl.datetime(dateString,timeString)},imageSubmissionEnabled:function(isEnabled){var sel=$("#openassessment_submission_image_editor",this.settingsElement);if(typeof isEnabled!=="undefined"){if(isEnabled){sel.val(1)}else{sel.val(0)}}return sel.val()==1},assessmentsDescription:function(){var assessmentDescList=[];var view=this;$(".openassessment_assessment_module_settings_editor",this.assessmentsElement).each(function(){var asmntView=view.assessmentViews[$(this).attr("id")];if(asmntView.isEnabled()){var description=asmntView.description();description["name"]=asmntView.name;assessmentDescList.push(description)}});return assessmentDescList},editorAssessmentsOrder:function(){var editorAssessments=[];var view=this;$(".openassessment_assessment_module_settings_editor",this.assessmentsElement).each(function(){var asmntView=view.assessmentViews[$(this).attr("id")];editorAssessments.push(asmntView.name)});return editorAssessments}};OpenAssessment.RubricEventHandler=function(){this.listeners=[new OpenAssessment.StudentTrainingListener]};OpenAssessment.RubricEventHandler.prototype={notificationFired:function(name,data){for(var i=0;i<this.listeners.length;i++){if(typeof this.listeners[i][name]==="function"){this.listeners[i][name](data)}}}};OpenAssessment.StudentTrainingListener=function(){this.element=$("#oa_student_training_editor");this.alert=new OpenAssessment.ValidationAlert($("#openassessment_rubric_validation_alert"))};OpenAssessment.StudentTrainingListener.prototype={generateOptionString:function(name,points){return name+" - "+points+gettext(" points")},optionUpdated:function(data){var view=this;$('.openassessment_training_example_criterion[data-criterion="'+data.criterionName+'"',this.element).each(function(){var criterion=this;var option=$("option[value='"+data.name+"'",criterion);$(option).text(view.generateOptionString(data.label,data.points))})},optionAdd:function(data){var options=$('.openassessment_training_example_criterion_option[data-criterion="'+data.criterionName+'"]');var view=this;var criterionAdded=false;var examplesUpdated=false;if(options.length==0){this.criterionAdd(data);criterionAdded=true}$(".openassessment_training_example_criterion_option",this.element).each(function(){if($(this).data("criterion")===data.criterionName){var criterion=this;$(criterion).append($("<option></option>").attr("value",data.name).text(view.generateOptionString(data.label,data.points)));examplesUpdated=true}});if(criterionAdded&&examplesUpdated){this.displayAlertMsg(gettext("Criterion Addition requires Training Example Updates"),gettext("Because you added a criterion, student training examples "+"will have to be updated."))}},optionRemove:function(data){var validator=this;var changed=false;$(".openassessment_training_example_criterion_option",this.element).each(function(){var criterionOption=this;if($(criterionOption).data("criterion")===data.criterionName){if($(criterionOption).val()==data.name){$(criterionOption).val("");$(criterionOption).addClass("openassessment_highlighted_field");$(criterionOption).click(function(){$(criterionOption).removeClass("openassessment_highlighted_field")});changed=true}$("option[value='"+data.name+"'",criterionOption).remove();if($("option",criterionOption).length==1){validator.removeAllOptions(data);return}}});if(changed){this.displayAlertMsg(gettext("Option Deletion Led to Invalidation"),gettext("Because you deleted an option, some student training "+"examples had to be reset."))}},removeAllOptions:function(data){var changed=false;$(".openassessment_training_example_criterion",this.element).each(function(){var criterion=this;if($(criterion).data("criterion")==data.criterionName){$(criterion).remove();changed=true}});if(changed){this.displayAlertMsg(gettext("Option Deletion Led to Invalidation"),gettext("The deletion of the last criterion option caused the "+"criterion to be removed in the student training examples."))}},criterionRemove:function(data){var changed=false;$('.openassessment_training_example_criterion[data-criterion="'+data.criterionName+'"',this.element).each(function(){$(this).remove();changed=true});if(changed){this.displayAlertMsg(gettext("Criterion Deletion Led to Invalidation"),gettext("Because you deleted a criterion, there were student "+"training examples where the criterion had to be removed."))}},displayAlertMsg:function(title,msg){this.alert.setMessage(title,msg);this.alert.show()},criterionUpdated:function(data){$('.openassessment_training_example_criterion[data-criterion="'+data.criterionName+'"',this.element).each(function(){$(".openassessment_training_example_criterion_name_wrapper",this).text(data.criterionLabel)})},criterionAdd:function(data){var view=this.element;var criterion=$("#openassessment_training_example_criterion_template").children().first().clone().removeAttr("id").attr("data-criterion",data.criterionName).toggleClass("is--hidden",false).appendTo(".openassessment_training_example_criteria_selections",view);criterion.find(".openassessment_training_example_criterion_option").attr("data-criterion",data.criterionName);criterion.find(".openassessment_training_example_criterion_name_wrapper").text(data.label)}}; if(typeof OpenAssessment=="undefined"||!OpenAssessment){OpenAssessment={}}if(typeof window.gettext==="undefined"){window.gettext=function(text){return text}}if(typeof OpenAssessment.Server=="undefined"||!OpenAssessment.Server){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.")])})})},scheduleTraining:function(){var url=this.url("schedule_training");return $.Deferred(function(defer){$.ajax({type:"POST",url:url,data:'""'}).done(function(data){if(data.success){defer.resolveWith(this,[data.msg])}else{defer.rejectWith(this,[data.msg])}}).fail(function(data){defer.rejectWith(this,[gettext("This assessment could not be submitted.")])})})},rescheduleUnfinishedTasks:function(){var url=this.url("reschedule_unfinished_tasks");return $.Deferred(function(defer){$.ajax({type:"POST",url:url,data:'""'}).done(function(data){if(data.success){defer.resolveWith(this,[data.msg])}else{defer.rejectWith(this,[data.msg])}}).fail(function(data){defer.rejectWith(this,[gettext("One or more rescheduling tasks failed.")])})})},updateEditorContext:function(kwargs){var url=this.url("update_editor_context");var payload=JSON.stringify({prompt:kwargs.prompt,feedback_prompt:kwargs.feedbackPrompt,title:kwargs.title,submission_start:kwargs.submissionStart,submission_due:kwargs.submissionDue,criteria:kwargs.criteria,assessments:kwargs.assessments,editor_assessments_order:kwargs.editorAssessmentsOrder,allow_file_upload:kwargs.imageSubmissionEnabled});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()},getUploadUrl:function(contentType){var url=this.url("upload_url");return $.Deferred(function(defer){$.ajax({type:"POST",url:url,data:JSON.stringify({contentType:contentType})}).done(function(data){if(data.success){defer.resolve(data.url)}else{defer.rejectWith(this,[data.msg])}}).fail(function(data){defer.rejectWith(this,[gettext("Could not retrieve upload url.")])})}).promise()},getDownloadUrl:function(){var url=this.url("download_url");return $.Deferred(function(defer){$.ajax({type:"POST",url:url,data:JSON.stringify({})}).done(function(data){if(data.success){defer.resolve(data.url)}else{defer.rejectWith(this,[data.msg])}}).fail(function(data){defer.rejectWith(this,[gettext("Could not retrieve download url.")])})}).promise()}}}if(typeof OpenAssessment=="undefined"||!OpenAssessment){OpenAssessment={}}if(typeof window.gettext==="undefined"){window.gettext=function(text){return text}}OpenAssessment.Container=function(containerItem,kwargs){this.containerElement=kwargs.containerElement;this.templateElement=kwargs.templateElement;this.addButtonElement=kwargs.addButtonElement;this.removeButtonClass=kwargs.removeButtonClass;this.containerItemClass=kwargs.containerItemClass;this.notifier=kwargs.notifier;var container=this;this.createContainerItem=function(element){return new containerItem(element,container.notifier)};$(this.addButtonElement).click($.proxy(this.add,this));$("."+this.removeButtonClass,this.containerElement).click(function(eventData){var item=container.createContainerItem(eventData.target);container.remove(item)});$("."+this.containerItemClass,this.containerElement).each(function(index,element){container.createContainerItem(element)})};OpenAssessment.Container.prototype={add:function(){$(this.templateElement).children().first().clone().removeAttr("id").toggleClass("is--hidden",false).toggleClass(this.containerItemClass,true).appendTo($(this.containerElement));var container=this;var containerItem=$("."+this.containerItemClass,this.containerElement).last();containerItem.find("."+this.removeButtonClass).click(function(eventData){var containerItem=container.createContainerItem(eventData.target);container.remove(containerItem)});var handlerItem=container.createContainerItem(containerItem);handlerItem.addHandler()},remove:function(item){var itemElement=$(item.element).closest("."+this.containerItemClass);var containerItem=this.createContainerItem(itemElement);containerItem.removeHandler();itemElement.remove()},getItemValues:function(){var values=[];var container=this;$("."+this.containerItemClass,this.containerElement).each(function(index,element){var containerItem=container.createContainerItem(element);var fieldValues=containerItem.getFieldValues();values.push(fieldValues)});return values},getItem:function(index){var element=$("."+this.containerItemClass,this.containerElement).get(index);return element!==undefined?this.createContainerItem(element):null},getAllItems:function(){var container=this;return $("."+this.containerItemClass,this.containerElement).map(function(){return container.createContainerItem(this)})}};OpenAssessment.ItemUtilities={createUniqueName:function(selector,nameAttribute){var index=0;while(index<=selector.length){if(selector.parent().find("*["+nameAttribute+"='"+index+"']").length===0){return index.toString()}index++}return null}};OpenAssessment.RubricOption=function(element,notifier){this.element=element;this.notifier=notifier;$(this.element).focusout($.proxy(this.updateHandler,this))};OpenAssessment.RubricOption.prototype={getFieldValues:function(){var fields={label:OpenAssessment.Fields.stringField($(".openassessment_criterion_option_label",this.element)),points:OpenAssessment.Fields.intField($(".openassessment_criterion_option_points",this.element)),explanation:OpenAssessment.Fields.stringField($(".openassessment_criterion_option_explanation",this.element))};var nameString=OpenAssessment.Fields.stringField($(".openassessment_criterion_option_name",this.element));if(nameString!==""){fields.name=nameString}return fields},addHandler:function(){var criterionElement=$(this.element).closest(".openassessment_criterion");var criterionName=$(criterionElement).data("criterion");var criterionLabel=$(".openassessment_criterion_label",criterionElement).val();var options=$(".openassessment_criterion_option",this.element.parent());var name=OpenAssessment.ItemUtilities.createUniqueName(options,"data-option");$(this.element).attr("data-criterion",criterionName).attr("data-option",name);$(".openassessment_criterion_option_name",this.element).attr("value",name);var fields=this.getFieldValues();this.notifier.notificationFired("optionAdd",{criterionName:criterionName,criterionLabel:criterionLabel,name:name,label:fields.label,points:fields.points})},removeHandler:function(){var criterionName=$(this.element).data("criterion");var optionName=$(this.element).data("option");this.notifier.notificationFired("optionRemove",{criterionName:criterionName,name:optionName})},updateHandler:function(){var fields=this.getFieldValues();var criterionName=$(this.element).data("criterion");var optionName=$(this.element).data("option");var optionLabel=fields.label;var optionPoints=fields.points;this.notifier.notificationFired("optionUpdated",{criterionName:criterionName,name:optionName,label:optionLabel,points:optionPoints})}};OpenAssessment.RubricCriterion=function(element,notifier){this.element=element;this.notifier=notifier;this.optionContainer=new OpenAssessment.Container(OpenAssessment.RubricOption,{containerElement:$(".openassessment_criterion_option_list",this.element).get(0),templateElement:$("#openassessment_option_template").get(0),addButtonElement:$(".openassessment_criterion_add_option",this.element).get(0),removeButtonClass:"openassessment_criterion_option_remove_button",containerItemClass:"openassessment_criterion_option",notifier:this.notifier});$(this.element).focusout($.proxy(this.updateHandler,this))};OpenAssessment.RubricCriterion.prototype={getFieldValues:function(){var fields={label:OpenAssessment.Fields.stringField($(".openassessment_criterion_label",this.element)),prompt:OpenAssessment.Fields.stringField($(".openassessment_criterion_prompt",this.element)),feedback:OpenAssessment.Fields.stringField($(".openassessment_criterion_feedback",this.element)),options:this.optionContainer.getItemValues()};var nameString=OpenAssessment.Fields.stringField($(".openassessment_criterion_name",this.element));if(nameString!==""){fields.name=nameString}return fields},addOption:function(){this.optionContainer.add()},addHandler:function(){var criteria=$(".openassessment_criterion",this.element.parent());var name=OpenAssessment.ItemUtilities.createUniqueName(criteria,"data-criterion");$(this.element).attr("data-criterion",name);$(".openassessment_criterion_name",this.element).attr("value",name)},removeHandler:function(){var criterionName=$(this.element).data("criterion");this.notifier.notificationFired("criterionRemove",{criterionName:criterionName})},updateHandler:function(){var fields=this.getFieldValues();var criterionName=fields.name;var criterionLabel=fields.label;this.notifier.notificationFired("criterionUpdated",{criterionName:criterionName,criterionLabel:criterionLabel})}};OpenAssessment.TrainingExample=function(element){this.element=element};OpenAssessment.TrainingExample.prototype={getFieldValues:function(){var optionsSelected=[];$(".openassessment_training_example_criterion_option",this.element).each(function(){optionsSelected.push({criterion:$(this).data("criterion"),option:$(this).prop("value")})});return{answer:$(".openassessment_training_example_essay",this.element).first().prop("value"),options_selected:optionsSelected}},addHandler:function(){},removeHandler:function(){},updateHandler:function(){}};OpenAssessment.StudioView=function(runtime,element,server){this.element=element;this.runtime=runtime;this.server=server;this.fixModalHeight();this.initializeTabs();this.promptView=new OpenAssessment.EditPromptView($("#oa_prompt_editor_wrapper",this.element).get(0));var studentTrainingView=new OpenAssessment.EditStudentTrainingView($("#oa_student_training_editor",this.element).get(0));var peerAssessmentView=new OpenAssessment.EditPeerAssessmentView($("#oa_peer_assessment_editor",this.element).get(0));var selfAssessmentView=new OpenAssessment.EditSelfAssessmentView($("#oa_self_assessment_editor",this.element).get(0));var exampleBasedAssessmentView=new OpenAssessment.EditExampleBasedAssessmentView($("#oa_ai_assessment_editor",this.element).get(0));var assessmentLookupDictionary={};assessmentLookupDictionary[studentTrainingView.getID()]=studentTrainingView;assessmentLookupDictionary[peerAssessmentView.getID()]=peerAssessmentView;assessmentLookupDictionary[selfAssessmentView.getID()]=selfAssessmentView;assessmentLookupDictionary[exampleBasedAssessmentView.getID()]=exampleBasedAssessmentView;this.settingsView=new OpenAssessment.EditSettingsView($("#oa_basic_settings_editor",this.element).get(0),assessmentLookupDictionary);this.rubricView=new OpenAssessment.EditRubricView($("#oa_rubric_editor_wrapper",this.element).get(0),new OpenAssessment.Notifier([new OpenAssessment.StudentTrainingListener]));$(".openassessment_save_button",this.element).click($.proxy(this.save,this));$(".openassessment_cancel_button",this.element).click($.proxy(this.cancel,this))};OpenAssessment.StudioView.prototype={fixModalHeight:function(){$(this.element).addClass("openassessment_full_height").parentsUntil(".modal-window").addClass("openassessment_full_height");$(this.element).closest(".modal-window").addClass("openassessment_modal_window")},initializeTabs:function(){if(typeof OpenAssessment.lastOpenEditingTab==="undefined"){OpenAssessment.lastOpenEditingTab=2}$(".openassessment_editor_content_and_tabs",this.element).tabs({active:OpenAssessment.lastOpenEditingTab})},saveTabState:function(){var tabElement=$(".openassessment_editor_content_and_tabs",this.element);OpenAssessment.lastOpenEditingTab=tabElement.tabs("option","active")},save:function(){var view=this;this.saveTabState();this.server.checkReleased().done(function(isReleased){if(isReleased){view.confirmPostReleaseUpdate($.proxy(view.updateEditorContext,view))}else{view.updateEditorContext()}}).fail(function(errMsg){view.showError(errMsg)})},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 view=this;this.server.updateEditorContext({prompt:view.promptView.promptText(),feedbackPrompt:view.rubricView.feedbackPrompt(),criteria:view.rubricView.criteriaDefinition(),title:view.settingsView.displayName(),submissionStart:view.settingsView.submissionStart(),submissionDue:view.settingsView.submissionDue(),assessments:view.settingsView.assessmentsDescription(),imageSubmissionEnabled:view.settingsView.imageSubmissionEnabled(),editorAssessmentsOrder:view.settingsView.editorAssessmentsOrder()}).done(function(){view.runtime.notify("save",{state:"end"})}).fail(function(msg){view.showError(msg)})},cancel:function(){this.saveTabState();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)}OpenAssessment.EditPeerAssessmentView=function(element){this.element=element;this.name="peer-assessment";new OpenAssessment.ToggleControl(this.element,"#peer_assessment_description_closed","#peer_assessment_settings_editor").install("#include_peer_assessment");this.startDatetimeControl=new OpenAssessment.DatetimeControl(this.element,"#peer_assessment_start_date","#peer_assessment_start_time").install();this.dueDatetimeControl=new OpenAssessment.DatetimeControl(this.element,"#peer_assessment_due_date","#peer_assessment_due_time").install()};OpenAssessment.EditPeerAssessmentView.prototype={description:function(){return{must_grade:this.mustGradeNum(),must_be_graded_by:this.mustBeGradedByNum(),start:this.startDatetime(),due:this.dueDatetime()}},isEnabled:function(isEnabled){var sel=$("#include_peer_assessment",this.element);return OpenAssessment.Fields.booleanField(sel,isEnabled)},mustGradeNum:function(num){var sel=$("#peer_assessment_must_grade",this.element);return OpenAssessment.Fields.intField(sel,num)},mustBeGradedByNum:function(num){var sel=$("#peer_assessment_graded_by",this.element);return OpenAssessment.Fields.intField(sel,num)},startDatetime:function(dateString,timeString){return this.startDatetimeControl.datetime(dateString,timeString)},dueDatetime:function(dateString,timeString){return this.dueDatetimeControl.datetime(dateString,timeString)},getID:function(){return $(this.element).attr("id")}};OpenAssessment.EditSelfAssessmentView=function(element){this.element=element;this.name="self-assessment";new OpenAssessment.ToggleControl(this.element,"#self_assessment_description_closed","#self_assessment_settings_editor").install("#include_self_assessment");this.startDatetimeControl=new OpenAssessment.DatetimeControl(this.element,"#self_assessment_start_date","#self_assessment_start_time").install();this.dueDatetimeControl=new OpenAssessment.DatetimeControl(this.element,"#self_assessment_due_date","#self_assessment_due_time").install()};OpenAssessment.EditSelfAssessmentView.prototype={description:function(){return{start:this.startDatetime(),due:this.dueDatetime()}},isEnabled:function(isEnabled){var sel=$("#include_self_assessment",this.element);return OpenAssessment.Fields.booleanField(sel,isEnabled)},startDatetime:function(dateString,timeString){return this.startDatetimeControl.datetime(dateString,timeString)},dueDatetime:function(dateString,timeString){return this.dueDatetimeControl.datetime(dateString,timeString)},getID:function(){return $(this.element).attr("id")}};OpenAssessment.EditStudentTrainingView=function(element){this.element=element;this.name="student-training";new OpenAssessment.ToggleControl(this.element,"#student_training_description_closed","#student_training_settings_editor").install("#include_student_training");this.exampleContainer=new OpenAssessment.Container(OpenAssessment.TrainingExample,{containerElement:$("#openassessment_training_example_list",this.element).get(0),templateElement:$("#openassessment_training_example_template",this.element).get(0),addButtonElement:$(".openassessment_add_training_example",this.element).get(0),removeButtonClass:"openassessment_training_example_remove",containerItemClass:"openassessment_training_example"})};OpenAssessment.EditStudentTrainingView.prototype={description:function(){return{examples:this.exampleContainer.getItemValues()}},isEnabled:function(isEnabled){var sel=$("#include_student_training",this.element);return OpenAssessment.Fields.booleanField(sel,isEnabled)},getID:function(){return $(this.element).attr("id")}};OpenAssessment.EditExampleBasedAssessmentView=function(element){this.element=element;this.name="example-based-assessment";new OpenAssessment.ToggleControl(this.element,"#ai_assessment_description_closed","#ai_assessment_settings_editor").install("#include_ai_assessment")};OpenAssessment.EditExampleBasedAssessmentView.prototype={description:function(){return{examples_xml:this.exampleDefinitions()}},isEnabled:function(isEnabled){var sel=$("#include_ai_assessment",this.element);return OpenAssessment.Fields.booleanField(sel,isEnabled)},exampleDefinitions:function(xml){var sel=$("#ai_training_examples",this.element);return OpenAssessment.Fields.stringField(sel,xml)},getID:function(){return $(this.element).attr("id")}};OpenAssessment.Fields={stringField:function(sel,value){if(typeof value!=="undefined"){sel.val(value)}return sel.val()},intField:function(sel,value){if(typeof value!=="undefined"){sel.val(value)}return parseInt(sel.val(),10)},booleanField:function(sel,value){if(typeof value!=="undefined"){sel.prop("checked",value)}return sel.prop("checked")}};OpenAssessment.ToggleControl=function(element,hiddenSelector,shownSelector){this.element=element;this.hiddenSelector=hiddenSelector;this.shownSelector=shownSelector};OpenAssessment.ToggleControl.prototype={install:function(checkboxSelector){$(checkboxSelector,this.element).change(this,function(event){var control=event.data;if(this.checked){control.show()}else{control.hide()}});return this},show:function(){$(this.hiddenSelector,this.element).addClass("is--hidden");$(this.shownSelector,this.element).removeClass("is--hidden")},hide:function(){$(this.hiddenSelector,this.element).removeClass("is--hidden");$(this.shownSelector,this.element).addClass("is--hidden")}};OpenAssessment.DatetimeControl=function(element,datePicker,timePicker){this.element=element;this.datePicker=datePicker;this.timePicker=timePicker};OpenAssessment.DatetimeControl.prototype={install:function(){var dateString=$(this.datePicker,this.element).val();$(this.datePicker,this.element).datepicker({showButtonPanel:true}).datepicker("option","dateFormat","yy-mm-dd").datepicker("setDate",dateString);$(this.timePicker,this.element).timepicker({timeFormat:"H:i",step:60});return this},datetime:function(dateString,timeString){var datePickerSel=$(this.datePicker,this.element);var timePickerSel=$(this.timePicker,this.element);if(typeof dateString!=="undefined"){datePickerSel.datepicker("setDate",dateString)}if(typeof timeString!=="undefined"){timePickerSel.val(timeString)}if(datePickerSel.val()===""&&timePickerSel.val()===""){return null}return datePickerSel.val()+"T"+timePickerSel.val()}};OpenAssessment.StudentTrainingListener=function(){this.element=$("#oa_student_training_editor");this.alert=new OpenAssessment.ValidationAlert($("#openassessment_rubric_validation_alert"))};OpenAssessment.StudentTrainingListener.prototype={optionUpdated:function(data){var view=this;var sel='.openassessment_training_example_criterion[data-criterion="'+data.criterionName+'"]';$(sel,this.element).each(function(){var criterion=this;var option=$('option[value="'+data.name+'"]',criterion);$(option).text(view._generateOptionString(data.label,data.points))})},optionAdd:function(data){var options=$('.openassessment_training_example_criterion_option[data-criterion="'+data.criterionName+'"]');var view=this;var criterionAdded=false;var examplesUpdated=false;if(options.length===0){this.criterionAdd(data);criterionAdded=true}$(".openassessment_training_example_criterion_option",this.element).each(function(){if($(this).data("criterion")===data.criterionName){var criterion=this;$(criterion).append($("<option></option>").attr("value",data.name).text(view._generateOptionString(data.label,data.points)));examplesUpdated=true}});if(criterionAdded&&examplesUpdated){this.displayAlertMsg(gettext("Criterion Addition requires Training Example Updates"),gettext("Because you added a criterion, student training examples will have to be updated."))}},optionRemove:function(data){var handler=this;var changed=false;$(".openassessment_training_example_criterion_option",this.element).each(function(){var criterionOption=this;if($(criterionOption).data("criterion")===data.criterionName){if($(criterionOption).val()==data.name){$(criterionOption).val("");$(criterionOption).addClass("openassessment_highlighted_field");$(criterionOption).click(function(){$(criterionOption).removeClass("openassessment_highlighted_field")});changed=true}$('option[value="'+data.name+'"]',criterionOption).remove();if($("option",criterionOption).length==1){handler.removeAllOptions(data);return}}});if(changed){this.displayAlertMsg(gettext("Option Deletion Led to Invalidation"),gettext("Because you deleted an option, some student training examples had to be reset."))}},removeAllOptions:function(data){var changed=false;$(".openassessment_training_example_criterion",this.element).each(function(){var criterion=this;if($(criterion).data("criterion")==data.criterionName){$(criterion).remove();changed=true}});if(changed){this.displayAlertMsg(gettext("Option Deletion Led to Invalidation"),gettext("The deletion of the last criterion option caused the criterion to be removed in the student training examples."))}},criterionRemove:function(data){var changed=false;var sel='.openassessment_training_example_criterion[data-criterion="'+data.criterionName+'"]';$(sel,this.element).each(function(){$(this).remove();changed=true});if(changed){this.displayAlertMsg(gettext("Criterion Deletion Led to Invalidation"),gettext("Because you deleted a criterion, there were student training examples where the criterion had to be removed."))}},displayAlertMsg:function(title,msg){this.alert.setMessage(title,msg);this.alert.show()},criterionUpdated:function(data){var sel='.openassessment_training_example_criterion[data-criterion="'+data.criterionName+'"]';$(sel,this.element).each(function(){$(".openassessment_training_example_criterion_name_wrapper",this).text(data.criterionLabel)})},criterionAdd:function(data){var view=this.element;var criterion=$("#openassessment_training_example_criterion_template").children().first().clone().removeAttr("id").attr("data-criterion",data.criterionName).toggleClass("is--hidden",false).appendTo(".openassessment_training_example_criteria_selections",view);criterion.find(".openassessment_training_example_criterion_option").attr("data-criterion",data.criterionName);criterion.find(".openassessment_training_example_criterion_name_wrapper").text(data.label)},examplesCriteriaLabels:function(){var examples=[];$(".openassessment_training_example_criteria_selections",this.element).each(function(){var exampleDescription={};$(".openassessment_training_example_criterion",this).each(function(){var criterionName=$(this).data("criterion");var criterionLabel=$(".openassessment_training_example_criterion_name_wrapper",this).text().trim();exampleDescription[criterionName]=criterionLabel});examples.push(exampleDescription)});return examples},examplesOptionsLabels:function(){var examples=[];$(".openassessment_training_example_criteria_selections",this.element).each(function(){var exampleDescription={};$(".openassessment_training_example_criterion_option",this).each(function(){var criterionName=$(this).data("criterion");exampleDescription[criterionName]={};$("option",this).each(function(){var optionName=$(this).val();var optionLabel=$(this).text().trim();exampleDescription[criterionName][optionName]=optionLabel})});examples.push(exampleDescription)});return examples},_generateOptionString:function(name,points){return name+" - "+points+gettext(" points")}};OpenAssessment.Notifier=function(listeners){this.listeners=listeners};OpenAssessment.Notifier.prototype={notificationFired:function(name,data){for(var i=0;i<this.listeners.length;i++){if(typeof this.listeners[i][name]==="function"){this.listeners[i][name](data)}}}};OpenAssessment.EditPromptView=function(element){this.element=element};OpenAssessment.EditPromptView.prototype={promptText:function(text){var sel=$("#openassessment_prompt_editor",this.element);return OpenAssessment.Fields.stringField(sel,text)}};OpenAssessment.EditRubricView=function(element,notifier){this.element=element;this.criteriaContainer=new OpenAssessment.Container(OpenAssessment.RubricCriterion,{containerElement:$("#openassessment_criterion_list",this.element).get(0),templateElement:$("#openassessment_criterion_template",this.element).get(0),addButtonElement:$("#openassessment_rubric_add_criterion",this.element).get(0),removeButtonClass:"openassessment_criterion_remove_button",containerItemClass:"openassessment_criterion",notifier:notifier});this.alert=new OpenAssessment.ValidationAlert($("#openassessment_rubric_validation_alert",this.element))};OpenAssessment.EditRubricView.prototype={criteriaDefinition:function(){var criteria=this.criteriaContainer.getItemValues();for(var criterion_idx=0;criterion_idx<criteria.length;criterion_idx++){var criterion=criteria[criterion_idx];criterion.order_num=criterion_idx;for(var option_idx=0;option_idx<criterion.options.length;option_idx++){var option=criterion.options[option_idx];option.order_num=option_idx}}return criteria},feedbackPrompt:function(text){var sel=$("#openassessment_rubric_feedback",this.element);return OpenAssessment.Fields.stringField(sel,text)},addCriterion:function(){this.criteriaContainer.add()},removeCriterion:function(item){this.criteriaContainer.remove(item)},getAllCriteria:function(){return this.criteriaContainer.getAllItems()},getCriterionItem:function(index){return this.criteriaContainer.getItem(index)},addOption:function(criterionIndex){var criterionItem=this.getCriterionItem(criterionIndex);criterionItem.optionContainer.add()},removeOption:function(criterionIndex,item){var criterionItem=this.getCriterionItem(criterionIndex);criterionItem.optionContainer.remove(item)},getAllOptions:function(criterionIndex){var criterionItem=this.getCriterionItem(criterionIndex);return criterionItem.optionContainer.getAllItems()},getOptionItem:function(criterionIndex,optionIndex){var criterionItem=this.getCriterionItem(criterionIndex);return criterionItem.optionContainer.getItem(optionIndex)}};OpenAssessment.EditSettingsView=function(element,assessmentViews){this.settingsElement=element;this.assessmentsElement=$(element).siblings("#openassessment_assessment_module_settings_editors").get(0);this.assessmentViews=assessmentViews;this.startDatetimeControl=new OpenAssessment.DatetimeControl(this.element,"#openassessment_submission_start_date","#openassessment_submission_start_time").install();this.dueDatetimeControl=new OpenAssessment.DatetimeControl(this.element,"#openassessment_submission_due_date","#openassessment_submission_due_time").install();this.initializeSortableAssessments()};OpenAssessment.EditSettingsView.prototype={initializeSortableAssessments:function(){var view=this;$("#openassessment_assessment_module_settings_editors",view.element).sortable({start:function(event,ui){$(".openassessment_assessment_module_editor",view.element).hide();var targetHeight="auto";ui.placeholder.height(targetHeight);ui.helper.height(targetHeight);$("#openassessment_assessment_module_settings_editors",view.element).sortable("refresh").sortable("refreshPositions")
\ No newline at end of file },stop:function(event,ui){$(".openassessment_assessment_module_editor",view.element).show()},snap:true,axis:"y",handle:".drag-handle",cursorAt:{top:20}});$("#openassessment_assessment_module_settings_editors .drag-handle",view.element).disableSelection()},displayName:function(name){var sel=$("#openassessment_title_editor",this.settingsElement);return OpenAssessment.Fields.stringField(sel,name)},submissionStart:function(dateString,timeString){return this.startDatetimeControl.datetime(dateString,timeString)},submissionDue:function(dateString,timeString){return this.dueDatetimeControl.datetime(dateString,timeString)},imageSubmissionEnabled:function(isEnabled){var sel=$("#openassessment_submission_image_editor",this.settingsElement);if(typeof isEnabled!=="undefined"){if(isEnabled){sel.val(1)}else{sel.val(0)}}return sel.val()==1},assessmentsDescription:function(){var assessmentDescList=[];var view=this;$(".openassessment_assessment_module_settings_editor",this.assessmentsElement).each(function(){var asmntView=view.assessmentViews[$(this).attr("id")];if(asmntView.isEnabled()){var description=asmntView.description();description["name"]=asmntView.name;assessmentDescList.push(description)}});return assessmentDescList},editorAssessmentsOrder:function(){var editorAssessments=[];var view=this;$(".openassessment_assessment_module_settings_editor",this.assessmentsElement).each(function(){var asmntView=view.assessmentViews[$(this).attr("id")];editorAssessments.push(asmntView.name)});return editorAssessments}};OpenAssessment.ValidationAlert=function(element){this.element=element;this.title=$(".openassessment_alert_title",this.element);this.message=$(".openassessment_alert_message",this.element)};OpenAssessment.ValidationAlert.prototype={hide:function(){this.element.addClass("is--hidden")},show:function(){this.element.removeClass("is--hidden")},setMessage:function(newTitle,newMessage){this.title.text(newTitle);this.message.text(newMessage)},isVisible:function(){return!this.element.hasClass("is--hidden")},getTitle:function(){return this.title.text()},getMessage:function(){return this.message.text()}};
\ No newline at end of file
...@@ -56,7 +56,6 @@ describe("OpenAssessment.BaseView", function() { ...@@ -56,7 +56,6 @@ describe("OpenAssessment.BaseView", function() {
beforeEach(function() { beforeEach(function() {
// Load the DOM fixture // Load the DOM fixture
jasmine.getFixtures().fixturesPath = 'base/fixtures';
loadFixtures('oa_base.html'); loadFixtures('oa_base.html');
// Create a new stub server // Create a new stub server
......
...@@ -42,7 +42,6 @@ describe("OpenAssessment.GradeView", function() { ...@@ -42,7 +42,6 @@ describe("OpenAssessment.GradeView", function() {
beforeEach(function() { beforeEach(function() {
// Load the DOM fixture // Load the DOM fixture
jasmine.getFixtures().fixturesPath = 'base/fixtures';
loadFixtures('oa_grade_complete.html'); loadFixtures('oa_grade_complete.html');
// Create the stub server // Create the stub server
......
...@@ -44,7 +44,6 @@ describe("OpenAssessment.PeerView", function() { ...@@ -44,7 +44,6 @@ describe("OpenAssessment.PeerView", function() {
beforeEach(function() { beforeEach(function() {
// Load the DOM fixture // Load the DOM fixture
jasmine.getFixtures().fixturesPath = 'base/fixtures';
loadFixtures('oa_peer_assessment.html'); loadFixtures('oa_peer_assessment.html');
// Create a new stub server // Create a new stub server
......
...@@ -97,7 +97,6 @@ describe("OpenAssessment.ResponseView", function() { ...@@ -97,7 +97,6 @@ describe("OpenAssessment.ResponseView", function() {
beforeEach(function() { beforeEach(function() {
// Load the DOM fixture // Load the DOM fixture
jasmine.getFixtures().fixturesPath = 'base/fixtures';
loadFixtures('oa_response.html'); loadFixtures('oa_response.html');
// Create stub objects // Create stub objects
......
...@@ -39,7 +39,6 @@ describe("OpenAssessment.SelfView", function() { ...@@ -39,7 +39,6 @@ describe("OpenAssessment.SelfView", function() {
beforeEach(function() { beforeEach(function() {
// Load the DOM fixture // Load the DOM fixture
jasmine.getFixtures().fixturesPath = 'base/fixtures';
loadFixtures('oa_self_assessment.html'); loadFixtures('oa_self_assessment.html');
// Create a new stub server // Create a new stub server
......
...@@ -69,9 +69,6 @@ describe("OpenAssessment.StaffInfoView", function() { ...@@ -69,9 +69,6 @@ describe("OpenAssessment.StaffInfoView", function() {
}; };
beforeEach(function() { beforeEach(function() {
// Configure the Jasmine fixtures path
jasmine.getFixtures().fixturesPath = 'base/fixtures';
// Create a new stub server // Create a new stub server
server = new StubServer(); server = new StubServer();
......
...@@ -45,7 +45,6 @@ describe("OpenAssessment.StudentTrainingView", function() { ...@@ -45,7 +45,6 @@ describe("OpenAssessment.StudentTrainingView", function() {
beforeEach(function() { beforeEach(function() {
// Load the DOM fixture // Load the DOM fixture
jasmine.getFixtures().fixturesPath = 'base/fixtures';
loadFixtures('oa_student_training.html'); loadFixtures('oa_student_training.html');
// Create a new stub server // Create a new stub server
......
...@@ -7,7 +7,6 @@ describe("OpenAssessment.Rubric", function() { ...@@ -7,7 +7,6 @@ describe("OpenAssessment.Rubric", function() {
var rubric = null; var rubric = null;
beforeEach(function() { beforeEach(function() {
jasmine.getFixtures().fixturesPath = 'base/fixtures';
loadFixtures('oa_rubric.html'); loadFixtures('oa_rubric.html');
var el = $("#peer-assessment--001__assessment").get(0); var el = $("#peer-assessment--001__assessment").get(0);
......
...@@ -52,28 +52,28 @@ describe("OpenAssessment.StudioView", function() { ...@@ -52,28 +52,28 @@ describe("OpenAssessment.StudioView", function() {
{ {
order_num: 0, order_num: 0,
label: "Criterion with two options", label: "Criterion with two options",
name: "52bfbd0eb3044212b809564866e77079", name: "criterion_1",
prompt: "Prompt for criterion with two options", prompt: "Prompt for criterion with two options",
feedback: "disabled", feedback: "disabled",
options: [ options: [
{ {
order_num: 0, order_num: 0,
points: 1, points: 1,
name: "85bbbecbb6a343f8a2146cde0e609ad0", name: "option_1",
label: "Fair", label: "Fair",
explanation: "Fair explanation" explanation: "Fair explanation"
}, },
{ {
order_num: 1, order_num: 1,
points: 2, points: 2,
name: "5936d5b9e281403ca123964055d4719a", name: "option_2",
label: "Good", label: "Good",
explanation: "Good explanation" explanation: "Good explanation"
} }
] ]
}, },
{ {
name: "d96bb68a69ee4ccb8f86c753b6924f75", name: "criterion_2",
label: "Criterion with no options", label: "Criterion with no options",
prompt: "Prompt for criterion with no options", prompt: "Prompt for criterion with no options",
order_num: 1, order_num: 1,
...@@ -81,7 +81,7 @@ describe("OpenAssessment.StudioView", function() { ...@@ -81,7 +81,7 @@ describe("OpenAssessment.StudioView", function() {
feedback: "required", feedback: "required",
}, },
{ {
name: "2ca052403b06424da714f7a80dfb954d", name: "criterion_3",
label: "Criterion with optional feedback", label: "Criterion with optional feedback",
prompt: "Prompt for criterion with optional feedback", prompt: "Prompt for criterion with optional feedback",
order_num: 2, order_num: 2,
...@@ -90,7 +90,7 @@ describe("OpenAssessment.StudioView", function() { ...@@ -90,7 +90,7 @@ describe("OpenAssessment.StudioView", function() {
{ {
order_num: 0, order_num: 0,
points: 2, points: 2,
name: "d7445661a89b4b339b9788cb7225a603", name: "option_1",
label: "Good", label: "Good",
explanation: "Good explanation" explanation: "Good explanation"
} }
...@@ -121,7 +121,6 @@ describe("OpenAssessment.StudioView", function() { ...@@ -121,7 +121,6 @@ describe("OpenAssessment.StudioView", function() {
beforeEach(function() { beforeEach(function() {
// Load the DOM fixture // Load the DOM fixture
jasmine.getFixtures().fixturesPath = 'base/fixtures';
loadFixtures('oa_edit.html'); loadFixtures('oa_edit.html');
// Create the stub server // Create the stub server
...@@ -190,7 +189,7 @@ describe("OpenAssessment.StudioView", function() { ...@@ -190,7 +189,7 @@ describe("OpenAssessment.StudioView", function() {
expect(runtime.notify).toHaveBeenCalledWith('cancel', {}); expect(runtime.notify).toHaveBeenCalledWith('cancel', {});
}); });
it("displays an error when server reports an update XML error", function() { it("displays an error when server reports an error", function() {
server.updateError = true; server.updateError = true;
view.save(); view.save();
expect(runtime.notify).toHaveBeenCalledWith('error', {msg: 'Test error'}); expect(runtime.notify).toHaveBeenCalledWith('error', {msg: 'Test error'});
......
...@@ -18,7 +18,6 @@ describe("OpenAssessment edit assessment views", function() { ...@@ -18,7 +18,6 @@ describe("OpenAssessment edit assessment views", function() {
}; };
beforeEach(function() { beforeEach(function() {
jasmine.getFixtures().fixturesPath = 'base/fixtures';
loadFixtures('oa_edit.html'); loadFixtures('oa_edit.html');
}); });
......
/**
Tests for the student training listener,
which dynamically updates student training examples
based on rubric changes.
**/
describe("OpenAssessment.StudentTrainingListener", function() {
var listener = null;
/**
Check that all student training examples have the expected
criteria or option labels.
Args:
actual (array): A list of example criteria or option labels
(object literals) retrieved from the DOM.
expected (object literal): The expected value for each example.
numExamples (int, optional): The number of student training examples
(defaults to 1).
**/
var assertExampleLabels = function(actual, expected, numExamples) {
// The most common case is one example, so use that as a default.
if (typeof(numExamples) == "undefined") {
numExamples = 1;
}
// Add one to the number of examples to include the client-side template.
expect(actual.length).toEqual(numExamples + 1);
// Verify that each example matches what we expect.
// Since there is only one rubric for the problem,
// the training examples should always match that rubric.
for (var index in actual) {
for (var criterionName in expected) {
expect(actual[index][criterionName]).toEqual(expected[criterionName]);
}
}
};
beforeEach(function() {
loadFixtures('oa_edit_student_training.html');
listener = new OpenAssessment.StudentTrainingListener();
});
it("updates the label of an option", function() {
// Initial state, set by the fixture
assertExampleLabels(
listener.examplesOptionsLabels(),
{
criterion_with_two_options: {
"": "Not Scored",
option_1: "Fair - 1 points",
option_2: "Good - 2 points"
}
}
);
// Update the option label and points,
listener.optionUpdated({
criterionName: "criterion_with_two_options",
name: "option_1",
label: "This is a new label!",
points: 42
});
// Verify the new state
assertExampleLabels(
listener.examplesOptionsLabels(),
{
criterion_with_two_options: {
"": "Not Scored",
option_1: "This is a new label! - 42 points",
option_2: "Good - 2 points"
}
}
);
});
it("removes an option and displays an alert", function() {
// Initial state, set by the fixture
assertExampleLabels(
listener.examplesOptionsLabels(),
{
criterion_with_two_options: {
"": "Not Scored",
option_1: "Fair - 1 points",
option_2: "Good - 2 points"
}
}
);
expect(listener.alert.isVisible()).toBe(false);
// Remove an option
listener.optionRemove({
criterionName: "criterion_with_two_options",
name: "option_1"
});
// Verify the new state
assertExampleLabels(
listener.examplesOptionsLabels(),
{
criterion_with_two_options: {
"": "Not Scored",
option_2: "Good - 2 points"
}
}
);
// The alert should be displayed
expect(listener.alert.isVisible()).toBe(true);
});
it("removes a criterion if the criterion has no options", function() {
// Initial state, set by the fixture
assertExampleLabels(
listener.examplesCriteriaLabels(),
{ criterion_with_two_options: "Criterion with two options" }
);
expect(listener.alert.isVisible()).toBe(false);
// Remove all options for the criterion
listener.removeAllOptions({
criterionName: "criterion_with_two_options"
});
// Since the criterion has no options, it should no longer
// be available in student training
assertExampleLabels(listener.examplesCriteriaLabels(), {}, 1);
// The alert should be displayed
expect(listener.alert.isVisible()).toBe(true);
});
it("updates the label of a criterion", function() {
// Initial state, set by the fixture
assertExampleLabels(
listener.examplesCriteriaLabels(),
{ criterion_with_two_options: "Criterion with two options" }
);
// Update a label
listener.criterionUpdated({
criterionName: "criterion_with_two_options",
criterionLabel: "This is a new label!",
});
// Verify the new state
assertExampleLabels(
listener.examplesCriteriaLabels(),
{ criterion_with_two_options: "This is a new label!" }
);
});
it("adds a criterion and options", function() {
// Initial state, set by the fixture
assertExampleLabels(
listener.examplesCriteriaLabels(),
{ criterion_with_two_options: "Criterion with two options" }
);
// Add the criterion, which has no options
listener.criterionAdd({
criterionName: "new_criterion",
label: "This is a new criterion!"
});
// Since the criterion has no options, it should not
// be displayed.
assertExampleLabels(
listener.examplesCriteriaLabels(),
{ criterion_with_two_options: "Criterion with two options" }
);
// Add an option to the criterion
listener.optionAdd({
criterionName: "new_criterion",
name: "new_option",
label: "This is a new option!",
points: 56
});
// Now the criterion should be visible in student training
assertExampleLabels(
listener.examplesCriteriaLabels(),
{
criterion_with_two_options: "Criterion with two options",
new_criterion: "This is a new criterion!"
}
);
assertExampleLabels(
listener.examplesOptionsLabels(),
{
criterion_with_two_options: {
"": "Not Scored",
option_1: "Fair - 1 points",
option_2: "Good - 2 points",
},
new_criterion: {
"": "Not Scored",
new_option: "This is a new option! - 56 points"
}
}
);
// Add another option to the criterion
listener.optionAdd({
criterionName: "new_criterion",
name: "yet_another_option",
label: "This is yet another option!",
points: 27
});
assertExampleLabels(
listener.examplesOptionsLabels(),
{
criterion_with_two_options: {
"": "Not Scored",
option_1: "Fair - 1 points",
option_2: "Good - 2 points",
},
new_criterion: {
"": "Not Scored",
new_option: "This is a new option! - 56 points",
yet_another_option: "This is yet another option! - 27 points"
}
}
);
});
it("removes a criterion and displays an alert", function() {
// Initial state, set by the fixture
assertExampleLabels(
listener.examplesCriteriaLabels(),
{ criterion_with_two_options: "Criterion with two options" }
);
expect(listener.alert.isVisible()).toBe(false);
// Remove the criterion
listener.criterionRemove({
criterionName: "criterion_with_two_options"
});
// The criterion should no longer be displayed
assertExampleLabels(listener.examplesCriteriaLabels(), {}, 1);
// The alert should be displayed
expect(listener.alert.isVisible()).toBe(true);
});
});
describe("OpenAssessment.Notifier", function() {
var notifier = null;
var listeners = [];
var StubListener = function() {
this.receivedData = null;
this.testNotification = function(data) {
this.receivedData = data;
};
};
beforeEach(function() {
listeners = [ new StubListener(), new StubListener() ];
notifier = new OpenAssessment.Notifier(listeners);
});
it("notifies listeners when a notification fires", function() {
// Fire a notification that the listeners don't respond to
notifier.notificationFired("ignore this!", {});
expect(listeners[0].receivedData).toBe(null);
expect(listeners[1].receivedData).toBe(null);
// Fire a notification that the listeners care about
var testData = { foo: "bar" };
notifier.notificationFired("testNotification", testData);
// Check that the listeners were notified
expect(listeners[0].receivedData).toBe(testData);
expect(listeners[1].receivedData).toBe(testData);
});
});
...@@ -8,7 +8,6 @@ describe("OpenAssessment.EditPromptView", function() { ...@@ -8,7 +8,6 @@ describe("OpenAssessment.EditPromptView", function() {
beforeEach(function() { beforeEach(function() {
// Load the DOM fixture // Load the DOM fixture
jasmine.getFixtures().fixturesPath = 'base/fixtures';
loadFixtures('oa_edit.html'); loadFixtures('oa_edit.html');
// Create the view // Create the view
......
...@@ -3,13 +3,25 @@ Tests for the rubric editing view. ...@@ -3,13 +3,25 @@ Tests for the rubric editing view.
**/ **/
describe("OpenAssessment.EditRubricView", function() { describe("OpenAssessment.EditRubricView", function() {
// Use a stub notifier implementation that simply stores
// the notifications it receives.
var notifier = null;
var StubNotifier = function() {
this.notifications = [];
this.notificationFired = function(name, data) {
this.notifications.push({
name: name,
data: data
});
};
};
var view = null; var view = null;
beforeEach(function() { beforeEach(function() {
jasmine.getFixtures().fixturesPath = 'base/fixtures';
loadFixtures('oa_edit.html'); loadFixtures('oa_edit.html');
var el = $("#oa_rubric_editor_wrapper").get(0); var el = $("#oa_rubric_editor_wrapper").get(0);
view = new OpenAssessment.EditRubricView(el); notifier = new StubNotifier();
view = new OpenAssessment.EditRubricView(el, notifier);
}); });
it("reads a criteria definition from the editor", function() { it("reads a criteria definition from the editor", function() {
...@@ -20,7 +32,7 @@ describe("OpenAssessment.EditRubricView", function() { ...@@ -20,7 +32,7 @@ describe("OpenAssessment.EditRubricView", function() {
// Criterion with two options, feedback disabled // Criterion with two options, feedback disabled
expect(criteria[0]).toEqual({ expect(criteria[0]).toEqual({
name: "52bfbd0eb3044212b809564866e77079", name: "criterion_1",
label: "Criterion with two options", label: "Criterion with two options",
prompt: "Prompt for criterion with two options", prompt: "Prompt for criterion with two options",
order_num: 0, order_num: 0,
...@@ -29,14 +41,14 @@ describe("OpenAssessment.EditRubricView", function() { ...@@ -29,14 +41,14 @@ describe("OpenAssessment.EditRubricView", function() {
{ {
order_num: 0, order_num: 0,
points: 1, points: 1,
name: "85bbbecbb6a343f8a2146cde0e609ad0", name: "option_1",
label: "Fair", label: "Fair",
explanation: "Fair explanation" explanation: "Fair explanation"
}, },
{ {
order_num: 1, order_num: 1,
points: 2, points: 2,
name: "5936d5b9e281403ca123964055d4719a", name: "option_2",
label: "Good", label: "Good",
explanation: "Good explanation" explanation: "Good explanation"
} }
...@@ -45,7 +57,7 @@ describe("OpenAssessment.EditRubricView", function() { ...@@ -45,7 +57,7 @@ describe("OpenAssessment.EditRubricView", function() {
// Criterion with no options, feedback required // Criterion with no options, feedback required
expect(criteria[1]).toEqual({ expect(criteria[1]).toEqual({
name: "d96bb68a69ee4ccb8f86c753b6924f75", name: "criterion_2",
label: "Criterion with no options", label: "Criterion with no options",
prompt: "Prompt for criterion with no options", prompt: "Prompt for criterion with no options",
order_num: 1, order_num: 1,
...@@ -55,7 +67,7 @@ describe("OpenAssessment.EditRubricView", function() { ...@@ -55,7 +67,7 @@ describe("OpenAssessment.EditRubricView", function() {
// Criterion with one option, feeback optional // Criterion with one option, feeback optional
expect(criteria[2]).toEqual({ expect(criteria[2]).toEqual({
name: "2ca052403b06424da714f7a80dfb954d", name: "criterion_3",
label: "Criterion with optional feedback", label: "Criterion with optional feedback",
prompt: "Prompt for criterion with optional feedback", prompt: "Prompt for criterion with optional feedback",
order_num: 2, order_num: 2,
...@@ -64,7 +76,7 @@ describe("OpenAssessment.EditRubricView", function() { ...@@ -64,7 +76,7 @@ describe("OpenAssessment.EditRubricView", function() {
{ {
order_num: 0, order_num: 0,
points: 2, points: 2,
name: "d7445661a89b4b339b9788cb7225a603", name: "option_1",
label: "Good", label: "Good",
explanation: "Good explanation" explanation: "Good explanation"
} }
...@@ -75,14 +87,13 @@ describe("OpenAssessment.EditRubricView", function() { ...@@ -75,14 +87,13 @@ describe("OpenAssessment.EditRubricView", function() {
it("creates new criteria and options", function() { it("creates new criteria and options", function() {
// Delete all existing criteria from the rubric // Delete all existing criteria from the rubric
// Then add new criteria (created from a client-side template) // Then add new criteria (created from a client-side template)
view.removeAllCriteria(); $.each(view.getAllCriteria(), function() { view.removeCriterion(this); });
view.addCriterion(); view.addCriterion();
view.addCriterion(); view.addCriterion();
// Add an option to the second criterion // Add an option to the second criterion
view.getCriterionItem(1).addOption(); view.addOption(1);
// Check the definition
// Since no criteria/option names are set, leave them out of the description. // Since no criteria/option names are set, leave them out of the description.
// This will cause the server to assign them unique names. // This will cause the server to assign them unique names.
var criteria = view.criteriaDefinition(); var criteria = view.criteriaDefinition();
...@@ -124,4 +135,77 @@ describe("OpenAssessment.EditRubricView", function() { ...@@ -124,4 +135,77 @@ describe("OpenAssessment.EditRubricView", function() {
expect(view.feedbackPrompt()).toEqual(prompt); expect(view.feedbackPrompt()).toEqual(prompt);
}); });
it("fires a notification when an option is added", function() {
view.addOption();
expect(notifier.notifications).toContain({
name: "optionAdd",
data: {
criterionName: 'criterion_1',
criterionLabel: 'Criterion with two options',
name:'0',
label: '',
points : 1
}
});
// Add a second option and ensure that it is given a unique name
view.addOption();
expect(notifier.notifications).toContain({
name: "optionAdd",
data: {
criterionName: 'criterion_1',
criterionLabel: 'Criterion with two options',
name:'1',
label: '',
points : 1
}
});
});
it("fires a notification when an option is removed", function() {
view.removeOption(0, view.getOptionItem(0, 0));
expect(notifier.notifications).toContain({
name: "optionRemove",
data: {
criterionName: 'criterion_1',
name: 'option_1'
}
});
});
it("fires a notification when an option's label or points are updated", function() {
// Simulate what happens when the options label or points are updated
view.getOptionItem(0, 0).updateHandler();
expect(notifier.notifications).toContain({
name: "optionUpdated",
data: {
criterionName: 'criterion_1',
name: 'option_1',
label: 'Fair',
points: 1
}
});
});
it("fires a notification when a criterion's label is updated", function() {
// Simulate what happens when a criterion label is updated
view.getCriterionItem(0).updateHandler();
expect(notifier.notifications).toContain({
name: "criterionUpdated",
data: {
criterionName: 'criterion_1',
criterionLabel: 'Criterion with two options'
}
});
});
it("fires a notification when a criterion is removed", function() {
view.criteriaContainer.remove(view.getCriterionItem(0));
expect(notifier.notifications).toContain({
name: "criterionRemove",
data: {criterionName : 'criterion_1'}
});
});
}); });
...@@ -22,7 +22,6 @@ describe("OpenAssessment.EditSettingsView", function() { ...@@ -22,7 +22,6 @@ describe("OpenAssessment.EditSettingsView", function() {
beforeEach(function() { beforeEach(function() {
// Load the DOM fixture // Load the DOM fixture
jasmine.getFixtures().fixturesPath = 'base/fixtures';
loadFixtures('oa_edit.html'); loadFixtures('oa_edit.html');
// Create the stub assessment views // Create the stub assessment views
......
describe("OpenAssessment.ValidationAlert", function() {
var alert = null;
beforeEach(function() {
loadFixtures('oa_edit.html');
alert = new OpenAssessment.ValidationAlert(
$("#openassessment_rubric_validation_alert")
);
});
it("shows and hides an alert", function() {
// Initially, the alert should be hidden
expect(alert.isVisible()).toBe(false);
// Show the alert
alert.show();
expect(alert.isVisible()).toBe(true);
// Hide the alert
alert.hide();
expect(alert.isVisible()).toBe(false);
});
it("sets the alert title and message", function() {
// Set the title and message
alert.setMessage("new title", "new message");
expect(alert.getTitle()).toEqual("new title");
expect(alert.getMessage()).toEqual("new message");
});
});
\ No newline at end of file
/**
Common test configuration, loaded before any of the spec files.
**/
// Set the fixture path
jasmine.getFixtures().fixturesPath = 'base/fixtures';
...@@ -44,8 +44,8 @@ including for pre-existing items in the container element. ...@@ -44,8 +44,8 @@ including for pre-existing items in the container element.
Templates elements are never deleted, so they should be hidden using CSS styles. Templates elements are never deleted, so they should be hidden using CSS styles.
Args: Args:
containerItem (object): The container item object used to access containerItem (constructor): The constructor of the container item object
the contents of items in the container. used to access the contents of items in the container.
Kwargs: Kwargs:
containerElement (DOM element): The element representing the container. containerElement (DOM element): The element representing the container.
...@@ -55,25 +55,33 @@ Kwargs: ...@@ -55,25 +55,33 @@ Kwargs:
There may be one of these for each item in the container. There may be one of these for each item in the container.
containerItemClass (string): The CSS class of items in the container. containerItemClass (string): The CSS class of items in the container.
New items will be assigned this class. New items will be assigned this class.
notifier (OpenAssessment.Notifier): Used to send notifications of updates to container items.
**/ **/
OpenAssessment.Container = function(containerItem, kwargs) { OpenAssessment.Container = function(containerItem, kwargs) {
this.containerItem = containerItem;
this.containerElement = kwargs.containerElement; this.containerElement = kwargs.containerElement;
this.templateElement = kwargs.templateElement; this.templateElement = kwargs.templateElement;
this.addButtonElement = kwargs.addButtonElement; this.addButtonElement = kwargs.addButtonElement;
this.removeButtonClass = kwargs.removeButtonClass; this.removeButtonClass = kwargs.removeButtonClass;
this.containerItemClass = kwargs.containerItemClass; this.containerItemClass = kwargs.containerItemClass;
this.notifier = kwargs.notifier;
// Since every container item should be instantiated with
// the notifier we were given, create a helper method
// that does this automatically.
var container = this;
this.createContainerItem = function(element) {
return new containerItem(element, container.notifier);
};
// Install a click handler for the add button // Install a click handler for the add button
$(this.addButtonElement).click($.proxy(this.add, this)); $(this.addButtonElement).click($.proxy(this.add, this));
// Find items already in the container and install click // Find items already in the container and install click
// handlers for the delete buttons. // handlers for the delete buttons.
var container = this;
$("." + this.removeButtonClass, this.containerElement).click( $("." + this.removeButtonClass, this.containerElement).click(
function(eventData) { function(eventData) {
var item = new container.containerItem(eventData.target); var item = container.createContainerItem(eventData.target);
container.remove(item); container.remove(item);
} }
); );
...@@ -82,7 +90,7 @@ OpenAssessment.Container = function(containerItem, kwargs) { ...@@ -82,7 +90,7 @@ OpenAssessment.Container = function(containerItem, kwargs) {
// own event handlers. // own event handlers.
$("." + this.containerItemClass, this.containerElement).each( $("." + this.containerItemClass, this.containerElement).each(
function(index, element) { function(index, element) {
new container.containerItem(element); container.createContainerItem(element);
} }
); );
}; };
...@@ -112,13 +120,13 @@ OpenAssessment.Container.prototype = { ...@@ -112,13 +120,13 @@ OpenAssessment.Container.prototype = {
var containerItem = $("." + this.containerItemClass, this.containerElement).last(); var containerItem = $("." + this.containerItemClass, this.containerElement).last();
containerItem.find('.' + this.removeButtonClass) containerItem.find('.' + this.removeButtonClass)
.click(function(eventData) { .click(function(eventData) {
var containerItem = new container.containerItem(eventData.target); var containerItem = container.createContainerItem(eventData.target);
container.remove(containerItem); container.remove(containerItem);
} ); } );
// Initialize the item, allowing it to install event handlers. // Initialize the item, allowing it to install event handlers.
// Fire event handler for adding a new element // Fire event handler for adding a new element
var handlerItem = new this.containerItem(containerItem); var handlerItem = container.createContainerItem(containerItem);
handlerItem.addHandler(); handlerItem.addHandler();
}, },
...@@ -133,7 +141,7 @@ OpenAssessment.Container.prototype = { ...@@ -133,7 +141,7 @@ OpenAssessment.Container.prototype = {
**/ **/
remove: function(item) { remove: function(item) {
var itemElement = $(item.element).closest("." + this.containerItemClass); var itemElement = $(item.element).closest("." + this.containerItemClass);
var containerItem = new this.containerItem(itemElement); var containerItem = this.createContainerItem(itemElement);
containerItem.removeHandler(); containerItem.removeHandler();
itemElement.remove(); itemElement.remove();
}, },
...@@ -152,7 +160,7 @@ OpenAssessment.Container.prototype = { ...@@ -152,7 +160,7 @@ OpenAssessment.Container.prototype = {
$("." + this.containerItemClass, this.containerElement).each( $("." + this.containerItemClass, this.containerElement).each(
function(index, element) { function(index, element) {
var containerItem = new container.containerItem(element); var containerItem = container.createContainerItem(element);
var fieldValues = containerItem.getFieldValues(); var fieldValues = containerItem.getFieldValues();
values.push(fieldValues); values.push(fieldValues);
} }
...@@ -173,7 +181,7 @@ OpenAssessment.Container.prototype = { ...@@ -173,7 +181,7 @@ OpenAssessment.Container.prototype = {
**/ **/
getItem: function(index) { getItem: function(index) {
var element = $("." + this.containerItemClass, this.containerElement).get(index); var element = $("." + this.containerItemClass, this.containerElement).get(index);
return (element !== undefined) ? new this.containerItem(element) : null; return (element !== undefined) ? this.createContainerItem(element) : null;
}, },
/** /**
...@@ -186,6 +194,6 @@ OpenAssessment.Container.prototype = { ...@@ -186,6 +194,6 @@ OpenAssessment.Container.prototype = {
getAllItems: function() { getAllItems: function() {
var container = this; var container = this;
return $("." + this.containerItemClass, this.containerElement) return $("." + this.containerItemClass, this.containerElement)
.map(function() { return new container.containerItem(this); }); .map(function() { return container.createContainerItem(this); });
} }
}; };
...@@ -15,7 +15,7 @@ OpenAssessment.ItemUtilities = { ...@@ -15,7 +15,7 @@ OpenAssessment.ItemUtilities = {
createUniqueName: function(selector, nameAttribute) { createUniqueName: function(selector, nameAttribute) {
var index = 0; var index = 0;
while (index <= selector.length) { while (index <= selector.length) {
if (selector.parent().find("*[" + nameAttribute + "='" + index + "']").length == 0) { if (selector.parent().find("*[" + nameAttribute + "='" + index + "']").length === 0) {
return index.toString(); return index.toString();
} }
index++; index++;
...@@ -30,13 +30,14 @@ container object. Constructs a new RubricOption element. ...@@ -30,13 +30,14 @@ container object. Constructs a new RubricOption element.
Args: Args:
element (OpenAssessment.Container): The container that the option is a member of. element (OpenAssessment.Container): The container that the option is a member of.
notifier (OpenAssessment.Notifier): Used to send notifications of updates to rubric options.
Returns: Returns:
OpenAssessment.RubricOption OpenAssessment.RubricOption
**/ **/
OpenAssessment.RubricOption = function(element) { OpenAssessment.RubricOption = function(element, notifier) {
this.element = element; this.element = element;
this.modificationHandler = new OpenAssessment.RubricEventHandler(); this.notifier = notifier;
$(this.element).focusout($.proxy(this.updateHandler, this)); $(this.element).focusout($.proxy(this.updateHandler, this));
}; };
...@@ -78,7 +79,7 @@ OpenAssessment.RubricOption.prototype = { ...@@ -78,7 +79,7 @@ OpenAssessment.RubricOption.prototype = {
}, },
/** /**
Hook into the event handler for removal of a criterion option. Hook into the event handler for addition of a criterion option.
*/ */
addHandler: function (){ addHandler: function (){
...@@ -97,7 +98,7 @@ OpenAssessment.RubricOption.prototype = { ...@@ -97,7 +98,7 @@ OpenAssessment.RubricOption.prototype = {
$(".openassessment_criterion_option_name", this.element).attr("value", name); $(".openassessment_criterion_option_name", this.element).attr("value", name);
var fields = this.getFieldValues(); var fields = this.getFieldValues();
this.modificationHandler.notificationFired( this.notifier.notificationFired(
"optionAdd", "optionAdd",
{ {
"criterionName": criterionName, "criterionName": criterionName,
...@@ -116,7 +117,7 @@ OpenAssessment.RubricOption.prototype = { ...@@ -116,7 +117,7 @@ OpenAssessment.RubricOption.prototype = {
removeHandler: function (){ removeHandler: function (){
var criterionName = $(this.element).data('criterion'); var criterionName = $(this.element).data('criterion');
var optionName = $(this.element).data('option'); var optionName = $(this.element).data('option');
this.modificationHandler.notificationFired( this.notifier.notificationFired(
"optionRemove", "optionRemove",
{ {
"criterionName": criterionName, "criterionName": criterionName,
...@@ -136,7 +137,7 @@ OpenAssessment.RubricOption.prototype = { ...@@ -136,7 +137,7 @@ OpenAssessment.RubricOption.prototype = {
var optionName = $(this.element).data('option'); var optionName = $(this.element).data('option');
var optionLabel = fields.label; var optionLabel = fields.label;
var optionPoints = fields.points; var optionPoints = fields.points;
this.modificationHandler.notificationFired( this.notifier.notificationFired(
"optionUpdated", "optionUpdated",
{ {
"criterionName": criterionName, "criterionName": criterionName,
...@@ -154,20 +155,22 @@ the DOM. ...@@ -154,20 +155,22 @@ the DOM.
Args: Args:
element (JQuery Object): The selection which describes the scope of the criterion. element (JQuery Object): The selection which describes the scope of the criterion.
notifier (OpenAssessment.Notifier): Used to send notifications of updates to rubric criteria.
Returns: Returns:
OpenAssessment.RubricCriterion OpenAssessment.RubricCriterion
**/ **/
OpenAssessment.RubricCriterion = function(element) { OpenAssessment.RubricCriterion = function(element, notifier) {
this.element = element; this.element = element;
this.modificationHandler = new OpenAssessment.RubricEventHandler(); this.notifier = notifier;
this.optionContainer = new OpenAssessment.Container( this.optionContainer = new OpenAssessment.Container(
OpenAssessment.RubricOption, { OpenAssessment.RubricOption, {
containerElement: $(".openassessment_criterion_option_list", this.element).get(0), containerElement: $(".openassessment_criterion_option_list", this.element).get(0),
templateElement: $("#openassessment_option_template").get(0), templateElement: $("#openassessment_option_template").get(0),
addButtonElement: $(".openassessment_criterion_add_option", this.element).get(0), addButtonElement: $(".openassessment_criterion_add_option", this.element).get(0),
removeButtonClass: "openassessment_criterion_option_remove_button", removeButtonClass: "openassessment_criterion_option_remove_button",
containerItemClass: "openassessment_criterion_option" containerItemClass: "openassessment_criterion_option",
notifier: this.notifier
} }
); );
...@@ -247,7 +250,7 @@ OpenAssessment.RubricCriterion.prototype = { ...@@ -247,7 +250,7 @@ OpenAssessment.RubricCriterion.prototype = {
*/ */
removeHandler: function(){ removeHandler: function(){
var criterionName = $(this.element).data('criterion'); var criterionName = $(this.element).data('criterion');
this.modificationHandler.notificationFired("criterionRemove", {'criterionName': criterionName}); this.notifier.notificationFired("criterionRemove", {'criterionName': criterionName});
}, },
/** /**
...@@ -258,7 +261,7 @@ OpenAssessment.RubricCriterion.prototype = { ...@@ -258,7 +261,7 @@ OpenAssessment.RubricCriterion.prototype = {
var fields = this.getFieldValues(); var fields = this.getFieldValues();
var criterionName = fields.name; var criterionName = fields.name;
var criterionLabel = fields.label; var criterionLabel = fields.label;
this.modificationHandler.notificationFired( this.notifier.notificationFired(
"criterionUpdated", "criterionUpdated",
{'criterionName': criterionName, 'criterionLabel': criterionLabel} {'criterionName': criterionName, 'criterionLabel': criterionLabel}
); );
...@@ -274,6 +277,7 @@ OpenAssessment.RubricCriterion.prototype = { ...@@ -274,6 +277,7 @@ OpenAssessment.RubricCriterion.prototype = {
Returns: Returns:
OpenAssessment.TrainingExample OpenAssessment.TrainingExample
**/ **/
OpenAssessment.TrainingExample = function(element){ OpenAssessment.TrainingExample = function(element){
this.element = element; this.element = element;
...@@ -304,5 +308,4 @@ OpenAssessment.TrainingExample.prototype = { ...@@ -304,5 +308,4 @@ OpenAssessment.TrainingExample.prototype = {
addHandler: function() {}, addHandler: function() {},
removeHandler: function() {}, removeHandler: function() {},
updateHandler: function() {} updateHandler: function() {}
}; };
\ No newline at end of file
...@@ -52,7 +52,10 @@ OpenAssessment.StudioView = function(runtime, element, server) { ...@@ -52,7 +52,10 @@ OpenAssessment.StudioView = function(runtime, element, server) {
// Initialize the rubric tab view // Initialize the rubric tab view
this.rubricView = new OpenAssessment.EditRubricView( this.rubricView = new OpenAssessment.EditRubricView(
$("#oa_rubric_editor_wrapper", this.element).get(0) $("#oa_rubric_editor_wrapper", this.element).get(0),
new OpenAssessment.Notifier([
new OpenAssessment.StudentTrainingListener()
])
); );
// Install the save and cancel buttons // Install the save and cancel buttons
......
...@@ -280,7 +280,7 @@ OpenAssessment.EditStudentTrainingView = function(element) { ...@@ -280,7 +280,7 @@ OpenAssessment.EditStudentTrainingView = function(element) {
removeButtonClass: "openassessment_training_example_remove", removeButtonClass: "openassessment_training_example_remove",
containerItemClass: "openassessment_training_example" containerItemClass: "openassessment_training_example"
} }
) );
}; };
OpenAssessment.EditStudentTrainingView.prototype = { OpenAssessment.EditStudentTrainingView.prototype = {
...@@ -333,21 +333,6 @@ OpenAssessment.EditStudentTrainingView.prototype = { ...@@ -333,21 +333,6 @@ OpenAssessment.EditStudentTrainingView.prototype = {
}, },
/** /**
Get or set the XML defining the training examples.
Args:
xml (string, optional): The XML of the training example definitions.
Returns:
string
**/
exampleDefinitions: function(xml) {
var sel = $("#student_training_examples", this.element);
return OpenAssessment.Fields.stringField(sel, xml);
},
/**
Gets the ID of the assessment Gets the ID of the assessment
Returns: Returns:
......
OpenAssessment.RubricEventHandler = function () { /**
this.listeners = [ Dynamically update student training examples based on
new OpenAssessment.StudentTrainingListener() changes to the rubric.
]; **/
}; OpenAssessment.StudentTrainingListener = function() {
OpenAssessment.RubricEventHandler.prototype = {
notificationFired: function(name, data) {
for (var i = 0; i < this.listeners.length; i++) {
if (typeof(this.listeners[i][name]) === 'function') {
this.listeners[i][name](data);
}
}
}
};
OpenAssessment.StudentTrainingListener = function () {
this.element = $('#oa_student_training_editor'); this.element = $('#oa_student_training_editor');
this.alert = new OpenAssessment.ValidationAlert($('#openassessment_rubric_validation_alert')); this.alert = new OpenAssessment.ValidationAlert($('#openassessment_rubric_validation_alert'));
}; };
OpenAssessment.StudentTrainingListener.prototype = { OpenAssessment.StudentTrainingListener.prototype = {
generateOptionString: function(name, points){
return name + ' - ' + points + gettext(' points')
},
/** /**
Event handler for updating training examples when a criterion option has Event handler for updating training examples when a criterion option has
been updated. been updated.
...@@ -38,14 +19,16 @@ OpenAssessment.StudentTrainingListener.prototype = { ...@@ -38,14 +19,16 @@ OpenAssessment.StudentTrainingListener.prototype = {
label (str): The label for the option. label (str): The label for the option.
points (int): The point value for the option. points (int): The point value for the option.
*/ */
optionUpdated: function(data){ optionUpdated: function(data) {
var view = this; var view = this;
$('.openassessment_training_example_criterion[data-criterion="' var sel = '.openassessment_training_example_criterion[data-criterion="' + data.criterionName + '"]';
+ data.criterionName + '"', this.element).each(function(){ $(sel, this.element).each(
function() {
var criterion = this; var criterion = this;
var option = $("option[value='" + data.name + "'", criterion); var option = $('option[value="' + data.name + '"]', criterion);
$(option).text(view.generateOptionString(data.label, data.points)); $(option).text(view._generateOptionString(data.label, data.points));
}); }
);
}, },
/** /**
...@@ -60,24 +43,22 @@ OpenAssessment.StudentTrainingListener.prototype = { ...@@ -60,24 +43,22 @@ OpenAssessment.StudentTrainingListener.prototype = {
Args: Args:
criterionName (str): The name of the criterion that will have an criterionName (str): The name of the criterion that will have an
additional option. additional option.
criterionLabel (str): The label for the criterion that will have an
additional option.
name (str): The name of the new option. name (str): The name of the new option.
label (str): The new option label. label (str): The new option label.
points (int): The point value of the new option. points (int): The point value of the new option.
*/ */
optionAdd: function(data){ optionAdd: function(data) {
// First, check to see if the criterion exists on the training examples // First, check to see if the criterion exists on the training examples
var options = $('.openassessment_training_example_criterion_option[data-criterion="' + data.criterionName + '"]'); var options = $('.openassessment_training_example_criterion_option[data-criterion="' + data.criterionName + '"]');
var view = this; var view = this;
var criterionAdded = false; var criterionAdded = false;
var examplesUpdated = false; var examplesUpdated = false;
if (options.length == 0) { if (options.length === 0) {
this.criterionAdd(data); this.criterionAdd(data);
criterionAdded = true; criterionAdded = true;
} }
$('.openassessment_training_example_criterion_option', this.element).each(function(){ $('.openassessment_training_example_criterion_option', this.element).each(function() {
if ($(this).data('criterion') === data.criterionName) { if ($(this).data('criterion') === data.criterionName) {
var criterion = this; var criterion = this;
// Risky; making an assumption that options will remain simple. // Risky; making an assumption that options will remain simple.
...@@ -85,7 +66,7 @@ OpenAssessment.StudentTrainingListener.prototype = { ...@@ -85,7 +66,7 @@ OpenAssessment.StudentTrainingListener.prototype = {
// but this avoids overly complex templating code. // but this avoids overly complex templating code.
$(criterion).append($("<option></option>") $(criterion).append($("<option></option>")
.attr("value", data.name) .attr("value", data.name)
.text(view.generateOptionString(data.label, data.points))); .text(view._generateOptionString(data.label, data.points)));
examplesUpdated = true; examplesUpdated = true;
} }
}); });
...@@ -93,8 +74,7 @@ OpenAssessment.StudentTrainingListener.prototype = { ...@@ -93,8 +74,7 @@ OpenAssessment.StudentTrainingListener.prototype = {
if (criterionAdded && examplesUpdated) { if (criterionAdded && examplesUpdated) {
this.displayAlertMsg( this.displayAlertMsg(
gettext("Criterion Addition requires Training Example Updates"), gettext("Criterion Addition requires Training Example Updates"),
gettext("Because you added a criterion, student training examples " + gettext("Because you added a criterion, student training examples will have to be updated.")
"will have to be updated.")
); );
} }
}, },
...@@ -114,10 +94,10 @@ OpenAssessment.StudentTrainingListener.prototype = { ...@@ -114,10 +94,10 @@ OpenAssessment.StudentTrainingListener.prototype = {
name (str): The option being removed. name (str): The option being removed.
*/ */
optionRemove: function(data){ optionRemove: function(data) {
var validator = this; var handler = this;
var changed = false; var changed = false;
$('.openassessment_training_example_criterion_option', this.element).each(function(){ $('.openassessment_training_example_criterion_option', this.element).each(function() {
var criterionOption = this; var criterionOption = this;
if ($(criterionOption).data('criterion') === data.criterionName) { if ($(criterionOption).data('criterion') === data.criterionName) {
if ($(criterionOption).val() == data.name) { if ($(criterionOption).val() == data.name) {
...@@ -129,12 +109,12 @@ OpenAssessment.StudentTrainingListener.prototype = { ...@@ -129,12 +109,12 @@ OpenAssessment.StudentTrainingListener.prototype = {
changed = true; changed = true;
} }
$("option[value='" + data.name + "'", criterionOption).remove(); $('option[value="' + data.name + '"]', criterionOption).remove();
// If all options have been removed from the Criterion, remove // If all options have been removed from the Criterion, remove
// the criterion entirely. // the criterion entirely.
if ($("option", criterionOption).length == 1) { if ($("option", criterionOption).length == 1) {
validator.removeAllOptions(data); handler.removeAllOptions(data);
return; return;
} }
} }
...@@ -143,8 +123,7 @@ OpenAssessment.StudentTrainingListener.prototype = { ...@@ -143,8 +123,7 @@ OpenAssessment.StudentTrainingListener.prototype = {
if (changed) { if (changed) {
this.displayAlertMsg( this.displayAlertMsg(
gettext("Option Deletion Led to Invalidation"), gettext("Option Deletion Led to Invalidation"),
gettext("Because you deleted an option, some student training " + gettext("Because you deleted an option, some student training examples had to be reset.")
"examples had to be reset.")
); );
} }
}, },
...@@ -159,9 +138,9 @@ OpenAssessment.StudentTrainingListener.prototype = { ...@@ -159,9 +138,9 @@ OpenAssessment.StudentTrainingListener.prototype = {
criterionName (str): The criterion where all options have been removed. criterionName (str): The criterion where all options have been removed.
*/ */
removeAllOptions: function(data){ removeAllOptions: function(data) {
var changed = false; var changed = false;
$('.openassessment_training_example_criterion', this.element).each(function(){ $('.openassessment_training_example_criterion', this.element).each(function() {
var criterion = this; var criterion = this;
if ($(criterion).data('criterion') == data.criterionName) { if ($(criterion).data('criterion') == data.criterionName) {
$(criterion).remove(); $(criterion).remove();
...@@ -172,8 +151,7 @@ OpenAssessment.StudentTrainingListener.prototype = { ...@@ -172,8 +151,7 @@ OpenAssessment.StudentTrainingListener.prototype = {
if (changed) { if (changed) {
this.displayAlertMsg( this.displayAlertMsg(
gettext("Option Deletion Led to Invalidation"), gettext("Option Deletion Led to Invalidation"),
gettext("The deletion of the last criterion option caused the " + gettext("The deletion of the last criterion option caused the criterion to be removed in the student training examples.")
"criterion to be removed in the student training examples.")
); );
} }
}, },
...@@ -187,19 +165,20 @@ OpenAssessment.StudentTrainingListener.prototype = { ...@@ -187,19 +165,20 @@ OpenAssessment.StudentTrainingListener.prototype = {
criterionName (str): The name of the criterion removed. criterionName (str): The name of the criterion removed.
*/ */
criterionRemove: function(data){ criterionRemove: function(data) {
var changed = false; var changed = false;
$('.openassessment_training_example_criterion[data-criterion="' var sel = '.openassessment_training_example_criterion[data-criterion="' + data.criterionName + '"]';
+ data.criterionName + '"', this.element).each(function(){ $(sel, this.element).each(
function() {
$(this).remove(); $(this).remove();
changed = true; changed = true;
}); }
);
if (changed) { if (changed) {
this.displayAlertMsg( this.displayAlertMsg(
gettext("Criterion Deletion Led to Invalidation"), gettext("Criterion Deletion Led to Invalidation"),
gettext("Because you deleted a criterion, there were student " + gettext("Because you deleted a criterion, there were student training examples where the criterion had to be removed.")
"training examples where the criterion had to be removed.")
); );
} }
}, },
...@@ -212,7 +191,7 @@ OpenAssessment.StudentTrainingListener.prototype = { ...@@ -212,7 +191,7 @@ OpenAssessment.StudentTrainingListener.prototype = {
msg (str): Message body for the alert. msg (str): Message body for the alert.
*/ */
displayAlertMsg: function(title, msg){ displayAlertMsg: function(title, msg) {
this.alert.setMessage(title, msg); this.alert.setMessage(title, msg);
this.alert.show(); this.alert.show();
}, },
...@@ -225,11 +204,14 @@ OpenAssessment.StudentTrainingListener.prototype = { ...@@ -225,11 +204,14 @@ OpenAssessment.StudentTrainingListener.prototype = {
criterionName (str): Name of the criterion criterionName (str): Name of the criterion
criterionLabel (str): New label to replace on the training examples. criterionLabel (str): New label to replace on the training examples.
*/ */
criterionUpdated: function(data){ criterionUpdated: function(data) {
$('.openassessment_training_example_criterion[data-criterion="' + var sel = '.openassessment_training_example_criterion[data-criterion="' + data.criterionName + '"]';
data.criterionName + '"', this.element).each(function(){ $(sel, this.element).each(
$(".openassessment_training_example_criterion_name_wrapper", this).text(data.criterionLabel); function() {
}); $(".openassessment_training_example_criterion_name_wrapper", this)
.text(data.criterionLabel);
}
);
}, },
/** /**
...@@ -239,7 +221,7 @@ OpenAssessment.StudentTrainingListener.prototype = { ...@@ -239,7 +221,7 @@ OpenAssessment.StudentTrainingListener.prototype = {
examples. examples.
Args: Args:
name (str): The name of the criterion being added. criterionName (str): The name of the criterion being added.
label (str): The label for the new criterion. label (str): The label for the new criterion.
*/ */
criterionAdd: function(data) { criterionAdd: function(data) {
...@@ -252,8 +234,113 @@ OpenAssessment.StudentTrainingListener.prototype = { ...@@ -252,8 +234,113 @@ OpenAssessment.StudentTrainingListener.prototype = {
.toggleClass('is--hidden', false) .toggleClass('is--hidden', false)
.appendTo(".openassessment_training_example_criteria_selections", view); .appendTo(".openassessment_training_example_criteria_selections", view);
criterion.find(".openassessment_training_example_criterion_option").attr('data-criterion', data.criterionName); criterion.find(".openassessment_training_example_criterion_option")
criterion.find(".openassessment_training_example_criterion_name_wrapper").text(data.label); .attr('data-criterion', data.criterionName);
criterion.find(".openassessment_training_example_criterion_name_wrapper")
.text(data.label);
},
/**
Retrieve the available criteria labels for training examples.
This is mainly useful for testing.
The returned array will always contain an extra example
for the client-side template for new examples.
Returns:
Array of object literals mapping criteria names to labels.
Example usage:
>>> listener.examplesCriteriaLabels();
>>> [
>>> { criterion_1: "abcd", criterion_2: "xyz" },
>>> { criterion_1: "abcd", criterion_2: "xyz" }
>>> ]
**/
examplesCriteriaLabels: function() {
var examples = [];
$(".openassessment_training_example_criteria_selections", this.element).each(
function() {
var exampleDescription = {};
$(".openassessment_training_example_criterion", this).each(
function() {
var criterionName = $(this).data('criterion');
var criterionLabel = $(".openassessment_training_example_criterion_name_wrapper", this)
.text().trim();
exampleDescription[criterionName] = criterionLabel;
}
);
examples.push(exampleDescription);
} }
);
return examples;
},
/**
Retrieve the available option labels for training examples.
This is mainly useful for testing.
The returned array will always contain an extra example
for the client-side template for new examples.
Returns:
Array of object literals
Example usage:
>>> listener.examplesOptionsLabels();
>>> [
>>> {
>>> criterion_1: {
>>> "": "Not Scored",
>>> option_1: "First Option - 1 points",
>>> option_2: "Second Option - 2 points",
>>> }
>>> },
>>> {
>>> criterion_1: {
>>> "": "Not Scored",
>>> option_1: "First Option - 1 points",
>>> option_2: "Second Option - 2 points",
>>> }
>>> }
>>> ]
**/
examplesOptionsLabels: function() {
var examples = [];
$(".openassessment_training_example_criteria_selections", this.element).each(
function() {
var exampleDescription = {};
$(".openassessment_training_example_criterion_option", this).each(
function() {
var criterionName = $(this).data('criterion');
exampleDescription[criterionName] = {};
$("option", this).each(
function() {
var optionName = $(this).val();
var optionLabel = $(this).text().trim();
exampleDescription[criterionName][optionName] = optionLabel;
}
);
}
);
examples.push(exampleDescription);
}
);
return examples;
},
/**
Format the option label, including the point value.
Args:
name (string): The option label (e.g. "Good", "Fair").
points (int): The number of points that the option is worth.
Returns:
string
**/
_generateOptionString: function(name, points) {
return name + ' - ' + points + gettext(' points');
}
}; };
/**
Notify multiple listeners that an event has occurred.
A listener is any object that implements a notification method.
For example, a listener for the notification "foo" might look like:
>>> var fooListener = {
>>> foo: function(data) {};
>>> };
Since `fooListener` implements `foo`, it will be notified when
a "foo" notification fires.
All notification methods must take a single argument, "data",
which is contains arbitrary information associated with the notification.
If a notification is fired that the listener does not respond to,
the listener will ignore the notification.
Args:
listeners (array): List of objects
**/
OpenAssessment.Notifier = function(listeners) {
this.listeners = listeners;
};
OpenAssessment.Notifier.prototype = {
/**
Fire a notification, which will be received
Args:
name (string): The name of the notification. This should
be the same as the name of the method implemented
by the listeners.
data (object literal): Arbitrary data to include with the notification.
**/
notificationFired: function(name, data) {
for (var i = 0; i < this.listeners.length; i++) {
if (typeof(this.listeners[i][name]) === 'function') {
this.listeners[i][name](data);
}
}
}
};
\ No newline at end of file
/** /**
Interface for editing rubric definitions. Interface for editing rubric definitions.
Args:
element (DOM element): The DOM element representing the rubric.
notifier (OpenAssessment.Notifier): Used to notify other views about updates to the rubric.
This view fires the following notification events:
* optionAdd: An option was added to the rubric.
* optionRemove: An option was removed from the rubric.
* optionUpdated: An option's label and/or points were updated in the rubric.
* criterionRemove: A criterion was removed from the rubric.
* criterionUpdated: A criterion's label was updated in the rubric.
**/ **/
OpenAssessment.EditRubricView = function(element) { OpenAssessment.EditRubricView = function(element, notifier) {
this.element = element; this.element = element;
this.criteriaContainer = new OpenAssessment.Container( this.criteriaContainer = new OpenAssessment.Container(
OpenAssessment.RubricCriterion, { OpenAssessment.RubricCriterion, {
containerElement: $("#openassessment_criterion_list", this.element).get(0), containerElement: $("#openassessment_criterion_list", this.element).get(0),
templateElement: $("#openassessment_criterion_template", this.element).get(0), templateElement: $("#openassessment_criterion_template", this.element).get(0),
addButtonElement: $("#openassessment_rubric_add_criterion", this.element).get(0), addButtonElement: $("#openassessment_rubric_add_criterion", this.element).get(0),
removeButtonClass: "openassessment_criterion_remove_button", removeButtonClass: "openassessment_criterion_remove_button",
containerItemClass: "openassessment_criterion" containerItemClass: "openassessment_criterion",
notifier: notifier
} }
); );
this.alert = new OpenAssessment.ValidationAlert($('#openassessment_rubric_validation_alert', this.element)); this.alert = new OpenAssessment.ValidationAlert($('#openassessment_rubric_validation_alert', this.element));
...@@ -78,16 +92,6 @@ OpenAssessment.EditRubricView.prototype = { ...@@ -78,16 +92,6 @@ OpenAssessment.EditRubricView.prototype = {
}, },
/** /**
Remove all criteria in this rubric.
Mainly useful for testing.
**/
removeAllCriteria: function() {
var items = this.criteriaContainer.getAllItems();
var view = this;
$.each(items, function() { view.criteriaContainer.remove(this); });
},
/**
Add a new criterion to the rubric. Add a new criterion to the rubric.
Uses a client-side template to create the new criterion. Uses a client-side template to create the new criterion.
**/ **/
...@@ -96,64 +100,94 @@ OpenAssessment.EditRubricView.prototype = { ...@@ -96,64 +100,94 @@ OpenAssessment.EditRubricView.prototype = {
}, },
/** /**
Retrieve a criterion item (a container item) from the rubric Remove a criterion from the rubric.
at a particular index.
Args:
item (OpenAssessment.RubricCriterion): The criterion item to remove.
**/
removeCriterion: function(item) {
this.criteriaContainer.remove(item);
},
/**
Retrieve all criteria from the rubric.
Returns:
Array of OpenAssessment.RubricCriterion objects.
**/
getAllCriteria: function() {
return this.criteriaContainer.getAllItems();
},
/**
Retrieve a criterion item from the rubric.
Args: Args:
index (int): The index of the criterion, starting from 0. index (int): The index of the criterion, starting from 0.
Returns: Returns:
OpenAssessment.RubricCriterion OpenAssessment.RubricCriterion or null
**/ **/
getCriterionItem: function(index) { getCriterionItem: function(index) {
return this.criteriaContainer.getItem(index); return this.criteriaContainer.getItem(index);
} },
};
/**
A class which controls the validation alert which we place at the top of the rubric page after
changes are made which will propagate to the settings section.
Args: /**
element (element): The element that specifies the div that the validation consists of. Add a new option to the rubric.
Returns: Args:
Openassessment.ValidationAlert criterionIndex (int): The index of the criterion to which
*/ the option will be added (starts from 0).
OpenAssessment.ValidationAlert = function (element) {
this.element = element;
this.title = $(".openassessment_alert_title", this.element);
this.message = $(".openassessment_alert_message", this.element);
};
OpenAssessment.ValidationAlert.prototype = { **/
addOption: function(criterionIndex) {
var criterionItem = this.getCriterionItem(criterionIndex);
criterionItem.optionContainer.add();
},
/** /**
Hides the alert. Remove an option from the rubric.
*/
hide: function () { Args:
this.element.addClass('is--hidden'); criterionIndex (int): The index of the criterion, starting from 0.
item (OpenAssessment.RubricOption): The option item to remove.
**/
removeOption: function(criterionIndex, item) {
var criterionItem = this.getCriterionItem(criterionIndex);
criterionItem.optionContainer.remove(item);
}, },
/** /**
Displays the alert. Retrieve all options for a particular criterion.
*/
show : function () { Args:
this.element.removeClass('is--hidden'); criterionIndex (int): The index of the criterion, starting from 0.
Returns:
Array of OpenAssessment.RubricOption
**/
getAllOptions: function(criterionIndex) {
var criterionItem = this.getCriterionItem(criterionIndex);
return criterionItem.optionContainer.getAllItems();
}, },
/** /**
Sets the message of the alert. Retrieve a particular option from the rubric.
How will this work with internationalization?
Args: Args:
newTitle (str): the new title that the message will have criterionIndex (int): The index of the criterion, starting from 0.
newMessage (str): the new text that the message's body will contain optionIndex (int): The index of the option within the criterion,
*/ starting from 0.
setMessage: function (newTitle, newMessage){
this.title.text(newTitle); Returns:
this.message.text(newMessage); OpenAssessment.RubricOption
**/
getOptionItem: function(criterionIndex, optionIndex) {
var criterionItem = this.getCriterionItem(criterionIndex);
return criterionItem.optionContainer.getItem(optionIndex);
} }
}; };
...@@ -3,7 +3,7 @@ Editing interface for OpenAssessment settings (including assessments). ...@@ -3,7 +3,7 @@ Editing interface for OpenAssessment settings (including assessments).
Args: Args:
element (DOM element): The DOM element representing this view. element (DOM element): The DOM element representing this view.
assessmentViews (array): List of assessment view objects. assessmentViews (object literal): Mapping of CSS IDs to view objects.
Returns: Returns:
OpenAssessment.EditSettingsView OpenAssessment.EditSettingsView
......
/**
A class which controls the validation alert which we place at the top of the rubric page after
changes are made which will propagate to the settings section.
Args:
element (element): The element that specifies the div that the validation consists of.
Returns:
Openassessment.ValidationAlert
*/
OpenAssessment.ValidationAlert = function (element) {
this.element = element;
this.title = $(".openassessment_alert_title", this.element);
this.message = $(".openassessment_alert_message", this.element);
};
OpenAssessment.ValidationAlert.prototype = {
/**
Hides the alert.
*/
hide: function() {
this.element.addClass('is--hidden');
},
/**
Displays the alert.
*/
show : function() {
this.element.removeClass('is--hidden');
},
/**
Sets the message of the alert.
How will this work with internationalization?
Args:
newTitle (str): the new title that the message will have
newMessage (str): the new text that the message's body will contain
*/
setMessage: function(newTitle, newMessage) {
this.title.text(newTitle);
this.message.text(newMessage);
},
/**
Check whether the alert is currently visible.
Returns:
boolean
**/
isVisible: function() {
return !this.element.hasClass('is--hidden');
},
/**
Retrieve the title of the alert.
Returns:
string
**/
getTitle: function() {
return this.title.text();
},
/**
Retrieve the message of the alert.
Returns:
string
**/
getMessage: function() {
return this.message.text();
}
};
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