Commit a93984c0 by Will Daly

Integrate container and container item into the rubric editing view.

Minify CSS.
parent 7b793ad4
{% load i18n %}
{% spaceless %}
<li class="openassessment_criterion is-collapsible">
<div class="openassessment_criterion_header view-outline">
<a class="action expand-collapse collapse"><i class="icon-caret-down ui-toggle-expansion"></i></a>
<h6 class="openassessment_criterion_header_title">{% trans "Criterion" %}</h6>
<div class="openassessment_rubric_remove_button"><h2>{% trans "Remove" %}</h2></div>
</div>
<div class="openassessment_criterion_body wrapper-comp-settings">
<ul class="list-input settings-list openassessment_criterion_basic_editor">
<li class="field comp-setting-entry">
<div class="wrapper-comp-settings">
<label class="openassessment_criterion_name_label setting-label">
{% trans "Criterion Name" %}
<input
class="openassessment_criterion_name input setting-input"
type="text"
value="{{ criterion_name }}"
>
</label>
</div>
</li>
<li class="field comp-setting-entry">
<div class="wrapper-comp-settings">
<label class="openassessment_criterion_prompt_label setting-label">
{% trans "Criterion Prompt" %}
<textarea class="openassessment_criterion_prompt setting-input">{{ criterion_prompt }}</textarea>
</label>
</div>
</li>
</ul>
<ul class="openassessment_criterion_option_list">
{% for option in criterion_options %}
{% include "openassessmentblock/edit/oa_edit_option.html" with option_name=option.name option_points=option.points option_explanation=option.explanation %}
{% endfor %}
</ul>
<div class="openassessment_criterion_add_option openassessment_option_header">
<h2>{% trans "Add Another Option"%}</h2>
</div>
<div class="openassessment_criterion_feedback_wrapper wrapper-comp-settings">
<ul class="list-input settings-list">
<li class="field comp-setting-entry">
<div class="wrapper-comp-setting">
<label class="setting-label">
{% trans "Criterion Feedback" %}
<select class="openassessment_criterion_feedback input setting-input">
<option value="disabled">{% trans "Disabled" %}</option>
<option value="optional" {% if criterion_feedback == "optional" %} selected="true" {% endif %}>{% trans "Optional" %}</option>
<option value="required" {% if criterion_feedback == "required" %} selected="true" {% endif %}>{% trans "Required" %}</option>
</select>
</label>
</div>
<p class="setting-help">
{% trans "Select one of the options above. This describes whether or not the student will have to provide criterion feedback." %}
</p>
</li>
</ul>
</div>
</div>
</li>
{% endspaceless %}
\ No newline at end of file
{% load i18n %}
{% spaceless %}
<li class="openassessment_criterion_option">
<div class="openassessment_option_header">
<span class="openassessment_option_header_title">{% trans "Option" %}</span>
<div class="openassessment_rubric_remove_button">
<h2>{% trans "Remove" %}</h2>
</div>
</div>
<div class="wrapper-comp-settings">
<ul class="list-input settings-list">
<li class="field comp-setting-entry openassessment_criterion_option_name_wrapper">
<div class="wrapper-comp-setting">
<label class="openassessment_criterion_option_name_label setting-label">
{% trans "Option Name"%}
<input
class="openassessment_criterion_option_name input input-label"
type="text"
value="{{ option_name }}"
>
</label>
</div>
</li>
<li class="field comp-setting-entry openassessment_criterion_option_point_wrapper">
<div class="wrapper-comp-setting">
<label class="openassessment_criterion_option_points_label setting-label">
{% trans "Option Points"%}
<input
class="openassessment_criterion_option_points input setting-input"
type="number"
value="{{ option_points }}"
min="0"
>
</label>
</div>
</li>
<li class="field comp-setting-entry openassessment_criterion_option_explanation_wrapper">
<div class="wrapper-comp-setting">
<label class="openassessment_criterion_option_explanation_label setting-label">
{% trans "Option Explanation"%}
<textarea class="openassessment_criterion_option_explanation setting-input">{{ option_explanation }}</textarea>
</label>
</div>
</li>
</ul>
</div>
</li>
{% endspaceless %}
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -385,44 +385,46 @@ ...@@ -385,44 +385,46 @@
"title": "The most important of all questions.", "title": "The most important of all questions.",
"submission_due": "2014-10-1T10:00:00", "submission_due": "2014-10-1T10:00:00",
"criteria": [ "criteria": [
{ {
"name": "Criterion 1", "name": "Criterion with two options",
"prompt": "Prompt 1", "prompt": "Prompt for criterion with two options",
"order_num": 0, "order_num": 0,
"feedback": "optional", "feedback": "disabled",
"options": [ "options": [
{ {
"order_num": 2, "order_num": 0,
"points": 1,
"name": "Fair",
"explanation": "Fair explanation"
},
{
"order_num": 1,
"points": 2, "points": 2,
"name": "Good" "name": "Good",
"explanation": "Good explanation"
} }
], ],
"points_possible": 2 "points_possible": 2
}, },
{ {
"name": "Criterion 2", "name": "Criterion with no options",
"prompt": "Prompt 2", "prompt": "Prompt for criterion with no options",
"order_num": 1, "order_num": 0,
"options": [ "options": [],
{ "feedback": "required",
"order_num": 1, "points_possible": 0
"points": 1,
"name": "Fair"
}
],
"points_possible": 2
}, },
{ {
"name": "Criterion 3", "name": "Criterion with optional feedback",
"prompt": "Prompt 3", "prompt": "Prompt for criterion with optional feedback",
"order_num": 2, "order_num": 2,
"feedback": "optional", "feedback": "optional",
"options": [ "options": [
{ {
"order_num": 2, "order_num": 0,
"points": 2, "points": 2,
"name": "Good" "name": "Good",
"explanation": "Good explanation"
} }
], ],
"points_possible": 2 "points_possible": 2
......
...@@ -4,80 +4,158 @@ ...@@ -4,80 +4,158 @@
describe("OpenAssessment.Container", function () { describe("OpenAssessment.Container", function () {
var counter = 0;
var StubContainerItem = function(element) {
// Assign an ID to the item if it doesn't already have one.
if ($(element).attr("test_id") === "") {
$(element).attr("test_id", counter);
counter += 1;
}
this.getFieldValues = function() {
var testIdNum = parseInt($(element).attr("test_id"), 10);
return { id: testIdNum };
};
};
var container = null; var container = null;
var createContainer = function() {
return new OpenAssessment.Container(
StubContainerItem, {
containerElement: $("#container").get(0),
templateElement: $("#template").get(0),
addButtonElement: $("#add_button").get(0),
removeButtonClass: "remove_button",
containerItemClass: "test_item",
}
);
};
beforeEach(function () { beforeEach(function () {
jasmine.getFixtures().fixturesPath = 'base/fixtures'; // Reset the counter before each test
loadFixtures('oa_edit.html'); counter = 0;
container = new OpenAssessment.Container( // Install a minimal fixture
$('#openassessment_criterion_list'), // We don't need to use a full ORA2 template for this,
{ // so we just define the fixture inline.
'openassessment_criterion': OpenAssessment.RubricCriterion setFixtures(
} '<div id="container" />' +
) '<div id="template" test_id="">' +
}); '<div class="remove_button" />' +
'</div>' +
'<div id="add_button" />'
);
it("adds a criterion", function () { // Create the container and configure it
var previousSize = $('.openassessment_criterion').length; // to use the stub container item.
container.add('openassessment_criterion'); container = createContainer();
var newSize = $('.openassessment_criterion').length;
expect(newSize).toEqual(previousSize + 1);
}); });
it("removes a criterion", function () { it("adds and removes items", function() {
container.add('openassessment_criterion'); // Initially, there should be no items
var previousSize = $('.openassessment_criterion').length; expect(container.getItemValues()).toEqual([]);
container.remove(1);
var newSize = $('.openassessment_criterion').length; // Add an item
expect(newSize).toEqual(previousSize - 1); container.add();
expect(container.getItemValues()).toEqual([
{ id: 0 }
]);
// Add a second item
container.add();
expect(container.getItemValues()).toEqual([
{ id: 0 },
{ id: 1 }
]);
// Add a third item
container.add();
expect(container.getItemValues()).toEqual([
{ id: 0 },
{ id: 1 },
{ id: 2 }
]);
// Remove the second item
container.remove(container.getItemElement(1));
expect(container.getItemValues()).toEqual([
{ id: 0 },
{ id: 2 },
]);
// Remove the first item
container.remove(container.getItemElement(0));
expect(container.getItemValues()).toEqual([
{ id: 2 },
]);
// Remove the last item
container.remove(container.getItemElement(0));
expect(container.getItemValues()).toEqual([]);
}); });
it("requests an invalid template", function () { it("ignores unrecognized DOM elements", function() {
var error = false; // Add some items to the container
try{ container.add();
container.getHtmlTemplate('not_a_template'); container.add();
} catch (e) { expect(container.getItemValues().length).toEqual(2);
error = true;
} // Add an extra element to the container in the DOM
expect(error).toBe(true); $("<p>Not a container item!</p>").appendTo("#parent_element");
// Expect the count to remain the same
expect(container.getItemValues().length).toEqual(2);
// Add another element
container.add();
expect(container.getItemValues().length).toEqual(3);
// Remove the first element
container.remove(container.getItemElement(0));
expect(container.getItemValues().length).toEqual(2);
}); });
it("installs delete buttons", function () { it("adds an element when the add button is pressed", function() {
container.installDeleteButtons($('#openassessment_criterion_list')); // Press the add button
expect(container.getItemValues().length).toEqual(0);
$("#add_button").click();
expect(container.getItemValues().length).toEqual(1);
}); });
it("parses out unacceptable container items", function () { it("removes an element when the remove button is pressed", function() {
container.element.append("<p> Hello, not an element here. </p>"); // Add some items
var error = false; container.add();
try{ container.add();
container.getItemValues(); container.add();
} catch (e) { expect(container.getItemValues().length).toEqual(3);
error = true;
} // Press the button to delete the second item
expect(error).toBe(true); $(".remove_button", container.getItemElement(1)).click();
expect(container.getItemValues().length).toEqual(2);
expect(container.getItemValues()).toEqual([
{ id: 0 },
{ id: 2 }
]);
}); });
it("returns correct item dictionary", function () { it("configures remove buttons for pre-existing items", function() {
var items = container.getItemValues(); // Add an item directly to the container element in the DOM,
var item = items[0]; // before initializing the container object.
$("#container").append(
'<div class="test_item" test_id="0">' +
'<div class="remove_button" />' +
'<div>'
);
expect(item.name).toEqual(jasmine.any(String)); // Initialize the container object
expect(item.prompt).toEqual(jasmine.any(String)); container = createContainer();
expect(item.feedback).toEqual(jasmine.any(String));
expect(item.options).toEqual(jasmine.any(Array));
expect(item.options[0].name).toEqual(jasmine.any(String));
expect(parseInt(item.options[0].points)).toEqual(jasmine.any(Number));
expect(item.options[0].explanation).toEqual(jasmine.any(String));
}); // Verify that the container recognizes the pre-existing item
expect(container.getItemValues()).toEqual([{ id: 0 }]);
it("checks for undefined selection type", function () { // Expect that we can click the "remove" button
var error = false; // to remove the item.
try{ $(".remove_button", container.getItemElement(0)).click();
container.add("lolz this isn't a valid selection type"); expect(container.getItemValues().length).toEqual(0);
} catch (e) {
error = true;
}
expect(error).toBe(true);
}); });
}); });
\ No newline at end of file
/**
Tests for the rubric editing view.
**/
describe("OpenAssessment.EditRubricView", function() {
var view = null;
beforeEach(function() {
jasmine.getFixtures().fixturesPath = 'base/fixtures';
loadFixtures('oa_edit.html');
var el = $("#oa_rubric_editor_wrapper").get(0);
view = new OpenAssessment.EditRubricView(el);
});
it("reads a criteria definition from the editor", function() {
// This assumes a particular structure of the DOM,
// which is set by the HTML fixture.
var criteria = view.criteriaDefinition();
expect(criteria.length).toEqual(3);
// Criterion with two options, feedback disabled
expect(criteria[0]).toEqual({
name: "Criterion with two options",
prompt: "Prompt for criterion with two options",
order_num: 0,
feedback: "disabled",
options: [
{
order_num: 0,
points: 1,
name: "Fair",
explanation: "Fair explanation"
},
{
order_num: 1,
points: 2,
name: "Good",
explanation: "Good explanation"
}
],
});
// Criterion with no options, feedback required
expect(criteria[1]).toEqual({
name: "Criterion with no options",
prompt: "Prompt for criterion with no options",
order_num: 1,
feedback: "required",
options: []
});
// Criterion with one option, feeback optional
expect(criteria[2]).toEqual({
name: "Criterion with optional feedback",
prompt: "Prompt for criterion with optional feedback",
order_num: 2,
feedback: "optional",
options: [
{
order_num: 0,
points: 2,
name: "Good",
explanation: "Good explanation"
}
]
});
});
it("reads the feedback prompt from the editor", function() {
view.feedbackPrompt("");
expect(view.feedbackPrompt()).toEqual("");
var prompt = "How do you think the student did overall?";
view.feedbackPrompt(prompt);
expect(view.feedbackPrompt()).toEqual(prompt);
});
});
\ No newline at end of file
/** /**
* Created by gward on 7/9/14. Container that handles addition / deletion of arbitrary items.
*/
An item is any object that has a `getFieldValues()` method,
/** which should return a JSON-serializable representation
Container to store arbitrary DOM elements for insertion, deletion and installation of self-delete buttons of the item.
Containers copy "template" elements to create new items.
For example, to create a container for an item called "test_item",
the DOM should look something like:
<div id="test_container" />
<div id="test_item_template">
<div class="test_item_remove_button">Remove</div>
<p>This is the default value for the item.</p>
</div>
<div id="test_item_add_button">Add</div>
You can then initialize the container:
>>> var container = $("#test_container").get(0);
>>> var template = $("#test_item_template").get(0);
>>> var addButton = $("#test_item_add_button").get(0);
>>>
>>> container = OpenAssessment.Container(
>>> ContainerItem, {
>>> containerElement: container,
>>> templateElement: template,
>>> addButtonElement: addButton,
>>> removeButtonClass: "test_item_remove_button"
>>> containerItemClass: "test_item"
>>> }
>>> );
The container is responsible for initializing the "add" and "remove" buttons,
including for pre-existing items in the container element.
Templates elements are never deleted, so they should be hidden using CSS styles.
Args: Args:
element (DOM element): The DOM element representing the container (usually an OL or a UL) containerItem (object): The container item object used to access
selectorDictionary (dict): Has keys which map element (str) to Container Item classes to which they are related the contents of items in the container.
Kwargs:
containerElement (DOM element): The element representing the container.
templateElement (DOM element): The element containing the template for creating new items.
addButtonElement (DOM element): The element of the button used to add new items to the container.
removeButtonClass (string): The CSS class of the button that removes an item from the container.
There may be one of these for each item in the container.
containerItemClass (string): The CSS class of items in the container.
New items will be assigned this class.
Returns:
OpenAssessment.Container
**/ **/
OpenAssessment.Container = function(element, selectorDictionary){ OpenAssessment.Container = function(containerItem, kwargs) {
this.element = element; this.containerItem = containerItem;
this.selectorDictionary = selectorDictionary; this.containerElement = kwargs.containerElement;
this.installDeleteButtons(element); this.templateElement = kwargs.templateElement;
this.addButtonElement = kwargs.addButtonElement;
this.removeButtonClass = kwargs.removeButtonClass;
this.containerItemClass = kwargs.containerItemClass;
// Install a click handler for the add button
$(this.addButtonElement).click($.proxy(this.add, this));
// Find items already in the container and install click
// handlers for the delete buttons.
var container = this;
$("." + this.removeButtonClass, this.containerElement).click(
function(eventData) { container.remove(eventData.target); }
);
// Initialize existing items, in case they need to install their
// own event handlers.
$("." + this.containerItemClass, this.containerElement).each(
function(index, element) { new container.containerItem(element); }
);
}; };
OpenAssessment.Container.prototype = { OpenAssessment.Container.prototype = {
/** /**
Adds a new item of the specified type to the DOM. Adds a new item to the container.
If the type is unrecognized,
Throws:
An error that alerts the user that an unknown type was attempted to be added to the container.
**/ **/
add: function(selectorString){ add: function() {
var type = this.selectorDictionary[selectorString]; // Copy the template into the container
if (type == undefined){ // Remove any CSS IDs (since now the element is not unique)
throw 'The string: ('+ selectorString + ') is not known by this container.'; // and add the item class so we can find it later.
} $(this.templateElement)
this.element.append(this.getHtmlTemplate(selectorString)); .clone()
}, .removeAttr('id')
.toggleClass('is--hidden', false)
/** .toggleClass(this.containerItemClass, true)
Removes a specified item from the DOM. This is distinct from (and not used by) delete buttons. .appendTo($(this.containerElement));
Args: // Install a click handler for the delete button
index(int): The index of the specified item to remove. // Since we just added the new element to the container,
// it should be the last one.
var container = this;
var containerItem = $("." + this.containerItemClass, this.containerElement).last()
containerItem.find('.' + this.removeButtonClass)
.click(function(eventData) { container.remove(eventData.target); } );
**/ // Initialize the item, allowing it to install event handlers.
remove: function(index){ new this.containerItem(containerItem.get(0));
var count = 0;
$(this.element).children().each(function(){
if (count == index){
$(this).remove();
return;
}
count++;
});
}, },
/** /**
Installs delete buttons on all sections of a certain element. Remove the item associated with an element.
Called both when we create a container, and when we add new elements. If the element is not itself an item, traverse up the
DOM tree until an item is found.
Args: Args:
liveElement (Jquery Element): an element that allows us to define the scope of delete button creation. element (DOM element): An element representing the container item
or an element within the container item.
**/ **/
installDeleteButtons: function(liveElement){ remove: function(element) {
$('.openassessment_delete_button', liveElement).each(function() { $(element).closest("." + this.containerItemClass).remove();
$(this).click(function () {
liveElement.closest('.openassessment_deletable').remove();
});
});
}, },
/** /**
Gets the values that each container defines for itself, in the order in which they are Retrieves the values that each container defines for itself, in the order in which they are
presented in the DOM. presented in the DOM.
Returns: Returns:
(list of ...): The list of the values that each container item associates with itself. array: The values representing each container item.
Throws:
An exception which notifies the user if there is an element in their container that is not
recognized as a part of the containers definition.
**/ **/
getItemValues: function () { getItemValues: function () {
var values = []; var values = [];
var container = this; var container = this;
$(this.element).children().each(function(){
//Attempts to find the type of a given element
var classes = $(this).attr('class').split(/\s+/);
var type = undefined;
for(var i = 0; i < classes.length; i++){
var c = classes[i];
if (container.selectorDictionary[c] != undefined){
type = container.selectorDictionary[c];
}
}
// If we couldn't resolve the type, we throw an exception. $("." + this.containerItemClass, this.containerElement).each(
if (type == undefined){ function(index, element) {
throw 'An item with classes (' + classes.join(' ') + var containerItem = new container.containerItem(element);
') was not found in a dict of known container items.'; var fieldValues = containerItem.getFieldValues();
values.push(fieldValues);
} }
);
var item = new type($(this));
var value = item.getFieldValues();
values.push(value);
});
return values; return values;
}, },
/** /**
Returns the specific HTML template that is defined for its container items. Retrieve the element representing an item in this container.
Args:
index (int): The index of the item, starting from 0.
Returns: Returns:
(str): The HTML template associated with the container item's type. DOM element if the item is found, otherwise null.
**/ **/
getHtmlTemplate: function(selectorString){ getItemElement: function(index) {
var selector = '.' + selectorString + '.openassessment_template'; var element = $("." + this.containerItemClass, this.containerElement).get(index);
var element = $(selector, this.element); return (element !== undefined) ? element : null;
if (element.length == 0){ },
throw "There is not an element which matches the selector (" + selector + ")";
}
// Because we are assuming each template will be found within a div which it is the sole occupant of,
// we can make this call safely to get the body and enclosing tab.
return element.parent().html();
}
}; };
...@@ -3,36 +3,39 @@ The RubricOption Class used to construct and maintain references to rubric optio ...@@ -3,36 +3,39 @@ The RubricOption Class used to construct and maintain references to rubric optio
container object. Constructs a new RubricOption element. container object. Constructs a new RubricOption element.
Args: Args:
parent (OpenAssessment.Container): The container that the option is a member of. element (OpenAssessment.Container): The container that the option is a member of.
Returns: Returns:
OpenAssessment.RubricOption OpenAssessment.RubricOption
**/ **/
OpenAssessment.RubricOption = function(element){ OpenAssessment.RubricOption = function(element) {
this.element = element; this.element = element;
}; };
OpenAssessment.RubricOption.prototype = { OpenAssessment.RubricOption.prototype = {
/** /**
Finds the values currently entered in the Option's fields, and returns them in a dictionary to the user. Finds the values currently entered in the Option's fields, and returns them.
Returns: Returns:
(dict) of the form: object literal of the form:
{ {
'name': 'Real Bad', 'name': 'Real Bad',
'points': 1, 'points': 1,
'explanation': 'Essay was primarily composed of emojis.' 'explanation': 'Essay was primarily composed of emojis.'
} }
**/ **/
getFieldValues: function (){ getFieldValues: function () {
var name = $('.openassessment_criterion_option_name', this.element).prop('value');
var points = $('.openassessment_criterion_option_points', this.element).prop('value');
var explanation = $('.openassessment_criterion_option_explanation', this.element).prop('value');
return { return {
'name': name, name: OpenAssessment.Fields.stringField(
'points': points, $('.openassessment_criterion_option_name', this.element)
'explanation': explanation ),
points: OpenAssessment.Fields.intField(
$('.openassessment_criterion_option_points', this.element)
),
explanation: OpenAssessment.Fields.stringField(
$('.openassessment_criterion_option_explanation', this.element)
)
}; };
} }
}; };
...@@ -47,12 +50,15 @@ Args: ...@@ -47,12 +50,15 @@ Args:
Returns: Returns:
OpenAssessment.RubricCriterion OpenAssessment.RubricCriterion
**/ **/
OpenAssessment.RubricCriterion = function(element){ OpenAssessment.RubricCriterion = function(element) {
this.element = element; this.element = element;
this.optionContainer = new OpenAssessment.Container( this.optionContainer = new OpenAssessment.Container(
$('.openassessment_criterion_option_list'), OpenAssessment.RubricOption, {
{ containerElement: $(".openassessment_criterion_option_list", this.element).get(0),
'openassessment_criterion_option': OpenAssessment.RubricOption templateElement: $("#openassessment_option_template").get(0),
addButtonElement: $(".openassessment_criterion_add_option", this.element).get(0),
removeButtonClass: "openassessment_rubric_remove_button",
containerItemClass: "openassessment_criterion_option",
} }
); );
}; };
...@@ -60,34 +66,36 @@ OpenAssessment.RubricCriterion = function(element){ ...@@ -60,34 +66,36 @@ OpenAssessment.RubricCriterion = function(element){
OpenAssessment.RubricCriterion.prototype = { OpenAssessment.RubricCriterion.prototype = {
/** /**
Finds the values currently entered in the Criterion's fields, and returns them in a dictionary to the user. Finds the values currently entered in the Criterion's fields, and returns them.
Returns: Returns:
(dict) of the form: object literal of the form:
{ {
'name': 'Emoji Content', 'name': 'Emoji Content',
'prompt': 'How expressive was the author with their words, and how much did they rely on emojis?', 'prompt': 'How expressive was the author with their words, and how much did they rely on emojis?',
'feedback': 'optional', 'feedback': 'optional',
'options': [ 'options': [
{ {
'name': 'Real Bad', 'name': 'Real Bad',
'points': 1, 'points': 1,
'explanation': 'Essay was primarily composed of emojis.' 'explanation': 'Essay was primarily composed of emojis.'
} }
... ...
] ]
} }
**/ **/
getFieldValues: function (){ getFieldValues: function () {
var name = $('.openassessment_criterion_name', this.element).prop('value');
var prompt = $('.openassessment_criterion_prompt', this.element).prop('value');
var feedback = $('.openassessment_criterion_feedback', this.element).prop('value');
var options = this.optionContainer.getItemValues();
return { return {
'name': name, name: OpenAssessment.Fields.stringField(
'prompt': prompt, $('.openassessment_criterion_name', this.element)
'options': options, ),
'feedback': feedback prompt: OpenAssessment.Fields.stringField(
$('.openassessment_criterion_prompt', this.element)
),
feedback: OpenAssessment.Fields.stringField(
$('.openassessment_criterion_feedback', this.element)
),
options: this.optionContainer.getItemValues()
}; };
} }
}; };
\ No newline at end of file
...@@ -3,38 +3,76 @@ Interface for editing rubric definitions. ...@@ -3,38 +3,76 @@ Interface for editing rubric definitions.
**/ **/
OpenAssessment.EditRubricView = function(element) { OpenAssessment.EditRubricView = function(element) {
this.element = element; this.element = element;
this.criteriaContainer = new OpenAssessment.Container(
OpenAssessment.RubricCriterion, {
containerElement: $("#openassessment_criterion_list", this.element).get(0),
templateElement: $("#openassessment_criterion_template", this.element).get(0),
addButtonElement: $("#openassessment_rubric_add_criterion", this.element).get(0),
removeButtonClass: "openassessment_rubric_remove_button",
containerItemClass: "openassessment_criterion",
}
);
}; };
OpenAssessment.EditRubricView.prototype = { OpenAssessment.EditRubricView.prototype = {
/** /**
Install event handlers. Construct a list of criteria definitions from the editor UI.
**/
load: function() {
//this.container = new Container(this.element, "openassessment__rubric__criterion", OpenAssessment.RubricCriterion);
},
/** Returns:
list of criteria objects
Example usage:
>>> editRubricView.criteriaDefinition();
[ [
{ {
name: "Criterion",
prompt: "Prompt",
order_num: 0, order_num: 0,
name: 'Criteria!' feedback: "disabled",
prompt: 'prompt',
feedback: 'disabled',
options: [ options: [
{ {
order_num: 0, order_num: 0,
name: 'name', points: 1,
explanation: 'explanation', name: "Good",
points: 1 explanation: "Explanation"
}, },
... ...
] ]
}, },
... ...
] ]
**/ **/
criteriaDefinition: function() { criteriaDefinition: function() {
//return this.container.getItemValues(); var criteria = this.criteriaContainer.getItemValues();
// Add order_num fields for criteria and options
for (var criterion_idx = 0; criterion_idx < criteria.length; criterion_idx++) {
var criterion = criteria[criterion_idx];
criterion.order_num = criterion_idx;
for (var option_idx = 0; option_idx < criterion.options.length; option_idx++) {
var option = criterion.options[option_idx];
option.order_num = option_idx;
}
}
return criteria;
}, },
/**
Get or set the feedback prompt in the editor.
This is the prompt shown to students when giving "overall" feedback
on a submission.
Args:
text (string, optional): If provided, set the feedback prompt to this value.
Returns:
string
**/
feedbackPrompt: function(text) {
var sel = $("#openassessment_rubric_feedback", this.element);
return OpenAssessment.Fields.stringField(sel, text);
}
}; };
\ No newline at end of file
...@@ -20,6 +20,9 @@ logger = logging.getLogger(__name__) ...@@ -20,6 +20,9 @@ logger = logging.getLogger(__name__)
class StudioMixin(object): class StudioMixin(object):
"""
Studio editing view for OpenAssessment XBlock.
"""
DEFAULT_CRITERIA = [ DEFAULT_CRITERIA = [
{ {
...@@ -30,10 +33,6 @@ class StudioMixin(object): ...@@ -30,10 +33,6 @@ class StudioMixin(object):
} }
] ]
"""
Studio editing view for OpenAssessment XBlock.
"""
def studio_view(self, context=None): def studio_view(self, context=None):
""" """
Render the OpenAssessment XBlock for editing in Studio. Render the OpenAssessment XBlock for editing in Studio.
......
#!/usr/bin/env bash #!/usr/bin/env bash
cd `dirname $BASH_SOURCE` && cd ../openassessment/xblock/static cd `dirname $BASH_SOURCE` && cd ../openassessment/xblock/static
sass --update sass:css --force sass --update sass:css --force --style compressed
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