Commit 5f1144f1 by gradyward

Merge branch 'authoring' of https://github.com/edx/edx-ora2 into grady/tab-memory

Conflicts:
	openassessment/xblock/static/js/openassessment-studio.min.js
parents fb30adba 2b17d244
...@@ -30,15 +30,59 @@ ...@@ -30,15 +30,59 @@
</li> </li>
<li class="openassessment_date_editor field comp-setting-entry"> <li class="openassessment_date_editor field comp-setting-entry">
<div class="wrapper-comp-setting"> <div class="wrapper-comp-setting">
<label for="openassessment_submission_start_editor" class="setting-label">{% trans "Response Submission Start Date"%} </label> <label
<input type="datetime-local" class="input setting-input" id="openassessment_submission_start_editor" value="{{ submission_start }}"> for="openassessment_submission_start_date"
class="setting-label">
{% trans "Submission Start Date" %}
</label>
<input
type="text"
class="input setting-input"
id="openassessment_submission_start_date"
value="{{ submission_start|date:"y-m-d" }}"
>
</div>
<div class="wrapper-comp-setting">
<label
for="openassessment_submission_start_time"
class="setting-label">
{% trans "Submission Start Time" %}
</label>
<input
type="text"
class="input setting-input"
id="openassessment_submission_start_time"
value="{{ submission_start|date:"H:i" }}"
>
</div> </div>
<p class="setting-help">{% trans "The date at which submissions will first be accepted." %}</p> <p class="setting-help">{% trans "The date at which submissions will first be accepted." %}</p>
</li> </li>
<li class="openassessment_date_editor field comp-setting-entry"> <li class="openassessment_date_editor field comp-setting-entry">
<div class="wrapper-comp-setting"> <div class="wrapper-comp-setting">
<label for="openassessment_submission_due_editor" class="setting-label">{% trans "Response Submission Due Date" %}</label> <label
<input type="datetime-local" class="input setting-input" id="openassessment_submission_due_editor" value="{{ submission_due }}"> for="openassessment_submission_due_date"
class="setting-label">
{% trans "Submission Due Date" %}
</label>
<input
type="text"
class="input setting-input"
id="openassessment_submission_due_date"
value="{{ submission_due|date:"y-m-d" }}"
>
</div>
<div class="wrapper-comp-setting">
<label
for="openassessment_submission_due_time"
class="setting-label">
{% trans "Submission Due Time" %}
</label>
<input
type="text"
class="input setting-input"
id="openassessment_submission_due_time"
value="{{ submission_due|date:"H:i" }}"
>
</div> </div>
<p class="setting-help">{% trans "The date at which submissions will stop being accepted." %}</p> <p class="setting-help">{% trans "The date at which submissions will stop being accepted." %}</p>
</li> </li>
......
{% load i18n %} {% load i18n %}
{% load tz %}
{% spaceless %} {% spaceless %}
<li class="openassessment_assessment_module_settings_editor" id="oa_peer_assessment_editor"> <li class="openassessment_assessment_module_settings_editor" id="oa_peer_assessment_editor">
<div class = "drag-handle action"></div> <div class = "drag-handle action"></div>
...@@ -33,16 +34,44 @@ ...@@ -33,16 +34,44 @@
<li class="field comp-setting-entry"> <li class="field comp-setting-entry">
<div class="wrapper-comp-setting"> <div class="wrapper-comp-setting">
<label for="peer_assessment_start_date" class="setting-label">{% trans "Start Date" %}</label> <label for="peer_assessment_start_date" class="setting-label">{% trans "Start Date" %}</label>
<input id="peer_assessment_start_date" type="datetime-local" class="input setting-input" value="{{ assessments.peer_assessment.start }}"> <input
id="peer_assessment_start_date"
type="text"
class="input setting-input"
value="{{ assessments.peer_assessment.start|utc|date:"Y-m-d" }}"
>
</div> </div>
<p class="setting-help">{% trans "If desired, specify a start date for the peer assessment period. If no date is specified, peer assessment can begin when submissions begin."%}</p> <div class="wrapper-comp-setting">
<label for="peer_assessment_start_time" class="setting-label">{% trans "Start Time" %}</label>
<input
id="peer_assessment_start_time"
type="text"
class="input setting-input"
value="{{ assessments.peer_assessment.start|utc|date:"H:i" }}"
>
</div>
<p class="setting-help">{% trans "Specify a start date for the peer assessment period." %}</p>
</li> </li>
<li class="field comp-setting-entry"> <li class="field comp-setting-entry">
<div class="wrapper-comp-setting"> <div class="wrapper-comp-setting">
<label for="peer_assessment_due_date" class="setting-label">{% trans "Due Date" %}</label> <label for="peer_assessment_due_date" class="setting-label">{% trans "Due Date" %}</label>
<input id="peer_assessment_due_date" type="datetime-local" class="input setting-input" value="{{ assessments.peer_assessment.due }}"> <input
id="peer_assessment_due_date"
type="text"
class="input setting-input"
value="{{ assessments.peer_assessment.due|utc|date:"Y-m-d" }}"
>
</div>
<div class="wrapper-comp-setting">
<label for="peer_assessment_due_time" class="setting-label">{% trans "Due Time" %}</label>
<input
id="peer_assessment_due_time"
type="text"
class="input setting-input"
value="{{ assessments.peer_assessment.due|utc|date:"H:i" }}"
>
</div> </div>
<p class="setting-help">{% trans "If desired, specify a due date for the peer assessment period. If no date is specified, peer assessment can run as long as the problem is open."%}</p> <p class="setting-help">{% trans "Specify a due date for the peer assessment period." %}</p>
</li> </li>
</ul> </ul>
</div> </div>
......
{% load i18n %} {% load i18n %}
{% load tz %}
{% spaceless %} {% spaceless %}
<li class="openassessment_assessment_module_settings_editor" id="oa_self_assessment_editor"> <li class="openassessment_assessment_module_settings_editor" id="oa_self_assessment_editor">
<div class = "drag-handle action"></div> <div class = "drag-handle action"></div>
...@@ -19,16 +20,44 @@ ...@@ -19,16 +20,44 @@
<li class="field comp-setting-entry"> <li class="field comp-setting-entry">
<div class="wrapper-comp-setting"> <div class="wrapper-comp-setting">
<label for="self_assessment_start_date" class="setting-label">{% trans "Start Date" %}</label> <label for="self_assessment_start_date" class="setting-label">{% trans "Start Date" %}</label>
<input id="self_assessment_start_date" type="datetime-local" class="input setting-input" value="{{ assessments.self_assessment.start }}"> <input
id="self_assessment_start_date"
type="text"
class="input setting-input"
value="{{ assessments.self_assessment.start|utc|date:"Y-m-d" }}"
>
</div> </div>
<p class="setting-help">{% trans "If desired, specify a start date for the self assessment period. If no date is specified, self assessment can begin when submissions begin."%}</p> <div class="wrapper-comp-setting">
<label for="self_assessment_start_time" class="setting-label">{% trans "Start Time" %}</label>
<input
id="self_assessment_start_time"
type="text"
class="input setting-input"
value="{{ assessments.self_assessment.start|utc|date:"H:i" }}"
>
</div>
<p class="setting-help">{% trans "Specify a start date for the self assessment period." %}</p>
</li> </li>
<li class="field comp-setting-entry"> <li class="field comp-setting-entry">
<div class="wrapper-comp-setting"> <div class="wrapper-comp-setting">
<label for="self_assessment_due_date" class="setting-label">{% trans "Due Date" %}</label> <label for="self_assessment_due_date" class="setting-label">{% trans "Due Date" %}</label>
<input id="self_assessment_due_date" type="datetime-local" class="input setting-input" value="{{ assessments.self_assessment.due }}"> <input
id="self_assessment_due_date"
type="text"
class="input setting-input"
value="{{ assessments.self_assessment.due|utc|date:"Y-m-d" }}"
>
</div>
<div class="wrapper-comp-setting">
<label for="self_assessment_due_time" class="setting-label">{% trans "Due Time" %}</label>
<input
id="self_assessment_due_time"
type="text"
class="input setting-input"
value="{{ assessments.self_assessment.due|utc|date:"H:i" }}"
>
</div> </div>
<p class="setting-help">{% trans "If desired, specify a due date for the self assessment period. If no date is specified, self assessment can run as long as the problem is open."%}</p> <p class="setting-help">{% trans "Specify a due date for the self assessment period." %}</p>
</li> </li>
</ul> </ul>
</div> </div>
......
...@@ -437,7 +437,8 @@ ...@@ -437,7 +437,8 @@
], ],
"assessments": { "assessments": {
"peer_assessment": { "peer_assessment": {
"start": "2014-10-04T00:00:00", "start": "",
"due": "",
"must_grade": 5, "must_grade": 5,
"must_be_graded_by": 3 "must_be_graded_by": 3
}, },
......
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -26,7 +26,7 @@ describe("OpenAssessment.Container", function () { ...@@ -26,7 +26,7 @@ describe("OpenAssessment.Container", function () {
templateElement: $("#template").get(0), templateElement: $("#template").get(0),
addButtonElement: $("#add_button").get(0), addButtonElement: $("#add_button").get(0),
removeButtonClass: "remove_button", removeButtonClass: "remove_button",
containerItemClass: "test_item", containerItemClass: "container_item",
} }
); );
}; };
...@@ -40,8 +40,10 @@ describe("OpenAssessment.Container", function () { ...@@ -40,8 +40,10 @@ describe("OpenAssessment.Container", function () {
// so we just define the fixture inline. // so we just define the fixture inline.
setFixtures( setFixtures(
'<div id="container" />' + '<div id="container" />' +
'<div id="template" test_id="">' + '<div id="template">' +
'<div class="remove_button" />' + '<div class="container_item" test_id="">' +
'<div class="remove_button" />' +
'</div>' +
'</div>' + '</div>' +
'<div id="add_button" />' '<div id="add_button" />'
); );
...@@ -142,7 +144,7 @@ describe("OpenAssessment.Container", function () { ...@@ -142,7 +144,7 @@ describe("OpenAssessment.Container", function () {
// Add an item directly to the container element in the DOM, // Add an item directly to the container element in the DOM,
// before initializing the container object. // before initializing the container object.
$("#container").append( $("#container").append(
'<div class="test_item" test_id="0">' + '<div class="container_item" test_id="0">' +
'<div class="remove_button" />' + '<div class="remove_button" />' +
'<div>' '<div>'
); );
......
...@@ -36,8 +36,8 @@ describe("OpenAssessment edit assessment views", function() { ...@@ -36,8 +36,8 @@ describe("OpenAssessment edit assessment views", function() {
it("Loads a description", function() { it("Loads a description", function() {
view.mustGradeNum(1); view.mustGradeNum(1);
view.mustBeGradedByNum(2); view.mustBeGradedByNum(2);
view.startDatetime("2014-01-01T00:00"); view.startDatetime("2014-01-01", "00:00");
view.dueDatetime("2014-03-04T00:00"); view.dueDatetime("2014-03-04", "00:00");
expect(view.description()).toEqual({ expect(view.description()).toEqual({
must_grade: 1, must_grade: 1,
must_be_graded_by: 2, must_be_graded_by: 2,
...@@ -65,8 +65,8 @@ describe("OpenAssessment edit assessment views", function() { ...@@ -65,8 +65,8 @@ describe("OpenAssessment edit assessment views", function() {
it("Enables and disables", function() { testEnableAndDisable(view); }); it("Enables and disables", function() { testEnableAndDisable(view); });
it("Loads a description", function() { it("Loads a description", function() {
view.startDatetime("2014-01-01T00:00"); view.startDatetime("2014-01-01", "00:00");
view.dueDatetime("2014-03-04T00:00"); view.dueDatetime("2014-03-04", "00:00");
expect(view.description()).toEqual({ expect(view.description()).toEqual({
start: "2014-01-01T00:00", start: "2014-01-01T00:00",
due: "2014-03-04T00:00" due: "2014-03-04T00:00"
...@@ -74,8 +74,8 @@ describe("OpenAssessment edit assessment views", function() { ...@@ -74,8 +74,8 @@ describe("OpenAssessment edit assessment views", function() {
}); });
it("Handles default dates", function() { it("Handles default dates", function() {
view.startDatetime(""); view.startDatetime("", "");
view.dueDatetime(""); view.dueDatetime("", "");
expect(view.description().start).toBe(null); expect(view.description().start).toBe(null);
expect(view.description().due).toBe(null); expect(view.description().due).toBe(null);
}); });
......
...@@ -47,17 +47,17 @@ describe("OpenAssessment.EditSettingsView", function() { ...@@ -47,17 +47,17 @@ describe("OpenAssessment.EditSettingsView", function() {
}); });
it("sets and loads the submission start/due dates", function() { it("sets and loads the submission start/due dates", function() {
view.submissionStart(""); view.submissionStart("", "");
expect(view.submissionStart()).toBe(null); expect(view.submissionStart()).toBe(null);
view.submissionStart("2014-04-01T00:00.0000Z"); view.submissionStart("2014-04-01", "00:00");
expect(view.submissionStart()).toEqual("2014-04-01T00:00.0000Z"); expect(view.submissionStart()).toEqual("2014-04-01T00:00");
view.submissionDue(""); view.submissionDue("", "");
expect(view.submissionDue()).toBe(null); expect(view.submissionDue()).toBe(null);
view.submissionDue("2014-05-02T00:00.0000Z"); view.submissionDue("2014-05-02", "00:00");
expect(view.submissionDue()).toEqual("2014-05-02T00:00.0000Z"); expect(view.submissionDue()).toEqual("2014-05-02T00:00");
}); });
it("sets and loads the image enabled state", function() { it("sets and loads the image enabled state", function() {
......
...@@ -10,11 +10,19 @@ For example, to create a container for an item called "test_item", ...@@ -10,11 +10,19 @@ For example, to create a container for an item called "test_item",
the DOM should look something like: the DOM should look something like:
<div id="test_container" /> <div id="test_container" />
<div id="test_item_template"> <div id="test_item_template">
<div class="test_item_remove_button">Remove</div> <div class="test_item">
<p>This is the default value for the item.</p> <div class="test_item_remove_button">Remove</div>
<p>This is the default value for the item.</p>
</div>
</div> </div>
<div id="test_item_add_button">Add</div> <div id="test_item_add_button">Add</div>
A critical property of this setup is that the element you want to
include/duplicate is wrapped inside of a template element which is
the one that your reference when referring to a template. In the
above example, $("#test_item_template") would be the appropriate
reference to the template.
You can then initialize the container: You can then initialize the container:
>>> var container = $("#test_container").get(0); >>> var container = $("#test_container").get(0);
>>> var template = $("#test_item_template").get(0); >>> var template = $("#test_item_template").get(0);
...@@ -82,7 +90,10 @@ OpenAssessment.Container.prototype = { ...@@ -82,7 +90,10 @@ OpenAssessment.Container.prototype = {
// Copy the template into the container // Copy the template into the container
// Remove any CSS IDs (since now the element is not unique) // Remove any CSS IDs (since now the element is not unique)
// and add the item class so we can find it later. // and add the item class so we can find it later.
// Note that the element we add is the first child of the template element.
// For more on the template structure expected, see the class comment
$(this.templateElement) $(this.templateElement)
.children().first()
.clone() .clone()
.removeAttr('id') .removeAttr('id')
.toggleClass('is--hidden', false) .toggleClass('is--hidden', false)
......
/** /**
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).addClass('is--hidden');
$(this.shownSelector, this.element).removeClass('is--hidden');
},
hide: function() {
$(this.hiddenSelector, this.element).removeClass('is--hidden');
$(this.shownSelector, this.element).addClass('is--hidden');
}
};
/**
Interface for editing peer assessment settings. Interface for editing peer assessment settings.
Args: Args:
...@@ -62,11 +12,25 @@ OpenAssessment.EditPeerAssessmentView = function(element) { ...@@ -62,11 +12,25 @@ OpenAssessment.EditPeerAssessmentView = function(element) {
this.element = element; this.element = element;
this.name = "peer-assessment"; this.name = "peer-assessment";
// Configure the toggle checkbox to enable/disable this assessment
new OpenAssessment.ToggleControl( new OpenAssessment.ToggleControl(
this.element, this.element,
"#peer_assessment_description_closed", "#peer_assessment_description_closed",
"#peer_assessment_settings_editor" "#peer_assessment_settings_editor"
).install("#include_peer_assessment"); ).install("#include_peer_assessment");
// Configure the date and time fields
this.startDatetimeControl = new OpenAssessment.DatetimeControl(
this.element,
"#peer_assessment_start_date",
"#peer_assessment_start_time"
).install();
this.dueDatetimeControl = new OpenAssessment.DatetimeControl(
this.element,
"#peer_assessment_due_date",
"#peer_assessment_due_time"
).install();
}; };
OpenAssessment.EditPeerAssessmentView.prototype = { OpenAssessment.EditPeerAssessmentView.prototype = {
...@@ -141,28 +105,28 @@ OpenAssessment.EditPeerAssessmentView.prototype = { ...@@ -141,28 +105,28 @@ OpenAssessment.EditPeerAssessmentView.prototype = {
Get or set the start date and time of the assessment. Get or set the start date and time of the assessment.
Args: Args:
datetime (string, optional): If provided, set the datetime to this value. dateString (string, optional): If provided, set the date (YY-MM-DD).
timeString (string, optional): If provided, set the time (HH:MM, 24-hour clock).
Returns: Returns:
string (ISO-formatted UTC datetime) string (ISO-formatted UTC datetime)
**/ **/
startDatetime: function(datetime) { startDatetime: function(dateString, timeString) {
var sel = $("#peer_assessment_start_date", this.element); return this.startDatetimeControl.datetime(dateString, timeString);
return OpenAssessment.Fields.datetimeField(sel, datetime);
}, },
/** /**
Get or set the due date and time of the assessment. Get or set the due date and time of the assessment.
Args: Args:
datetime (string, optional): If provided, set the datetime to this value. dateString (string, optional): If provided, set the date (YY-MM-DD).
timeString (string, optional): If provided, set the time (HH:MM, 24-hour clock).
Returns: Returns:
string (ISO-formatted UTC datetime) string (ISO-formatted UTC datetime)
**/ **/
dueDatetime: function(datetime) { dueDatetime: function(dateString, timeString) {
var sel = $("#peer_assessment_due_date", this.element); return this.dueDatetimeControl.datetime(dateString, timeString);
return OpenAssessment.Fields.datetimeField(sel, datetime);
}, },
/** /**
...@@ -191,11 +155,25 @@ OpenAssessment.EditSelfAssessmentView = function(element) { ...@@ -191,11 +155,25 @@ OpenAssessment.EditSelfAssessmentView = function(element) {
this.element = element; this.element = element;
this.name = "self-assessment"; this.name = "self-assessment";
// Configure the toggle checkbox to enable/disable this assessment
new OpenAssessment.ToggleControl( new OpenAssessment.ToggleControl(
this.element, this.element,
"#self_assessment_description_closed", "#self_assessment_description_closed",
"#self_assessment_settings_editor" "#self_assessment_settings_editor"
).install("#include_self_assessment"); ).install("#include_self_assessment");
// Configure the date and time fields
this.startDatetimeControl = new OpenAssessment.DatetimeControl(
this.element,
"#self_assessment_start_date",
"#self_assessment_start_time"
).install();
this.dueDatetimeControl = new OpenAssessment.DatetimeControl(
this.element,
"#self_assessment_due_date",
"#self_assessment_due_time"
).install();
}; };
OpenAssessment.EditSelfAssessmentView.prototype = { OpenAssessment.EditSelfAssessmentView.prototype = {
...@@ -239,28 +217,28 @@ OpenAssessment.EditSelfAssessmentView.prototype = { ...@@ -239,28 +217,28 @@ OpenAssessment.EditSelfAssessmentView.prototype = {
Get or set the start date and time of the assessment. Get or set the start date and time of the assessment.
Args: Args:
datetime (string, optional): If provided, set the datetime to this value. dateString (string, optional): If provided, set the date (YY-MM-DD).
timeString (string, optional): If provided, set the time (HH:MM, 24-hour clock).
Returns: Returns:
string (ISO-formatted UTC datetime) string (ISO-formatted UTC datetime)
**/ **/
startDatetime: function(datetime) { startDatetime: function(dateString, timeString) {
var sel = $("#self_assessment_start_date", this.element); return this.startDatetimeControl.datetime(dateString, timeString);
return OpenAssessment.Fields.datetimeField(sel, datetime);
}, },
/** /**
Get or set the due date and time of the assessment. Get or set the due date and time of the assessment.
Args: Args:
datetime (string, optional): If provided, set the datetime to this value. dateString (string, optional): If provided, set the date (YY-MM-DD).
timeString (string, optional): If provided, set the time (HH:MM, 24-hour clock).
Returns: Returns:
string (ISO-formatted UTC datetime) string (ISO-formatted UTC datetime)
**/ **/
dueDatetime: function(datetime) { dueDatetime: function(dateString, timeString) {
var sel = $("#self_assessment_due_date", this.element); return this.dueDatetimeControl.datetime(dateString, timeString);
return OpenAssessment.Fields.datetimeField(sel, datetime);
}, },
/** /**
......
...@@ -7,12 +7,6 @@ OpenAssessment.Fields = { ...@@ -7,12 +7,6 @@ OpenAssessment.Fields = {
return sel.val(); 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) { intField: function(sel, value) {
if (typeof(value) !== "undefined") { sel.val(value); } if (typeof(value) !== "undefined") { sel.val(value); }
return parseInt(sel.val(), 10); return parseInt(sel.val(), 10);
...@@ -23,3 +17,113 @@ OpenAssessment.Fields = { ...@@ -23,3 +17,113 @@ OpenAssessment.Fields = {
return sel.prop("checked"); return sel.prop("checked");
}, },
}; };
/**
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).addClass('is--hidden');
$(this.shownSelector, this.element).removeClass('is--hidden');
},
hide: function() {
$(this.hiddenSelector, this.element).removeClass('is--hidden');
$(this.shownSelector, this.element).addClass('is--hidden');
}
};
/**
Date and time input fields.
Args:
element (DOM element): The parent element of the control inputs.
datePicker (string): The CSS selector for the date input field.
timePicker (string): The CSS selector for the time input field.
**/
OpenAssessment.DatetimeControl = function(element, datePicker, timePicker) {
this.element = element;
this.datePicker = datePicker;
this.timePicker = timePicker;
};
OpenAssessment.DatetimeControl.prototype = {
/**
Configure the date and time picker inputs.
Returns:
OpenAssessment.DatetimeControl
**/
install: function() {
var dateString = $(this.datePicker, this.element).val();
$(this.datePicker, this.element).datepicker({ showButtonPanel: true })
.datepicker("option", "dateFormat", "yy-mm-dd")
.datepicker("setDate", dateString);
$(this.timePicker, this.element).timepicker({
timeFormat: 'H:i',
step: 60
});
return this;
},
/**
Get or set the date and time.
Args:
dateString (string, optional): If provided, set the date (YY-MM-DD).
timeString (string, optional): If provided, set the time (HH:MM, 24-hour clock).
Returns:
ISO-formatted datetime string.
**/
datetime: function(dateString, timeString) {
var datePickerSel = $(this.datePicker, this.element);
var timePickerSel = $(this.timePicker, this.element);
if (typeof(dateString) !== "undefined") { datePickerSel.datepicker("setDate", dateString); }
if (typeof(timeString) !== "undefined") { timePickerSel.val(timeString); }
if (datePickerSel.val() === "" && timePickerSel.val() === "") {
return null;
}
return datePickerSel.val() + "T" + timePickerSel.val();
}
};
\ No newline at end of file
...@@ -13,6 +13,19 @@ OpenAssessment.EditSettingsView = function(element, assessmentViews) { ...@@ -13,6 +13,19 @@ OpenAssessment.EditSettingsView = function(element, assessmentViews) {
this.settingsElement = element; this.settingsElement = element;
this.assessmentsElement = $(element).siblings('#openassessment_assessment_module_settings_editors').get(0); this.assessmentsElement = $(element).siblings('#openassessment_assessment_module_settings_editors').get(0);
this.assessmentViews = assessmentViews; this.assessmentViews = assessmentViews;
// Configure the date and time fields
this.startDatetimeControl = new OpenAssessment.DatetimeControl(
this.element,
"#openassessment_submission_start_date",
"#openassessment_submission_start_time"
).install();
this.dueDatetimeControl = new OpenAssessment.DatetimeControl(
this.element,
"#openassessment_submission_due_date",
"#openassessment_submission_due_time"
).install();
}; };
...@@ -37,30 +50,30 @@ OpenAssessment.EditSettingsView.prototype = { ...@@ -37,30 +50,30 @@ OpenAssessment.EditSettingsView.prototype = {
Get or set the submission start date. Get or set the submission start date.
Args: Args:
datetime (string, optional): If provided, set the datetime. dateString (string, optional): If provided, set the date (YY-MM-DD).
timeString (string, optional): If provided, set the time (HH:MM, 24-hour clock).
Returns: Returns:
string (ISO-format UTC datetime) string (ISO-format UTC datetime)
**/ **/
submissionStart: function(datetime) { submissionStart: function(dateString, timeString) {
var sel = $("#openassessment_submission_start_editor", this.settingsElement); return this.startDatetimeControl.datetime(dateString, timeString);
return OpenAssessment.Fields.datetimeField(sel, datetime);
}, },
/** /**
Get or set the submission end date. Get or set the submission end date.
Args: Args:
datetime (string, optional): If provided, set the datetime. dateString (string, optional): If provided, set the date (YY-MM-DD).
timeString (string, optional): If provided, set the time (HH:MM, 24-hour clock).
Returns: Returns:
string (ISO-format UTC datetime) string (ISO-format UTC datetime)
**/ **/
submissionDue: function(datetime) { submissionDue: function(dateString, timeString) {
var sel = $("#openassessment_submission_start_editor", this.settingsElement); return this.dueDatetimeControl.datetime(dateString, timeString);
return OpenAssessment.Fields.datetimeField(sel, datetime);
}, },
/** /**
......
...@@ -7,6 +7,8 @@ import copy ...@@ -7,6 +7,8 @@ import copy
import logging import logging
from django.template.loader import get_template from django.template.loader import get_template
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
from dateutil.parser import parse as parse_date
import pytz
from voluptuous import MultipleInvalid from voluptuous import MultipleInvalid
from xblock.core import XBlock from xblock.core import XBlock
from xblock.fragment import Fragment from xblock.fragment import Fragment
...@@ -14,6 +16,7 @@ from openassessment.xblock import xml ...@@ -14,6 +16,7 @@ from openassessment.xblock import xml
from openassessment.xblock.validation import validator from openassessment.xblock.validation import validator
from openassessment.xblock.data_conversion import create_rubric_dict from openassessment.xblock.data_conversion import create_rubric_dict
from openassessment.xblock.schema import EDITOR_UPDATE_SCHEMA from openassessment.xblock.schema import EDITOR_UPDATE_SCHEMA
from openassessment.xblock.resolve_dates import resolve_dates
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
...@@ -62,34 +65,27 @@ class StudioMixin(object): ...@@ -62,34 +65,27 @@ class StudioMixin(object):
'assessments (dict) 'assessments (dict)
""" """
# Copies the rubric assessments so that we can change student # In the authoring GUI, date and time fields should never be null.
# training examples from dict -> str without negatively modifying # Therefore, we need to resolve all "default" dates to datetime objects
# the openassessmentblock definition. # before displaying them in the editor.
# Django Templates cannot handle dict keys with dashes, so we'll convert __, __, date_ranges = resolve_dates(
# the dashes to underscores. self.start, self.due,
[(self.submission_start, self.submission_due)] +
# used_assessments (and its unused counterpart) are lists intended to indicate [(asmnt.get('start'), asmnt.get('due')) for asmnt in self.valid_assessments]
# the order that settings editors should be rendered. Using lists allows a set order )
# which django can easily convert into template names.
used_assessments = []
assessments = {}
for assessment in self.rubric_assessments:
name = assessment['name'].replace('-', '_')
used_assessments.append(name)
assessments[name] = copy.deepcopy(assessment)
unused_assessments = {'student_training', 'peer_assessment', 'self_assessment', 'example_based_assessment'} submission_start, submission_due = date_ranges[0]
unused_assessments = unused_assessments - set(used_assessments) assessments = self._assessments_editor_context(date_ranges[1:])
student_training_module = self.get_assessment_module( used_assessments = assessments.keys()
'student-training' all_assessments = set(['student_training', 'peer_assessment', 'self_assessment', 'example_based_assessment'])
) unused_assessments = all_assessments - set(used_assessments)
student_training_module = self.get_assessment_module('student-training')
if student_training_module: if student_training_module:
student_training_module = copy.deepcopy(student_training_module) student_training_module = copy.deepcopy(student_training_module)
try: try:
examples = xml.serialize_examples_to_xml_str( examples = xml.serialize_examples_to_xml_str(student_training_module )
student_training_module
)
student_training_module["examples"] = examples student_training_module["examples"] = examples
assessments['training'] = student_training_module assessments['training'] = student_training_module
# We do not expect serialization to raise an exception, but if it does, # We do not expect serialization to raise an exception, but if it does,
...@@ -97,8 +93,8 @@ class StudioMixin(object): ...@@ -97,8 +93,8 @@ class StudioMixin(object):
except: except:
logger.exception("An error occurred while serializing the XBlock") logger.exception("An error occurred while serializing the XBlock")
submission_due = self.submission_due if self.submission_due else '' submission_due = parse_date(self.submission_due).replace(tzinfo=pytz.utc) if self.submission_due else ''
submission_start = self.submission_start if self.submission_start else '' submission_start = parse_date(self.submission_start).replace(tzinfo=pytz.utc) if self.submission_start else ''
# Every rubric requires one criterion. If there is no criteria # Every rubric requires one criterion. If there is no criteria
# configured for the XBlock, return one empty default criterion, with # configured for the XBlock, return one empty default criterion, with
...@@ -192,3 +188,27 @@ class StudioMixin(object): ...@@ -192,3 +188,27 @@ class StudioMixin(object):
'success': True, 'msg': u'', 'success': True, 'msg': u'',
'is_released': self.is_released() 'is_released': self.is_released()
} }
def _assessments_editor_context(self, assessment_dates):
"""
Transform the rubric assessments list into the context
we will pass to the Django template.
Args:
assessment_dates: List of assessment date ranges (tuples of start/end datetimes).
Returns:
dict
"""
assessments = {}
for asmnt, date_range in zip(self.rubric_assessments, assessment_dates):
# Django Templates cannot handle dict keys with dashes, so we'll convert
# the dashes to underscores.
name = asmnt['name']
template_name = name.replace('-', '_')
assessments[template_name] = copy.deepcopy(asmnt)
assessments[template_name]['start'] = date_range[0]
assessments[template_name]['due'] = date_range[1]
return assessments
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