Commit 85323091 by Will Daly

Split up Studio view into subviews for each tab.

Implement assessment editing views
parent 86a5d3be
if(typeof OpenAssessment=="undefined"||!OpenAssessment){OpenAssessment={}}if(typeof window.gettext==="undefined"){window.gettext=function(text){return text}}OpenAssessment.BaseView=function(runtime,element,server){this.runtime=runtime;this.element=element;this.server=server;this.responseView=new OpenAssessment.ResponseView(this.element,this.server,this);this.trainingView=new OpenAssessment.StudentTrainingView(this.element,this.server,this);this.selfView=new OpenAssessment.SelfView(this.element,this.server,this);this.peerView=new OpenAssessment.PeerView(this.element,this.server,this);this.gradeView=new OpenAssessment.GradeView(this.element,this.server,this);this.messageView=new OpenAssessment.MessageView(this.element,this.server,this);this.staffInfoView=new OpenAssessment.StaffInfoView(this.element,this.server,this)};OpenAssessment.BaseView.prototype={scrollToTop:function(){if($.scrollTo instanceof Function){$(window).scrollTo($("#openassessment__steps"),800,{offset:-50})}},setUpCollapseExpand:function(parentSel,onExpand){parentSel.find(".ui-toggle-visibility__control").click(function(eventData){var sel=$(eventData.target).closest(".ui-toggle-visibility");if(sel.hasClass("is--collapsed")&&onExpand!==undefined){onExpand()}sel.toggleClass("is--collapsed")})},load:function(){this.responseView.load();this.loadAssessmentModules();this.staffInfoView.load()},loadAssessmentModules:function(){this.trainingView.load();this.peerView.load();this.selfView.load();this.gradeView.load()},loadMessageView:function(){this.messageView.load()},toggleActionError:function(type,msg){var element=this.element;var container=null;if(type=="save"){container=".response__submission__actions"}else if(type=="submit"||type=="peer"||type=="self"||type=="student-training"){container=".step__actions"}else if(type=="feedback_assess"){container=".submission__feedback__actions"}if(container===null){if(msg!==null){console.log(msg)}}else{var msgHtml=msg===null?"":msg;$(container+" .message__content",element).html("<p>"+msgHtml+"</p>");$(container,element).toggleClass("has--error",msg!==null)}},showLoadError:function(step){var container="#openassessment__"+step;$(container).toggleClass("has--error",true);$(container+" .step__status__value i").removeClass().addClass("ico icon-warning-sign");$(container+" .step__status__value .copy").html(gettext("Unable to Load"))}};function OpenAssessmentBlock(runtime,element){var server=new OpenAssessment.Server(runtime,element);var view=new OpenAssessment.BaseView(runtime,element,server);view.load()}OpenAssessment.StudioView=function(runtime,element,server){this.runtime=runtime;this.server=server;this.liveElement=$(element);var liveElement=this.liveElement;this.settingsFieldSelectors={promptBox:$("#openassessment_prompt_editor",liveElement),titleField:$("#openassessment_title_editor",liveElement),submissionStartField:$("#openassessment_submission_start_editor",liveElement),submissionDueField:$("#openassessment_submission_due_editor",liveElement),hasPeer:$("#include_peer_assessment",liveElement),hasSelf:$("#include_self_assessment",liveElement),hasAI:$("#include_ai_assessment",liveElement),hasTraining:$("#include_student_training",liveElement),peerMustGrade:$("#peer_assessment_must_grade",liveElement),peerGradedBy:$("#peer_assessment_graded_by",liveElement),peerStart:$("#peer_assessment_start_date",liveElement),peerDue:$("#peer_assessment_due_date",liveElement),selfStart:$("#self_assessment_start_date",liveElement),selfDue:$("#self_assessment_due_date",liveElement)};var criterionHtml=$("#openassessment_criterion_1",liveElement).parent().html();this.criterionHtmlTemplate=criterionHtml.replace(new RegExp("1","g"),"C-C-C");var optionHtml=$("#openassessment_criterion_1_option_1",liveElement).parent().html();var criteriaReplaced=optionHtml.replace(new RegExp("criterion_1","g"),"criterion_C-C-C");this.optionHtmlTemplate=criteriaReplaced.replace(new RegExp("option_1","g"),"option_O-O-O");this.numberOfCriteria=0;this.numberOfOptions=[];this.rubricCriteriaSelectors=[];this.rubricFeedbackPrompt=$("#openassessment_rubric_feedback",liveElement);$("#openassessment_criterion_list",liveElement).empty();this.addNewCriterionToRubric();var view=this;$(".openassessment_save_button",liveElement).click(function(eventData){view.save()});$(".openassessment_cancel_button",liveElement).click(function(eventData){view.cancel()});$(".openassessment_editor_content_and_tabs",liveElement).tabs();view.addSettingsAssessmentCheckboxListener("ai_assessment",liveElement);view.addSettingsAssessmentCheckboxListener("self_assessment",liveElement);view.addSettingsAssessmentCheckboxListener("peer_assessment",liveElement);view.addSettingsAssessmentCheckboxListener("student_training",liveElement);$("#openassessment_rubric_add_criterion",liveElement).click(function(eventData){view.addNewCriterionToRubric(liveElement)})};OpenAssessment.StudioView.prototype={load:function(){var view=this},save:function(){var view=this;this.server.checkReleased().done(function(isReleased){if(isReleased){view.confirmPostReleaseUpdate($.proxy(view.updateEditorContext,view))}else{view.updateEditorContext()}}).fail(function(errMsg){view.showError(errMsg)})},addSettingsAssessmentCheckboxListener:function(name,liveElement){$("#include_"+name,liveElement).change(function(){$("#"+name+"_description_closed",liveElement).toggleClass("is--hidden",this.checked);$("#"+name+"_settings_editor",liveElement).toggleClass("is--hidden",!this.checked)})},confirmPostReleaseUpdate:function(onConfirm){var msg=gettext("This problem has already been released. Any changes will apply only to future assessments.");if(confirm(msg)){onConfirm()}},addNewCriterionToRubric:function(){var view=this;var liveElement=this.liveElement;var newCriterionID=this.numberOfCriteria+1;this.numberOfCriteria+=1;this.numberOfOptions[newCriterionID]=0;var criterionHtml=this.criterionHtmlTemplate.replace(new RegExp("C-C-C","g"),""+newCriterionID);$("#openassessment_criterion_list",liveElement).append(criterionHtml);liveElement=$("#openassessment_criterion_"+newCriterionID);$(".openassessment_criterion_option_list",liveElement).empty();view.rubricCriteriaSelectors[newCriterionID]={criterion:liveElement,name:$(".openassessment_criterion_name",liveElement).first(),prompt:$(".openassessment_criterion_prompt",liveElement).first(),options:[],feedback:"disabled"};$("input:radio[value=disabled]",liveElement).prop("checked",true);view.addNewOptionToCriterion(liveElement,newCriterionID);$("#openassessment_display_criterion_"+newCriterionID,liveElement).change(function(){if(this.checked){$("#openassessment_criterion_body_"+newCriterionID,liveElement).fadeIn()}else{$("#openassessment_criterion_body_"+newCriterionID,liveElement).fadeOut()}});$("#openassessment_criterion_"+newCriterionID+"_remove",liveElement).click(function(eventData){view.removeCriterionFromRubric(newCriterionID)});$("#openassessment_criterion_"+newCriterionID+"_add_option",liveElement).click(function(eventData){view.addNewOptionToCriterion(liveElement,newCriterionID)});$(".openassessment_feedback_remove_button",liveElement).click(function(eventData){$(".openassessment_criterion_feedback_direction",liveElement).fadeOut();$(".openassessment_criterion_feedback_header_open",liveElement).fadeOut();$(".openassessment_criterion_feedback_header_closed",liveElement).fadeIn();$(".openassessment_feedback_remove_button",liveElement).fadeOut();view.rubricCriteriaSelectors[newCriterionID].hasFeedback=false});$(".openassessment_criterion_feedback_header_closed",liveElement).click(function(eventData){$(".openassessment_criterion_feedback_direction",liveElement).fadeIn();$(".openassessment_criterion_feedback_header_open",liveElement).fadeIn();$(".openassessment_criterion_feedback_header_closed",liveElement).fadeOut();$(".openassessment_feedback_remove_button",liveElement).fadeIn();view.rubricCriteriaSelectors[newCriterionID].hasFeedback=true});$(".openassessment_criterion_feedback_header_closed",liveElement).hide()},removeCriterionFromRubric:function(criterionToRemove){var view=this;var numCriteria=view.numberOfCriteria;var selectors=view.rubricCriteriaSelectors;for(var i=criterionToRemove;i<numCriteria;i++){selectors[i].name.prop("value",selectors[i+1].name.prop("value"));selectors[i].prompt.prop("value",selectors[i+1].prompt.prop("value"));selectors[i].feedback=selectors[i+1].feedback;$('input:radio[value="disabled"]',selectors[i].criterion).prop("checked",true);while(view.numberOfOptions[i]<view.numberOfOptions[i+1]){view.addNewOptionToCriterion(selectors[i].criteria,i)}while(view.numberOfOptions[i]>view.numberOfOptions[i+1]){view.removeOptionFromCriterion(selectors[i].criteria,i,1)}var options1=selectors[i].options;var options2=selectors[i+1].options;var numOptions2=view.numberOfOptions[i+1];for(var j=1;j<numOptions2;j++){options1[j].points.prop("value",options2[j].points.prop("value"));options1[j].name.prop("value",options2[j].name.prop("value"));options1[j].explanation.prop("value",options2[j].explanation.prop("value"))}}view.rubricCriteriaSelectors[view.rubricCriteriaSelectors.length-1].criterion.remove();view.rubricCriteriaSelectors=view.rubricCriteriaSelectors.slice(0,numCriteria);view.numberOfOptions=view.numberOfOptions.slice(0,numCriteria);view.numberOfCriteria-=1},addNewOptionToCriterion:function(liveElement,criterionID){var view=this;var newOptionID=this.numberOfOptions[criterionID]+1;this.numberOfOptions[criterionID]+=1;var optionHtml=this.optionHtmlTemplate;optionHtml=optionHtml.replace(new RegExp("C-C-C","g"),""+criterionID);optionHtml=optionHtml.replace(new RegExp("O-O-O","g"),""+newOptionID);$("#openassessment_criterion_"+criterionID+"_options",liveElement).append(optionHtml);liveElement=$("#openassessment_criterion_"+criterionID+"_option_"+newOptionID);view.rubricCriteriaSelectors[criterionID].options[newOptionID]={option:liveElement,points:$("#openassessment_criterion_"+criterionID+"_option_"+newOptionID+"_points",liveElement),name:$("#openassessment_criterion_"+criterionID+"_option_"+newOptionID+"_name",liveElement),explanation:$("#openassessment_criterion_"+criterionID+"_option_"+newOptionID+"_explanation",liveElement)};$("#openassessment_criterion_"+criterionID+"_option_"+newOptionID+"_remove",liveElement).click(function(eventData){view.removeOptionFromCriterion(liveElement,criterionID,newOptionID)})},removeOptionFromCriterion:function(liveElement,criterionID,optionToRemove){var view=this;var numberOfOptions=view.numberOfOptions[criterionID];var optionSelectors=view.rubricCriteriaSelectors[criterionID].options;for(var i=optionToRemove;i<numberOfOptions;i++){optionSelectors[i].points.prop("value",optionSelectors[i+1].points.prop("value"));optionSelectors[i].name.prop("value",optionSelectors[i+1].name.prop("value"));optionSelectors[i].explanation.prop("value",optionSelectors[i+1].explanation.prop("value"))}optionSelectors[optionSelectors.length-1].option.remove();view.rubricCriteriaSelectors[criterionID].options=view.rubricCriteriaSelectors[criterionID].options.slice(0,optionSelectors.length-1);view.numberOfOptions[criterionID]-=1},updateEditorContext:function(){this.runtime.notify("save",{state:"start"});var rubricCriteria=[];for(var i=1;i<=this.numberOfCriteria;i++){var selectorDict=this.rubricCriteriaSelectors[i];var criterionValueDict={order_num:i-1,name:selectorDict.name.prop("value"),prompt:selectorDict.prompt.prop("value"),feedback:$("#openassessment_criterion_"+i+"_feedback").val()};var optionSelectorList=selectorDict.options;var optionValueList=[];for(var j=1;j<=this.numberOfOptions[i];j++){var optionSelectors=optionSelectorList[j];optionValueList=optionValueList.concat([{order_num:j-1,points:this._getInt(optionSelectors.points),name:optionSelectors.name.val(),explanation:optionSelectors.explanation.val()}])}criterionValueDict.options=optionValueList;rubricCriteria=rubricCriteria.concat([criterionValueDict])}var assessments=[];if(this.settingsFieldSelectors.hasTraining.prop("checked")){assessments.push({name:"student-training",examples:this.studentTrainingExamplesCodeBox.getValue()})}if(this.settingsFieldSelectors.hasPeer.prop("checked")){assessments.push({name:"peer-assessment",must_grade:this._getInt(this.settingsFieldSelectors.peerMustGrade),must_be_graded_by:this._getInt(this.settingsFieldSelectors.peerGradedBy),start:this._getDateTime(this.settingsFieldSelectors.peerStart),due:this._getDateTime(this.settingsFieldSelectors.peerDue)})}if(this.settingsFieldSelectors.hasSelf.prop("checked")){assessments.push({name:"self-assessment",start:this._getDateTime(this.settingsFieldSelectors.selfStart),due:this._getDateTime(this.settingsFieldSelectors.selfDue)})}if(this.settingsFieldSelectors.hasAI.prop("checked")){assessments.push({name:"example-based-assessment",examples:this.aiTrainingExamplesCodeBox.getValue()})}var view=this;this.server.updateEditorContext({title:this.settingsFieldSelectors.titleField.val(),prompt:this.settingsFieldSelectors.promptBox.val(),feedbackPrompt:this.rubricFeedbackPrompt.val(),submissionStart:this._getDateTime(this.settingsFieldSelectors.submissionStartField),submissionDue:this._getDateTime(this.settingsFieldSelectors.submissionDueField),criteria:rubricCriteria,assessments:assessments}).done(function(){view.runtime.notify("save",{state:"end"})}).fail(function(msg){view.showError(msg)})},cancel:function(){this.runtime.notify("cancel",{})},showError:function(errorMsg){this.runtime.notify("error",{msg:errorMsg})},_getDateTime:function(selector){var dateStr=selector.val();if(dateStr===""){return null}var timestamp=Date.parse(dateStr);if(isNaN(timestamp)){return null}return new Date(timestamp).toISOString()},_getInt:function(selector){return parseInt(selector.val(),10)}};function OpenAssessmentEditor(runtime,element){var server=new OpenAssessment.Server(runtime,element);var view=new OpenAssessment.StudioView(runtime,element,server);view.load()}OpenAssessment.GradeView=function(element,server,baseView){this.element=element;this.server=server;this.baseView=baseView};OpenAssessment.GradeView.prototype={load:function(){var view=this;var baseView=this.baseView;this.server.render("grade").done(function(html){$("#openassessment__grade",view.element).replaceWith(html);view.installHandlers()}).fail(function(errMsg){baseView.showLoadError("grade",errMsg)})},installHandlers:function(){var sel=$("#openassessment__grade",this.element);this.baseView.setUpCollapseExpand(sel);var view=this;sel.find("#feedback__submit").click(function(eventObject){eventObject.preventDefault();view.submitFeedbackOnAssessment()})},feedbackText:function(text){if(typeof text==="undefined"){return $("#feedback__remarks__value",this.element).val()}else{$("#feedback__remarks__value",this.element).val(text)}},feedbackOptions:function(options){var view=this;if(typeof options==="undefined"){return $.map($(".feedback__overall__value:checked",view.element),function(element,index){return $(element).val()})}else{$(".feedback__overall__value",this.element).prop("checked",false);$.each(options,function(index,opt){$("#feedback__overall__value--"+opt,view.element).prop("checked",true)})}},setHidden:function(sel,hidden){sel.toggleClass("is--hidden",hidden);sel.attr("aria-hidden",hidden?"true":"false")},isHidden:function(sel){return sel.hasClass("is--hidden")&&sel.attr("aria-hidden")=="true"},feedbackState:function(newState){var containerSel=$(".submission__feedback__content",this.element);var instructionsSel=containerSel.find(".submission__feedback__instructions");var fieldsSel=containerSel.find(".submission__feedback__fields");var actionsSel=containerSel.find(".submission__feedback__actions");var transitionSel=containerSel.find(".transition__status");var messageSel=containerSel.find(".message--complete");if(typeof newState==="undefined"){var isSubmitting=containerSel.hasClass("is--transitioning")&&containerSel.hasClass("is--submitting")&&!this.isHidden(transitionSel)&&this.isHidden(messageSel)&&this.isHidden(instructionsSel)&&this.isHidden(fieldsSel)&&this.isHidden(actionsSel);var hasSubmitted=containerSel.hasClass("is--submitted")&&this.isHidden(transitionSel)&&!this.isHidden(messageSel)&&this.isHidden(instructionsSel)&&this.isHidden(fieldsSel)&&this.isHidden(actionsSel);var isOpen=!containerSel.hasClass("is--submitted")&&!containerSel.hasClass("is--transitioning")&&!containerSel.hasClass("is--submitting")&&this.isHidden(transitionSel)&&this.isHidden(messageSel)&&!this.isHidden(instructionsSel)&&!this.isHidden(fieldsSel)&&!this.isHidden(actionsSel);if(isOpen){return"open"}else if(isSubmitting){return"submitting"}else if(hasSubmitted){return"submitted"}else{throw"Invalid feedback state"}}else{if(newState=="open"){containerSel.toggleClass("is--transitioning",false);containerSel.toggleClass("is--submitting",false);containerSel.toggleClass("is--submitted",false);this.setHidden(instructionsSel,false);this.setHidden(fieldsSel,false);this.setHidden(actionsSel,false);this.setHidden(transitionSel,true);this.setHidden(messageSel,true)}else if(newState=="submitting"){containerSel.toggleClass("is--transitioning",true);containerSel.toggleClass("is--submitting",true);containerSel.toggleClass("is--submitted",false);this.setHidden(instructionsSel,true);this.setHidden(fieldsSel,true);this.setHidden(actionsSel,true);this.setHidden(transitionSel,false);this.setHidden(messageSel,true)}else if(newState=="submitted"){containerSel.toggleClass("is--transitioning",false);containerSel.toggleClass("is--submitting",false);containerSel.toggleClass("is--submitted",true);this.setHidden(instructionsSel,true);this.setHidden(fieldsSel,true);this.setHidden(actionsSel,true);this.setHidden(transitionSel,true);this.setHidden(messageSel,false)}}},submitFeedbackOnAssessment:function(){var view=this;var baseView=this.baseView;$("#feedback__submit",this.element).toggleClass("is--disabled",true);view.feedbackState("submitting");this.server.submitFeedbackOnAssessment(this.feedbackText(),this.feedbackOptions()).done(function(){view.feedbackState("submitted")}).fail(function(errMsg){baseView.toggleActionError("feedback_assess",errMsg)})}};OpenAssessment.MessageView=function(element,server,baseView){this.element=element;this.server=server;this.baseView=baseView};OpenAssessment.MessageView.prototype={load:function(){var view=this;var baseView=this.baseView;this.server.render("message").done(function(html){$("#openassessment__message",view.element).replaceWith(html)}).fail(function(errMsg){baseView.showLoadError("message",errMsg)})}};OpenAssessment.PeerView=function(element,server,baseView){this.element=element;this.server=server;this.baseView=baseView;this.rubric=null};OpenAssessment.PeerView.prototype={load:function(){var view=this;this.server.render("peer_assessment").done(function(html){$("#openassessment__peer-assessment",view.element).replaceWith(html);view.installHandlers(false)}).fail(function(errMsg){view.baseView.showLoadError("peer-assessment")});view.baseView.loadMessageView()},loadContinuedAssessment:function(){var view=this;this.server.renderContinuedPeer().done(function(html){$("#openassessment__peer-assessment",view.element).replaceWith(html);view.installHandlers(true)}).fail(function(errMsg){view.baseView.showLoadError("peer-assessment")})},installHandlers:function(isContinuedAssessment){var sel=$("#openassessment__peer-assessment",this.element);var view=this;this.baseView.setUpCollapseExpand(sel,$.proxy(view.loadContinuedAssessment,view));var rubricSelector=$("#peer-assessment--001__assessment",this.element);if(rubricSelector.size()>0){var rubricElement=rubricSelector.get(0);this.rubric=new OpenAssessment.Rubric(rubricElement)}if(this.rubric!==null){this.rubric.canSubmitCallback($.proxy(view.peerSubmitEnabled,view))}sel.find("#peer-assessment--001__assessment__submit").click(function(eventObject){eventObject.preventDefault();if(!isContinuedAssessment){view.peerAssess()}else{view.continuedPeerAssess()}})},peerSubmitEnabled:function(enabled){var button=$("#peer-assessment--001__assessment__submit",this.element);if(typeof enabled==="undefined"){return!button.hasClass("is--disabled")}else{button.toggleClass("is--disabled",!enabled)}},peerAssess:function(){var view=this;var baseView=view.baseView;this.peerAssessRequest(function(){view.load();baseView.loadAssessmentModules();baseView.scrollToTop()})},continuedPeerAssess:function(){var view=this;var gradeView=this.baseView.gradeView;var baseView=view.baseView;view.peerAssessRequest(function(){view.loadContinuedAssessment();gradeView.load();baseView.scrollToTop()})},peerAssessRequest:function(successFunction){var view=this;view.baseView.toggleActionError("peer",null);view.peerSubmitEnabled(false);this.server.peerAssess(this.rubric.optionsSelected(),this.rubric.criterionFeedback(),this.overallFeedback()).done(successFunction).fail(function(errMsg){view.baseView.toggleActionError("peer",errMsg);view.peerSubmitEnabled(true)})},overallFeedback:function(overallFeedback){var selector="#assessment__rubric__question--feedback__value";if(typeof overallFeedback==="undefined"){return $(selector,this.element).val()}else{$(selector,this.element).val(overallFeedback)}}};OpenAssessment.ResponseView=function(element,server,baseView){this.element=element;this.server=server;this.baseView=baseView;this.savedResponse="";this.lastChangeTime=Date.now();this.errorOnLastSave=false;this.autoSaveTimerId=null};OpenAssessment.ResponseView.prototype={AUTO_SAVE_POLL_INTERVAL:2e3,AUTO_SAVE_WAIT:3e4,load:function(){var view=this;this.server.render("submission").done(function(html){$("#openassessment__response",view.element).replaceWith(html);view.installHandlers();view.setAutoSaveEnabled(true)}).fail(function(errMsg){view.baseView.showLoadError("response")})},installHandlers:function(){var sel=$("#openassessment__response",this.element);var view=this;this.baseView.setUpCollapseExpand(sel);this.savedResponse=this.response();var handleChange=function(eventData){view.handleResponseChanged()};sel.find("#submission__answer__value").on("change keyup drop paste",handleChange);sel.find("#step--response__submit").click(function(eventObject){eventObject.preventDefault();view.submit()});sel.find("#submission__save").click(function(eventObject){eventObject.preventDefault();view.save()})},setAutoSaveEnabled:function(enabled){if(enabled){if(this.autoSaveTimerId===null){this.autoSaveTimerId=setInterval($.proxy(this.autoSave,this),this.AUTO_SAVE_POLL_INTERVAL)}}else{if(this.autoSaveTimerId!==null){clearInterval(this.autoSaveTimerId)}}},submitEnabled:function(enabled){var sel=$("#step--response__submit",this.element);if(typeof enabled==="undefined"){return!sel.hasClass("is--disabled")}else{sel.toggleClass("is--disabled",!enabled)}},saveEnabled:function(enabled){var sel=$("#submission__save",this.element);if(typeof enabled==="undefined"){return!sel.hasClass("is--disabled")}else{sel.toggleClass("is--disabled",!enabled)}},saveStatus:function(msg){var sel=$("#response__save_status h3",this.element);if(typeof msg==="undefined"){return sel.text()}else{var label=gettext("Status of Your Response");sel.html('<span class="sr">'+label+":"+"</span>\n"+msg)}},unsavedWarningEnabled:function(enabled){if(typeof enabled==="undefined"){return window.onbeforeunload!==null}else{if(enabled){window.onbeforeunload=function(){return gettext("If you leave this page without saving or submitting your response, you'll lose any work you've done on the response.")}}else{window.onbeforeunload=null}}},response:function(text){var sel=$("#submission__answer__value",this.element);if(typeof text==="undefined"){return sel.val()}else{sel.val(text)}},responseChanged:function(){var currentResponse=$.trim(this.response());var savedResponse=$.trim(this.savedResponse);return savedResponse!==currentResponse},autoSave:function(){var timeSinceLastChange=Date.now()-this.lastChangeTime;if(this.responseChanged()&&timeSinceLastChange>this.AUTO_SAVE_WAIT&&!this.errorOnLastSave){this.save()}},handleResponseChanged:function(){var isBlank=$.trim(this.response())!=="";this.submitEnabled(isBlank);if(this.responseChanged()){this.saveEnabled(isBlank);this.saveStatus(gettext("This response has not been saved."));this.unsavedWarningEnabled(true)}this.lastChangeTime=Date.now()},save:function(){this.errorOnLastSave=false;this.saveStatus(gettext("Saving..."));this.baseView.toggleActionError("save",null);this.unsavedWarningEnabled(false);var view=this;var savedResponse=this.response();this.server.save(savedResponse).done(function(){view.savedResponse=savedResponse;var currentResponse=view.response();view.submitEnabled(currentResponse!=="");if(currentResponse==savedResponse){view.saveEnabled(false);view.saveStatus(gettext("This response has been saved but not submitted."))}}).fail(function(errMsg){view.saveStatus(gettext("Error"));view.baseView.toggleActionError("save",errMsg);view.errorOnLastSave=true})},submit:function(){this.submitEnabled(false);var view=this;var baseView=this.baseView;this.confirmSubmission().pipe(function(){var submission=$("#submission__answer__value",view.element).val();baseView.toggleActionError("response",null);return view.server.submit(submission)}).done($.proxy(view.moveToNextStep,view)).fail(function(errCode,errMsg){if(errCode=="ENOMULTI"){view.moveToNextStep()}else{if(errMsg){baseView.toggleActionError("submit",errMsg)}view.submitEnabled(true)}})},moveToNextStep:function(){this.load();this.baseView.loadAssessmentModules();this.unsavedWarningEnabled(false)},confirmSubmission:function(){var msg="You're about to submit your response for this assignment. "+"After you submit this response, you can't change it or submit a new response.";return $.Deferred(function(defer){if(confirm(msg)){defer.resolve()}else{defer.reject()}})}};OpenAssessment.Rubric=function(element){this.element=element};OpenAssessment.Rubric.prototype={criterionFeedback:function(criterionFeedback){var selector="textarea.answer__value";var feedback={};$(selector,this.element).each(function(index,sel){if(typeof criterionFeedback!=="undefined"){$(sel).val(criterionFeedback[sel.name]);feedback[sel.name]=criterionFeedback[sel.name]}else{feedback[sel.name]=$(sel).val()}});return feedback},optionsSelected:function(optionsSelected){var selector="input[type=radio]";if(typeof optionsSelected==="undefined"){var options={};$(selector+":checked",this.element).each(function(index,sel){options[sel.name]=sel.value});return options}else{$(selector,this.element).prop("checked",false);$(selector,this.element).each(function(index,sel){if(optionsSelected.hasOwnProperty(sel.name)){if(sel.value==optionsSelected[sel.name]){$(sel).prop("checked",true)}}})}},canSubmitCallback:function(callback){$(this.element).change(function(){var numChecked=$("input[type=radio]:checked",this).length;var numAvailable=$(".field--radio.assessment__rubric__question",this).length;var canSubmit=numChecked==numAvailable;callback(canSubmit)})},showCorrections:function(corrections){var selector="input[type=radio]";var hasErrors=false;$(selector,this.element).each(function(index,sel){var listItem=$(sel).parents(".assessment__rubric__question");if(corrections.hasOwnProperty(sel.name)){hasErrors=true;listItem.find(".message--incorrect").removeClass("is--hidden");listItem.find(".message--correct").addClass("is--hidden")}else{listItem.find(".message--correct").removeClass("is--hidden");listItem.find(".message--incorrect").addClass("is--hidden")}});return hasErrors}};OpenAssessment.SelfView=function(element,server,baseView){this.element=element;this.server=server;this.baseView=baseView;this.rubric=null};OpenAssessment.SelfView.prototype={load:function(){var view=this;this.server.render("self_assessment").done(function(html){$("#openassessment__self-assessment",view.element).replaceWith(html);view.installHandlers()}).fail(function(errMsg){view.showLoadError("self-assessment")})},installHandlers:function(){var view=this;var sel=$("#openassessment__self-assessment",view.element);this.baseView.setUpCollapseExpand(sel);var rubricSelector=$("#self-assessment--001__assessment",this.element);if(rubricSelector.size()>0){var rubricElement=rubricSelector.get(0);this.rubric=new OpenAssessment.Rubric(rubricElement)}if(this.rubric!==null){this.rubric.canSubmitCallback($.proxy(this.selfSubmitEnabled,this))}sel.find("#self-assessment--001__assessment__submit").click(function(eventObject){eventObject.preventDefault();view.selfAssess()})},selfSubmitEnabled:function(enabled){var button=$("#self-assessment--001__assessment__submit",this.element);if(typeof enabled==="undefined"){return!button.hasClass("is--disabled")}else{button.toggleClass("is--disabled",!enabled)}},selfAssess:function(){var view=this;var baseView=this.baseView;baseView.toggleActionError("self",null);view.selfSubmitEnabled(false);var options=this.rubric.optionsSelected();this.server.selfAssess(options).done(function(){baseView.loadAssessmentModules();baseView.scrollToTop()}).fail(function(errMsg){baseView.toggleActionError("self",errMsg);view.selfSubmitEnabled(true)})}};OpenAssessment.Server=function(runtime,element){this.runtime=runtime;this.element=element};OpenAssessment.Server.prototype={url:function(handler){return this.runtime.handlerUrl(this.element,handler)},render:function(component){var url=this.url("render_"+component);return $.Deferred(function(defer){$.ajax({url:url,type:"POST",dataType:"html"}).done(function(data){defer.resolveWith(this,[data])}).fail(function(data){defer.rejectWith(this,[gettext("This section could not be loaded.")])})}).promise()},renderContinuedPeer:function(){var url=this.url("render_peer_assessment");return $.Deferred(function(defer){$.ajax({url:url,type:"POST",dataType:"html",data:{continue_grading:true}}).done(function(data){defer.resolveWith(this,[data])}).fail(function(data){defer.rejectWith(this,[gettext("This section could not be loaded.")])})}).promise()},studentInfo:function(student_id){var url=this.url("render_student_info");return $.Deferred(function(defer){$.ajax({url:url,type:"POST",dataType:"html",data:{student_id:student_id}}).done(function(data){defer.resolveWith(this,[data])}).fail(function(data){defer.rejectWith(this,[gettext("This section could not be loaded.")])})}).promise()},submit:function(submission){var url=this.url("submit");return $.Deferred(function(defer){$.ajax({type:"POST",url:url,data:JSON.stringify({submission:submission})}).done(function(data){var success=data[0];if(success){var studentId=data[1];var attemptNum=data[2];defer.resolveWith(this,[studentId,attemptNum])}else{var errorNum=data[1];var errorMsg=data[2];defer.rejectWith(this,[errorNum,errorMsg])}}).fail(function(data){defer.rejectWith(this,["AJAX",gettext("This response could not be submitted.")])})}).promise()},save:function(submission){var url=this.url("save_submission");return $.Deferred(function(defer){$.ajax({type:"POST",url:url,data:JSON.stringify({submission:submission})}).done(function(data){if(data.success){defer.resolve()}else{defer.rejectWith(this,[data.msg])}}).fail(function(data){defer.rejectWith(this,[gettext("This response could not be saved.")])})}).promise()},submitFeedbackOnAssessment:function(text,options){var url=this.url("submit_feedback");var payload=JSON.stringify({feedback_text:text,feedback_options:options});return $.Deferred(function(defer){$.ajax({type:"POST",url:url,data:payload}).done(function(data){if(data.success){defer.resolve()}else{defer.rejectWith(this,[data.msg])}}).fail(function(data){defer.rejectWith(this,[gettext("This feedback could not be submitted.")])})}).promise()},peerAssess:function(optionsSelected,criterionFeedback,overallFeedback){var url=this.url("peer_assess");var payload=JSON.stringify({options_selected:optionsSelected,criterion_feedback:criterionFeedback,overall_feedback:overallFeedback});return $.Deferred(function(defer){$.ajax({type:"POST",url:url,data:payload}).done(function(data){if(data.success){defer.resolve()}else{defer.rejectWith(this,[data.msg])}}).fail(function(data){defer.rejectWith(this,[gettext("This assessment could not be submitted.")])})}).promise()},selfAssess:function(optionsSelected){var url=this.url("self_assess");
var payload=JSON.stringify({options_selected:optionsSelected});return $.Deferred(function(defer){$.ajax({type:"POST",url:url,data:payload}).done(function(data){if(data.success){defer.resolve()}else{defer.rejectWith(this,[data.msg])}}).fail(function(data){defer.rejectWith(this,[gettext("This assessment could not be submitted.")])})})},trainingAssess:function(optionsSelected){var url=this.url("training_assess");var payload=JSON.stringify({options_selected:optionsSelected});return $.Deferred(function(defer){$.ajax({type:"POST",url:url,data:payload}).done(function(data){if(data.success){defer.resolveWith(this,[data.corrections])}else{defer.rejectWith(this,[data.msg])}}).fail(function(data){defer.rejectWith(this,[gettext("This assessment could not be submitted.")])})})},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});return $.Deferred(function(defer){$.ajax({type:"POST",url:url,data:payload}).done(function(data){if(data.success){defer.resolve()}else{defer.rejectWith(this,[data.msg])}}).fail(function(data){defer.rejectWith(this,[gettext("This problem could not be saved.")])})}).promise()},checkReleased:function(){var url=this.url("check_released");var payload='""';return $.Deferred(function(defer){$.ajax({type:"POST",url:url,data:payload}).done(function(data){if(data.success){defer.resolveWith(this,[data.is_released])}else{defer.rejectWith(this,[data.msg])}}).fail(function(data){defer.rejectWith(this,[gettext("The server could not be contacted.")])})}).promise()}};if(typeof OpenAssessment=="undefined"||!OpenAssessment){OpenAssessment={}}if(typeof window.gettext==="undefined"){window.gettext=function(text){return text}}OpenAssessment.StaffInfoView=function(element,server,baseView){this.element=element;this.server=server;this.baseView=baseView};OpenAssessment.StaffInfoView.prototype={load:function(){var view=this;if($("#openassessment__staff-info",view.element).length>0){this.server.render("staff_info").done(function(html){$("#openassessment__staff-info",view.element).replaceWith(html);view.installHandlers()}).fail(function(errMsg){view.baseView.showLoadError("staff_info")})}},loadStudentInfo:function(){var view=this;var sel=$("#openassessment__staff-info",this.element);var student_id=sel.find("#openassessment__student_id").val();this.server.studentInfo(student_id).done(function(html){$("#openassessment__student-info",view.element).replaceWith(html)}).fail(function(errMsg){view.showLoadError("student_info")})},installHandlers:function(){var sel=$("#openassessment__staff-info",this.element);var view=this;if(sel.length<=0){return}this.baseView.setUpCollapseExpand(sel,function(){});sel.find("#openassessment_student_info_form").submit(function(eventObject){eventObject.preventDefault();view.loadStudentInfo()});sel.find("#submit_student_id").click(function(eventObject){eventObject.preventDefault();view.loadStudentInfo()});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
if (typeof OpenAssessment == "undefined" || !OpenAssessment) {
OpenAssessment = {};
}
if (typeof window.gettext === "undefined") {
window.gettext = function(text) {
return text;
};
}
OpenAssessment.BaseView = function(runtime, element, server) {
this.runtime = runtime;
this.element = element;
this.server = server;
this.responseView = new OpenAssessment.ResponseView(this.element, this.server, this);
this.trainingView = new OpenAssessment.StudentTrainingView(this.element, this.server, this);
this.selfView = new OpenAssessment.SelfView(this.element, this.server, this);
this.peerView = new OpenAssessment.PeerView(this.element, this.server, this);
this.gradeView = new OpenAssessment.GradeView(this.element, this.server, this);
this.messageView = new OpenAssessment.MessageView(this.element, this.server, this);
this.staffInfoView = new OpenAssessment.StaffInfoView(this.element, this.server, this);
};
OpenAssessment.BaseView.prototype = {
scrollToTop: function() {
if ($.scrollTo instanceof Function) {
$(window).scrollTo($("#openassessment__steps"), 800, {
offset: -50
});
}
},
setUpCollapseExpand: function(parentSel, onExpand) {
parentSel.find(".ui-toggle-visibility__control").click(function(eventData) {
var sel = $(eventData.target).closest(".ui-toggle-visibility");
if (sel.hasClass("is--collapsed") && onExpand !== undefined) {
onExpand();
}
sel.toggleClass("is--collapsed");
});
},
load: function() {
this.responseView.load();
this.loadAssessmentModules();
this.staffInfoView.load();
},
loadAssessmentModules: function() {
this.trainingView.load();
this.peerView.load();
this.selfView.load();
this.gradeView.load();
},
loadMessageView: function() {
this.messageView.load();
},
toggleActionError: function(type, msg) {
var element = this.element;
var container = null;
if (type == "save") {
container = ".response__submission__actions";
} else if (type == "submit" || type == "peer" || type == "self" || type == "student-training") {
container = ".step__actions";
} else if (type == "feedback_assess") {
container = ".submission__feedback__actions";
}
if (container === null) {
if (msg !== null) {
console.log(msg);
}
} else {
var msgHtml = msg === null ? "" : msg;
$(container + " .message__content", element).html("<p>" + msgHtml + "</p>");
$(container, element).toggleClass("has--error", msg !== null);
}
},
showLoadError: function(step) {
var container = "#openassessment__" + step;
$(container).toggleClass("has--error", true);
$(container + " .step__status__value i").removeClass().addClass("ico icon-warning-sign");
$(container + " .step__status__value .copy").html(gettext("Unable to Load"));
}
};
function OpenAssessmentBlock(runtime, element) {
var server = new OpenAssessment.Server(runtime, element);
var view = new OpenAssessment.BaseView(runtime, element, server);
view.load();
}
OpenAssessment.StudioView = function(runtime, element, server) {
this.runtime = runtime;
this.server = server;
this.promptView = new OpenAssessment.EditPromptView($("#oa_prompt_editor_wrapper", this.element).get(0));
this.settingsView = new OpenAssessment.EditSettingsView($("#oa_basic_settings_editor", this.element).get(0), [ new OpenAssessment.EditPeerAssessmentView($("#oa_peer_assessment_editor", this.element).get(0)), new OpenAssessment.EditSelfAssessmentView($("#oa_self_assessment_editor", this.element).get(0)), new OpenAssessment.EditStudentTrainingView($("#oa_student_training_editor", this.element).get(0)), new OpenAssessment.EditExampleBasedAssessmentView($("#oa_ai_assessment_editor", this.element).get(0)) ]);
this.liveElement = $(element);
var liveElement = this.liveElement;
var criterionHtml = $("#openassessment_criterion_1", liveElement).parent().html();
this.criterionHtmlTemplate = criterionHtml.replace(new RegExp("1", "g"), "C-C-C");
var optionHtml = $("#openassessment_criterion_1_option_1", liveElement).parent().html();
var criteriaReplaced = optionHtml.replace(new RegExp("criterion_1", "g"), "criterion_C-C-C");
this.optionHtmlTemplate = criteriaReplaced.replace(new RegExp("option_1", "g"), "option_O-O-O");
this.numberOfCriteria = 0;
this.numberOfOptions = [];
this.rubricCriteriaSelectors = [];
this.rubricFeedbackPrompt = $("#openassessment_rubric_feedback", liveElement);
$("#openassessment_criterion_list", liveElement).empty();
this.addNewCriterionToRubric();
var view = this;
$(".openassessment_save_button", this.element).click(function(eventData) {
view.save();
});
$(".openassessment_cancel_button", this.element).click(function(eventData) {
view.cancel();
});
$(".openassessment_editor_content_and_tabs", this.element).tabs();
$("#openassessment_rubric_add_criterion", this.element).click(function(eventData) {
view.addNewCriterionToRubric(liveElement);
});
};
OpenAssessment.StudioView.prototype = {
save: function() {
var view = this;
this.server.checkReleased().done(function(isReleased) {
if (isReleased) {
view.confirmPostReleaseUpdate($.proxy(view.updateEditorContext, view));
} else {
view.updateEditorContext();
}
}).fail(function(errMsg) {
view.showError(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();
}
},
addNewCriterionToRubric: function() {
var view = this;
var liveElement = this.liveElement;
var newCriterionID = this.numberOfCriteria + 1;
this.numberOfCriteria += 1;
this.numberOfOptions[newCriterionID] = 0;
var criterionHtml = this.criterionHtmlTemplate.replace(new RegExp("C-C-C", "g"), "" + newCriterionID);
$("#openassessment_criterion_list", liveElement).append(criterionHtml);
liveElement = $("#openassessment_criterion_" + newCriterionID);
$(".openassessment_criterion_option_list", liveElement).empty();
view.rubricCriteriaSelectors[newCriterionID] = {
criterion: liveElement,
name: $(".openassessment_criterion_name", liveElement).first(),
prompt: $(".openassessment_criterion_prompt", liveElement).first(),
options: [],
feedback: "disabled"
};
$("input:radio[value=disabled]", liveElement).prop("checked", true);
view.addNewOptionToCriterion(liveElement, newCriterionID);
$("#openassessment_display_criterion_" + newCriterionID, liveElement).change(function() {
if (this.checked) {
$("#openassessment_criterion_body_" + newCriterionID, liveElement).fadeIn();
} else {
$("#openassessment_criterion_body_" + newCriterionID, liveElement).fadeOut();
}
});
$("#openassessment_criterion_" + newCriterionID + "_remove", liveElement).click(function(eventData) {
view.removeCriterionFromRubric(newCriterionID);
});
$("#openassessment_criterion_" + newCriterionID + "_add_option", liveElement).click(function(eventData) {
view.addNewOptionToCriterion(liveElement, newCriterionID);
});
$(".openassessment_feedback_remove_button", liveElement).click(function(eventData) {
$(".openassessment_criterion_feedback_direction", liveElement).fadeOut();
$(".openassessment_criterion_feedback_header_open", liveElement).fadeOut();
$(".openassessment_criterion_feedback_header_closed", liveElement).fadeIn();
$(".openassessment_feedback_remove_button", liveElement).fadeOut();
view.rubricCriteriaSelectors[newCriterionID].hasFeedback = false;
});
$(".openassessment_criterion_feedback_header_closed", liveElement).click(function(eventData) {
$(".openassessment_criterion_feedback_direction", liveElement).fadeIn();
$(".openassessment_criterion_feedback_header_open", liveElement).fadeIn();
$(".openassessment_criterion_feedback_header_closed", liveElement).fadeOut();
$(".openassessment_feedback_remove_button", liveElement).fadeIn();
view.rubricCriteriaSelectors[newCriterionID].hasFeedback = true;
});
$(".openassessment_criterion_feedback_header_closed", liveElement).hide();
},
removeCriterionFromRubric: function(criterionToRemove) {
var view = this;
var numCriteria = view.numberOfCriteria;
var selectors = view.rubricCriteriaSelectors;
for (var i = criterionToRemove; i < numCriteria; i++) {
selectors[i].name.prop("value", selectors[i + 1].name.prop("value"));
selectors[i].prompt.prop("value", selectors[i + 1].prompt.prop("value"));
selectors[i].feedback = selectors[i + 1].feedback;
$('input:radio[value="disabled"]', selectors[i].criterion).prop("checked", true);
while (view.numberOfOptions[i] < view.numberOfOptions[i + 1]) {
view.addNewOptionToCriterion(selectors[i].criteria, i);
}
while (view.numberOfOptions[i] > view.numberOfOptions[i + 1]) {
view.removeOptionFromCriterion(selectors[i].criteria, i, 1);
}
var options1 = selectors[i].options;
var options2 = selectors[i + 1].options;
var numOptions2 = view.numberOfOptions[i + 1];
for (var j = 1; j < numOptions2; j++) {
options1[j].points.prop("value", options2[j].points.prop("value"));
options1[j].name.prop("value", options2[j].name.prop("value"));
options1[j].explanation.prop("value", options2[j].explanation.prop("value"));
}
}
view.rubricCriteriaSelectors[view.rubricCriteriaSelectors.length - 1].criterion.remove();
view.rubricCriteriaSelectors = view.rubricCriteriaSelectors.slice(0, numCriteria);
view.numberOfOptions = view.numberOfOptions.slice(0, numCriteria);
view.numberOfCriteria -= 1;
},
addNewOptionToCriterion: function(liveElement, criterionID) {
var view = this;
var newOptionID = this.numberOfOptions[criterionID] + 1;
this.numberOfOptions[criterionID] += 1;
var optionHtml = this.optionHtmlTemplate;
optionHtml = optionHtml.replace(new RegExp("C-C-C", "g"), "" + criterionID);
optionHtml = optionHtml.replace(new RegExp("O-O-O", "g"), "" + newOptionID);
$("#openassessment_criterion_" + criterionID + "_options", liveElement).append(optionHtml);
liveElement = $("#openassessment_criterion_" + criterionID + "_option_" + newOptionID);
view.rubricCriteriaSelectors[criterionID].options[newOptionID] = {
option: liveElement,
points: $("#openassessment_criterion_" + criterionID + "_option_" + newOptionID + "_points", liveElement),
name: $("#openassessment_criterion_" + criterionID + "_option_" + newOptionID + "_name", liveElement),
explanation: $("#openassessment_criterion_" + criterionID + "_option_" + newOptionID + "_explanation", liveElement)
};
$("#openassessment_criterion_" + criterionID + "_option_" + newOptionID + "_remove", liveElement).click(function(eventData) {
view.removeOptionFromCriterion(liveElement, criterionID, newOptionID);
});
},
removeOptionFromCriterion: function(liveElement, criterionID, optionToRemove) {
var view = this;
var numberOfOptions = view.numberOfOptions[criterionID];
var optionSelectors = view.rubricCriteriaSelectors[criterionID].options;
for (var i = optionToRemove; i < numberOfOptions; i++) {
optionSelectors[i].points.prop("value", optionSelectors[i + 1].points.prop("value"));
optionSelectors[i].name.prop("value", optionSelectors[i + 1].name.prop("value"));
optionSelectors[i].explanation.prop("value", optionSelectors[i + 1].explanation.prop("value"));
}
optionSelectors[optionSelectors.length - 1].option.remove();
view.rubricCriteriaSelectors[criterionID].options = view.rubricCriteriaSelectors[criterionID].options.slice(0, optionSelectors.length - 1);
view.numberOfOptions[criterionID] -= 1;
},
updateEditorContext: function() {
this.runtime.notify("save", {
state: "start"
});
var rubricCriteria = [];
for (var i = 1; i <= this.numberOfCriteria; i++) {
var selectorDict = this.rubricCriteriaSelectors[i];
var criterionValueDict = {
order_num: i - 1,
name: selectorDict.name.prop("value"),
prompt: selectorDict.prompt.prop("value"),
feedback: $("#openassessment_criterion_" + i + "_feedback").val()
};
var optionSelectorList = selectorDict.options;
var optionValueList = [];
for (var j = 1; j <= this.numberOfOptions[i]; j++) {
var optionSelectors = optionSelectorList[j];
optionValueList = optionValueList.concat([ {
order_num: j - 1,
points: parseInt(optionSelectors.points.val(), 10),
name: optionSelectors.name.val(),
explanation: optionSelectors.explanation.val()
} ]);
}
criterionValueDict.options = optionValueList;
rubricCriteria = rubricCriteria.concat([ criterionValueDict ]);
}
var view = this;
this.server.updateEditorContext({
title: view.settingsView.displayName(),
prompt: view.promptView.promptText(),
feedbackPrompt: this.rubricFeedbackPrompt.val(),
submissionStart: view.settingsView.submissionStart(),
submissionDue: view.settingsView.submissionDue(),
criteria: rubricCriteria,
assessments: view.settingsView.assessmentsDescription()
}).done(function() {
view.runtime.notify("save", {
state: "end"
});
}).fail(function(msg) {
view.showError(msg);
});
},
cancel: function() {
this.runtime.notify("cancel", {});
},
showError: function(errorMsg) {
this.runtime.notify("error", {
msg: errorMsg
});
}
};
function OpenAssessmentEditor(runtime, element) {
var server = new OpenAssessment.Server(runtime, element);
var view = new OpenAssessment.StudioView(runtime, element, server);
}
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).fadeOut("fast");
$(this.shownSelector, this.element).fadeIn();
},
hide: function() {
$(this.hiddenSelector, this.element).fadeIn();
$(this.shownSelector, this.element).fadeOut();
}
};
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");
};
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(datetime) {
var sel = $("#peer_assessment_start_date", this.element);
return OpenAssessment.Fields.datetimeField(sel, datetime);
},
dueDatetime: function(datetime) {
var sel = $("#peer_assessment_due_date", this.element);
return OpenAssessment.Fields.datetimeField(sel, datetime);
}
};
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");
};
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(datetime) {
var sel = $("#self_assessment_start_date", this.element);
return OpenAssessment.Fields.datetimeField(sel, datetime);
},
dueDatetime: function(datetime) {
var sel = $("#self_assessment_due_date", this.element);
return OpenAssessment.Fields.datetimeField(sel, datetime);
}
};
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");
};
OpenAssessment.EditStudentTrainingView.prototype = {
description: function() {
return {
examples: this.exampleDefinitions()
};
},
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);
}
};
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: 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);
}
};
OpenAssessment.Fields = {
stringField: function(sel, value) {
if (typeof value !== "undefined") {
sel.val(value);
}
return sel.val();
},
datetimeField: function(sel, value) {
if (typeof value !== "undefined") {
sel.val(value);
}
var fieldValue = sel.val();
return fieldValue !== "" ? fieldValue : null;
},
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.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;
};
OpenAssessment.EditRubricView.prototype = {
load: function() {},
criteriaDefinition: function() {}
};
OpenAssessment.EditSettingsView = function(element, assessmentViews) {
this.element = element;
this.assessmentViews = assessmentViews;
};
OpenAssessment.EditSettingsView.prototype = {
displayName: function(name) {
var sel = $("#openassessment_title_editor", this.element);
return OpenAssessment.Fields.stringField(sel, name);
},
submissionStart: function(datetime) {
var sel = $("#openassessment_submission_start_editor", this.element);
return OpenAssessment.Fields.datetimeField(sel, datetime);
},
submissionDue: function(datetime) {
var sel = $("#openassessment_submission_start_editor", this.element);
return OpenAssessment.Fields.datetimeField(sel, datetime);
},
imageSubmissionEnabled: function(isEnabled) {
var sel = $("#openassessment_submission_image_editor", this.element);
if (typeof isEnabled !== "undefined") {
if (isEnabled) {
sel.val(1);
} else {
sel.val(0);
}
}
return sel.val() == 1;
},
assessmentsDescription: function() {
assessmentDescList = [];
for (var idx in this.assessmentViews) {
var asmntView = this.assessmentViews[idx];
if (asmntView.isEnabled()) {
var description = asmntView.description();
description["name"] = asmntView.name;
assessmentDescList.push(description);
}
}
return assessmentDescList;
}
};
OpenAssessment.GradeView = function(element, server, baseView) {
this.element = element;
this.server = server;
this.baseView = baseView;
};
OpenAssessment.GradeView.prototype = {
load: function() {
var view = this;
var baseView = this.baseView;
this.server.render("grade").done(function(html) {
$("#openassessment__grade", view.element).replaceWith(html);
view.installHandlers();
}).fail(function(errMsg) {
baseView.showLoadError("grade", errMsg);
});
},
installHandlers: function() {
var sel = $("#openassessment__grade", this.element);
this.baseView.setUpCollapseExpand(sel);
var view = this;
sel.find("#feedback__submit").click(function(eventObject) {
eventObject.preventDefault();
view.submitFeedbackOnAssessment();
});
},
feedbackText: function(text) {
if (typeof text === "undefined") {
return $("#feedback__remarks__value", this.element).val();
} else {
$("#feedback__remarks__value", this.element).val(text);
}
},
feedbackOptions: function(options) {
var view = this;
if (typeof options === "undefined") {
return $.map($(".feedback__overall__value:checked", view.element), function(element, index) {
return $(element).val();
});
} else {
$(".feedback__overall__value", this.element).prop("checked", false);
$.each(options, function(index, opt) {
$("#feedback__overall__value--" + opt, view.element).prop("checked", true);
});
}
},
setHidden: function(sel, hidden) {
sel.toggleClass("is--hidden", hidden);
sel.attr("aria-hidden", hidden ? "true" : "false");
},
isHidden: function(sel) {
return sel.hasClass("is--hidden") && sel.attr("aria-hidden") == "true";
},
feedbackState: function(newState) {
var containerSel = $(".submission__feedback__content", this.element);
var instructionsSel = containerSel.find(".submission__feedback__instructions");
var fieldsSel = containerSel.find(".submission__feedback__fields");
var actionsSel = containerSel.find(".submission__feedback__actions");
var transitionSel = containerSel.find(".transition__status");
var messageSel = containerSel.find(".message--complete");
if (typeof newState === "undefined") {
var isSubmitting = containerSel.hasClass("is--transitioning") && containerSel.hasClass("is--submitting") && !this.isHidden(transitionSel) && this.isHidden(messageSel) && this.isHidden(instructionsSel) && this.isHidden(fieldsSel) && this.isHidden(actionsSel);
var hasSubmitted = containerSel.hasClass("is--submitted") && this.isHidden(transitionSel) && !this.isHidden(messageSel) && this.isHidden(instructionsSel) && this.isHidden(fieldsSel) && this.isHidden(actionsSel);
var isOpen = !containerSel.hasClass("is--submitted") && !containerSel.hasClass("is--transitioning") && !containerSel.hasClass("is--submitting") && this.isHidden(transitionSel) && this.isHidden(messageSel) && !this.isHidden(instructionsSel) && !this.isHidden(fieldsSel) && !this.isHidden(actionsSel);
if (isOpen) {
return "open";
} else if (isSubmitting) {
return "submitting";
} else if (hasSubmitted) {
return "submitted";
} else {
throw "Invalid feedback state";
}
} else {
if (newState == "open") {
containerSel.toggleClass("is--transitioning", false);
containerSel.toggleClass("is--submitting", false);
containerSel.toggleClass("is--submitted", false);
this.setHidden(instructionsSel, false);
this.setHidden(fieldsSel, false);
this.setHidden(actionsSel, false);
this.setHidden(transitionSel, true);
this.setHidden(messageSel, true);
} else if (newState == "submitting") {
containerSel.toggleClass("is--transitioning", true);
containerSel.toggleClass("is--submitting", true);
containerSel.toggleClass("is--submitted", false);
this.setHidden(instructionsSel, true);
this.setHidden(fieldsSel, true);
this.setHidden(actionsSel, true);
this.setHidden(transitionSel, false);
this.setHidden(messageSel, true);
} else if (newState == "submitted") {
containerSel.toggleClass("is--transitioning", false);
containerSel.toggleClass("is--submitting", false);
containerSel.toggleClass("is--submitted", true);
this.setHidden(instructionsSel, true);
this.setHidden(fieldsSel, true);
this.setHidden(actionsSel, true);
this.setHidden(transitionSel, true);
this.setHidden(messageSel, false);
}
}
},
submitFeedbackOnAssessment: function() {
var view = this;
var baseView = this.baseView;
$("#feedback__submit", this.element).toggleClass("is--disabled", true);
view.feedbackState("submitting");
this.server.submitFeedbackOnAssessment(this.feedbackText(), this.feedbackOptions()).done(function() {
view.feedbackState("submitted");
}).fail(function(errMsg) {
baseView.toggleActionError("feedback_assess", errMsg);
});
}
};
OpenAssessment.MessageView = function(element, server, baseView) {
this.element = element;
this.server = server;
this.baseView = baseView;
};
OpenAssessment.MessageView.prototype = {
load: function() {
var view = this;
var baseView = this.baseView;
this.server.render("message").done(function(html) {
$("#openassessment__message", view.element).replaceWith(html);
}).fail(function(errMsg) {
baseView.showLoadError("message", errMsg);
});
}
};
OpenAssessment.PeerView = function(element, server, baseView) {
this.element = element;
this.server = server;
this.baseView = baseView;
this.rubric = null;
};
OpenAssessment.PeerView.prototype = {
load: function() {
var view = this;
this.server.render("peer_assessment").done(function(html) {
$("#openassessment__peer-assessment", view.element).replaceWith(html);
view.installHandlers(false);
}).fail(function(errMsg) {
view.baseView.showLoadError("peer-assessment");
});
view.baseView.loadMessageView();
},
loadContinuedAssessment: function() {
var view = this;
this.server.renderContinuedPeer().done(function(html) {
$("#openassessment__peer-assessment", view.element).replaceWith(html);
view.installHandlers(true);
}).fail(function(errMsg) {
view.baseView.showLoadError("peer-assessment");
});
},
installHandlers: function(isContinuedAssessment) {
var sel = $("#openassessment__peer-assessment", this.element);
var view = this;
this.baseView.setUpCollapseExpand(sel, $.proxy(view.loadContinuedAssessment, view));
var rubricSelector = $("#peer-assessment--001__assessment", this.element);
if (rubricSelector.size() > 0) {
var rubricElement = rubricSelector.get(0);
this.rubric = new OpenAssessment.Rubric(rubricElement);
}
if (this.rubric !== null) {
this.rubric.canSubmitCallback($.proxy(view.peerSubmitEnabled, view));
}
sel.find("#peer-assessment--001__assessment__submit").click(function(eventObject) {
eventObject.preventDefault();
if (!isContinuedAssessment) {
view.peerAssess();
} else {
view.continuedPeerAssess();
}
});
},
peerSubmitEnabled: function(enabled) {
var button = $("#peer-assessment--001__assessment__submit", this.element);
if (typeof enabled === "undefined") {
return !button.hasClass("is--disabled");
} else {
button.toggleClass("is--disabled", !enabled);
}
},
peerAssess: function() {
var view = this;
var baseView = view.baseView;
this.peerAssessRequest(function() {
view.load();
baseView.loadAssessmentModules();
baseView.scrollToTop();
});
},
continuedPeerAssess: function() {
var view = this;
var gradeView = this.baseView.gradeView;
var baseView = view.baseView;
view.peerAssessRequest(function() {
view.loadContinuedAssessment();
gradeView.load();
baseView.scrollToTop();
});
},
peerAssessRequest: function(successFunction) {
var view = this;
view.baseView.toggleActionError("peer", null);
view.peerSubmitEnabled(false);
this.server.peerAssess(this.rubric.optionsSelected(), this.rubric.criterionFeedback(), this.overallFeedback()).done(successFunction).fail(function(errMsg) {
view.baseView.toggleActionError("peer", errMsg);
view.peerSubmitEnabled(true);
});
},
overallFeedback: function(overallFeedback) {
var selector = "#assessment__rubric__question--feedback__value";
if (typeof overallFeedback === "undefined") {
return $(selector, this.element).val();
} else {
$(selector, this.element).val(overallFeedback);
}
}
};
OpenAssessment.ResponseView = function(element, server, baseView) {
this.element = element;
this.server = server;
this.baseView = baseView;
this.savedResponse = "";
this.lastChangeTime = Date.now();
this.errorOnLastSave = false;
this.autoSaveTimerId = null;
};
OpenAssessment.ResponseView.prototype = {
AUTO_SAVE_POLL_INTERVAL: 2e3,
AUTO_SAVE_WAIT: 3e4,
load: function() {
var view = this;
this.server.render("submission").done(function(html) {
$("#openassessment__response", view.element).replaceWith(html);
view.installHandlers();
view.setAutoSaveEnabled(true);
}).fail(function(errMsg) {
view.baseView.showLoadError("response");
});
},
installHandlers: function() {
var sel = $("#openassessment__response", this.element);
var view = this;
this.baseView.setUpCollapseExpand(sel);
this.savedResponse = this.response();
var handleChange = function(eventData) {
view.handleResponseChanged();
};
sel.find("#submission__answer__value").on("change keyup drop paste", handleChange);
sel.find("#step--response__submit").click(function(eventObject) {
eventObject.preventDefault();
view.submit();
});
sel.find("#submission__save").click(function(eventObject) {
eventObject.preventDefault();
view.save();
});
},
setAutoSaveEnabled: function(enabled) {
if (enabled) {
if (this.autoSaveTimerId === null) {
this.autoSaveTimerId = setInterval($.proxy(this.autoSave, this), this.AUTO_SAVE_POLL_INTERVAL);
}
} else {
if (this.autoSaveTimerId !== null) {
clearInterval(this.autoSaveTimerId);
}
}
},
submitEnabled: function(enabled) {
var sel = $("#step--response__submit", this.element);
if (typeof enabled === "undefined") {
return !sel.hasClass("is--disabled");
} else {
sel.toggleClass("is--disabled", !enabled);
}
},
saveEnabled: function(enabled) {
var sel = $("#submission__save", this.element);
if (typeof enabled === "undefined") {
return !sel.hasClass("is--disabled");
} else {
sel.toggleClass("is--disabled", !enabled);
}
},
saveStatus: function(msg) {
var sel = $("#response__save_status h3", this.element);
if (typeof msg === "undefined") {
return sel.text();
} else {
var label = gettext("Status of Your Response");
sel.html('<span class="sr">' + label + ":" + "</span>\n" + msg);
}
},
unsavedWarningEnabled: function(enabled) {
if (typeof enabled === "undefined") {
return window.onbeforeunload !== null;
} else {
if (enabled) {
window.onbeforeunload = function() {
return gettext("If you leave this page without saving or submitting your response, you'll lose any work you've done on the response.");
};
} else {
window.onbeforeunload = null;
}
}
},
response: function(text) {
var sel = $("#submission__answer__value", this.element);
if (typeof text === "undefined") {
return sel.val();
} else {
sel.val(text);
}
},
responseChanged: function() {
var currentResponse = $.trim(this.response());
var savedResponse = $.trim(this.savedResponse);
return savedResponse !== currentResponse;
},
autoSave: function() {
var timeSinceLastChange = Date.now() - this.lastChangeTime;
if (this.responseChanged() && timeSinceLastChange > this.AUTO_SAVE_WAIT && !this.errorOnLastSave) {
this.save();
}
},
handleResponseChanged: function() {
var isBlank = $.trim(this.response()) !== "";
this.submitEnabled(isBlank);
if (this.responseChanged()) {
this.saveEnabled(isBlank);
this.saveStatus(gettext("This response has not been saved."));
this.unsavedWarningEnabled(true);
}
this.lastChangeTime = Date.now();
},
save: function() {
this.errorOnLastSave = false;
this.saveStatus(gettext("Saving..."));
this.baseView.toggleActionError("save", null);
this.unsavedWarningEnabled(false);
var view = this;
var savedResponse = this.response();
this.server.save(savedResponse).done(function() {
view.savedResponse = savedResponse;
var currentResponse = view.response();
view.submitEnabled(currentResponse !== "");
if (currentResponse == savedResponse) {
view.saveEnabled(false);
view.saveStatus(gettext("This response has been saved but not submitted."));
}
}).fail(function(errMsg) {
view.saveStatus(gettext("Error"));
view.baseView.toggleActionError("save", errMsg);
view.errorOnLastSave = true;
});
},
submit: function() {
this.submitEnabled(false);
var view = this;
var baseView = this.baseView;
this.confirmSubmission().pipe(function() {
var submission = $("#submission__answer__value", view.element).val();
baseView.toggleActionError("response", null);
return view.server.submit(submission);
}).done($.proxy(view.moveToNextStep, view)).fail(function(errCode, errMsg) {
if (errCode == "ENOMULTI") {
view.moveToNextStep();
} else {
if (errMsg) {
baseView.toggleActionError("submit", errMsg);
}
view.submitEnabled(true);
}
});
},
moveToNextStep: function() {
this.load();
this.baseView.loadAssessmentModules();
this.unsavedWarningEnabled(false);
},
confirmSubmission: function() {
var msg = "You're about to submit your response for this assignment. " + "After you submit this response, you can't change it or submit a new response.";
return $.Deferred(function(defer) {
if (confirm(msg)) {
defer.resolve();
} else {
defer.reject();
}
});
}
};
OpenAssessment.Rubric = function(element) {
this.element = element;
};
OpenAssessment.Rubric.prototype = {
criterionFeedback: function(criterionFeedback) {
var selector = "textarea.answer__value";
var feedback = {};
$(selector, this.element).each(function(index, sel) {
if (typeof criterionFeedback !== "undefined") {
$(sel).val(criterionFeedback[sel.name]);
feedback[sel.name] = criterionFeedback[sel.name];
} else {
feedback[sel.name] = $(sel).val();
}
});
return feedback;
},
optionsSelected: function(optionsSelected) {
var selector = "input[type=radio]";
if (typeof optionsSelected === "undefined") {
var options = {};
$(selector + ":checked", this.element).each(function(index, sel) {
options[sel.name] = sel.value;
});
return options;
} else {
$(selector, this.element).prop("checked", false);
$(selector, this.element).each(function(index, sel) {
if (optionsSelected.hasOwnProperty(sel.name)) {
if (sel.value == optionsSelected[sel.name]) {
$(sel).prop("checked", true);
}
}
});
}
},
canSubmitCallback: function(callback) {
$(this.element).change(function() {
var numChecked = $("input[type=radio]:checked", this).length;
var numAvailable = $(".field--radio.assessment__rubric__question", this).length;
var canSubmit = numChecked == numAvailable;
callback(canSubmit);
});
},
showCorrections: function(corrections) {
var selector = "input[type=radio]";
var hasErrors = false;
$(selector, this.element).each(function(index, sel) {
var listItem = $(sel).parents(".assessment__rubric__question");
if (corrections.hasOwnProperty(sel.name)) {
hasErrors = true;
listItem.find(".message--incorrect").removeClass("is--hidden");
listItem.find(".message--correct").addClass("is--hidden");
} else {
listItem.find(".message--correct").removeClass("is--hidden");
listItem.find(".message--incorrect").addClass("is--hidden");
}
});
return hasErrors;
}
};
OpenAssessment.SelfView = function(element, server, baseView) {
this.element = element;
this.server = server;
this.baseView = baseView;
this.rubric = null;
};
OpenAssessment.SelfView.prototype = {
load: function() {
var view = this;
this.server.render("self_assessment").done(function(html) {
$("#openassessment__self-assessment", view.element).replaceWith(html);
view.installHandlers();
}).fail(function(errMsg) {
view.showLoadError("self-assessment");
});
},
installHandlers: function() {
var view = this;
var sel = $("#openassessment__self-assessment", view.element);
this.baseView.setUpCollapseExpand(sel);
var rubricSelector = $("#self-assessment--001__assessment", this.element);
if (rubricSelector.size() > 0) {
var rubricElement = rubricSelector.get(0);
this.rubric = new OpenAssessment.Rubric(rubricElement);
}
if (this.rubric !== null) {
this.rubric.canSubmitCallback($.proxy(this.selfSubmitEnabled, this));
}
sel.find("#self-assessment--001__assessment__submit").click(function(eventObject) {
eventObject.preventDefault();
view.selfAssess();
});
},
selfSubmitEnabled: function(enabled) {
var button = $("#self-assessment--001__assessment__submit", this.element);
if (typeof enabled === "undefined") {
return !button.hasClass("is--disabled");
} else {
button.toggleClass("is--disabled", !enabled);
}
},
selfAssess: function() {
var view = this;
var baseView = this.baseView;
baseView.toggleActionError("self", null);
view.selfSubmitEnabled(false);
var options = this.rubric.optionsSelected();
this.server.selfAssess(options).done(function() {
baseView.loadAssessmentModules();
baseView.scrollToTop();
}).fail(function(errMsg) {
baseView.toggleActionError("self", errMsg);
view.selfSubmitEnabled(true);
});
}
};
OpenAssessment.Server = function(runtime, element) {
this.runtime = runtime;
this.element = element;
};
OpenAssessment.Server.prototype = {
url: function(handler) {
return this.runtime.handlerUrl(this.element, handler);
},
render: function(component) {
var url = this.url("render_" + component);
return $.Deferred(function(defer) {
$.ajax({
url: url,
type: "POST",
dataType: "html"
}).done(function(data) {
defer.resolveWith(this, [ data ]);
}).fail(function(data) {
defer.rejectWith(this, [ gettext("This section could not be loaded.") ]);
});
}).promise();
},
renderContinuedPeer: function() {
var url = this.url("render_peer_assessment");
return $.Deferred(function(defer) {
$.ajax({
url: url,
type: "POST",
dataType: "html",
data: {
continue_grading: true
}
}).done(function(data) {
defer.resolveWith(this, [ data ]);
}).fail(function(data) {
defer.rejectWith(this, [ gettext("This section could not be loaded.") ]);
});
}).promise();
},
studentInfo: function(student_id) {
var url = this.url("render_student_info");
return $.Deferred(function(defer) {
$.ajax({
url: url,
type: "POST",
dataType: "html",
data: {
student_id: student_id
}
}).done(function(data) {
defer.resolveWith(this, [ data ]);
}).fail(function(data) {
defer.rejectWith(this, [ gettext("This section could not be loaded.") ]);
});
}).promise();
},
submit: function(submission) {
var url = this.url("submit");
return $.Deferred(function(defer) {
$.ajax({
type: "POST",
url: url,
data: JSON.stringify({
submission: submission
})
}).done(function(data) {
var success = data[0];
if (success) {
var studentId = data[1];
var attemptNum = data[2];
defer.resolveWith(this, [ studentId, attemptNum ]);
} else {
var errorNum = data[1];
var errorMsg = data[2];
defer.rejectWith(this, [ errorNum, errorMsg ]);
}
}).fail(function(data) {
defer.rejectWith(this, [ "AJAX", gettext("This response could not be submitted.") ]);
});
}).promise();
},
save: function(submission) {
var url = this.url("save_submission");
return $.Deferred(function(defer) {
$.ajax({
type: "POST",
url: url,
data: JSON.stringify({
submission: submission
})
}).done(function(data) {
if (data.success) {
defer.resolve();
} else {
defer.rejectWith(this, [ data.msg ]);
}
}).fail(function(data) {
defer.rejectWith(this, [ gettext("This response could not be saved.") ]);
});
}).promise();
},
submitFeedbackOnAssessment: function(text, options) {
var url = this.url("submit_feedback");
var payload = JSON.stringify({
feedback_text: text,
feedback_options: options
});
return $.Deferred(function(defer) {
$.ajax({
type: "POST",
url: url,
data: payload
}).done(function(data) {
if (data.success) {
defer.resolve();
} else {
defer.rejectWith(this, [ data.msg ]);
}
}).fail(function(data) {
defer.rejectWith(this, [ gettext("This feedback could not be submitted.") ]);
});
}).promise();
},
peerAssess: function(optionsSelected, criterionFeedback, overallFeedback) {
var url = this.url("peer_assess");
var payload = JSON.stringify({
options_selected: optionsSelected,
criterion_feedback: criterionFeedback,
overall_feedback: overallFeedback
});
return $.Deferred(function(defer) {
$.ajax({
type: "POST",
url: url,
data: payload
}).done(function(data) {
if (data.success) {
defer.resolve();
} else {
defer.rejectWith(this, [ data.msg ]);
}
}).fail(function(data) {
defer.rejectWith(this, [ gettext("This assessment could not be submitted.") ]);
});
}).promise();
},
selfAssess: function(optionsSelected) {
var url = this.url("self_assess");
var payload = JSON.stringify({
options_selected: optionsSelected
});
return $.Deferred(function(defer) {
$.ajax({
type: "POST",
url: url,
data: payload
}).done(function(data) {
if (data.success) {
defer.resolve();
} else {
defer.rejectWith(this, [ data.msg ]);
}
}).fail(function(data) {
defer.rejectWith(this, [ gettext("This assessment could not be submitted.") ]);
});
});
},
trainingAssess: function(optionsSelected) {
var url = this.url("training_assess");
var payload = JSON.stringify({
options_selected: optionsSelected
});
return $.Deferred(function(defer) {
$.ajax({
type: "POST",
url: url,
data: payload
}).done(function(data) {
if (data.success) {
defer.resolveWith(this, [ data.corrections ]);
} else {
defer.rejectWith(this, [ data.msg ]);
}
}).fail(function(data) {
defer.rejectWith(this, [ gettext("This assessment could not be submitted.") ]);
});
});
},
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
});
return $.Deferred(function(defer) {
$.ajax({
type: "POST",
url: url,
data: payload
}).done(function(data) {
if (data.success) {
defer.resolve();
} else {
defer.rejectWith(this, [ data.msg ]);
}
}).fail(function(data) {
defer.rejectWith(this, [ gettext("This problem could not be saved.") ]);
});
}).promise();
},
checkReleased: function() {
var url = this.url("check_released");
var payload = '""';
return $.Deferred(function(defer) {
$.ajax({
type: "POST",
url: url,
data: payload
}).done(function(data) {
if (data.success) {
defer.resolveWith(this, [ data.is_released ]);
} else {
defer.rejectWith(this, [ data.msg ]);
}
}).fail(function(data) {
defer.rejectWith(this, [ gettext("The server could not be contacted.") ]);
});
}).promise();
}
};
if (typeof OpenAssessment == "undefined" || !OpenAssessment) {
OpenAssessment = {};
}
if (typeof window.gettext === "undefined") {
window.gettext = function(text) {
return text;
};
}
OpenAssessment.StaffInfoView = function(element, server, baseView) {
this.element = element;
this.server = server;
this.baseView = baseView;
};
OpenAssessment.StaffInfoView.prototype = {
load: function() {
var view = this;
if ($("#openassessment__staff-info", view.element).length > 0) {
this.server.render("staff_info").done(function(html) {
$("#openassessment__staff-info", view.element).replaceWith(html);
view.installHandlers();
}).fail(function(errMsg) {
view.baseView.showLoadError("staff_info");
});
}
},
loadStudentInfo: function() {
var view = this;
var sel = $("#openassessment__staff-info", this.element);
var student_id = sel.find("#openassessment__student_id").val();
this.server.studentInfo(student_id).done(function(html) {
$("#openassessment__student-info", view.element).replaceWith(html);
}).fail(function(errMsg) {
view.showLoadError("student_info");
});
},
installHandlers: function() {
var sel = $("#openassessment__staff-info", this.element);
var view = this;
if (sel.length <= 0) {
return;
}
this.baseView.setUpCollapseExpand(sel, function() {});
sel.find("#openassessment_student_info_form").submit(function(eventObject) {
eventObject.preventDefault();
view.loadStudentInfo();
});
sel.find("#submit_student_id").click(function(eventObject) {
eventObject.preventDefault();
view.loadStudentInfo();
});
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
......@@ -57,23 +57,6 @@ describe("OpenAssessment.StudioView", function() {
view = new OpenAssessment.StudioView(runtime, el, server);
});
it("saves the editor context definition", function() {
// Update the context
view.settingsFieldSelectors.titleField.val('THIS IS THE NEW TITLE');
view.settingsFieldSelectors.submissionStartField.val('2014-01-01');
// Save the updated editor definition
view.save();
// Expect the saving notification to start/end
expect(runtime.notify).toHaveBeenCalledWith('save', {state: 'start'});
expect(runtime.notify).toHaveBeenCalledWith('save', {state: 'end'});
// Expect the server's context to have been updated
expect(server.receivedData.title).toEqual('THIS IS THE NEW TITLE');
expect(server.receivedData.submissionStart).toEqual('2014-01-01T00:00:00.000Z');
});
it("confirms changes for a released problem", function() {
// Simulate an XBlock that has been released
server.isReleased = true;
......
/**
Tests for assessment editing views.
**/
describe("OpenAssessment edit assessment views", function() {
var testEnableAndDisable = function(view) {
view.isEnabled(false);
expect(view.isEnabled()).toBe(false);
view.isEnabled(true);
expect(view.isEnabled()).toBe(true);
};
var testLoadXMLExamples = function(view) {
var xml = "XML DEFINITIONS WOULD BE HERE";
view.exampleDefinitions(xml);
expect(view.description()).toEqual({ examples: xml });
};
beforeEach(function() {
jasmine.getFixtures().fixturesPath = 'base/fixtures';
loadFixtures('oa_edit.html');
});
describe("OpenAssessment.EditPeerAssessmentView", function() {
var view = null;
beforeEach(function() {
var element = $("#oa_peer_assessment_editor").get(0);
view = new OpenAssessment.EditPeerAssessmentView(element);
});
it("Enables and disables", function() { testEnableAndDisable(view); });
it("Loads a description", function() {
view.mustGradeNum(1);
view.mustBeGradedByNum(2);
view.startDatetime("2014-01-01T00:00");
view.dueDatetime("2014-03-04T00:00");
expect(view.description()).toEqual({
must_grade: 1,
must_be_graded_by: 2,
start: "2014-01-01T00:00",
due: "2014-03-04T00:00"
});
});
it("Handles default dates", function() {
view.startDatetime("");
view.dueDatetime("");
expect(view.description().start).toBe(null);
expect(view.description().due).toBe(null);
});
});
describe("OpenAssessment.EditSelfAssessmentView", function() {
var view = null;
beforeEach(function() {
var element = $("#oa_self_assessment_editor").get(0);
view = new OpenAssessment.EditSelfAssessmentView(element);
});
it("Enables and disables", function() { testEnableAndDisable(view); });
it("Loads a description", function() {
view.startDatetime("2014-01-01T00:00");
view.dueDatetime("2014-03-04T00:00");
expect(view.description()).toEqual({
start: "2014-01-01T00:00",
due: "2014-03-04T00:00"
});
});
it("Handles default dates", function() {
view.startDatetime("");
view.dueDatetime("");
expect(view.description().start).toBe(null);
expect(view.description().due).toBe(null);
});
});
describe("OpenAssessment.EditStudentTrainingView", function() {
var view = null;
beforeEach(function() {
var element = $("#oa_student_training_editor").get(0);
view = new OpenAssessment.EditStudentTrainingView(element);
});
it("Enables and disables", function() { testEnableAndDisable(view); });
it("Loads a description", function() { testLoadXMLExamples(view); });
});
describe("OpenAssessment.EditExampleBasedAssessmentView", function() {
var view = null;
beforeEach(function() {
var element = $("#oa_ai_assessment_editor").get(0);
view = new OpenAssessment.EditExampleBasedAssessmentView(element);
});
it("Enables and disables", function() { testEnableAndDisable(view); });
it("Loads a description", function() { testLoadXMLExamples(view); });
});
});
\ No newline at end of file
/**
Tests for OpenAssessment prompt editing view.
**/
describe("OpenAssessment.EditPromptView", function() {
var view = null;
beforeEach(function() {
// Load the DOM fixture
jasmine.getFixtures().fixturesPath = 'base/fixtures';
loadFixtures('oa_edit.html');
// Create the view
var element = $("#oa_prompt_editor_wrapper").get(0);
view = new OpenAssessment.EditPromptView(element);
});
it("sets and loads prompt text", function() {
view.promptText("");
expect(view.promptText()).toEqual("");
view.promptText("This is a test prompt!");
expect(view.promptText()).toEqual("This is a test prompt!");
});
});
\ No newline at end of file
/**
Tests for the edit settings view.
**/
describe("OpenAssessment.EditSettingsView", function() {
var StubView = function(name, descriptionText) {
this.name = name;
this.description = function() {
return { dummy: descriptionText };
};
var _enabled = true;
this.isEnabled = function(isEnabled) {
if (typeof(isEnabled) !== "undefined") { this._enabled = isEnabled; }
return this._enabled;
};
};
var view = null;
var assessmentViews = null;
beforeEach(function() {
// Load the DOM fixture
jasmine.getFixtures().fixturesPath = 'base/fixtures';
loadFixtures('oa_edit.html');
// Create the stub assessment views
assessmentViews = [
new StubView("self-assessment", "Self assessment description"),
new StubView("peer-assessment", "Peer assessment description")
];
// Create the view
var element = $("#oa_basic_settings_editor").get(0);
view = new OpenAssessment.EditSettingsView(element, assessmentViews);
});
it("sets and loads display name", function() {
view.displayName("");
expect(view.displayName()).toEqual("");
view.displayName("This is the name of the problem!");
expect(view.displayName()).toEqual("This is the name of the problem!");
});
it("sets and loads the submission start/due dates", function() {
view.submissionStart("");
expect(view.submissionStart()).toBe(null);
view.submissionStart("2014-04-01T00:00.0000Z");
expect(view.submissionStart()).toEqual("2014-04-01T00:00.0000Z");
view.submissionDue("");
expect(view.submissionDue()).toBe(null);
view.submissionDue("2014-05-02T00:00.0000Z");
expect(view.submissionDue()).toEqual("2014-05-02T00:00.0000Z");
});
it("sets and loads the image enabled state", function() {
view.imageSubmissionEnabled(true);
expect(view.imageSubmissionEnabled()).toBe(true);
view.imageSubmissionEnabled(false);
expect(view.imageSubmissionEnabled()).toBe(false);
});
it("builds a description of enabled assessments", function() {
// Disable all assessments, and expect an empty description
assessmentViews[0].isEnabled(false);
assessmentViews[1].isEnabled(false);
expect(view.assessmentsDescription()).toEqual([]);
// Enable the first assessment only
assessmentViews[0].isEnabled(true);
assessmentViews[1].isEnabled(false);
expect(view.assessmentsDescription()).toEqual([
{
name: "self-assessment",
dummy: "Self assessment description"
}
]);
// Enable the second assessment only
assessmentViews[0].isEnabled(false);
assessmentViews[1].isEnabled(true);
expect(view.assessmentsDescription()).toEqual([
{
name: "peer-assessment",
dummy: "Peer assessment description"
}
]);
// Enable both assessments
assessmentViews[0].isEnabled(true);
assessmentViews[1].isEnabled(true);
expect(view.assessmentsDescription()).toEqual([
{
name: "self-assessment",
dummy: "Self assessment description"
},
{
name: "peer-assessment",
dummy: "Peer assessment description"
}
]);
});
});
......@@ -15,28 +15,33 @@ OpenAssessment.StudioView = function(runtime, element, server) {
this.runtime = runtime;
this.server = server;
// Initialize the prompt tab view
this.promptView = new OpenAssessment.EditPromptView(
$("#oa_prompt_editor_wrapper", this.element).get(0)
);
// Initialize the settings tab view
this.settingsView = new OpenAssessment.EditSettingsView(
$("#oa_basic_settings_editor", this.element).get(0), [
new OpenAssessment.EditPeerAssessmentView(
$("#oa_peer_assessment_editor", this.element).get(0)
),
new OpenAssessment.EditSelfAssessmentView(
$("#oa_self_assessment_editor", this.element).get(0)
),
new OpenAssessment.EditStudentTrainingView(
$("#oa_student_training_editor", this.element).get(0)
),
new OpenAssessment.EditExampleBasedAssessmentView(
$("#oa_ai_assessment_editor", this.element).get(0)
)
]
);
this.liveElement = $(element);
var liveElement = this.liveElement;
// Instantiates JQuery selector variables which will allow manipulation and display controls.
this.settingsFieldSelectors = {
promptBox: $('#openassessment_prompt_editor', liveElement),
titleField: $('#openassessment_title_editor', liveElement),
submissionStartField: $('#openassessment_submission_start_editor', liveElement),
submissionDueField: $('#openassessment_submission_due_editor', liveElement),
hasPeer: $('#include_peer_assessment', liveElement),
hasSelf: $('#include_self_assessment', liveElement),
hasAI: $('#include_ai_assessment', liveElement),
hasTraining: $('#include_student_training', liveElement),
peerMustGrade: $('#peer_assessment_must_grade', liveElement),
peerGradedBy: $('#peer_assessment_graded_by', liveElement),
peerStart: $('#peer_assessment_start_date', liveElement),
peerDue: $('#peer_assessment_due_date', liveElement),
selfStart: $('#self_assessment_start_date', liveElement),
selfDue: $('#self_assessment_due_date', liveElement)
};
// Captures the HTML definition of the original criterion element. This will be the template
// used for all other criterion creations
var criterionHtml = $("#openassessment_criterion_1", liveElement).parent().html();
......@@ -64,39 +69,27 @@ OpenAssessment.StudioView = function(runtime, element, server) {
var view = this;
// Installs the save and cancel buttons
$('.openassessment_save_button', liveElement) .click( function (eventData) {
view.save();
});
$(".openassessment_save_button", this.element).click(
function (eventData) { view.save(); }
);
$('.openassessment_cancel_button', liveElement) .click( function (eventData) {
view.cancel();
});
$(".openassessment_cancel_button", this.element).click(
function (eventData) { view.cancel(); }
);
// Adds the tabbing functionality
$('.openassessment_editor_content_and_tabs', liveElement) .tabs();
$(".openassessment_editor_content_and_tabs", this.element).tabs();
// Installs all of the checkbox listeners in the settings tab
view.addSettingsAssessmentCheckboxListener("ai_assessment", liveElement);
view.addSettingsAssessmentCheckboxListener("self_assessment", liveElement);
view.addSettingsAssessmentCheckboxListener("peer_assessment", liveElement);
view.addSettingsAssessmentCheckboxListener("student_training", liveElement);
$('#openassessment_rubric_add_criterion', liveElement) .click( function (eventData) {
$('#openassessment_rubric_add_criterion', this.element).click(
function (eventData) {
view.addNewCriterionToRubric(liveElement);
});
}
);
};
OpenAssessment.StudioView.prototype = {
/**
Load the XBlock XML definition from the server and display it in the view.
**/
load: function () {
var view = this;
},
/**
Save the problem's XML definition to the server.
If the problem has been released, make the user confirm the save.
**/
......@@ -120,20 +113,6 @@ OpenAssessment.StudioView.prototype = {
},
/**
Construct checkbox listeners for all of our assessment modules
Args:
name (string): name of assessment module to install listener on
liveElement (DOM element): the live DOM selector
*/
addSettingsAssessmentCheckboxListener: function (name, liveElement) {
$("#include_" + name , liveElement) .change(function () {
$("#" + name + "_description_closed", liveElement).toggleClass('is--hidden', this.checked);
$("#" + name + "_settings_editor", liveElement).toggleClass('is--hidden', !this.checked);
});
},
/**
Make the user confirm that he/she wants to update a problem
that has already been released.
......@@ -376,7 +355,7 @@ OpenAssessment.StudioView.prototype = {
var optionSelectors = optionSelectorList[j];
optionValueList = optionValueList.concat([{
order_num: j-1,
points: this._getInt(optionSelectors.points),
points: parseInt(optionSelectors.points.val(), 10),
name: optionSelectors.name.val(),
explanation: optionSelectors.explanation.val()
}]);
......@@ -385,49 +364,15 @@ OpenAssessment.StudioView.prototype = {
rubricCriteria = rubricCriteria.concat([criterionValueDict]);
}
var assessments = [];
if (this.settingsFieldSelectors.hasTraining.prop('checked')){
assessments.push({
name: "student-training",
examples: this.studentTrainingExamplesCodeBox.getValue()
});
}
if (this.settingsFieldSelectors.hasPeer.prop('checked')) {
assessments.push({
name: "peer-assessment",
must_grade: this._getInt(this.settingsFieldSelectors.peerMustGrade),
must_be_graded_by: this._getInt(this.settingsFieldSelectors.peerGradedBy),
start: this._getDateTime(this.settingsFieldSelectors.peerStart),
due: this._getDateTime(this.settingsFieldSelectors.peerDue)
});
}
if (this.settingsFieldSelectors.hasSelf.prop('checked')) {
assessments.push({
name: "self-assessment",
start: this._getDateTime(this.settingsFieldSelectors.selfStart),
due: this._getDateTime(this.settingsFieldSelectors.selfDue)
});
}
if (this.settingsFieldSelectors.hasAI.prop('checked')) {
assessments.push({
name: "example-based-assessment",
examples: this.aiTrainingExamplesCodeBox.getValue()
});
}
var view = this;
this.server.updateEditorContext({
title: this.settingsFieldSelectors.titleField.val(),
prompt: this.settingsFieldSelectors.promptBox.val(),
title: view.settingsView.displayName(),
prompt: view.promptView.promptText(),
feedbackPrompt: this.rubricFeedbackPrompt.val(),
submissionStart: this._getDateTime(this.settingsFieldSelectors.submissionStartField),
submissionDue: this._getDateTime(this.settingsFieldSelectors.submissionDueField),
submissionStart: view.settingsView.submissionStart(),
submissionDue: view.settingsView.submissionDue(),
criteria: rubricCriteria,
assessments: assessments
assessments: view.settingsView.assessmentsDescription()
}).done(
function () {
// Notify the client-side runtime that we finished saving
......@@ -456,54 +401,6 @@ OpenAssessment.StudioView.prototype = {
showError: function (errorMsg) {
this.runtime.notify('error', {msg: errorMsg});
},
/**
Retrieve a value from a datetime input.
Args:
selector: The JQuery selector for the datetime input.
Returns:
ISO-formatted datetime string or null
**/
_getDateTime: function(selector) {
var dateStr = selector.val();
// By convention, empty date strings are null,
// meaning choose the default date based on
// other dates set in the problem configuration.
if (dateStr === "") {
return null;
}
// Attempt to parse the date string
// TO DO: currently invalid dates also are set as null,
// which is probably NOT what the user wants!
// We should add proper validation here.
var timestamp = Date.parse(dateStr);
if (isNaN(timestamp)) {
return null;
}
// Send the datetime in ISO format
// This will also convert the timezone to UTC
return new Date(timestamp).toISOString();
},
/**
Retrieve an integer value from an input.
Args:
selector: The JQuery selector for the input.
Returns:
int
**/
_getInt: function(selector) {
return parseInt(selector.val(), 10);
}
};
......@@ -515,5 +412,4 @@ function OpenAssessmentEditor(runtime, element) {
**/
var server = new OpenAssessment.Server(runtime, element);
var view = new OpenAssessment.StudioView(runtime, element, server);
view.load();
}
/**
Show and hide elements based on a checkbox.
Args:
element (DOM element): The parent element, used to scope the selectors.
hiddenSelector (string): The CSS selector string for elements
to show when the checkbox is in the "off" state.
shownSelector (string): The CSS selector string for elements
to show when the checkbox is in the "on" state.
**/
OpenAssessment.ToggleControl = function(element, hiddenSelector, shownSelector) {
this.element = element;
this.hiddenSelector = hiddenSelector;
this.shownSelector = shownSelector;
};
OpenAssessment.ToggleControl.prototype = {
/**
Install the event handler for the checkbox,
passing in the toggle control object as the event data.
Args:
checkboxSelector (string): The CSS selector string for the checkbox.
Returns:
OpenAssessment.ToggleControl
**/
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).fadeOut('fast');
$(this.shownSelector, this.element).fadeIn();
},
hide: function() {
$(this.hiddenSelector, this.element).fadeIn();
$(this.shownSelector, this.element).fadeOut();
}
};
/**
Interface for editing peer assessment settings.
Args:
element (DOM element): The DOM element representing this view.
Returns:
OpenAssessment.EditPeerAssessmentView
**/
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");
};
OpenAssessment.EditPeerAssessmentView.prototype = {
/**
Return a description of the assessment.
Returns:
object literal
Example usage:
>>> editPeerView.description();
{
must_grade: 5,
must_be_graded_by: 2,
start: null,
due: "2014-04-1T00:00"
}
**/
description: function() {
return {
must_grade: this.mustGradeNum(),
must_be_graded_by: this.mustBeGradedByNum(),
start: this.startDatetime(),
due: this.dueDatetime()
};
},
/**
Get or set whether the assessment is enabled.
Args:
isEnabled (boolean, optional): If provided, set the enabled state of the assessment.
Returns:
boolean
***/
isEnabled: function(isEnabled) {
var sel = $("#include_peer_assessment", this.element);
return OpenAssessment.Fields.booleanField(sel, isEnabled);
},
/**
Get or set the required number of submissions a student must peer-assess.
Args:
num (int, optional): If provided, set the required number of assessments.
Returns:
int
**/
mustGradeNum: function(num) {
var sel = $("#peer_assessment_must_grade", this.element);
return OpenAssessment.Fields.intField(sel, num);
},
/**
Get or set the required number of peer-assessments a student must receive.
Args:
num (int, optional): If provided, set the required number of assessments.
Returns:
int
**/
mustBeGradedByNum: function(num) {
var sel = $("#peer_assessment_graded_by", this.element);
return OpenAssessment.Fields.intField(sel, num);
},
/**
Get or set the start date and time of the assessment.
Args:
datetime (string, optional): If provided, set the datetime to this value.
Returns:
string (ISO-formatted UTC datetime)
**/
startDatetime: function(datetime) {
var sel = $("#peer_assessment_start_date", this.element);
return OpenAssessment.Fields.datetimeField(sel, datetime);
},
/**
Get or set the due date and time of the assessment.
Args:
datetime (string, optional): If provided, set the datetime to this value.
Returns:
string (ISO-formatted UTC datetime)
**/
dueDatetime: function(datetime) {
var sel = $("#peer_assessment_due_date", this.element);
return OpenAssessment.Fields.datetimeField(sel, datetime);
},
};
/**
Interface for editing self assessment settings.
Args:
element (DOM element): The DOM element representing this view.
Returns:
OpenAssessment.EditSelfAssessmentView
**/
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");
};
OpenAssessment.EditSelfAssessmentView.prototype = {
/**
Return a description of the assessment.
Returns:
object literal
Example usage:
>>> editSelfView.description();
{
start: null,
due: "2014-04-1T00:00"
}
**/
description: function() {
return {
start: this.startDatetime(),
due: this.dueDatetime()
};
},
/**
Get or set whether the assessment is enabled.
Args:
isEnabled (boolean, optional): If provided, set the enabled state of the assessment.
Returns:
boolean
***/
isEnabled: function(isEnabled) {
var sel = $("#include_self_assessment", this.element);
return OpenAssessment.Fields.booleanField(sel, isEnabled);
},
/**
Get or set the start date and time of the assessment.
Args:
datetime (string, optional): If provided, set the datetime to this value.
Returns:
string (ISO-formatted UTC datetime)
**/
startDatetime: function(datetime) {
var sel = $("#self_assessment_start_date", this.element);
return OpenAssessment.Fields.datetimeField(sel, datetime);
},
/**
Get or set the due date and time of the assessment.
Args:
datetime (string, optional): If provided, set the datetime to this value.
Returns:
string (ISO-formatted UTC datetime)
**/
dueDatetime: function(datetime) {
var sel = $("#self_assessment_due_date", this.element);
return OpenAssessment.Fields.datetimeField(sel, datetime);
},
};
/**
Interface for editing self assessment settings.
Args:
element (DOM element): The DOM element representing this view.
Returns:
OpenAssessment.EditStudentTrainingView
**/
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");
};
OpenAssessment.EditStudentTrainingView.prototype = {
/**
Return a description of the assessment.
Returns:
object literal
Example usage:
>>> editTrainingView.description();
{
examples: "XML DEFINITION HERE"
}
**/
description: function() {
return {
examples: this.exampleDefinitions()
};
},
/**
Get or set whether the assessment is enabled.
Args:
isEnabled (boolean, optional): If provided, set the enabled state of the assessment.
Returns:
boolean
***/
isEnabled: function(isEnabled) {
var sel = $("#include_student_training", this.element);
return OpenAssessment.Fields.booleanField(sel, isEnabled);
},
/**
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);
},
};
/**
Interface for editing example-based assessment settings.
Args:
element (DOM element): The DOM element representing this view.
Returns:
OpenAssessment.EditExampleBasedAssessmentView
**/
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 = {
/**
Return a description of the assessment.
Returns:
object literal
Example usage:
>>> editTrainingView.description();
{
examples: "XML DEFINITION HERE"
}
**/
description: function() {
return {
examples: this.exampleDefinitions()
};
},
/**
Get or set whether the assessment is enabled.
Args:
isEnabled (boolean, optional): If provided, set the enabled state of the assessment.
Returns:
boolean
***/
isEnabled: function(isEnabled) {
var sel = $("#include_ai_assessment", this.element);
return OpenAssessment.Fields.booleanField(sel, isEnabled);
},
/**
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 = $("#ai_training_examples", this.element);
return OpenAssessment.Fields.stringField(sel, xml);
},
};
\ No newline at end of file
/**
Utilities for reading / writing fields.
**/
OpenAssessment.Fields = {
stringField: function(sel, value) {
if (typeof(value) !== "undefined") { sel.val(value); }
return sel.val();
},
datetimeField: function(sel, value) {
if (typeof(value) !== "undefined") { sel.val(value); }
var fieldValue = sel.val();
return (fieldValue !== "") ? fieldValue : null;
},
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");
},
};
/**
Editing interface for the rubric prompt.
Args:
element (DOM element): The DOM element representing this view.
Returns:
OpenAssessment.EditPromptView
**/
OpenAssessment.EditPromptView = function(element) {
this.element = element;
};
OpenAssessment.EditPromptView.prototype = {
/**
Get or set the text of the prompt.
Args:
text (string, optional): If provided, set the text of the prompt.
Returns:
string
**/
promptText: function(text) {
var sel = $('#openassessment_prompt_editor', this.element);
return OpenAssessment.Fields.stringField(sel, text);
},
};
\ No newline at end of file
/**
Interface for editing rubric definitions.
**/
OpenAssessment.EditRubricView = function(element) {
this.element = element;
};
OpenAssessment.EditRubricView.prototype = {
/**
Install event handlers.
**/
load: function() {
//this.container = new Container(this.element, "openassessment__rubric__criterion", OpenAssessment.RubricCriterion);
},
/**
[
{
order_num: 0,
name: 'Criteria!'
prompt: 'prompt',
feedback: 'disabled',
options: [
{
order_num: 0,
name: 'name',
explanation: 'explanation',
points: 1
},
...
]
},
...
]
**/
criteriaDefinition: function() {
//return this.container.getItemValues();
},
};
\ No newline at end of file
/**
Editing interface for OpenAssessment settings (including assessments).
Args:
element (DOM element): The DOM element representing this view.
assessmentViews (array): List of assessment view objects.
Returns:
OpenAssessment.EditSettingsView
**/
OpenAssessment.EditSettingsView = function(element, assessmentViews) {
this.element = element;
this.assessmentViews = assessmentViews;
};
OpenAssessment.EditSettingsView.prototype = {
/**
Get or set the display name of the problem.
Args:
name (string, optional): If provided, set the display name.
Returns:
string
**/
displayName: function(name) {
var sel = $("#openassessment_title_editor", this.element);
return OpenAssessment.Fields.stringField(sel, name);
},
/**
Get or set the submission start date.
Args:
datetime (string, optional): If provided, set the datetime.
Returns:
string (ISO-format UTC datetime)
**/
submissionStart: function(datetime) {
var sel = $("#openassessment_submission_start_editor", this.element);
return OpenAssessment.Fields.datetimeField(sel, datetime);
},
/**
Get or set the submission end date.
Args:
datetime (string, optional): If provided, set the datetime.
Returns:
string (ISO-format UTC datetime)
**/
submissionDue: function(datetime) {
var sel = $("#openassessment_submission_start_editor", this.element);
return OpenAssessment.Fields.datetimeField(sel, datetime);
},
/**
Enable / disable image submission.
Args:
isEnabled (boolean, optional): If provided, enable/disable image submission.
Returns:
boolean
**/
imageSubmissionEnabled: function(isEnabled) {
var sel = $("#openassessment_submission_image_editor", this.element);
if (typeof(isEnabled) !== "undefined") {
if (isEnabled) { sel.val(1); }
else { sel.val(0); }
}
return (sel.val() == 1);
},
/**
Construct a list of enabled assessments and their properties.
Returns:
list of object literals representing the assessments.
Example usage:
>>> editSettingsView.assessmentsDescription()
[
{
name: "peer-assessment",
start: "2014-04-01T00:00",
due: null
must_grade: 5,
must_be_graded_by: 2,
},
{
name: "self-assessment",
start: null,
due: null
}
]
**/
assessmentsDescription: function() {
assessmentDescList = [];
for (var idx in this.assessmentViews) {
var asmntView = this.assessmentViews[idx];
if (asmntView.isEnabled()) {
var description = asmntView.description();
description["name"] = asmntView.name;
assessmentDescList.push(description);
}
}
return assessmentDescList;
},
};
\ No newline at end of file
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