Commit 85323091 by Will Daly

Split up Studio view into subviews for each tab.

Implement assessment editing views
parent 86a5d3be
...@@ -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();
} }
/**
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