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"); if (typeof OpenAssessment == "undefined" || !OpenAssessment) {
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)}}}; OpenAssessment = {};
\ No newline at end of file }
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() { ...@@ -57,23 +57,6 @@ describe("OpenAssessment.StudioView", function() {
view = new OpenAssessment.StudioView(runtime, el, server); 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() { it("confirms changes for a released problem", function() {
// Simulate an XBlock that has been released // Simulate an XBlock that has been released
server.isReleased = true; 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) { ...@@ -15,28 +15,33 @@ OpenAssessment.StudioView = function(runtime, element, server) {
this.runtime = runtime; this.runtime = runtime;
this.server = server; 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); this.liveElement = $(element);
var liveElement = this.liveElement; 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 // Captures the HTML definition of the original criterion element. This will be the template
// used for all other criterion creations // used for all other criterion creations
var criterionHtml = $("#openassessment_criterion_1", liveElement).parent().html(); var criterionHtml = $("#openassessment_criterion_1", liveElement).parent().html();
...@@ -64,39 +69,27 @@ OpenAssessment.StudioView = function(runtime, element, server) { ...@@ -64,39 +69,27 @@ OpenAssessment.StudioView = function(runtime, element, server) {
var view = this; var view = this;
// Installs the save and cancel buttons // Installs the save and cancel buttons
$('.openassessment_save_button', liveElement) .click( function (eventData) { $(".openassessment_save_button", this.element).click(
view.save(); function (eventData) { view.save(); }
}); );
$('.openassessment_cancel_button', liveElement) .click( function (eventData) { $(".openassessment_cancel_button", this.element).click(
view.cancel(); function (eventData) { view.cancel(); }
}); );
// Adds the tabbing functionality // 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); view.addNewCriterionToRubric(liveElement);
}); }
);
}; };
OpenAssessment.StudioView.prototype = { 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. Save the problem's XML definition to the server.
If the problem has been released, make the user confirm the save. If the problem has been released, make the user confirm the save.
**/ **/
...@@ -120,20 +113,6 @@ OpenAssessment.StudioView.prototype = { ...@@ -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 Make the user confirm that he/she wants to update a problem
that has already been released. that has already been released.
...@@ -376,7 +355,7 @@ OpenAssessment.StudioView.prototype = { ...@@ -376,7 +355,7 @@ OpenAssessment.StudioView.prototype = {
var optionSelectors = optionSelectorList[j]; var optionSelectors = optionSelectorList[j];
optionValueList = optionValueList.concat([{ optionValueList = optionValueList.concat([{
order_num: j-1, order_num: j-1,
points: this._getInt(optionSelectors.points), points: parseInt(optionSelectors.points.val(), 10),
name: optionSelectors.name.val(), name: optionSelectors.name.val(),
explanation: optionSelectors.explanation.val() explanation: optionSelectors.explanation.val()
}]); }]);
...@@ -385,49 +364,15 @@ OpenAssessment.StudioView.prototype = { ...@@ -385,49 +364,15 @@ OpenAssessment.StudioView.prototype = {
rubricCriteria = rubricCriteria.concat([criterionValueDict]); 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; var view = this;
this.server.updateEditorContext({ this.server.updateEditorContext({
title: this.settingsFieldSelectors.titleField.val(), title: view.settingsView.displayName(),
prompt: this.settingsFieldSelectors.promptBox.val(), prompt: view.promptView.promptText(),
feedbackPrompt: this.rubricFeedbackPrompt.val(), feedbackPrompt: this.rubricFeedbackPrompt.val(),
submissionStart: this._getDateTime(this.settingsFieldSelectors.submissionStartField), submissionStart: view.settingsView.submissionStart(),
submissionDue: this._getDateTime(this.settingsFieldSelectors.submissionDueField), submissionDue: view.settingsView.submissionDue(),
criteria: rubricCriteria, criteria: rubricCriteria,
assessments: assessments assessments: view.settingsView.assessmentsDescription()
}).done( }).done(
function () { function () {
// Notify the client-side runtime that we finished saving // Notify the client-side runtime that we finished saving
...@@ -456,54 +401,6 @@ OpenAssessment.StudioView.prototype = { ...@@ -456,54 +401,6 @@ OpenAssessment.StudioView.prototype = {
showError: function (errorMsg) { showError: function (errorMsg) {
this.runtime.notify('error', {msg: 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) { ...@@ -515,5 +412,4 @@ function OpenAssessmentEditor(runtime, element) {
**/ **/
var server = new OpenAssessment.Server(runtime, element); var server = new OpenAssessment.Server(runtime, element);
var view = new OpenAssessment.StudioView(runtime, element, server); 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