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 @@
"title": "The most important of all questions.",
"submission_due": "2014-10-1T10:00:00",
"criteria": [
{
"name": "Criterion 1",
"prompt": "Prompt 1",
"name": "Criterion with two options",
"prompt": "Prompt for criterion with two options",
"order_num": 0,
"feedback": "optional",
"feedback": "disabled",
"options": [
{
"order_num": 2,
"order_num": 0,
"points": 1,
"name": "Fair",
"explanation": "Fair explanation"
},
{
"order_num": 1,
"points": 2,
"name": "Good"
"name": "Good",
"explanation": "Good explanation"
}
],
"points_possible": 2
},
{
"name": "Criterion 2",
"prompt": "Prompt 2",
"order_num": 1,
"options": [
{
"order_num": 1,
"points": 1,
"name": "Fair"
}
],
"points_possible": 2
"name": "Criterion with no options",
"prompt": "Prompt for criterion with no options",
"order_num": 0,
"options": [],
"feedback": "required",
"points_possible": 0
},
{
"name": "Criterion 3",
"prompt": "Prompt 3",
"name": "Criterion with optional feedback",
"prompt": "Prompt for criterion with optional feedback",
"order_num": 2,
"feedback": "optional",
"options": [
{
"order_num": 2,
"order_num": 0,
"points": 2,
"name": "Good"
"name": "Good",
"explanation": "Good explanation"
}
],
"points_possible": 2
......
......@@ -4,80 +4,158 @@
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 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 () {
jasmine.getFixtures().fixturesPath = 'base/fixtures';
loadFixtures('oa_edit.html');
// Reset the counter before each test
counter = 0;
container = new OpenAssessment.Container(
$('#openassessment_criterion_list'),
{
'openassessment_criterion': OpenAssessment.RubricCriterion
}
)
});
// Install a minimal fixture
// We don't need to use a full ORA2 template for this,
// so we just define the fixture inline.
setFixtures(
'<div id="container" />' +
'<div id="template" test_id="">' +
'<div class="remove_button" />' +
'</div>' +
'<div id="add_button" />'
);
it("adds a criterion", function () {
var previousSize = $('.openassessment_criterion').length;
container.add('openassessment_criterion');
var newSize = $('.openassessment_criterion').length;
expect(newSize).toEqual(previousSize + 1);
// Create the container and configure it
// to use the stub container item.
container = createContainer();
});
it("removes a criterion", function () {
container.add('openassessment_criterion');
var previousSize = $('.openassessment_criterion').length;
container.remove(1);
var newSize = $('.openassessment_criterion').length;
expect(newSize).toEqual(previousSize - 1);
it("adds and removes items", function() {
// Initially, there should be no items
expect(container.getItemValues()).toEqual([]);
// Add an item
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 () {
var error = false;
try{
container.getHtmlTemplate('not_a_template');
} catch (e) {
error = true;
}
expect(error).toBe(true);
it("ignores unrecognized DOM elements", function() {
// Add some items to the container
container.add();
container.add();
expect(container.getItemValues().length).toEqual(2);
// Add an extra element to the container in the DOM
$("<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 () {
container.installDeleteButtons($('#openassessment_criterion_list'));
it("adds an element when the add button is pressed", function() {
// 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 () {
container.element.append("<p> Hello, not an element here. </p>");
var error = false;
try{
container.getItemValues();
} catch (e) {
error = true;
}
expect(error).toBe(true);
it("removes an element when the remove button is pressed", function() {
// Add some items
container.add();
container.add();
container.add();
expect(container.getItemValues().length).toEqual(3);
// Press the button to delete the second item
$(".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 () {
var items = container.getItemValues();
var item = items[0];
it("configures remove buttons for pre-existing items", function() {
// Add an item directly to the container element in the DOM,
// 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));
expect(item.prompt).toEqual(jasmine.any(String));
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));
// Initialize the container object
container = createContainer();
});
// Verify that the container recognizes the pre-existing item
expect(container.getItemValues()).toEqual([{ id: 0 }]);
it("checks for undefined selection type", function () {
var error = false;
try{
container.add("lolz this isn't a valid selection type");
} catch (e) {
error = true;
}
expect(error).toBe(true);
// Expect that we can click the "remove" button
// to remove the item.
$(".remove_button", container.getItemElement(0)).click();
expect(container.getItemValues().length).toEqual(0);
});
});
\ 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 to store arbitrary DOM elements for insertion, deletion and installation of self-delete buttons
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
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:
element (DOM element): The DOM element representing the container (usually an OL or a UL)
selectorDictionary (dict): Has keys which map element (str) to Container Item classes to which they are related
containerItem (object): The container item object used to access
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){
this.element = element;
this.selectorDictionary = selectorDictionary;
this.installDeleteButtons(element);
OpenAssessment.Container = function(containerItem, kwargs) {
this.containerItem = containerItem;
this.containerElement = kwargs.containerElement;
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 = {
/**
Adds a new item of the specified type to the DOM.
If the type is unrecognized,
Throws:
An error that alerts the user that an unknown type was attempted to be added to the container.
Adds a new item to the container.
**/
add: function(selectorString){
var type = this.selectorDictionary[selectorString];
if (type == undefined){
throw 'The string: ('+ selectorString + ') is not known by this container.';
}
this.element.append(this.getHtmlTemplate(selectorString));
},
/**
Removes a specified item from the DOM. This is distinct from (and not used by) delete buttons.
Args:
index(int): The index of the specified item to remove.
add: function() {
// Copy the template into the container
// Remove any CSS IDs (since now the element is not unique)
// and add the item class so we can find it later.
$(this.templateElement)
.clone()
.removeAttr('id')
.toggleClass('is--hidden', false)
.toggleClass(this.containerItemClass, true)
.appendTo($(this.containerElement));
// Install a click handler for the delete button
// 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); } );
**/
remove: function(index){
var count = 0;
$(this.element).children().each(function(){
if (count == index){
$(this).remove();
return;
}
count++;
});
// Initialize the item, allowing it to install event handlers.
new this.containerItem(containerItem.get(0));
},
/**
Installs delete buttons on all sections of a certain element.
Called both when we create a container, and when we add new elements.
Remove the item associated with an element.
If the element is not itself an item, traverse up the
DOM tree until an item is found.
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){
$('.openassessment_delete_button', liveElement).each(function() {
$(this).click(function () {
liveElement.closest('.openassessment_deletable').remove();
});
});
remove: function(element) {
$(element).closest("." + this.containerItemClass).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.
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 () {
var values = [];
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.
if (type == undefined){
throw 'An item with classes (' + classes.join(' ') +
') was not found in a dict of known container items.';
$("." + this.containerItemClass, this.containerElement).each(
function(index, element) {
var containerItem = new container.containerItem(element);
var fieldValues = containerItem.getFieldValues();
values.push(fieldValues);
}
);
var item = new type($(this));
var value = item.getFieldValues();
values.push(value);
});
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:
(str): The HTML template associated with the container item's type.
DOM element if the item is found, otherwise null.
**/
getHtmlTemplate: function(selectorString){
var selector = '.' + selectorString + '.openassessment_template';
var element = $(selector, this.element);
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();
}
getItemElement: function(index) {
var element = $("." + this.containerItemClass, this.containerElement).get(index);
return (element !== undefined) ? element : null;
},
};
......@@ -3,36 +3,39 @@ The RubricOption Class used to construct and maintain references to rubric optio
container object. Constructs a new RubricOption element.
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:
OpenAssessment.RubricOption
**/
OpenAssessment.RubricOption = function(element){
OpenAssessment.RubricOption = function(element) {
this.element = element;
};
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:
(dict) of the form:
{
'name': 'Real Bad',
'points': 1,
'explanation': 'Essay was primarily composed of emojis.'
}
object literal of the form:
{
'name': 'Real Bad',
'points': 1,
'explanation': 'Essay was primarily composed of emojis.'
}
**/
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');
getFieldValues: function () {
return {
'name': name,
'points': points,
'explanation': explanation
name: OpenAssessment.Fields.stringField(
$('.openassessment_criterion_option_name', this.element)
),
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:
Returns:
OpenAssessment.RubricCriterion
**/
OpenAssessment.RubricCriterion = function(element){
OpenAssessment.RubricCriterion = function(element) {
this.element = element;
this.optionContainer = new OpenAssessment.Container(
$('.openassessment_criterion_option_list'),
{
'openassessment_criterion_option': OpenAssessment.RubricOption
OpenAssessment.RubricOption, {
containerElement: $(".openassessment_criterion_option_list", this.element).get(0),
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){
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:
(dict) of the form:
{
'name': 'Emoji Content',
'prompt': 'How expressive was the author with their words, and how much did they rely on emojis?',
'feedback': 'optional',
'options': [
{
'name': 'Real Bad',
'points': 1,
'explanation': 'Essay was primarily composed of emojis.'
}
...
]
}
object literal of the form:
{
'name': 'Emoji Content',
'prompt': 'How expressive was the author with their words, and how much did they rely on emojis?',
'feedback': 'optional',
'options': [
{
'name': 'Real Bad',
'points': 1,
'explanation': 'Essay was primarily composed of emojis.'
}
...
]
}
**/
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();
getFieldValues: function () {
return {
'name': name,
'prompt': prompt,
'options': options,
'feedback': feedback
name: OpenAssessment.Fields.stringField(
$('.openassessment_criterion_name', this.element)
),
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.
**/
OpenAssessment.EditRubricView = function(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 = {
/**
Install event handlers.
**/
load: function() {
//this.container = new Container(this.element, "openassessment__rubric__criterion", OpenAssessment.RubricCriterion);
},
Construct a list of criteria definitions from the editor UI.
/**
Returns:
list of criteria objects
Example usage:
>>> editRubricView.criteriaDefinition();
[
{
name: "Criterion",
prompt: "Prompt",
order_num: 0,
name: 'Criteria!'
prompt: 'prompt',
feedback: 'disabled',
feedback: "disabled",
options: [
{
order_num: 0,
name: 'name',
explanation: 'explanation',
points: 1
points: 1,
name: "Good",
explanation: "Explanation"
},
...
]
},
...
]
**/
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__)
class StudioMixin(object):
"""
Studio editing view for OpenAssessment XBlock.
"""
DEFAULT_CRITERIA = [
{
......@@ -30,10 +33,6 @@ class StudioMixin(object):
}
]
"""
Studio editing view for OpenAssessment XBlock.
"""
def studio_view(self, context=None):
"""
Render the OpenAssessment XBlock for editing in Studio.
......
#!/usr/bin/env bash
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