Commit 00d6a0e5 by Will Daly

Merge remote-tracking branch 'origin/authoring' into will/js-field-validation

Conflicts:
	openassessment/xblock/static/css/openassessment.css
	openassessment/xblock/static/js/openassessment-studio.min.js
	openassessment/xblock/static/js/src/studio/oa_container_item.js
	openassessment/xblock/static/js/src/studio/oa_edit_rubric.js
	openassessment/xblock/static/sass/oa/utilities/_developer.scss
parents f7492b20 f76313c7
......@@ -26,7 +26,7 @@
</div>
<div id="oa_prompt_editor_wrapper" class="oa_editor_content_wrapper">
<textarea id="openassessment_prompt_editor">{{ prompt }}</textarea>
<textarea id="openassessment_prompt_editor" maxlength="10000">{{ prompt }}</textarea>
</div>
{% include "openassessmentblock/edit/oa_edit_rubric.html" %}
......
......@@ -25,7 +25,7 @@
<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>
<textarea class="openassessment_criterion_prompt setting-input" maxlength="10000">{{ criterion_prompt }}</textarea>
</label>
</div>
</li>
......
{% load i18n %}
{% spaceless %}
<li class="openassessment_assessment_module_settings_editor" id="oa_ai_assessment_editor">
<div class = "drag-handle action"></div>
<div class = "openassessment_inclusion_wrapper">
<div class="drag-handle action"></div>
<div class="openassessment_inclusion_wrapper">
<input id="include_ai_assessment" type="checkbox"
{% if assessments.example_based_assessment %} checked="true" {% endif %}>
<label for="include_ai_assessment">{% trans "Step: Example-Based Assessment" %}</label>
......
......@@ -40,7 +40,7 @@
<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>
<textarea class="openassessment_criterion_option_explanation setting-input" maxlength="10000">{{ option_explanation }}</textarea>
</label>
</div>
</li>
......
......@@ -2,13 +2,13 @@
{% load tz %}
{% spaceless %}
<li class="openassessment_assessment_module_settings_editor" id="oa_peer_assessment_editor">
<div class = "drag-handle action"></div>
<div class="drag-handle action"></div>
<div class="openassessment_inclusion_wrapper">
<input type="checkbox" id="include_peer_assessment"
{% if assessments.peer_assessment %} checked="true" {% endif %}>
<label for="include_peer_assessment">{% trans "Step: Peer Assessment" %}</label>
</div>
<div class = "openassessment_assessment_module_editor">
<div class="openassessment_assessment_module_editor">
<p id="peer_assessment_description_closed" class="openassessment_description_closed {% if assessments.peer_assessment %} is--hidden {% endif %}">
{% trans "Students assess a specified number of other students' responses using the rubric for the assignment." %}
</p>
......
......@@ -10,7 +10,7 @@
</div>
<div id="openassessment_rubric_instructions">
<p class = openassessment_description>
<p class="openassessment_description">
{% trans "For open response problems, assessment is rubric-based. Rubric criterion have point breakdowns and explanations to help students with peer and self assessment steps. For more information on how to build your rubric, see our online help documentation."%}
</p>
</div>
......
......@@ -2,8 +2,8 @@
{% load tz %}
{% spaceless %}
<li class="openassessment_assessment_module_settings_editor" id="oa_self_assessment_editor">
<div class = "drag-handle action"></div>
<div class = "openassessment_inclusion_wrapper">
<div class="drag-handle action"></div>
<div class="openassessment_inclusion_wrapper">
<input id="include_self_assessment" type="checkbox"
{% if assessments.self_assessment %} checked="true" {% endif %}>
<label for="include_self_assessment">{% trans "Step: Self Assessment" %}</label>
......
{% load i18n %}
{% spaceless %}
<li class="openassessment_assessment_module_settings_editor" id="oa_student_training_editor">
<div class = "drag-handle action"></div>
<div class="drag-handle action"></div>
<div class = "openassessment_inclusion_wrapper">
<div class="openassessment_inclusion_wrapper">
<input type="checkbox" id="include_student_training"
{% if assessments.student_training %} checked="true" {% endif %}>
<label for="include_student_training">{% trans "Step: Student Training" %}</label>
</div>
<div class = "openassessment_assessment_module_editor">
<div class="openassessment_assessment_module_editor">
<p id="student_training_description_closed" class="openassessment_description_closed {% if assessments.student_training %} is--hidden {% endif %}">
{% trans "Students learn to assess responses by scoring pre-assessed sample responses that the instructor provides. Students move to the next step when the scores they give match the instructor's scores. Note that Student Training Requires that the Peer Assessment module is also selected." %}
</p>
......
......@@ -28,7 +28,7 @@
<div class="openassessment_training_example_essay_wrapper">
<h2>{% trans "Response" %}</h2>
<textarea class="openassessment_training_example_essay">{{ example.answer }}</textarea>
<textarea class="openassessment_training_example_essay" maxlength="100000">{{ example.answer }}</textarea>
</div>
</div>
</li>
......
......@@ -9,7 +9,7 @@
<select class="openassessment_training_example_criterion_option setting-input" data-criterion="{{ criterion.name }}" data-option="{{ option.name }}">
<option value="">{% trans "Not Scored" %}</option>
{% for option in criterion.options %}
<option value={{ option.name }}
<option value="{{ option.name }}" data-points="{{ option.points }}" data-label="{{ option.label }}"
{% if criterion.option_selected == option.name %} selected {% endif %}
>
{{ option.label }} - {{ option.points }} {% trans "points" %}
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -22,6 +22,7 @@ describe("OpenAssessment.Container", function () {
this.addHandler = function() {};
this.removeHandler = function() {};
this.updateHandler = function() {};
this.addEventListeners = function() {};
};
var container = null;
......@@ -57,6 +58,9 @@ describe("OpenAssessment.Container", function () {
// Create the container and configure it
// to use the stub container item.
container = createContainer();
// Explicitly add event listeners.
container.addEventListeners();
});
it("adds and removes items", function() {
......@@ -130,6 +134,19 @@ describe("OpenAssessment.Container", function () {
expect(container.getItemValues().length).toEqual(1);
});
it("only creates one item when add is fired", function() {
// Initialize multiple containers without explicitly adding event
// listeners
createContainer();
createContainer();
createContainer();
// Press the add button
expect(container.getItemValues().length).toEqual(0);
$("#add_button").click();
expect(container.getItemValues().length).toEqual(1);
});
it("removes an element when the remove button is pressed", function() {
// Add some items
container.add();
......@@ -158,6 +175,9 @@ describe("OpenAssessment.Container", function () {
// Initialize the container object
container = createContainer();
// Explicitly add event listeners.
container.addEventListeners();
// Verify that the container recognizes the pre-existing item
expect(container.getItemValues()).toEqual([{ id: 0 }]);
......
......@@ -18,6 +18,19 @@ if (typeof window.gettext === 'undefined') {
window.gettext = function(text) { return text; };
}
// If ngettext isn't found (workbench, testing, etc.), return the simplistic english version
if (typeof window.ngetgext === 'undefined') {
window.ngettext = function (singular_text, plural_text, n) {
if (n > 1) {
return plural_text;
} else {
return singular_text;
}
}
}
// Stub event logging if the runtime doesn't provide it
if (typeof window.Logger === 'undefined') {
window.Logger = {
......
......@@ -73,29 +73,38 @@ OpenAssessment.Container = function(containerItem, kwargs) {
this.createContainerItem = function(element) {
return new containerItem(element, container.notifier);
};
// 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.
$("." + this.removeButtonClass, this.containerElement).click(
function(eventData) {
var item = container.createContainerItem(eventData.target);
container.remove(item);
}
);
// Initialize existing items, in case they need to install their
// own event handlers.
$("." + this.containerItemClass, this.containerElement).each(
function(index, element) {
container.createContainerItem(element);
}
);
};
OpenAssessment.Container.prototype = {
/**
Adds event listeners to the container and its children. Must be
called explicitly when the container is initially created.
*/
addEventListeners: function() {
var container = this;
// 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.
$("." + this.removeButtonClass, this.containerElement).click(
function(eventData) {
var item = container.createContainerItem(eventData.target);
container.remove(item);
}
);
// Initialize existing items, in case they need to install their
// own event handlers.
$("." + this.containerItemClass, this.containerElement).each(
function(index, element) {
var item = container.createContainerItem(element);
item.addEventListeners();
}
);
},
/**
Adds a new item to the container.
**/
......@@ -127,6 +136,7 @@ OpenAssessment.Container.prototype = {
// Initialize the item, allowing it to install event handlers.
// Fire event handler for adding a new element
var handlerItem = container.createContainerItem(containerItem);
handlerItem.addEventListeners();
handlerItem.addHandler();
},
......
......@@ -21,6 +21,37 @@ OpenAssessment.ItemUtilities = {
index++;
}
return index.toString();
},
/**
Format the option label, including the point value, and add it to the option.
Relies on the data-points and data-label attributes to provide information about the option.
Args:
element (Jquery Element): The element that represents the object.
**/
refreshOptionString: function(element) {
var points = $(element).data('points');
var label = $(element).data('label');
// We don't want the lack of a label to make it look like - 1 points.
if (label == ""){
label = gettext('Unnamed Option');
}
var singularString = label + " - " + points + " point";
var multipleString = label + " - " + points + " points";
// If the option doesn't have a data points value, that indicates to us that it is not a user-specified option,
// but represents the "Not Selected" option which all criterion drop-downs have.
if (typeof points === 'undefined') {
$(element).text(
gettext('Not Selected')
);
}
// Otherwise, set the text of the option element to be the properly conjugated, translated string.
else {
$(element).text(
ngettext(singularString, multipleString, points)
);
}
}
};
......@@ -42,10 +73,16 @@ OpenAssessment.RubricOption = function(element, notifier) {
$(".openassessment_criterion_option_points", this.element),
{ min: 0, max: 999 }
);
$(this.element).focusout($.proxy(this.updateHandler, this));
};
OpenAssessment.RubricOption.prototype = {
/**
Adds event listeners specific to this container item.
**/
addEventListeners: function() {
// Install a focus out handler for container changes.
$(this.element).focusout($.proxy(this.updateHandler, this));
},
/**
Finds the values currently entered in the Option's fields, and returns them.
......@@ -247,12 +284,21 @@ OpenAssessment.RubricCriterion = function(element, notifier) {
notifier: this.notifier
}
);
$(this.element).focusout($.proxy(this.updateHandler, this));
};
OpenAssessment.RubricCriterion.prototype = {
/**
Invoked by the container to add event listeners to all child containers
of this item, and add event listeners specific to this container item.
**/
addEventListeners: function() {
this.optionContainer.addEventListeners();
// Install a focus out handler for container changes.
$(this.element).focusout($.proxy(this.updateHandler, this));
},
/**
Finds the values currently entered in the Criterion's fields, and returns them.
......@@ -431,6 +477,12 @@ OpenAssessment.RubricCriterion.prototype = {
**/
OpenAssessment.TrainingExample = function(element){
this.element = element;
// Goes through and instantiates the option description in the training example for each option.
$(".openassessment_training_example_criterion_option", this.element) .each( function () {
$('option', this).each(function(){
OpenAssessment.ItemUtilities.refreshOptionString($(this));
});
});
};
OpenAssessment.TrainingExample.prototype = {
......@@ -456,6 +508,7 @@ OpenAssessment.TrainingExample.prototype = {
},
addHandler: function() {},
addEventListeners: function() {},
removeHandler: function() {},
updateHandler: function() {},
......
......@@ -379,6 +379,8 @@ OpenAssessment.EditStudentTrainingView = function(element) {
containerItemClass: "openassessment_training_example"
}
);
this.exampleContainer.addEventListeners();
};
OpenAssessment.EditStudentTrainingView.prototype = {
......
......@@ -25,8 +25,10 @@ OpenAssessment.StudentTrainingListener.prototype = {
$(sel, this.element).each(
function() {
var criterion = this;
var option = $('option[value="' + data.name + '"]', criterion);
$(option).text(view._generateOptionString(data.label, data.points));
var option = $('option[value="' + data.name + '"]', criterion)
.data("points", data.points)
.data("label", data.label);
OpenAssessment.ItemUtilities.refreshOptionString(option);
}
);
},
......@@ -64,9 +66,14 @@ OpenAssessment.StudentTrainingListener.prototype = {
// Risky; making an assumption that options will remain simple.
// updates could cause this to get out of sync with templates,
// but this avoids overly complex templating code.
$(criterion).append($("<option></option>")
var option = $("<option></option>")
.attr("value", data.name)
.text(view._generateOptionString(data.label, data.points)));
.data("points", data.points)
.data("label", data.label);
// Sets the option's text description, and adds it to the criterion.
OpenAssessment.ItemUtilities.refreshOptionString(option);
$(criterion).append(option);
examplesUpdated = true;
}
});
......@@ -328,19 +335,5 @@ OpenAssessment.StudentTrainingListener.prototype = {
}
);
return examples;
},
/**
Format the option label, including the point value.
Args:
name (string): The option label (e.g. "Good", "Fair").
points (int): The number of points that the option is worth.
Returns:
string
**/
_generateOptionString: function(name, points) {
return name + ' - ' + points + gettext(' points');
}
};
......@@ -26,7 +26,7 @@ OpenAssessment.EditRubricView = function(element, notifier) {
notifier: notifier
}
);
this.alert = new OpenAssessment.ValidationAlert();
this.criteriaContainer.addEventListeners();
};
OpenAssessment.EditRubricView.prototype = {
......
......@@ -224,8 +224,29 @@
a {
padding: 8px 0 0 0;
width: 100%;
text-transform: uppercase;
outline-color: transparent;
}
}
.ui-state-default.oa_editor_tab{
background: #e5e5e5 none;
a {
color: $edx-gray-d3;
}
}
.ui-state-active.ui-state-default.oa_editor_tab:hover,
.ui-state-active.oa_editor_tab {
background: $edx-gray-d2 none;
a {
color: $white;
}
}
.ui-state-default.oa_editor_tab:hover{
background-color: $edx-gray-t3;
}
}
}
......@@ -471,33 +492,85 @@
bottom: 0;
}
.ui-widget-header .ui-state-default{
background: #e5e5e5;
a{
color: $edx-gray-d3;
text-transform: uppercase;
outline-color: transparent;
}
}
.ui-widget-header .ui-state-active.ui-state-default:hover,
.ui-widget-header .ui-state-active{
background: $edx-gray-d2;
color: $white;
a{
color: $white;
text-transform: uppercase;
outline-color: transparent;
#oa_rubric_editor_wrapper{
<<<<<<< HEAD
=======
#openassessment_rubric_validation_alert{
height: auto;
width: 100%;
border-top-left-radius: 2px;
border-top-right-radius: 2px;
background-color: #323232;
border-bottom: 3px solid rgb(192, 172, 0);
padding: 10px;
position: absolute;
z-index: 10;
min-height: 70px;
@include transition (color 0.50s ease-in-out 0s);
.openassessment_alert_icon:before{
font-family: FontAwesome;
content: "\f071";
display: inline-block;
color: rgb(192, 172, 0);
float: left;
font-size: 200%;
margin: 1.5% 0px 0px 2%;
}
.openassessment_alert_header {
width: 85%;
margin: 0 5% 0 10%;
.openassessment_alert_title {
width: auto;
color: white;
}
.openassessment_alert_message {
font-size: 80%;
color: darkgray;
}
}
// with cancel
.openassessment_alert_close {
display: inline-block;
position: absolute;
top: 0px;
right: 0px;
color: #e9e9e9;
background-color: #323232;
text-align: center;
margin: 5px 10px;
[class^="icon"] {
width: auto;
margin: 0;
padding: 2px;
}
&:hover {
color: $blue;
}
}
}
}
.ui-widget-header .ui-state-default:hover{
background: $edx-gray-t3;
}
#openassessment_rubric_content_editor{
height: 100%;
width: 100%;
overflow-y: scroll;
}
#oa_rubric_editor_wrapper{
#openassessment_rubric_content_editor.openassessment_alert_shown{
height: Calc(100% - 70px);
position: absolute;
bottom: 0;
}
>>>>>>> origin/authoring
.wrapper-comp-settings{
display: initial;
display: block;
}
#openassessment_rubric_instructions{
......@@ -774,7 +847,7 @@
float: right;
}
.openassessment_rubric_remove_button:hover{
background: $edx-gray-d2;
background-color: $edx-gray-d2;
border-radius: 4px;
color: white;
}
......
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