@@ -213,7 +213,7 @@ class CombinedOpenEndedFields(object):
|
||||
help="The number of times the student can try to answer this problem.",
|
||||
default=1,
|
||||
scope=Scope.settings,
|
||||
values={"min" : 1 }
|
||||
values={"min": 1 }
|
||||
)
|
||||
accept_file_upload = Boolean(
|
||||
display_name="Allow File Uploads",
|
||||
@@ -229,12 +229,10 @@ class CombinedOpenEndedFields(object):
|
||||
)
|
||||
due = Date(
|
||||
help="Date that this problem is due by",
|
||||
default=None,
|
||||
scope=Scope.settings
|
||||
)
|
||||
graceperiod = Timedelta(
|
||||
help="Amount of time after the due date that submissions will be accepted",
|
||||
default=None,
|
||||
scope=Scope.settings
|
||||
)
|
||||
version = VersionInteger(help="Current version number", default=DEFAULT_VERSION, scope=Scope.settings)
|
||||
@@ -244,7 +242,7 @@ class CombinedOpenEndedFields(object):
|
||||
display_name="Problem Weight",
|
||||
help="Defines the number of points each problem is worth. If the value is not set, each problem is worth one point.",
|
||||
scope=Scope.settings,
|
||||
values={"min" : 0 , "step": ".1"},
|
||||
values={"min": 0, "step": ".1"},
|
||||
default=1
|
||||
)
|
||||
min_to_calibrate = Integer(
|
||||
@@ -252,28 +250,28 @@ class CombinedOpenEndedFields(object):
|
||||
help="The minimum number of calibration essays each student will need to complete for peer grading.",
|
||||
default=3,
|
||||
scope=Scope.settings,
|
||||
values={"min" : 1, "max" : 20, "step" : "1"}
|
||||
values={"min": 1, "max": 20, "step": "1"}
|
||||
)
|
||||
max_to_calibrate = Integer(
|
||||
display_name="Maximum Peer Grading Calibrations",
|
||||
help="The maximum number of calibration essays each student will need to complete for peer grading.",
|
||||
default=6,
|
||||
scope=Scope.settings,
|
||||
values={"min" : 1, "max" : 20, "step" : "1"}
|
||||
values={"min": 1, "max": 20, "step": "1"}
|
||||
)
|
||||
peer_grader_count = Integer(
|
||||
display_name="Peer Graders per Response",
|
||||
help="The number of peers who will grade each submission.",
|
||||
default=3,
|
||||
scope=Scope.settings,
|
||||
values={"min" : 1, "step" : "1", "max" : 5}
|
||||
values={"min": 1, "step": "1", "max": 5}
|
||||
)
|
||||
required_peer_grading = Integer(
|
||||
display_name="Required Peer Grading",
|
||||
help="The number of other students each student making a submission will have to grade.",
|
||||
default=3,
|
||||
scope=Scope.settings,
|
||||
values={"min" : 1, "step" : "1", "max" : 5}
|
||||
values={"min": 1, "step": "1", "max": 5}
|
||||
)
|
||||
markdown = String(
|
||||
help="Markdown source of this module",
|
||||
|
||||
@@ -19,10 +19,10 @@ h2 {
|
||||
|
||||
|
||||
iframe[seamless]{
|
||||
background-color: transparent;
|
||||
border: 0px none transparent;
|
||||
padding: 0px;
|
||||
overflow: hidden;
|
||||
overflow: hidden;
|
||||
padding: 0px;
|
||||
border: 0px none transparent;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.inline-error {
|
||||
@@ -31,17 +31,17 @@ iframe[seamless]{
|
||||
|
||||
section.problem-progress {
|
||||
display: inline-block;
|
||||
color: #999;
|
||||
font-size: em(16);
|
||||
font-weight: 100;
|
||||
padding-left: 5px;
|
||||
color: #999;
|
||||
font-weight: 100;
|
||||
font-size: em(16);
|
||||
}
|
||||
|
||||
section.problem {
|
||||
@media print {
|
||||
display: block;
|
||||
width: auto;
|
||||
padding: 0;
|
||||
width: auto;
|
||||
|
||||
canvas, img {
|
||||
page-break-inside: avoid;
|
||||
@@ -49,30 +49,29 @@ section.problem {
|
||||
}
|
||||
|
||||
.inline {
|
||||
display: inline;
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.choicegroup {
|
||||
@include clearfix;
|
||||
|
||||
label.choicegroup_correct{
|
||||
&:after{
|
||||
content: url('../images/correct-icon.png');
|
||||
margin-left:15px
|
||||
}
|
||||
}
|
||||
|
||||
label.choicegroup_incorrect{
|
||||
&:after{
|
||||
content: url('../images/incorrect-icon.png');
|
||||
margin-left:15px;
|
||||
}
|
||||
}
|
||||
|
||||
min-width:100px;
|
||||
min-width: 100px;
|
||||
width: auto !important;
|
||||
width: 100px;
|
||||
|
||||
label.choicegroup_correct {
|
||||
&:after {
|
||||
margin-left: 15px;
|
||||
content: url('../images/correct-icon.png');
|
||||
}
|
||||
}
|
||||
|
||||
label.choicegroup_incorrect {
|
||||
&:after {
|
||||
margin-left: 15px;
|
||||
content: url('../images/incorrect-icon.png');
|
||||
}
|
||||
}
|
||||
|
||||
.indicator_container {
|
||||
float: left;
|
||||
width: 25px;
|
||||
@@ -82,9 +81,9 @@ section.problem {
|
||||
|
||||
fieldset {
|
||||
@include box-sizing(border-box);
|
||||
margin: 0px 0px $baseline;
|
||||
padding-left: $baseline;
|
||||
border-left: 1px solid #ddd;
|
||||
padding-left: 20px;
|
||||
margin: 0px 0px 20px;
|
||||
}
|
||||
|
||||
input[type="radio"],
|
||||
@@ -102,21 +101,21 @@ section.problem {
|
||||
ol.enumerate {
|
||||
li {
|
||||
&:before {
|
||||
content: " ";
|
||||
display: block;
|
||||
height: 0;
|
||||
visibility: hidden;
|
||||
height: 0;
|
||||
content: " ";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.solution-span {
|
||||
> span {
|
||||
margin: 20px 0;
|
||||
margin: $baseline 0;
|
||||
display: block;
|
||||
border: 1px solid #ddd;
|
||||
padding: 9px 15px 20px;
|
||||
background: #FFF;
|
||||
padding: 9px 15px $baseline;
|
||||
background: #fff;
|
||||
position: relative;
|
||||
box-shadow: inset 0 0 0 1px #eee;
|
||||
border-radius: 3px;
|
||||
@@ -133,26 +132,26 @@ section.problem {
|
||||
margin-top: -2px;
|
||||
}
|
||||
&.status {
|
||||
margin: 8px 0 0 $baseline/2;
|
||||
text-indent: -9999px;
|
||||
margin: 8px 0 0 10px;
|
||||
}
|
||||
}
|
||||
|
||||
&.unanswered {
|
||||
p.status {
|
||||
@include inline-block();
|
||||
background: url('../images/unanswered-icon.png') center center no-repeat;
|
||||
height: 14px;
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
background: url('../images/unanswered-icon.png') center center no-repeat;
|
||||
}
|
||||
}
|
||||
|
||||
&.correct, &.ui-icon-check {
|
||||
p.status {
|
||||
@include inline-block();
|
||||
background: url('../images/correct-icon.png') center center no-repeat;
|
||||
height: 20px;
|
||||
width: 25px;
|
||||
height: 20px;
|
||||
background: url('../images/correct-icon.png') center center no-repeat;
|
||||
}
|
||||
|
||||
input {
|
||||
@@ -163,9 +162,9 @@ section.problem {
|
||||
&.processing {
|
||||
p.status {
|
||||
@include inline-block();
|
||||
background: url('../images/spinner.gif') center center no-repeat;
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
background: url('../images/spinner.gif') center center no-repeat;
|
||||
}
|
||||
|
||||
input {
|
||||
@@ -176,9 +175,9 @@ section.problem {
|
||||
&.incorrect, &.incomplete, &.ui-icon-close {
|
||||
p.status {
|
||||
@include inline-block();
|
||||
background: url('../images/incorrect-icon.png') center center no-repeat;
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
background: url('../images/incorrect-icon.png') center center no-repeat;
|
||||
text-indent: -9999px;
|
||||
}
|
||||
|
||||
@@ -195,12 +194,12 @@ section.problem {
|
||||
p.answer {
|
||||
@include inline-block();
|
||||
margin-bottom: 0;
|
||||
margin-left: 10px;
|
||||
margin-left: $baseline/2;
|
||||
|
||||
&:before {
|
||||
display: inline;
|
||||
content: "Answer: ";
|
||||
font-weight: bold;
|
||||
display: inline;
|
||||
|
||||
}
|
||||
&:empty {
|
||||
@@ -228,12 +227,12 @@ section.problem {
|
||||
margin-bottom: 0;
|
||||
|
||||
&.math {
|
||||
padding: 6px;
|
||||
background: #f1f1f1;
|
||||
border: 1px solid #e3e3e3;
|
||||
@include inline-block;
|
||||
border-radius: 4px;
|
||||
padding: 6px;
|
||||
min-width: 30px;
|
||||
border: 1px solid #e3e3e3;
|
||||
border-radius: 4px;
|
||||
background: #f1f1f1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -241,98 +240,91 @@ section.problem {
|
||||
span {
|
||||
&.unanswered, &.ui-icon-bullet {
|
||||
@include inline-block();
|
||||
background: url('../images/unanswered-icon.png') center center no-repeat;
|
||||
height: 14px;
|
||||
position: relative;
|
||||
top: 4px;
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
background: url('../images/unanswered-icon.png') center center no-repeat;
|
||||
}
|
||||
|
||||
&.processing, &.ui-icon-processing {
|
||||
@include inline-block();
|
||||
background: url('../images/spinner.gif') center center no-repeat;
|
||||
height: 20px;
|
||||
position: relative;
|
||||
top: 6px;
|
||||
width: 25px;
|
||||
height: 20px;
|
||||
background: url('../images/spinner.gif') center center no-repeat;
|
||||
}
|
||||
|
||||
&.correct, &.ui-icon-check {
|
||||
@include inline-block();
|
||||
background: url('../images/correct-icon.png') center center no-repeat;
|
||||
height: 20px;
|
||||
position: relative;
|
||||
top: 3px;
|
||||
width: 25px;
|
||||
height: 20px;
|
||||
background: url('../images/correct-icon.png') center center no-repeat;
|
||||
}
|
||||
|
||||
&.partially-correct {
|
||||
@include inline-block();
|
||||
background: url('../images/partially-correct-icon.png') center center no-repeat;
|
||||
height: 20px;
|
||||
position: relative;
|
||||
top: 6px;
|
||||
width: 25px;
|
||||
height: 20px;
|
||||
background: url('../images/partially-correct-icon.png') center center no-repeat;
|
||||
}
|
||||
|
||||
&.incorrect, &.incomplete, &.ui-icon-close {
|
||||
@include inline-block();
|
||||
background: url('../images/incorrect-icon.png') center center no-repeat;
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
position: relative;
|
||||
top: 3px;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
background: url('../images/incorrect-icon.png') center center no-repeat;
|
||||
}
|
||||
}
|
||||
|
||||
.reload
|
||||
{
|
||||
.reload {
|
||||
float:right;
|
||||
margin: 10px;
|
||||
margin: $baseline/2;
|
||||
}
|
||||
|
||||
|
||||
.grader-status {
|
||||
padding: 9px;
|
||||
background: #F6F6F6;
|
||||
border: 1px solid #ddd;
|
||||
border-top: 0;
|
||||
margin-bottom: 20px;
|
||||
@include clearfix;
|
||||
margin: $baseline/2 0;
|
||||
padding: $baseline/2;
|
||||
border-radius: 5px;
|
||||
background: #F6F6F6;
|
||||
|
||||
span {
|
||||
text-indent: -9999px;
|
||||
overflow: hidden;
|
||||
display: block;
|
||||
float: left;
|
||||
overflow: hidden;
|
||||
margin: -7px 7px 0 0;
|
||||
text-indent: -9999px;
|
||||
}
|
||||
|
||||
.grading {
|
||||
background: url('../images/info-icon.png') left center no-repeat;
|
||||
padding-left: 25px;
|
||||
text-indent: 0px;
|
||||
margin: 0px 7px 0 0;
|
||||
padding-left: 25px;
|
||||
background: url('../images/info-icon.png') left center no-repeat;
|
||||
text-indent: 0px;
|
||||
}
|
||||
|
||||
p {
|
||||
line-height: 20px;
|
||||
text-transform: capitalize;
|
||||
margin-bottom: 0;
|
||||
float: left;
|
||||
margin-bottom: 0;
|
||||
text-transform: capitalize;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
&.file {
|
||||
background: #FFF;
|
||||
margin-top: 20px;
|
||||
padding: 20px 0 0 0;
|
||||
|
||||
border: {
|
||||
top: 1px solid #eee;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
}
|
||||
margin-top: $baseline;
|
||||
padding: $baseline 0 0 0;
|
||||
border: 0;
|
||||
border-top: 1px solid #eee;
|
||||
background: #fff;
|
||||
|
||||
p.debug {
|
||||
display: none;
|
||||
@@ -345,54 +337,54 @@ section.problem {
|
||||
|
||||
}
|
||||
.evaluation {
|
||||
p {
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
p {
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.feedback-on-feedback {
|
||||
height: 100px;
|
||||
margin-right: 20px;
|
||||
margin-right: $baseline;
|
||||
height: 100px;
|
||||
}
|
||||
|
||||
.evaluation-response {
|
||||
header {
|
||||
text-align: right;
|
||||
a {
|
||||
font-size: .85em;
|
||||
}
|
||||
header {
|
||||
text-align: right;
|
||||
a {
|
||||
font-size: .85em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.evaluation-scoring {
|
||||
.scoring-list {
|
||||
list-style-type: none;
|
||||
margin-left: 3px;
|
||||
.scoring-list {
|
||||
margin-left: 3px;
|
||||
list-style-type: none;
|
||||
|
||||
li {
|
||||
&:first-child {
|
||||
margin-left: 0px;
|
||||
}
|
||||
display:inline;
|
||||
margin-left: 50px;
|
||||
li {
|
||||
display:inline;
|
||||
margin-left: 50px;
|
||||
|
||||
&:first-child {
|
||||
margin-left: 0px;
|
||||
}
|
||||
|
||||
label {
|
||||
font-size: .9em;
|
||||
}
|
||||
|
||||
}
|
||||
label {
|
||||
font-size: .9em;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.submit-message-container {
|
||||
margin: 10px 0px ;
|
||||
margin: $baseline 0px ;
|
||||
}
|
||||
}
|
||||
|
||||
form.option-input {
|
||||
margin: -10px 0 20px;
|
||||
padding-bottom: 20px;
|
||||
margin: -$baseline/2 0 $baseline;
|
||||
padding-bottom: $baseline;
|
||||
|
||||
select {
|
||||
margin-right: flex-gutter();
|
||||
@@ -400,17 +392,17 @@ section.problem {
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style: disc outside none;
|
||||
margin-bottom: lh();
|
||||
margin-left: .75em;
|
||||
margin-left: .75rem;
|
||||
list-style: disc outside none;
|
||||
}
|
||||
|
||||
ol {
|
||||
list-style: decimal outside none;
|
||||
margin-bottom: lh();
|
||||
margin-left: .75em;
|
||||
margin-left: .75rem;
|
||||
list-style: decimal outside none;
|
||||
}
|
||||
|
||||
dl {
|
||||
@@ -431,8 +423,8 @@ section.problem {
|
||||
}
|
||||
|
||||
li {
|
||||
line-height: 1.4em;
|
||||
margin-bottom: lh(.5);
|
||||
line-height: 1.4em;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
@@ -449,8 +441,8 @@ section.problem {
|
||||
table-layout: auto;
|
||||
|
||||
th {
|
||||
font-weight: bold;
|
||||
text-align: left;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
td {
|
||||
@@ -463,44 +455,43 @@ section.problem {
|
||||
}
|
||||
|
||||
caption {
|
||||
background: #f1f1f1;
|
||||
margin-bottom: .75em;
|
||||
margin-bottom: .75rem;
|
||||
padding: .75em 0;
|
||||
padding: .75rem 0;
|
||||
background: #f1f1f1;
|
||||
}
|
||||
|
||||
tr, td, th {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
code {
|
||||
margin: 0 2px;
|
||||
padding: 0px 5px;
|
||||
white-space: nowrap;
|
||||
border: 1px solid #EAEAEA;
|
||||
background-color: #F8F8F8;
|
||||
border: 1px solid #eaeaea;
|
||||
border-radius: 3px;
|
||||
background-color: #f8f8f8;
|
||||
white-space: nowrap;
|
||||
font-size: .9em;
|
||||
}
|
||||
|
||||
pre {
|
||||
background-color: #F8F8F8;
|
||||
border: 1px solid #CCC;
|
||||
overflow: auto;
|
||||
padding: 6px $baseline/2;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 3px;
|
||||
background-color: #f8f8f8;
|
||||
font-size: .9em;
|
||||
line-height: 1.4;
|
||||
overflow: auto;
|
||||
padding: 6px 10px;
|
||||
border-radius: 3px;
|
||||
|
||||
> code {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
white-space: pre;
|
||||
border: none;
|
||||
background: transparent;
|
||||
white-space: pre;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -517,26 +508,25 @@ section.problem {
|
||||
}
|
||||
|
||||
pre {
|
||||
border-radius: 0;
|
||||
border-radius: 0;
|
||||
border-width: 0;
|
||||
overflow: hidden;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border-width: 0;
|
||||
border-radius: 0;
|
||||
background: transparent;
|
||||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
white-space: pre;
|
||||
word-wrap: normal;
|
||||
overflow: hidden;
|
||||
font-size: inherit;
|
||||
font-family: inherit;
|
||||
resize: none;
|
||||
|
||||
&.CodeMirror-cursor {
|
||||
z-index: 10;
|
||||
position: absolute;
|
||||
z-index: 10;
|
||||
visibility: hidden;
|
||||
border-left: 1px solid black;
|
||||
border-right: none;
|
||||
width: 0;
|
||||
border-right: none;
|
||||
border-left: 1px solid black;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -546,14 +536,14 @@ section.problem {
|
||||
}
|
||||
|
||||
hr {
|
||||
background: #ddd;
|
||||
border: none;
|
||||
clear: both;
|
||||
color: #ddd;
|
||||
float: none;
|
||||
height: 1px;
|
||||
clear: both;
|
||||
margin: 0 0 .75rem;
|
||||
width: 100%;
|
||||
height: 1px;
|
||||
border: none;
|
||||
background: #ddd;
|
||||
color: #ddd;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
@@ -570,17 +560,17 @@ section.problem {
|
||||
center {
|
||||
display: block;
|
||||
margin: lh() 0;
|
||||
border: 1px solid #ccc;
|
||||
padding: lh();
|
||||
border: 1px solid #ccc;
|
||||
}
|
||||
|
||||
section.action {
|
||||
margin-top: 20px;
|
||||
margin-top: $baseline;
|
||||
|
||||
.save, .check, .show, .reset {
|
||||
height: ($baseline*2);
|
||||
font-weight: 600;
|
||||
vertical-align: middle;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.save {
|
||||
@@ -590,8 +580,8 @@ section.problem {
|
||||
.show {
|
||||
|
||||
.show-label {
|
||||
font-size: 1.0em;
|
||||
font-weight: 600;
|
||||
font-size: 1.0em;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -602,20 +592,20 @@ section.problem {
|
||||
// padding: 8px 12px;
|
||||
// margin-top: 10px;
|
||||
@include inline-block;
|
||||
font-style: italic;
|
||||
margin: 8px 0 0 10px;
|
||||
margin: 8px 0 0 $baseline/2;
|
||||
color: #777;
|
||||
font-style: italic;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
}
|
||||
|
||||
.detailed-solution {
|
||||
> p:first-child {
|
||||
font-size: 0.9em;
|
||||
color: #aaa;
|
||||
text-transform: uppercase;
|
||||
font-weight: bold;
|
||||
font-style: normal;
|
||||
text-transform: uppercase;
|
||||
color: #AAA;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
p:last-child {
|
||||
@@ -624,12 +614,12 @@ section.problem {
|
||||
}
|
||||
|
||||
div.capa_alert {
|
||||
margin-top: $baseline;
|
||||
padding: 8px 12px;
|
||||
border: 1px solid #EBE8BF;
|
||||
border: 1px solid #ebe8bf;
|
||||
border-radius: 3px;
|
||||
background: #FFFCDD;
|
||||
background: #fffcdd;
|
||||
font-size: 0.9em;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
div.capa_reset {
|
||||
@@ -638,12 +628,14 @@ section.problem {
|
||||
background-color: lighten($error-red, 25%);
|
||||
border-radius: 3px;
|
||||
font-size: 1em;
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
margin-top: $baseline/2;
|
||||
margin-bottom: $baseline/2;
|
||||
}
|
||||
|
||||
.capa_reset>h2 {
|
||||
color: #AA0000;
|
||||
color: #aa0000;
|
||||
}
|
||||
|
||||
.capa_reset li {
|
||||
font-size: 0.9em;
|
||||
}
|
||||
@@ -652,10 +644,10 @@ section.problem {
|
||||
border: 1px solid #ccc;
|
||||
|
||||
h3 {
|
||||
border-bottom: 1px solid #e3e3e3;
|
||||
text-shadow: 0 1px 0 #fff;
|
||||
padding: 9px;
|
||||
border-bottom: 1px solid #e3e3e3;
|
||||
background: #eee;
|
||||
text-shadow: 0 1px 0 #fff;
|
||||
font-weight: bold;
|
||||
font-size: em(16);
|
||||
}
|
||||
@@ -675,7 +667,7 @@ section.problem {
|
||||
a {
|
||||
display: block;
|
||||
padding: 9px;
|
||||
background: #F6F6F6;
|
||||
background: #f6f6f6;
|
||||
box-shadow: inset 0 0 0 1px #fff;
|
||||
}
|
||||
}
|
||||
@@ -693,22 +685,22 @@ section.problem {
|
||||
margin-bottom: 12px;
|
||||
|
||||
h3 {
|
||||
font-size: 0.9em;
|
||||
color: #aaa;
|
||||
text-transform: uppercase;
|
||||
font-weight: bold;
|
||||
font-style: normal;
|
||||
text-transform: uppercase;
|
||||
color: #AAA;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
}
|
||||
|
||||
> section {
|
||||
border: 1px solid #ddd;
|
||||
padding: 9px 9px 20px;
|
||||
margin-bottom: 10px;
|
||||
background: #FFF;
|
||||
position: relative;
|
||||
box-shadow: inset 0 0 0 1px #eee;
|
||||
margin-bottom: $baseline/2;
|
||||
padding: 9px 9px $baseline;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 3px;
|
||||
background: #fff;
|
||||
box-shadow: inset 0 0 0 1px #eee;
|
||||
|
||||
p:last-of-type {
|
||||
margin-bottom: 0;
|
||||
@@ -719,28 +711,29 @@ section.problem {
|
||||
}
|
||||
|
||||
a.full {
|
||||
@include position(absolute, 0 0 1px 0px);
|
||||
font-size: .8em;
|
||||
padding: 4px;
|
||||
text-align: right;
|
||||
width: 100%;
|
||||
display: block;
|
||||
background: #F3F3F3;
|
||||
@include position(absolute, 0 0 1px 0);
|
||||
@include box-sizing(border-box);
|
||||
display: block;
|
||||
padding: 4px;
|
||||
width: 100%;
|
||||
background: #f3f3f3;
|
||||
text-align: right;
|
||||
font-size: .8em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.external-grader-message {
|
||||
section {
|
||||
padding-left: 20px;
|
||||
background-color: #FAFAFA;
|
||||
color: #2C2C2C;
|
||||
font-family: monospace;
|
||||
padding-top: $baseline/2;
|
||||
padding-left: $baseline;
|
||||
background-color: #fafafa;
|
||||
color: #2c2c2c;
|
||||
font-size: 1em;
|
||||
padding-top: 10px;
|
||||
font-family: monospace;
|
||||
|
||||
header {
|
||||
font-size: 1.4em;
|
||||
font-size: 1.4em;
|
||||
}
|
||||
|
||||
.shortform {
|
||||
@@ -748,35 +741,36 @@ section.problem {
|
||||
}
|
||||
|
||||
.longform {
|
||||
padding: 0px;
|
||||
margin: 0px;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
|
||||
.result-errors {
|
||||
margin: 5px;
|
||||
padding: 10px 10px 10px 40px;
|
||||
margin: $baseline/4;
|
||||
padding: $baseline/2 $baseline/2 $baseline/2 $baseline*2;
|
||||
background: url('../images/incorrect-icon.png') center left no-repeat;
|
||||
|
||||
li {
|
||||
color: #B00;
|
||||
}
|
||||
color: #b00;
|
||||
}
|
||||
}
|
||||
|
||||
.result-output {
|
||||
margin: 5px;
|
||||
padding: 20px 0px 15px 50px;
|
||||
border-top: 1px solid #DDD;
|
||||
border-left: 20px solid #FAFAFA;
|
||||
margin: $baseline/4;
|
||||
padding: $baseline 0 15px 50px;
|
||||
border-top: 1px solid #ddd;
|
||||
border-left: $baseline solid #fafafa;
|
||||
|
||||
h4 {
|
||||
font-family: monospace;
|
||||
font-size: 1em;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
dl {
|
||||
margin: 0px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
dt {
|
||||
margin-top: 20px;
|
||||
margin-top: $baseline;
|
||||
}
|
||||
|
||||
dd {
|
||||
@@ -786,6 +780,7 @@ section.problem {
|
||||
|
||||
.result-correct {
|
||||
background: url('../images/correct-icon.png') left 20px no-repeat;
|
||||
|
||||
.result-actual-output {
|
||||
color: #090;
|
||||
}
|
||||
@@ -793,6 +788,7 @@ section.problem {
|
||||
|
||||
.result-incorrect {
|
||||
background: url('../images/incorrect-icon.png') left 20px no-repeat;
|
||||
|
||||
.result-actual-output {
|
||||
color: #B00;
|
||||
}
|
||||
@@ -800,16 +796,16 @@ section.problem {
|
||||
|
||||
.markup-text{
|
||||
margin: 5px;
|
||||
padding: 20px 0px 15px 50px;
|
||||
border-top: 1px solid #DDD;
|
||||
border-left: 20px solid #FAFAFA;
|
||||
padding: $baseline 0 15px 50px;
|
||||
border-top: 1px solid #ddd;
|
||||
border-left: 20px solid #fafafa;
|
||||
|
||||
bs {
|
||||
color: #BB0000;
|
||||
color: #bb0000;
|
||||
}
|
||||
|
||||
bg {
|
||||
color: #BDA046;
|
||||
color: #bda046;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -817,96 +813,111 @@ section.problem {
|
||||
}
|
||||
|
||||
.rubric {
|
||||
tr {
|
||||
margin:10px 0px;
|
||||
height: 100%;
|
||||
}
|
||||
td {
|
||||
padding: 20px 0px;
|
||||
margin: 10px 0px;
|
||||
height: 100%;
|
||||
}
|
||||
th {
|
||||
padding: 5px;
|
||||
margin: 5px;
|
||||
}
|
||||
label,
|
||||
.view-only {
|
||||
margin:3px;
|
||||
position: relative;
|
||||
padding: 15px;
|
||||
width: 150px;
|
||||
height:100%;
|
||||
display: inline-block;
|
||||
min-height: 50px;
|
||||
min-width: 50px;
|
||||
background-color: #CCC;
|
||||
font-size: .9em;
|
||||
}
|
||||
.grade {
|
||||
position: absolute;
|
||||
bottom:0px;
|
||||
right:0px;
|
||||
margin:10px;
|
||||
}
|
||||
.selected-grade {
|
||||
background: #666;
|
||||
color: white;
|
||||
}
|
||||
input[type=radio]:checked + label {
|
||||
background: #666;
|
||||
color: white; }
|
||||
input[class='score-selection'] {
|
||||
display: none;
|
||||
}
|
||||
tr {
|
||||
margin: $baseline/2 0;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
td {
|
||||
margin: $baseline/2 0;
|
||||
padding: $baseline 0;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
th {
|
||||
margin: $baseline/4;
|
||||
padding: $baseline/4;
|
||||
}
|
||||
|
||||
label,
|
||||
.view-only {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
margin: 3px;
|
||||
padding: 15px;
|
||||
min-width: 50px;
|
||||
min-height: 50px;
|
||||
width: 150px;
|
||||
height: 100%;
|
||||
background-color: #ccc;
|
||||
font-size: .9em;
|
||||
}
|
||||
|
||||
.grade {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
margin: $baseline/2;
|
||||
}
|
||||
|
||||
.selected-grade {
|
||||
background: #666;
|
||||
color: white;
|
||||
}
|
||||
|
||||
input[type=radio]:checked + label {
|
||||
background: #666;
|
||||
color: white;
|
||||
}
|
||||
|
||||
input[class='score-selection'] {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.annotation-input {
|
||||
$yellow: rgba(255,255,10,0.3);
|
||||
|
||||
margin: 0 0 1em 0;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 1em;
|
||||
margin: 0 0 1em 0;
|
||||
|
||||
.annotation-header {
|
||||
font-weight: bold;
|
||||
border-bottom: 1px solid #ccc;
|
||||
padding: .5em 1em;
|
||||
border-bottom: 1px solid #ccc;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.annotation-body { padding: .5em 1em; }
|
||||
|
||||
a.annotation-return {
|
||||
float: right;
|
||||
font: inherit;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
a.annotation-return:after { content: " \2191" }
|
||||
|
||||
.block, ul.tags {
|
||||
margin: .5em 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.block-highlight {
|
||||
padding: .5em;
|
||||
border: 1px solid darken($yellow, 10%);
|
||||
background-color: $yellow;
|
||||
color: #333;
|
||||
font-style: normal;
|
||||
background-color: $yellow;
|
||||
border: 1px solid darken($yellow, 10%);
|
||||
}
|
||||
|
||||
.block-comment { font-style: italic; }
|
||||
|
||||
ul.tags {
|
||||
display: block;
|
||||
list-style-type: none;
|
||||
margin-left: 1em;
|
||||
list-style-type: none;
|
||||
|
||||
li {
|
||||
position: relative;
|
||||
display: block;
|
||||
margin: 1em 0 0 0;
|
||||
position: relative;
|
||||
|
||||
.tag {
|
||||
display: inline-block;
|
||||
cursor: pointer;
|
||||
margin-left: $baseline*2;
|
||||
border: 1px solid rgb(102,102,102);
|
||||
margin-left: 40px;
|
||||
cursor: pointer;
|
||||
|
||||
&.selected {
|
||||
background-color: $yellow;
|
||||
}
|
||||
@@ -918,42 +929,49 @@ section.problem {
|
||||
.tag-status, .tag { padding: .25em .5em; }
|
||||
}
|
||||
}
|
||||
|
||||
textarea.comment {
|
||||
$num-lines-to-show: 5;
|
||||
$line-height: 1.4em;
|
||||
$padding: .2em;
|
||||
width: 100%;
|
||||
padding: $padding (2 * $padding);
|
||||
line-height: $line-height;
|
||||
width: 100%;
|
||||
height: ($num-lines-to-show * $line-height) + (2*$padding) - (($line-height - 1)/2);
|
||||
line-height: $line-height;
|
||||
}
|
||||
|
||||
.answer-annotation { display: block; margin: 0; }
|
||||
|
||||
/* for debugging the input value field. enable the debug flag on the inputtype */
|
||||
.debug-value {
|
||||
color: #fff;
|
||||
padding: 1em;
|
||||
margin: 1em 0;
|
||||
background-color: #999;
|
||||
border: 1px solid #000;
|
||||
input[type="text"] { width: 100%; }
|
||||
pre { background-color: #CCC; color: #000; }
|
||||
&:before {
|
||||
display: block;
|
||||
content: "debug input value";
|
||||
text-transform: uppercase;
|
||||
font-weight: bold;
|
||||
font-size: 1.5em;
|
||||
}
|
||||
margin: 1em 0;
|
||||
padding: 1em;
|
||||
border: 1px solid #000;
|
||||
background-color: #999;
|
||||
color: #fff;
|
||||
|
||||
input[type="text"] { width: 100%; }
|
||||
|
||||
pre { background-color: #CCC; color: #000; }
|
||||
|
||||
&:before {
|
||||
display: block;
|
||||
content: "debug input value";
|
||||
text-transform: uppercase;
|
||||
font-weight: bold;
|
||||
font-size: 1.5em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.choicetextgroup{
|
||||
@extend .choicegroup;
|
||||
|
||||
input[type="text"]{
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
@extend .choicegroup;
|
||||
|
||||
label.choicetextgroup_correct, section.choicetextgroup_correct{
|
||||
label.choicetextgroup_correct, section.choicetextgroup_correct {
|
||||
@extend label.choicegroup_correct;
|
||||
|
||||
input[type="text"] {
|
||||
@@ -961,17 +979,18 @@ section.problem {
|
||||
}
|
||||
}
|
||||
|
||||
label.choicetextgroup_incorrect, section.choicetextgroup_incorrect{
|
||||
label.choicetextgroup_incorrect, section.choicetextgroup_incorrect {
|
||||
@extend label.choicegroup_incorrect;
|
||||
}
|
||||
|
||||
label.choicetextgroup_show_correct, section.choicetextgroup_show_correct{
|
||||
&:after{
|
||||
content: url('../images/correct-icon.png');
|
||||
label.choicetextgroup_show_correct, section.choicetextgroup_show_correct {
|
||||
&:after {
|
||||
margin-left:15px;
|
||||
content: url('../images/correct-icon.png');
|
||||
}
|
||||
}
|
||||
span.mock_label{
|
||||
|
||||
span.mock_label {
|
||||
cursor : default;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// lms - xmodule - combinedopenended
|
||||
// ====================
|
||||
|
||||
h2 {
|
||||
margin-top: 0;
|
||||
margin-bottom: 15px;
|
||||
@@ -16,244 +19,470 @@ h2 {
|
||||
}
|
||||
}
|
||||
|
||||
// Problem Header
|
||||
div.name{
|
||||
padding-bottom: 15px;
|
||||
|
||||
h2 {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.progress-container {
|
||||
display: inline;
|
||||
float: right;
|
||||
padding-top: 3px;
|
||||
}
|
||||
}
|
||||
|
||||
.inline-error {
|
||||
color: darken($error-red, 10%);
|
||||
}
|
||||
|
||||
section.combined-open-ended {
|
||||
@include clearfix;
|
||||
.status-container
|
||||
{
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
|
||||
|
||||
div.problemwrapper {
|
||||
border: 1px solid lightgray;
|
||||
border-radius: $baseline/2;
|
||||
|
||||
.status-bar {
|
||||
background-color: #eee;
|
||||
border-radius: $baseline/2 $baseline/2 0 0;
|
||||
border-bottom: 1px solid lightgray;
|
||||
|
||||
.statustable {
|
||||
width: 100%;
|
||||
padding: $baseline;
|
||||
}
|
||||
|
||||
.status-container {
|
||||
display: table-cell;
|
||||
text-align: center;
|
||||
|
||||
.status-elements {
|
||||
border-radius: $baseline/4;
|
||||
border: 1px solid lightgray;
|
||||
}
|
||||
}
|
||||
|
||||
.problemtype-container {
|
||||
padding: $baseline/2;
|
||||
width: 60%;
|
||||
}
|
||||
|
||||
.problemtype{
|
||||
padding: $baseline/2;
|
||||
}
|
||||
|
||||
.assessments-container {
|
||||
float: right;
|
||||
padding: $baseline/2 $baseline $baseline/2 $baseline/2;
|
||||
|
||||
.assessment-text {
|
||||
display: inline-block;
|
||||
display: table-cell;
|
||||
padding-right: $baseline/2;
|
||||
}
|
||||
}
|
||||
}
|
||||
.item-container
|
||||
{
|
||||
padding-bottom: 10px;
|
||||
.item-container {
|
||||
padding-bottom: $baseline/2;
|
||||
margin: 15px;
|
||||
}
|
||||
|
||||
.result-container
|
||||
{
|
||||
float:left;
|
||||
width: 100%;
|
||||
position:relative;
|
||||
}
|
||||
h4
|
||||
{
|
||||
margin-bottom:10px;
|
||||
.result-container {
|
||||
float: left;
|
||||
width: 100%;
|
||||
position: relative;
|
||||
}
|
||||
}
|
||||
|
||||
section.legend-container {
|
||||
margin: 15px;
|
||||
border-radius: $baseline/4;
|
||||
|
||||
.legenditem {
|
||||
background-color : #d4d4d4;
|
||||
font-size: .9em;
|
||||
padding: 2px;
|
||||
display: inline;
|
||||
padding: $baseline/2;
|
||||
width: 20%;
|
||||
background-color: #eee;
|
||||
font-size: .9em;
|
||||
}
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
section.combined-open-ended-status {
|
||||
vertical-align: center;
|
||||
|
||||
.statusitem {
|
||||
color: #2C2C2C;
|
||||
background-color : #d4d4d4;
|
||||
font-size: .9em;
|
||||
padding: 2px;
|
||||
display: inline;
|
||||
width: 20%;
|
||||
.show-results {
|
||||
margin-top: .3em;
|
||||
text-align:right;
|
||||
}
|
||||
.show-results-button {
|
||||
font: 1em monospace;
|
||||
}
|
||||
.statusitem {
|
||||
display: table-cell;
|
||||
padding: $baseline/2;
|
||||
width: 30px;
|
||||
border-right: 1px solid lightgray;
|
||||
background-color: #eee;
|
||||
color: #2c2c2c;
|
||||
font-size: .9em;
|
||||
|
||||
&:first-child {
|
||||
border-radius: $baseline/4 0 0 $baseline/4;
|
||||
}
|
||||
|
||||
.statusitem-current {
|
||||
background-color: #B2B2B2;
|
||||
color: #222;
|
||||
}
|
||||
|
||||
span {
|
||||
&.unanswered {
|
||||
@include inline-block();
|
||||
background: url('../images/unanswered-icon.png') center center no-repeat;
|
||||
height: 14px;
|
||||
position: relative;
|
||||
width: 14px;
|
||||
float: right;
|
||||
}
|
||||
|
||||
&.correct {
|
||||
@include inline-block();
|
||||
background: url('../images/correct-icon.png') center center no-repeat;
|
||||
height: 20px;
|
||||
position: relative;
|
||||
width: 25px;
|
||||
float: right;
|
||||
}
|
||||
|
||||
&.incorrect {
|
||||
@include inline-block();
|
||||
background: url('../images/incorrect-icon.png') center center no-repeat;
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
position: relative;
|
||||
float: right;
|
||||
}
|
||||
&:last-child {
|
||||
border-right: 0;
|
||||
border-radius: 0 $baseline/4 $baseline/4 0;
|
||||
}
|
||||
|
||||
&:only-child {
|
||||
border-radius: $baseline/4;
|
||||
}
|
||||
|
||||
.show-results {
|
||||
margin-top: .3em;
|
||||
text-align:right;
|
||||
}
|
||||
|
||||
.show-results-button {
|
||||
font: 1em monospace;
|
||||
}
|
||||
}
|
||||
|
||||
.statusitem-current {
|
||||
background-color: #fff;
|
||||
color: #222;
|
||||
}
|
||||
|
||||
span {
|
||||
&.unanswered {
|
||||
@include inline-block();
|
||||
position: relative;
|
||||
float: right;
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
background: url('../images/unanswered-icon.png') center center no-repeat;
|
||||
}
|
||||
|
||||
&.correct {
|
||||
@include inline-block();
|
||||
position: relative;
|
||||
float: right;
|
||||
width: 25px;
|
||||
height: 20px;
|
||||
background: url('../images/correct-icon.png') center center no-repeat;
|
||||
}
|
||||
|
||||
&.incorrect {
|
||||
@include inline-block();
|
||||
position: relative;
|
||||
float: right;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
background: url('../images/incorrect-icon.png') center center no-repeat;
|
||||
}
|
||||
}
|
||||
|
||||
.icon-caret-right {
|
||||
display: inline-block;
|
||||
margin-right: ($baseline/4);
|
||||
vertical-align: baseline;
|
||||
}
|
||||
}
|
||||
|
||||
// Problem Section Controls
|
||||
|
||||
.visibility-control, .visibility-control-prompt {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
|
||||
.inner {
|
||||
float: left;
|
||||
margin-top: $baseline;
|
||||
width: 85%;
|
||||
height: 5px;
|
||||
border-top: 1px dotted #ddd;
|
||||
}
|
||||
}
|
||||
|
||||
.section-header {
|
||||
display: block;
|
||||
float: right;
|
||||
padding-top: $baseline/2;
|
||||
width: 15%;
|
||||
text-align: center;
|
||||
font-size: .9em;
|
||||
}
|
||||
|
||||
// Rubric Styling
|
||||
|
||||
.wrapper-score-selection {
|
||||
display: table-cell;
|
||||
padding: 0 $baseline/2;
|
||||
width: 20px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.wrappable {
|
||||
display: table-cell;
|
||||
padding: $baseline/4;
|
||||
}
|
||||
|
||||
.rubric-list-item {
|
||||
margin-bottom: 2px;
|
||||
padding: $baseline/2;
|
||||
|
||||
&:hover {
|
||||
background-color: #eee;
|
||||
}
|
||||
.rubric-label-selected{
|
||||
border-radius: $baseline/4;
|
||||
background-color: #eee;
|
||||
}
|
||||
}
|
||||
|
||||
span.rubric-category {
|
||||
display: block;
|
||||
margin-bottom: $baseline/2;
|
||||
padding-top: $baseline/2;
|
||||
width: 100%;
|
||||
border-bottom: 1px solid lightgray;
|
||||
font-size: 1.1em;
|
||||
}
|
||||
|
||||
div.combined-rubric-container {
|
||||
ul.rubric-list{
|
||||
margin: 15px;
|
||||
padding-top: $baseline/2;
|
||||
padding-bottom: $baseline/4;
|
||||
|
||||
ul.rubric-list {
|
||||
margin: 0 $baseline $baseline/2 $baseline;
|
||||
padding: 0;
|
||||
list-style-type: none;
|
||||
padding:0;
|
||||
margin:0;
|
||||
|
||||
li {
|
||||
&.rubric-list-item{
|
||||
|
||||
&.rubric-list-item {
|
||||
margin-bottom: 2px;
|
||||
padding: 0px;
|
||||
padding: $baseline/2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
h4 {
|
||||
padding-top: $baseline/2;
|
||||
}
|
||||
|
||||
span.rubric-category {
|
||||
font-size: .9em;
|
||||
display: block;
|
||||
width: 100%;
|
||||
border-bottom: 1px solid lightgray;
|
||||
font-weight: bold;
|
||||
font-size: .9em;
|
||||
}
|
||||
padding-bottom: 5px;
|
||||
padding-top: 10px;
|
||||
|
||||
label.choicegroup_correct {
|
||||
&:before {
|
||||
margin-right: 15px;
|
||||
content: url('../images/correct-icon.png');
|
||||
}
|
||||
}
|
||||
|
||||
label.choicegroup_partialcorrect {
|
||||
&:before {
|
||||
margin-right: 15px;
|
||||
content: url('../images/partially-correct-icon.png');
|
||||
}
|
||||
}
|
||||
|
||||
label.choicegroup_incorrect {
|
||||
&:before {
|
||||
margin-right: 15px;
|
||||
content: url('../images/incorrect-icon.png');
|
||||
}
|
||||
}
|
||||
|
||||
div.written-feedback {
|
||||
background: #f6f6f6;
|
||||
padding: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
div.result-container {
|
||||
padding-top: 10px;
|
||||
padding-bottom: 5px;
|
||||
.evaluation {
|
||||
padding-top: $baseline/2;
|
||||
padding-bottom: $baseline/4;
|
||||
|
||||
p {
|
||||
margin-bottom: 1px;
|
||||
.evaluation {
|
||||
p {
|
||||
margin-bottom: 1px;
|
||||
}
|
||||
}
|
||||
|
||||
.feedback-on-feedback {
|
||||
height: 100px;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.evaluation-response {
|
||||
margin-bottom: 2px;
|
||||
|
||||
header {
|
||||
a {
|
||||
font-size: .85em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.evaluation-scoring {
|
||||
.scoring-list {
|
||||
margin-left: 3px;
|
||||
list-style-type: none;
|
||||
|
||||
li {
|
||||
display:inline;
|
||||
margin-left: 0;
|
||||
|
||||
&:first-child {
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.feedback-on-feedback {
|
||||
height: 100px;
|
||||
margin-right: 0px;
|
||||
}
|
||||
|
||||
.evaluation-response {
|
||||
margin-bottom: 2px;
|
||||
header {
|
||||
a {
|
||||
font-size: .85em;
|
||||
}
|
||||
label {
|
||||
font-size: .9em;
|
||||
}
|
||||
}
|
||||
}
|
||||
.evaluation-scoring {
|
||||
.scoring-list {
|
||||
list-style-type: none;
|
||||
margin-left: 3px;
|
||||
}
|
||||
|
||||
li {
|
||||
&:first-child {
|
||||
margin-left: 0px;
|
||||
}
|
||||
display:inline;
|
||||
margin-left: 0px;
|
||||
.submit-message-container {
|
||||
margin: $baseline/2 0;
|
||||
}
|
||||
|
||||
label {
|
||||
font-size: .9em;
|
||||
}
|
||||
}
|
||||
.external-grader-message {
|
||||
margin-bottom: $baseline/4;
|
||||
|
||||
section {
|
||||
padding-left: $baseline;
|
||||
background-color: #fafafa;
|
||||
color: #2c2c2c;
|
||||
font-family: monospace;
|
||||
font-size: 1em;
|
||||
padding-top: $baseline/2;
|
||||
padding-bottom: 30px;
|
||||
|
||||
header {
|
||||
font-size: 1.4em;
|
||||
}
|
||||
|
||||
.shortform {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.longform {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
|
||||
.result-errors {
|
||||
margin: $baseline/4;
|
||||
padding: $baseline/2 $baseline/2 $baseline/2 $baseline*2;
|
||||
background: url('../images/incorrect-icon.png') center left no-repeat;
|
||||
|
||||
li {
|
||||
color: #B00;
|
||||
}
|
||||
}
|
||||
}
|
||||
.submit-message-container {
|
||||
margin: 10px 0px ;
|
||||
}
|
||||
|
||||
.external-grader-message {
|
||||
margin-bottom: 5px;
|
||||
section {
|
||||
padding-left: 20px;
|
||||
background-color: #FAFAFA;
|
||||
color: #2C2C2C;
|
||||
font-family: monospace;
|
||||
font-size: 1em;
|
||||
padding-top: 10px;
|
||||
padding-bottom:30px;
|
||||
header {
|
||||
font-size: 1.4em;
|
||||
.result-output {
|
||||
margin: $baseline/4;
|
||||
padding: $baseline 0 15px 50px;
|
||||
border-top: 1px solid #ddd;
|
||||
border-left: 20px solid #fafafa;
|
||||
|
||||
h4 {
|
||||
font-size: 1em;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
.shortform {
|
||||
font-weight: bold;
|
||||
dl {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.longform {
|
||||
padding: 0px;
|
||||
margin: 0px;
|
||||
dt {
|
||||
margin-top: $baseline;
|
||||
}
|
||||
|
||||
.result-errors {
|
||||
margin: 5px;
|
||||
padding: 10px 10px 10px 40px;
|
||||
background: url('../images/incorrect-icon.png') center left no-repeat;
|
||||
li {
|
||||
color: #B00;
|
||||
}
|
||||
}
|
||||
dd {
|
||||
margin-left: 24pt;
|
||||
}
|
||||
}
|
||||
|
||||
.result-output {
|
||||
margin: 5px;
|
||||
padding: 20px 0px 15px 50px;
|
||||
border-top: 1px solid #DDD;
|
||||
border-left: 20px solid #FAFAFA;
|
||||
.markup-text{
|
||||
margin: $baseline/4;
|
||||
padding: $baseline 0 15px 50px;
|
||||
border-top: 1px solid #ddd;
|
||||
border-left: 20px solid #fafafa;
|
||||
|
||||
h4 {
|
||||
font-family: monospace;
|
||||
font-size: 1em;
|
||||
}
|
||||
bs {
|
||||
color: #bb0000;
|
||||
}
|
||||
|
||||
dl {
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
dt {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
dd {
|
||||
margin-left: 24pt;
|
||||
}
|
||||
}
|
||||
|
||||
.markup-text{
|
||||
margin: 5px;
|
||||
padding: 20px 0px 15px 50px;
|
||||
border-top: 1px solid #DDD;
|
||||
border-left: 20px solid #FAFAFA;
|
||||
|
||||
bs {
|
||||
color: #BB0000;
|
||||
}
|
||||
|
||||
bg {
|
||||
color: #BDA046;
|
||||
}
|
||||
}
|
||||
bg {
|
||||
color: #bda046;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.rubric-result-container {
|
||||
padding: 2px;
|
||||
margin: 0;
|
||||
display: inline;
|
||||
|
||||
.rubric-result {
|
||||
font-size: .9em;
|
||||
padding: 2px;
|
||||
display: inline-table;
|
||||
}
|
||||
padding: 2px;
|
||||
margin: 0px;
|
||||
display : inline;
|
||||
}
|
||||
}
|
||||
|
||||
div.rubric {
|
||||
ul.rubric-list{
|
||||
margin: 0 $baseline $baseline/2 $baseline;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
list-style-type: none;
|
||||
|
||||
li {
|
||||
&.rubric-list-item {
|
||||
margin-bottom: 2px;
|
||||
padding: $baseline/2;
|
||||
border-radius: $baseline/4;
|
||||
|
||||
&:hover {
|
||||
background-color: #eee;
|
||||
}
|
||||
|
||||
.wrapper-score-selection {
|
||||
display: table-cell;
|
||||
padding: 0 $baseline/2;
|
||||
width: 20px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.wrappable {
|
||||
display: table-cell;
|
||||
padding: $baseline/4;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
span.rubric-category {
|
||||
display: block;
|
||||
width: 100%;
|
||||
border-bottom: 1px solid lightgray;
|
||||
font-weight: bold;
|
||||
font-size: .9em;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -261,8 +490,8 @@ div.result-container {
|
||||
section.open-ended-child {
|
||||
@media print {
|
||||
display: block;
|
||||
width: auto;
|
||||
padding: 0;
|
||||
width: auto;
|
||||
|
||||
canvas, img {
|
||||
page-break-inside: avoid;
|
||||
@@ -270,30 +499,30 @@ section.open-ended-child {
|
||||
}
|
||||
|
||||
.inline {
|
||||
display: inline;
|
||||
display: inline;
|
||||
}
|
||||
|
||||
ol.enumerate {
|
||||
li {
|
||||
&:before {
|
||||
content: " ";
|
||||
display: block;
|
||||
height: 0;
|
||||
visibility: hidden;
|
||||
height: 0;
|
||||
content: " ";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.solution-span {
|
||||
> span {
|
||||
margin: 20px 0;
|
||||
display: block;
|
||||
border: 1px solid #ddd;
|
||||
padding: 9px 15px 20px;
|
||||
background: #FFF;
|
||||
position: relative;
|
||||
box-shadow: inset 0 0 0 1px #eee;
|
||||
display: block;
|
||||
margin: $baseline 0;
|
||||
padding: 9px 15px $baseline;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 3px;
|
||||
background: #fff;
|
||||
box-shadow: inset 0 0 0 1px #eee;
|
||||
|
||||
&:empty {
|
||||
display: none;
|
||||
@@ -301,196 +530,190 @@ section.open-ended-child {
|
||||
}
|
||||
}
|
||||
|
||||
p {
|
||||
&.answer {
|
||||
margin-top: -2px;
|
||||
}
|
||||
&.status {
|
||||
text-indent: -9999px;
|
||||
margin: 8px 0 0 10px;
|
||||
}
|
||||
p {
|
||||
&.answer {
|
||||
margin-top: -2px;
|
||||
}
|
||||
|
||||
div.unanswered {
|
||||
p.status {
|
||||
@include inline-block();
|
||||
background: url('../images/unanswered-icon.png') center center no-repeat;
|
||||
height: 14px;
|
||||
width: 14px;
|
||||
}
|
||||
&.status {
|
||||
margin: 8px 0 0 $baseline/2;
|
||||
text-indent: -9999px;
|
||||
}
|
||||
}
|
||||
|
||||
div.correct, div.ui-icon-check {
|
||||
p.status {
|
||||
@include inline-block();
|
||||
background: url('../images/correct-icon.png') center center no-repeat;
|
||||
height: 20px;
|
||||
width: 25px;
|
||||
}
|
||||
|
||||
input {
|
||||
border-color: green;
|
||||
}
|
||||
}
|
||||
|
||||
div.processing {
|
||||
p.status {
|
||||
@include inline-block();
|
||||
background: url('../images/spinner.gif') center center no-repeat;
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
}
|
||||
|
||||
input {
|
||||
border-color: #aaa;
|
||||
}
|
||||
}
|
||||
|
||||
div.incorrect, div.ui-icon-close {
|
||||
p.status {
|
||||
@include inline-block();
|
||||
background: url('../images/incorrect-icon.png') center center no-repeat;
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
text-indent: -9999px;
|
||||
}
|
||||
|
||||
input {
|
||||
border-color: red;
|
||||
}
|
||||
}
|
||||
|
||||
> span {
|
||||
display: block;
|
||||
margin-bottom: lh(.5);
|
||||
}
|
||||
|
||||
p.answer {
|
||||
div.unanswered {
|
||||
p.status {
|
||||
@include inline-block();
|
||||
margin-bottom: 0;
|
||||
margin-left: 10px;
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
background: url('../images/unanswered-icon.png') center center no-repeat;
|
||||
}
|
||||
}
|
||||
|
||||
div.correct, div.ui-icon-check {
|
||||
p.status {
|
||||
@include inline-block();
|
||||
width: 25px;
|
||||
height: 20px;
|
||||
background: url('../images/correct-icon.png') center center no-repeat;
|
||||
}
|
||||
|
||||
input {
|
||||
border-color: green;
|
||||
}
|
||||
}
|
||||
|
||||
div.processing {
|
||||
p.status {
|
||||
@include inline-block();
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
background: url('../images/spinner.gif') center center no-repeat;
|
||||
}
|
||||
|
||||
input {
|
||||
border-color: #aaa;
|
||||
}
|
||||
}
|
||||
|
||||
div.incorrect, div.ui-icon-close {
|
||||
p.status {
|
||||
@include inline-block();
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
background: url('../images/incorrect-icon.png') center center no-repeat;
|
||||
text-indent: -9999px;
|
||||
}
|
||||
|
||||
input {
|
||||
border-color: red;
|
||||
}
|
||||
}
|
||||
|
||||
> span {
|
||||
display: block;
|
||||
margin-bottom: lh(.5);
|
||||
}
|
||||
|
||||
p.answer {
|
||||
@include inline-block();
|
||||
margin-bottom: 0;
|
||||
margin-left: $baseline/2;
|
||||
|
||||
&:before {
|
||||
content: "Answer: ";
|
||||
font-weight: bold;
|
||||
display: inline;
|
||||
|
||||
}
|
||||
&:empty {
|
||||
&:before {
|
||||
content: "Answer: ";
|
||||
font-weight: bold;
|
||||
display: inline;
|
||||
|
||||
}
|
||||
&:empty {
|
||||
&:before {
|
||||
display: none;
|
||||
}
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
span {
|
||||
&.unanswered, &.ui-icon-bullet {
|
||||
@include inline-block();
|
||||
position: relative;
|
||||
top: 4px;
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
background: url('../images/unanswered-icon.png') center center no-repeat;
|
||||
}
|
||||
|
||||
&.processing, &.ui-icon-processing {
|
||||
@include inline-block();
|
||||
position: relative;
|
||||
top: 6px;
|
||||
width: 25px;
|
||||
height: 20px;
|
||||
background: url('../images/spinner.gif') center center no-repeat;
|
||||
}
|
||||
|
||||
&.correct, &.ui-icon-check {
|
||||
@include inline-block();
|
||||
position: relative;
|
||||
top: 6px;
|
||||
width: 25px;
|
||||
height: 20px;
|
||||
background: url('../images/correct-icon.png') center center no-repeat;
|
||||
}
|
||||
|
||||
&.incorrect, &.ui-icon-close {
|
||||
@include inline-block();
|
||||
position: relative;
|
||||
top: 6px;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
background: url('../images/incorrect-icon.png') center center no-repeat;
|
||||
}
|
||||
}
|
||||
|
||||
.reload {
|
||||
float:right;
|
||||
margin: $baseline/2;
|
||||
}
|
||||
|
||||
div.short-form-response {
|
||||
@include clearfix;
|
||||
overflow-y: auto;
|
||||
margin-bottom: 0;
|
||||
padding: $baseline/2;
|
||||
min-height: 20px;
|
||||
height: auto;
|
||||
border: 1px solid #ddd;
|
||||
background: #f6f6f6;
|
||||
}
|
||||
|
||||
.grader-status {
|
||||
@include clearfix;
|
||||
margin: $baseline/2 0;
|
||||
padding: $baseline/2;
|
||||
border-radius: 5px;
|
||||
background: #f6f6f6;
|
||||
|
||||
span {
|
||||
&.unanswered, &.ui-icon-bullet {
|
||||
@include inline-block();
|
||||
background: url('../images/unanswered-icon.png') center center no-repeat;
|
||||
height: 14px;
|
||||
position: relative;
|
||||
top: 4px;
|
||||
width: 14px;
|
||||
}
|
||||
|
||||
&.processing, &.ui-icon-processing {
|
||||
@include inline-block();
|
||||
background: url('../images/spinner.gif') center center no-repeat;
|
||||
height: 20px;
|
||||
position: relative;
|
||||
top: 6px;
|
||||
width: 25px;
|
||||
}
|
||||
|
||||
&.correct, &.ui-icon-check {
|
||||
@include inline-block();
|
||||
background: url('../images/correct-icon.png') center center no-repeat;
|
||||
height: 20px;
|
||||
position: relative;
|
||||
top: 6px;
|
||||
width: 25px;
|
||||
}
|
||||
|
||||
&.incorrect, &.ui-icon-close {
|
||||
@include inline-block();
|
||||
background: url('../images/incorrect-icon.png') center center no-repeat;
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
position: relative;
|
||||
top: 6px;
|
||||
}
|
||||
display: block;
|
||||
float: left;
|
||||
overflow: hidden;
|
||||
margin: -7px 7px 0 0;
|
||||
text-indent: -9999px;
|
||||
}
|
||||
|
||||
.reload
|
||||
{
|
||||
float:right;
|
||||
margin: 10px;
|
||||
.grading {
|
||||
margin: 0 7px 0 0;
|
||||
padding-left: 25px;
|
||||
background: url('../images/info-icon.png') left center no-repeat;
|
||||
text-indent: 0;
|
||||
}
|
||||
|
||||
div.short-form-response {
|
||||
background: #F6F6F6;
|
||||
border: 1px solid #ddd;
|
||||
margin-bottom: 0px;
|
||||
overflow-y: auto;
|
||||
height: 200px;
|
||||
@include clearfix;
|
||||
}
|
||||
p {
|
||||
float: left;
|
||||
margin-bottom: 0;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
.grader-status {
|
||||
padding: 9px;
|
||||
background: #F6F6F6;
|
||||
border: 1px solid #ddd;
|
||||
border-top: 0;
|
||||
margin-bottom: 20px;
|
||||
@include clearfix;
|
||||
&.file {
|
||||
margin-top: $baseline;
|
||||
padding: $baseline 0 0 0;
|
||||
border: 0;
|
||||
border-top: 1px solid #eee;
|
||||
background: #fff;
|
||||
|
||||
span {
|
||||
text-indent: -9999px;
|
||||
overflow: hidden;
|
||||
display: block;
|
||||
float: left;
|
||||
margin: -7px 7px 0 0;
|
||||
p.debug {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.grading {
|
||||
background: url('../images/info-icon.png') left center no-repeat;
|
||||
padding-left: 25px;
|
||||
text-indent: 0px;
|
||||
margin: 0px 7px 0 0;
|
||||
}
|
||||
|
||||
p {
|
||||
line-height: 20px;
|
||||
margin-bottom: 0;
|
||||
input {
|
||||
float: left;
|
||||
}
|
||||
|
||||
&.file {
|
||||
background: #FFF;
|
||||
margin-top: 20px;
|
||||
padding: 20px 0 0 0;
|
||||
|
||||
border: {
|
||||
top: 1px solid #eee;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
p.debug {
|
||||
display: none;
|
||||
}
|
||||
|
||||
input {
|
||||
float: left;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
form.option-input {
|
||||
margin: -10px 0 20px;
|
||||
padding-bottom: 20px;
|
||||
margin: -$baseline/2 0 $baseline;
|
||||
padding-bottom: $baseline;
|
||||
|
||||
select {
|
||||
margin-right: flex-gutter();
|
||||
@@ -498,29 +721,31 @@ section.open-ended-child {
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style: disc outside none;
|
||||
margin-bottom: lh();
|
||||
margin-left: .75em;
|
||||
margin-left: .75rem;
|
||||
}
|
||||
|
||||
ul.rubric-list{
|
||||
list-style-type: none;
|
||||
padding:0;
|
||||
margin:0;
|
||||
li {
|
||||
&.rubric-list-item{
|
||||
margin-bottom: 0px;
|
||||
padding: 0px;
|
||||
}
|
||||
}
|
||||
ul.rubric-list{
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style-type: none;
|
||||
list-style: none;
|
||||
|
||||
li {
|
||||
&.rubric-list-item {
|
||||
margin-bottom: 0;
|
||||
padding: 0;
|
||||
border-radius: $baseline/4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ol {
|
||||
list-style: decimal outside none;
|
||||
margin-bottom: lh();
|
||||
margin-left: .75em;
|
||||
margin-left: .75rem;
|
||||
list-style: decimal outside none;
|
||||
}
|
||||
|
||||
dl {
|
||||
@@ -541,8 +766,9 @@ section.open-ended-child {
|
||||
}
|
||||
|
||||
li {
|
||||
margin-bottom: 0px;
|
||||
padding: 0px;
|
||||
margin-bottom: 0;
|
||||
padding: 0;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
@@ -553,14 +779,14 @@ section.open-ended-child {
|
||||
}
|
||||
|
||||
hr {
|
||||
background: #ddd;
|
||||
border: none;
|
||||
clear: both;
|
||||
color: #ddd;
|
||||
float: none;
|
||||
height: 1px;
|
||||
clear: both;
|
||||
margin: 0 0 .75rem;
|
||||
width: 100%;
|
||||
height: 1px;
|
||||
border: none;
|
||||
background: #ddd;
|
||||
color: #ddd;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
@@ -574,7 +800,7 @@ section.open-ended-child {
|
||||
}
|
||||
|
||||
section.action {
|
||||
margin-top: 20px;
|
||||
margin-top: $baseline;
|
||||
|
||||
input.save {
|
||||
@extend .blue-button !optional;
|
||||
@@ -582,20 +808,20 @@ section.open-ended-child {
|
||||
|
||||
.submission_feedback {
|
||||
@include inline-block;
|
||||
font-style: italic;
|
||||
margin: 8px 0 0 10px;
|
||||
margin: 8px 0 0 $baseline/2;
|
||||
color: #777;
|
||||
font-style: italic;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
}
|
||||
|
||||
.detailed-solution {
|
||||
> p:first-child {
|
||||
font-size: 0.9em;
|
||||
color: #aaa;
|
||||
text-transform: uppercase;
|
||||
font-weight: bold;
|
||||
font-style: normal;
|
||||
text-transform: uppercase;
|
||||
color: #AAA;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
p:last-child {
|
||||
@@ -605,56 +831,136 @@ section.open-ended-child {
|
||||
|
||||
div.open-ended-alert,
|
||||
.save_message {
|
||||
margin-top: $baseline/2;
|
||||
margin-bottom: $baseline/4;
|
||||
padding: 8px 12px;
|
||||
border: 1px solid #EBE8BF;
|
||||
border: 1px solid #ebe8bf;
|
||||
border-radius: 3px;
|
||||
background: #FFFCDD;
|
||||
background: #fffcdd;
|
||||
font-size: 0.9em;
|
||||
margin-top: 10px;
|
||||
margin-bottom:5px;
|
||||
}
|
||||
|
||||
div.capa_reset {
|
||||
margin-top: $baseline/2;
|
||||
margin-bottom: $baseline/2;
|
||||
padding: 25px;
|
||||
border: 1px solid $error-red;
|
||||
background-color: lighten($error-red, 25%);
|
||||
border-radius: 3px;
|
||||
background-color: lighten($error-red, 25%);
|
||||
font-size: 1em;
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.capa_reset>h2 {
|
||||
color: #AA0000;
|
||||
|
||||
.capa_reset > h2 {
|
||||
color: #aa0000;
|
||||
}
|
||||
|
||||
.capa_reset li {
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
.assessment-container {
|
||||
margin: 40px 0px 30px 0px;
|
||||
.scoring-container
|
||||
{
|
||||
p
|
||||
{
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
label {
|
||||
margin: 10px;
|
||||
padding: 5px;
|
||||
display: inline-block;
|
||||
min-width: 50px;
|
||||
background-color: #CCC;
|
||||
text-size: 1.5em;
|
||||
}
|
||||
|
||||
input[type=radio]:checked + label {
|
||||
background: #666;
|
||||
color: white;
|
||||
}
|
||||
input[class='grade-selection'] {
|
||||
display: none;
|
||||
}
|
||||
margin: $baseline*2 0px 30px 0px;
|
||||
|
||||
.scoring-container {
|
||||
p {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
label {
|
||||
display: inline-block;
|
||||
margin: $baseline/2;
|
||||
padding: $baseline/4;
|
||||
min-width: 50px;
|
||||
background-color: #ccc;
|
||||
text-size: 1.5em;
|
||||
}
|
||||
|
||||
input[type=radio]:checked + label {
|
||||
background: #666;
|
||||
color: white;
|
||||
}
|
||||
|
||||
input[class='grade-selection'] {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
div.prompt {
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
h4 {
|
||||
padding: $baseline/2 0;
|
||||
}
|
||||
}
|
||||
|
||||
//OE Tool Area Styling
|
||||
|
||||
.oe-tools {
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
border-radius: 5px;
|
||||
|
||||
.oe-tools-label, .oe-tools-scores-label {
|
||||
display: inline-block;
|
||||
padding: $baseline/2;
|
||||
vertical-align: middle;
|
||||
font-size: 0.8em;
|
||||
}
|
||||
|
||||
.rubric-button {
|
||||
padding: 8px $baseline/4;
|
||||
}
|
||||
|
||||
.rubric-previous-button {
|
||||
margin-right: $baseline/4;
|
||||
}
|
||||
|
||||
.rubric-next-button {
|
||||
margin-left: $baseline/4;
|
||||
}
|
||||
|
||||
.next-step-button {
|
||||
margin: $baseline/2;
|
||||
}
|
||||
.reset-button {
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
|
||||
// Staff Grading
|
||||
.problem-list-container {
|
||||
margin: $baseline/2;
|
||||
|
||||
.instructions {
|
||||
padding-bottom: $baseline/2;
|
||||
}
|
||||
}
|
||||
|
||||
.staff-grading {
|
||||
|
||||
.breadcrumbs {
|
||||
padding: $baseline/10;
|
||||
background-color: #f6f6f6;
|
||||
border-radius: 5px;
|
||||
margin-bottom: $baseline/2;
|
||||
}
|
||||
|
||||
.prompt-wrapper {
|
||||
padding-top: $baseline/2;
|
||||
|
||||
.meta-info-wrapper {
|
||||
padding: $baseline/2;
|
||||
border-radius: $baseline/4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
section.peer-grading-container{
|
||||
div.peer-grading{
|
||||
section.calibration-feedback {
|
||||
padding: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,75 +1,80 @@
|
||||
<section class="course-content">
|
||||
<section class="xmodule_display xmodule_CombinedOpenEndedModule" data-type="CombinedOpenEnded">
|
||||
<section class="xmodule_display xmodule_CombinedOpenEndedModule" data-type="CombinedOpenEnded">
|
||||
<section id="combined-open-ended" class="combined-open-ended" data-ajax-url="/courses/MITx/6.002x/2012_Fall/modx/i4x://MITx/6.002x/combinedopenended/CombinedOE" data-allow_reset="False" data-state="assessing" data-task-count="2" data-task-number="1">
|
||||
|
||||
<h2>Problem 1</h2>
|
||||
<div class="status-container">
|
||||
<h4>Status</h4>
|
||||
<div class="status-elements">
|
||||
<section id="combined-open-ended-status" class="combined-open-ended-status">
|
||||
|
||||
<div class="statusitem" data-status-number="0">
|
||||
|
||||
Step 1 (Problem complete) : 1 / 1
|
||||
<h2>Problem 1</h2>
|
||||
<div class="status-container">
|
||||
<h4>Status</h4>
|
||||
<div class="status-elements">
|
||||
<section id="combined-open-ended-status" class="combined-open-ended-status">
|
||||
<div class="statusitem" data-status-number="0">
|
||||
Step 1 (Problem complete) : 1 / 1
|
||||
<span class="correct" id="status"></span>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="statusitem statusitem-current" data-status-number="1">
|
||||
|
||||
Step 2 (Being scored) : None / 1
|
||||
</div>
|
||||
<div class="statusitem statusitem-current" data-status-number="1">
|
||||
Step 2 (Being scored) : None / 1
|
||||
<span class="grading" id="status"></span>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="item-container">
|
||||
<h4>Problem</h4>
|
||||
<div class="item-container">
|
||||
<h4>Problem</h4>
|
||||
<div class="problem-container">
|
||||
<div class="item"><section id="openended_open_ended" class="open-ended-child" data-state="assessing" data-child-type="openended"><div class="error"></div>
|
||||
<div class="prompt">
|
||||
|
||||
Some prompt.
|
||||
|
||||
</div>
|
||||
<textarea rows="30" cols="80" name="answer" class="answer short-form-response" id="input_open_ended" disabled="disabled">Test submission. Yaaaaaaay!</textarea><div class="message-wrapper"></div>
|
||||
<div class="grader-status">
|
||||
<span class="grading" id="status_open_ended">Submitted for grading.</span>
|
||||
|
||||
</div>
|
||||
|
||||
<input type="button" value="Submit assessment" class="submit-button" name="show" style="display: none;"><input name="skip" class="skip-button" type="button" value="Skip Post-Assessment" style="display: none;"><div class="open-ended-action"></div>
|
||||
|
||||
<span id="answer_open_ended"></span>
|
||||
</section></div>
|
||||
<div class="item">
|
||||
<section id="openended_open_ended" class="open-ended-child" data-state="assessing" data-child-type="openended">
|
||||
<div class="error">
|
||||
</div>
|
||||
<div class="prompt">
|
||||
Some prompt.
|
||||
</div>
|
||||
<textarea rows="30" cols="80" name="answer" class="answer short-form-response" id="input_open_ended" disabled="disabled">
|
||||
Test submission. Yaaaaaaay!
|
||||
</textarea>
|
||||
<div class="message-wrapper"></div>
|
||||
<div class="grader-status">
|
||||
<span class="grading" id="status_open_ended">Submitted for grading.</span>
|
||||
</div>
|
||||
<input type="button" value="Submit assessment" class="submit-button" name="show" style="display: none;">
|
||||
<input name="skip" class="skip-button" type="button" value="Skip Post-Assessment" style="display: none;">
|
||||
<div class="open-ended-action"></div>
|
||||
<span id="answer_open_ended"></span>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
<div class="oe-tools response-tools">
|
||||
<span class="oe-tools-label"></span>
|
||||
<input type="button" value="Reset" class="reset-button" name="reset" style="display: none;">
|
||||
<input type="button" value="Next Step" class="next-step-button" name="reset" style="display: none;">
|
||||
</div>
|
||||
<input type="button" value="Next Step" class="next-step-button" name="reset" style="display: none;">
|
||||
</div>
|
||||
|
||||
<a name="results">
|
||||
<div class="result-container">
|
||||
</div>
|
||||
</a></section><a name="results">
|
||||
|
||||
|
||||
</a></section><a name="results">
|
||||
|
||||
</a><div><a name="results">
|
||||
</a><a href="https://github.com/MITx/content-mit-6002x/tree/master/combinedopenended/CombinedOE.xml">Edit</a> /
|
||||
<a href="#i4x_MITx_6_002x_combinedopenended_CombinedOE_xqa-modal" onclick="javascript:getlog('i4x_MITx_6_002x_combinedopenended_CombinedOE', {
|
||||
<div class="result-container">
|
||||
</div>
|
||||
</a>
|
||||
</section>
|
||||
<a name="results">
|
||||
</a>
|
||||
</section>
|
||||
<a name="results">
|
||||
</a>
|
||||
<div>
|
||||
<a name="results">
|
||||
</a>
|
||||
<a href="https://github.com/MITx/content-mit-6002x/tree/master/combinedopenended/CombinedOE.xml">
|
||||
Edit
|
||||
</a> /
|
||||
<a href="#i4x_MITx_6_002x_combinedopenended_CombinedOE_xqa-modal" onclick="javascript:getlog('i4x_MITx_6_002x_combinedopenended_CombinedOE', {
|
||||
'location': 'i4x://MITx/6.002x/combinedopenended/CombinedOE',
|
||||
'xqa_key': 'KUBrWtK3RAaBALLbccHrXeD3RHOpmZ2A',
|
||||
'category': 'CombinedOpenEndedModule',
|
||||
'user': 'blah'
|
||||
})" id="i4x_MITx_6_002x_combinedopenended_CombinedOE_xqa_log">QA</a>
|
||||
</div>
|
||||
<div><a href="#i4x_MITx_6_002x_combinedopenended_CombinedOE_debug" id="i4x_MITx_6_002x_combinedopenended_CombinedOE_trig">Staff Debug Info</a></div>
|
||||
</div>
|
||||
<div>
|
||||
<a href="#i4x_MITx_6_002x_combinedopenended_CombinedOE_debug" id="i4x_MITx_6_002x_combinedopenended_CombinedOE_trig">
|
||||
Staff Debug Info
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<section id="i4x_MITx_6_002x_combinedopenended_CombinedOE_xqa-modal" class="modal xqa-modal" style="width:80%; left:20%; height:80%; overflow:auto">
|
||||
<div class="inner-wrapper">
|
||||
|
||||
321
common/lib/xmodule/xmodule/js/fixtures/rubric.html
Normal file
321
common/lib/xmodule/xmodule/js/fixtures/rubric.html
Normal file
@@ -0,0 +1,321 @@
|
||||
<section id="combined-open-ended" class="combined-open-ended" data-location="i4x://test/2323/combinedopenended/b893eedec151441f8644187266ccce00" data-ajax-url="/courses/test/2323/Test2/modx/i4x://test/2323/combinedopenended/b893eedec151441f8644187266ccce00" data-allow_reset="False" data-state="initial" data-task-count="1" data-task-number="1" data-accept-file-upload="False">
|
||||
<div class="name">
|
||||
<h2>Open Response Assessment</h2>
|
||||
<div class="progress-container">
|
||||
</div>
|
||||
</div>
|
||||
<div class="problemwrapper">
|
||||
<div class="status-bar">
|
||||
<table class="statustable">
|
||||
<tbody><tr>
|
||||
<td class="problemtype-container">
|
||||
<div class="problemtype">
|
||||
Open Response
|
||||
</div>
|
||||
</td>
|
||||
<td class="assessments-container">
|
||||
<div class="assessment-text">
|
||||
Assessments:
|
||||
</div>
|
||||
<div class="status-container">
|
||||
|
||||
<div class="status-elements">
|
||||
<section id="combined-open-ended-status" class="combined-open-ended-status">
|
||||
|
||||
<div class="statusitem statusitem-current" data-status-number="0">
|
||||
Peer
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody></table>
|
||||
</div>
|
||||
|
||||
<div class="item-container">
|
||||
<div class="visibility-control visibility-control-prompt">
|
||||
<div class="inner">
|
||||
</div>
|
||||
<a href="" class="question-header">Show Prompt</a>
|
||||
</div>
|
||||
<div class="problem-container">
|
||||
<div class="item">
|
||||
<section id="openended_open_ended" class="open-ended-child" data-state="post_assessment" data-child-type="openended">
|
||||
<div class="error"></div>
|
||||
<div class="prompt open" style="display: none;">
|
||||
<h3>Censorship in the Libraries</h3><p>'All of us can think of a book that we hope none of our children or any other children have taken off the shelf. But if I have the right to remove that book from the shelf -- that work I abhor -- then you also have exactly the same right and so does everyone else. And then we have no books left on the shelf for any of us.' --Katherine Paterson, Author
|
||||
</p><p>
|
||||
Write a persuasive essay to a newspaper reflecting your vies on censorship in libraries. Do you believe that certain materials, such as books, music, movies, magazines, etc., should be removed from the shelves if they are found offensive? Support your position with convincing arguments from your own experience, observations, and/or reading.
|
||||
</p>
|
||||
</div>
|
||||
<div class="visibility-control visibility-control-response">
|
||||
<div class="inner">
|
||||
</div>
|
||||
<span class="section-header section-header-response">Response</span>
|
||||
</div>
|
||||
<div class="answer short-form-response" id="input_open_ended"></div>
|
||||
|
||||
<div class="message-wrapper"></div>
|
||||
<div class="grader-status">
|
||||
|
||||
</div>
|
||||
|
||||
<div class="file-upload"></div>
|
||||
|
||||
<input type="button" value="Submit post-assessment" class="submit-button" name="show" style="display: none;">
|
||||
<input name="skip" class="skip-button" type="button" value="Skip Post-Assessment" style="display: none;">
|
||||
|
||||
<div class="open-ended-action"></div>
|
||||
|
||||
<span id="answer_open_ended"></span>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
<div class="oe-tools response-tools">
|
||||
<span class="oe-tools-label"></span>
|
||||
<input type="button" value="Reset" class="reset-button" name="reset" style="display: inline-block;">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="combined-rubric-container" data-status="shown" data-number="0" style="">
|
||||
<div class="visibility-control visibility-control-rubric">
|
||||
<div class="inner">
|
||||
</div>
|
||||
<span class="section-header section-header-rubric">Submitted Rubric</span>
|
||||
</div>
|
||||
<div class="rubric-header">
|
||||
<button class="rubric-collapse" href="#">Show Full Rubric</button>
|
||||
Scored rubric from grader 1
|
||||
</div>
|
||||
<div class="rubric">
|
||||
|
||||
<span class="rubric-category">
|
||||
Ideas
|
||||
</span> <br>
|
||||
<ul class="rubric-list">
|
||||
|
||||
<li class="rubric-list-item">
|
||||
<div class="rubric-label">
|
||||
<label class="choicegroup_incorrect wrapper-score-selection"></label>
|
||||
<span class="wrappable"> 0 points :
|
||||
Difficult for the reader to discern the main idea. Too brief or too repetitive to establish or maintain a focus.
|
||||
</span>
|
||||
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="rubric-list-item rubric-info-item" style="display: none;">
|
||||
<div class="rubric-label">
|
||||
<label class="rubric-elements-info">
|
||||
<span class="wrapper-score-selection"> </span>
|
||||
<span class="wrappable"> 1 points :
|
||||
Attempts a main idea. Sometimes loses focus or ineffectively displays focus.
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="rubric-list-item rubric-info-item" style="display: none;">
|
||||
<div class="rubric-label">
|
||||
<label class="rubric-elements-info">
|
||||
<span class="wrapper-score-selection"> </span>
|
||||
<span class="wrappable"> 2 points :
|
||||
Presents a unifying theme or main idea, but may include minor tangents. Stays somewhat focused on topic and task.
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="rubric-list-item rubric-info-item" style="display: none;">
|
||||
<div class="rubric-label">
|
||||
<label class="rubric-elements-info">
|
||||
<span class="wrapper-score-selection"> </span>
|
||||
<span class="wrappable"> 3 points :
|
||||
Presents a unifying theme or main idea without going off on tangents. Stays completely focused on topic and task.
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<span class="rubric-category">
|
||||
Content
|
||||
</span> <br>
|
||||
<ul class="rubric-list">
|
||||
|
||||
<li class="rubric-list-item">
|
||||
<div class="rubric-label">
|
||||
<label class="choicegroup_incorrect wrapper-score-selection"></label>
|
||||
<span class="wrappable"> 0 points :
|
||||
Includes little information with few or no details or unrelated details. Unsuccessful in attempts to explore any facets of the topic.
|
||||
</span>
|
||||
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="rubric-list-item rubric-info-item" style="display: none;">
|
||||
<div class="rubric-label">
|
||||
<label class="rubric-elements-info">
|
||||
<span class="wrapper-score-selection"> </span>
|
||||
<span class="wrappable"> 1 points :
|
||||
Includes little information and few or no details. Explores only one or two facets of the topic.
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="rubric-list-item rubric-info-item" style="display: none;">
|
||||
<div class="rubric-label">
|
||||
<label class="rubric-elements-info">
|
||||
<span class="wrapper-score-selection"> </span>
|
||||
<span class="wrappable"> 2 points :
|
||||
Includes sufficient information and supporting details. (Details may not be fully developed; ideas may be listed.) Explores some facets of the topic.
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="rubric-list-item rubric-info-item" style="display: none;">
|
||||
<div class="rubric-label">
|
||||
<label class="rubric-elements-info">
|
||||
<span class="wrapper-score-selection"> </span>
|
||||
<span class="wrappable"> 3 points :
|
||||
Includes in-depth information and exceptional supporting details that are fully developed. Explores all facets of the topic.
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<span class="rubric-category">
|
||||
Organization
|
||||
</span> <br>
|
||||
<ul class="rubric-list">
|
||||
|
||||
<li class="rubric-list-item">
|
||||
<div class="rubric-label">
|
||||
<label class="choicegroup_incorrect wrapper-score-selection"></label>
|
||||
<span class="wrappable"> 0 points :
|
||||
Ideas organized illogically, transitions weak, and response difficult to follow.
|
||||
</span>
|
||||
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="rubric-list-item rubric-info-item" style="display: none;">
|
||||
<div class="rubric-label">
|
||||
<label class="rubric-elements-info">
|
||||
<span class="wrapper-score-selection"> </span>
|
||||
<span class="wrappable"> 1 points :
|
||||
Attempts to logically organize ideas. Attempts to progress in an order that enhances meaning, and demonstrates use of transitions.
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="rubric-list-item rubric-info-item" style="display: none;">
|
||||
<div class="rubric-label">
|
||||
<label class="rubric-elements-info">
|
||||
<span class="wrapper-score-selection"> </span>
|
||||
<span class="wrappable"> 2 points :
|
||||
Ideas organized logically. Progresses in an order that enhances meaning. Includes smooth transitions.
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<span class="rubric-category">
|
||||
Style
|
||||
</span> <br>
|
||||
<ul class="rubric-list">
|
||||
|
||||
<li class="rubric-list-item">
|
||||
<div class="rubric-label">
|
||||
<label class="choicegroup_incorrect wrapper-score-selection"></label>
|
||||
<span class="wrappable"> 0 points :
|
||||
Contains limited vocabulary, with many words used incorrectly. Demonstrates problems with sentence patterns.
|
||||
</span>
|
||||
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="rubric-list-item rubric-info-item" style="display: none;">
|
||||
<div class="rubric-label">
|
||||
<label class="rubric-elements-info">
|
||||
<span class="wrapper-score-selection"> </span>
|
||||
<span class="wrappable"> 1 points :
|
||||
Contains basic vocabulary, with words that are predictable and common. Contains mostly simple sentences (although there may be an attempt at more varied sentence patterns).
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="rubric-list-item rubric-info-item" style="display: none;">
|
||||
<div class="rubric-label">
|
||||
<label class="rubric-elements-info">
|
||||
<span class="wrapper-score-selection"> </span>
|
||||
<span class="wrappable"> 2 points :
|
||||
Includes vocabulary to make explanations detailed and precise. Includes varied sentence patterns, including complex sentences.
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<span class="rubric-category">
|
||||
Voice
|
||||
</span> <br>
|
||||
<ul class="rubric-list">
|
||||
|
||||
<li class="rubric-list-item">
|
||||
<div class="rubric-label">
|
||||
<label class="choicegroup_incorrect wrapper-score-selection"></label>
|
||||
<span class="wrappable"> 0 points :
|
||||
Demonstrates language and tone that may be inappropriate to task and reader.
|
||||
</span>
|
||||
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="rubric-list-item rubric-info-item" style="display: none;">
|
||||
<div class="rubric-label">
|
||||
<label class="rubric-elements-info">
|
||||
<span class="wrapper-score-selection"> </span>
|
||||
<span class="wrappable"> 1 points :
|
||||
Demonstrates an attempt to adjust language and tone to task and reader.
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="rubric-list-item rubric-info-item" style="display: none;">
|
||||
<div class="rubric-label">
|
||||
<label class="rubric-elements-info">
|
||||
<span class="wrapper-score-selection"> </span>
|
||||
<span class="wrappable"> 2 points :
|
||||
Demonstrates effective adjustment of language and tone to task and reader.
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="written-feedback">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<input type="button" value="Next Step" class="next-step-button" name="reset" style="display: none;">
|
||||
|
||||
<section class="legend-container">
|
||||
</section>
|
||||
|
||||
<div class="result-container">
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@@ -1,3 +1,30 @@
|
||||
describe 'Rubric', ->
|
||||
beforeEach ->
|
||||
spyOn Logger, 'log'
|
||||
# load up some fixtures
|
||||
loadFixtures 'rubric.html'
|
||||
jasmine.Clock.useMock()
|
||||
@element = $('.combined-open-ended')
|
||||
@location = @element.data('location')
|
||||
|
||||
describe 'constructor', ->
|
||||
beforeEach ->
|
||||
@rub = new Rubric @element
|
||||
|
||||
it 'rubric should properly grab the element', ->
|
||||
expect(@rub.el).toEqual @element
|
||||
|
||||
describe 'initialize', ->
|
||||
beforeEach ->
|
||||
@rub = new Rubric @element
|
||||
@rub.initialize @location
|
||||
|
||||
it 'rubric correctly sets location', ->
|
||||
expect($(@rub.rubric_sel).data('location')).toEqual @location
|
||||
|
||||
it 'rubric correctly read', ->
|
||||
expect(@rub.categories.length).toEqual 5
|
||||
|
||||
describe 'CombinedOpenEnded', ->
|
||||
beforeEach ->
|
||||
spyOn Logger, 'log'
|
||||
@@ -13,7 +40,7 @@ describe 'CombinedOpenEnded', ->
|
||||
@combined = new CombinedOpenEnded @element
|
||||
|
||||
it 'set the element', ->
|
||||
expect(@combined.element).toEqual @element
|
||||
expect(@combined.el).toEqual @element
|
||||
|
||||
it 'get the correct values from data fields', ->
|
||||
expect(@combined.ajax_url).toEqual '/courses/MITx/6.002x/2012_Fall/modx/i4x://MITx/6.002x/combinedopenended/CombinedOE'
|
||||
@@ -77,7 +104,7 @@ describe 'CombinedOpenEnded', ->
|
||||
@combined.child_state = 'done'
|
||||
@combined.rebind()
|
||||
expect(@combined.answer_area.attr("disabled")).toBe("disabled")
|
||||
expect(@combined.next_problem).toHaveBeenCalled()
|
||||
expect(@combined.next_problem_button).toBe(":visible")
|
||||
|
||||
describe 'next_problem', ->
|
||||
beforeEach ->
|
||||
@@ -109,3 +136,5 @@ describe 'CombinedOpenEnded', ->
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,22 +1,29 @@
|
||||
class @Rubric
|
||||
constructor: () ->
|
||||
|
||||
@initialize: (location) ->
|
||||
$('.rubric').data("location", location)
|
||||
$('input[class="score-selection"]').change @tracking_callback
|
||||
rubric_category_sel: '.rubric-category'
|
||||
rubric_sel: '.rubric'
|
||||
|
||||
constructor: (el) ->
|
||||
@el = el
|
||||
|
||||
initialize: (location) =>
|
||||
@$(@rubric_sel).data("location", location)
|
||||
@$('input[class="score-selection"]').change @tracking_callback
|
||||
# set up the hotkeys
|
||||
$(window).unbind('keydown', @keypress_callback)
|
||||
$(window).keydown @keypress_callback
|
||||
# display the 'current' carat
|
||||
@categories = $('.rubric-category')
|
||||
@category = $(@categories.first())
|
||||
@category.prepend('> ')
|
||||
@categories = @$(@rubric_category_sel)
|
||||
@category = @$(@categories.first())
|
||||
@category_index = 0
|
||||
|
||||
|
||||
@keypress_callback: (event) =>
|
||||
|
||||
# locally scoped jquery.
|
||||
$: (selector) ->
|
||||
$(selector, @el)
|
||||
|
||||
keypress_callback: (event) =>
|
||||
# don't try to do this when user is typing in a text input
|
||||
if $(event.target).is('input, textarea')
|
||||
if @$(event.target).is('input, textarea')
|
||||
return
|
||||
# for when we select via top row
|
||||
if event.which >= 48 and event.which <= 57
|
||||
@@ -31,124 +38,158 @@ class @Rubric
|
||||
# if we actually have a current category (not past the end)
|
||||
if(@category_index <= @categories.length)
|
||||
# find the valid selections for this category
|
||||
inputs = $("input[name='score-selection-#{@category_index}']")
|
||||
inputs = @$("input[name='score-selection-#{@category_index}']")
|
||||
max_score = inputs.length - 1
|
||||
|
||||
if selected > max_score or selected < 0
|
||||
return
|
||||
inputs.filter("input[value=#{selected}]").click()
|
||||
|
||||
# move to the next category
|
||||
old_category_text = @category.html().substring(5)
|
||||
@category.html(old_category_text)
|
||||
@category_index++
|
||||
@category = $(@categories[@category_index])
|
||||
@category.prepend('> ')
|
||||
@category = @$(@categories[@category_index])
|
||||
|
||||
@tracking_callback: (event) ->
|
||||
target_selection = $(event.target).val()
|
||||
tracking_callback: (event) =>
|
||||
target_selection = @$(event.target).val()
|
||||
# chop off the beginning of the name so that we can get the number of the category
|
||||
category = $(event.target).data("category")
|
||||
location = $('.rubric').data('location')
|
||||
category = @$(event.target).data("category")
|
||||
location = @$(@rubric_sel).data('location')
|
||||
# probably want the original problem location as well
|
||||
|
||||
data = {location: location, selection: target_selection, category: category}
|
||||
Logger.log 'rubric_select', data
|
||||
|
||||
|
||||
# finds the scores for each rubric category
|
||||
@get_score_list: () =>
|
||||
get_score_list: () =>
|
||||
# find the number of categories:
|
||||
num_categories = $('.rubric-category').length
|
||||
num_categories = @$(@rubric_category_sel).length
|
||||
|
||||
score_lst = []
|
||||
# get the score for each one
|
||||
for i in [0..(num_categories-1)]
|
||||
score = $("input[name='score-selection-#{i}']:checked").val()
|
||||
score = @$("input[name='score-selection-#{i}']:checked").val()
|
||||
score_lst.push(score)
|
||||
|
||||
return score_lst
|
||||
|
||||
@get_total_score: () ->
|
||||
get_total_score: () =>
|
||||
score_lst = @get_score_list()
|
||||
tot = 0
|
||||
for score in score_lst
|
||||
tot += parseInt(score)
|
||||
return tot
|
||||
|
||||
@check_complete: () ->
|
||||
check_complete: () =>
|
||||
# check to see whether or not any categories have not been scored
|
||||
num_categories = $('.rubric-category').length
|
||||
num_categories = @$(@rubric_category_sel).length
|
||||
for i in [0..(num_categories-1)]
|
||||
score = $("input[name='score-selection-#{i}']:checked").val()
|
||||
score = @$("input[name='score-selection-#{i}']:checked").val()
|
||||
if score == undefined
|
||||
return false
|
||||
return true
|
||||
|
||||
class @CombinedOpenEnded
|
||||
constructor: (element) ->
|
||||
@element=element
|
||||
@reinitialize(element)
|
||||
|
||||
wrapper_sel: 'section.xmodule_CombinedOpenEndedModule'
|
||||
coe_sel: 'section.combined-open-ended'
|
||||
reset_button_sel: '.reset-button'
|
||||
next_step_sel: '.next-step-button'
|
||||
question_header_sel: '.question-header'
|
||||
submit_evaluation_sel: '.submit-evaluation-button'
|
||||
result_container_sel: 'div.result-container'
|
||||
combined_rubric_sel: '.combined-rubric-container'
|
||||
open_ended_child_sel: 'section.open-ended-child'
|
||||
error_sel: '.error'
|
||||
answer_area_sel: 'textarea.answer'
|
||||
answer_area_div_sel : 'div.answer'
|
||||
prompt_sel: '.prompt'
|
||||
rubric_wrapper_sel: '.rubric-wrapper'
|
||||
hint_wrapper_sel: '.hint-wrapper'
|
||||
message_wrapper_sel: '.message-wrapper'
|
||||
submit_button_sel: '.submit-button'
|
||||
skip_button_sel: '.skip-button'
|
||||
file_upload_sel: '.file-upload'
|
||||
file_upload_box_sel: '.file-upload-box'
|
||||
file_upload_preview_sel: '.file-upload-preview'
|
||||
fof_sel: 'textarea.feedback-on-feedback'
|
||||
sub_id_sel: 'input.submission_id'
|
||||
grader_id_sel: 'input.grader_id'
|
||||
grader_status_sel: '.grader-status'
|
||||
info_rubric_elements_sel: '.rubric-info-item'
|
||||
rubric_collapse_sel: '.rubric-collapse'
|
||||
next_rubric_sel: '.rubric-next-button'
|
||||
previous_rubric_sel: '.rubric-previous-button'
|
||||
oe_alert_sel: '.open-ended-alert'
|
||||
|
||||
constructor: (el) ->
|
||||
@el=el
|
||||
@$el = $(el)
|
||||
@reinitialize(el)
|
||||
$(window).keydown @keydown_handler
|
||||
$(window).keyup @keyup_handler
|
||||
|
||||
reinitialize: (element) ->
|
||||
@wrapper=$(element).find('section.xmodule_CombinedOpenEndedModule')
|
||||
@el = $(element).find('section.combined-open-ended')
|
||||
@combined_open_ended=$(element).find('section.combined-open-ended')
|
||||
@id = @el.data('id')
|
||||
@ajax_url = @el.data('ajax-url')
|
||||
@state = @el.data('state')
|
||||
@task_count = @el.data('task-count')
|
||||
@task_number = @el.data('task-number')
|
||||
@accept_file_upload = @el.data('accept-file-upload')
|
||||
@location = @el.data('location')
|
||||
# locally scoped jquery.
|
||||
$: (selector) ->
|
||||
$(selector, @el)
|
||||
|
||||
reinitialize: () ->
|
||||
@has_been_reset = false
|
||||
@wrapper=@$(@wrapper_sel)
|
||||
@coe = @$(@coe_sel)
|
||||
|
||||
@ajax_url = @coe.data('ajax-url')
|
||||
@get_html()
|
||||
@coe = @$(@coe_sel)
|
||||
|
||||
#Get data from combinedopenended
|
||||
@allow_reset = @coe.data('allow_reset')
|
||||
@id = @coe.data('id')
|
||||
@state = @coe.data('state')
|
||||
@task_count = @coe.data('task-count')
|
||||
@task_number = @coe.data('task-number')
|
||||
@accept_file_upload = @coe.data('accept-file-upload')
|
||||
@location = @coe.data('location')
|
||||
|
||||
# set up handlers for click tracking
|
||||
Rubric.initialize(@location)
|
||||
@rub = new Rubric(@coe)
|
||||
@rub.initialize(@location)
|
||||
@is_ctrl = false
|
||||
|
||||
@allow_reset = @el.data('allow_reset')
|
||||
@reset_button = @$('.reset-button')
|
||||
#Setup reset
|
||||
@reset_button = @$(@reset_button_sel)
|
||||
@reset_button.click @reset
|
||||
@next_problem_button = @$('.next-step-button')
|
||||
#Setup next problem
|
||||
@next_problem_button = @$(@next_step_sel)
|
||||
@next_problem_button.click @next_problem
|
||||
@status_container = @$('.status-elements')
|
||||
|
||||
@show_results_button=@$('.show-results-button')
|
||||
@show_results_button.click @show_results
|
||||
|
||||
@question_header = @$('.question-header')
|
||||
@question_header = @$(@question_header_sel)
|
||||
@question_header.click @collapse_question
|
||||
|
||||
# valid states: 'initial', 'assessing', 'post_assessment', 'done'
|
||||
Collapsible.setCollapsibles(@el)
|
||||
@submit_evaluation_button = $('.submit-evaluation-button')
|
||||
Collapsible.setCollapsibles(@$el)
|
||||
@submit_evaluation_button = @$(@submit_evaluation_sel)
|
||||
@submit_evaluation_button.click @message_post
|
||||
|
||||
@results_container = $('.result-container')
|
||||
@combined_rubric_container = $('.combined-rubric-container')
|
||||
|
||||
@legend_container= $('.legend-container')
|
||||
@show_legend_current()
|
||||
@results_container = @$(@result_container_sel)
|
||||
@combined_rubric_container = @$(@combined_rubric_sel)
|
||||
|
||||
# Where to put the rubric once we load it
|
||||
@el = $(element).find('section.open-ended-child')
|
||||
@errors_area = @$('.error')
|
||||
@answer_area = @$('textarea.answer')
|
||||
@prompt_container = @$('.prompt')
|
||||
@rubric_wrapper = @$('.rubric-wrapper')
|
||||
@hint_wrapper = @$('.hint-wrapper')
|
||||
@message_wrapper = @$('.message-wrapper')
|
||||
@submit_button = @$('.submit-button')
|
||||
@child_state = @el.data('state')
|
||||
@child_type = @el.data('child-type')
|
||||
@oe = @$(@open_ended_child_sel)
|
||||
|
||||
@errors_area = @$(@oe).find(@error_sel)
|
||||
@answer_area = @$(@oe).find(@answer_area_sel)
|
||||
@prompt_container = @$(@oe).find(@prompt_sel)
|
||||
@rubric_wrapper = @$(@oe).find(@rubric_wrapper_sel)
|
||||
@hint_wrapper = @$(@oe).find(@hint_wrapper_sel)
|
||||
@message_wrapper = @$(@oe).find(@message_wrapper_sel)
|
||||
@submit_button = @$(@oe).find(@submit_button_sel)
|
||||
@child_state = @oe.data('state')
|
||||
@child_type = @oe.data('child-type')
|
||||
if @child_type=="openended"
|
||||
@skip_button = @$('.skip-button')
|
||||
@skip_button = @$(@oe).find(@skip_button_sel)
|
||||
@skip_button.click @skip_post_assessment
|
||||
|
||||
@file_upload_area = @$('.file-upload')
|
||||
@file_upload_area = @$(@oe).find(@file_upload_sel)
|
||||
@can_upload_files = false
|
||||
@open_ended_child= @$('.open-ended-child')
|
||||
@open_ended_child= @$(@oe).find(@open_ended_child_sel)
|
||||
|
||||
@out_of_sync_message = 'The problem state got out of sync. Try reloading the page.'
|
||||
|
||||
@@ -162,71 +203,43 @@ class @CombinedOpenEnded
|
||||
|
||||
@rebind()
|
||||
|
||||
if @task_number>1
|
||||
@show_combined_rubric_current()
|
||||
@show_results_current()
|
||||
get_html_callback: (response) =>
|
||||
@coe.replaceWith(response.html)
|
||||
|
||||
# locally scoped jquery.
|
||||
$: (selector) ->
|
||||
$(selector, @el)
|
||||
|
||||
show_results_current: () =>
|
||||
data = {'task_number' : @task_number-1}
|
||||
$.postWithPrefix "#{@ajax_url}/get_results", data, (response) =>
|
||||
if response.success
|
||||
@results_container.after(response.html).remove()
|
||||
@results_container = $('div.result-container')
|
||||
@submit_evaluation_button = $('.submit-evaluation-button')
|
||||
@submit_evaluation_button.click @message_post
|
||||
Collapsible.setCollapsibles(@results_container)
|
||||
# make sure we still have click tracking
|
||||
$('.evaluation-response a').click @log_feedback_click
|
||||
$('input[name="evaluation-score"]').change @log_feedback_selection
|
||||
|
||||
show_results: (event) =>
|
||||
status_item = $(event.target).parent()
|
||||
status_number = status_item.data('status-number')
|
||||
data = {'task_number' : status_number}
|
||||
$.postWithPrefix "#{@ajax_url}/get_results", data, (response) =>
|
||||
if response.success
|
||||
@results_container.after(response.html).remove()
|
||||
@results_container = $('div.result-container')
|
||||
@submit_evaluation_button = $('.submit-evaluation-button')
|
||||
@submit_evaluation_button.click @message_post
|
||||
Collapsible.setCollapsibles(@results_container)
|
||||
else
|
||||
@gentle_alert response.error
|
||||
get_html: () =>
|
||||
url = "#{@ajax_url}/get_html"
|
||||
$.ajaxWithPrefix({
|
||||
type: 'POST',
|
||||
url: url,
|
||||
data: {},
|
||||
success: @get_html_callback,
|
||||
async:false
|
||||
});
|
||||
|
||||
show_combined_rubric_current: () =>
|
||||
data = {}
|
||||
$.postWithPrefix "#{@ajax_url}/get_combined_rubric", data, (response) =>
|
||||
if response.success
|
||||
@combined_rubric_container.after(response.html).remove()
|
||||
@combined_rubric_container= $('div.combined_rubric_container')
|
||||
|
||||
show_status_current: () =>
|
||||
data = {}
|
||||
$.postWithPrefix "#{@ajax_url}/get_status", data, (response) =>
|
||||
if response.success
|
||||
@status_container.after(response.html).remove()
|
||||
@status_container= $('.status-elements')
|
||||
|
||||
show_legend_current: () =>
|
||||
data = {}
|
||||
$.postWithPrefix "#{@ajax_url}/get_legend", data, (response) =>
|
||||
if response.success
|
||||
@legend_container.after(response.html).remove()
|
||||
@legend_container= $('.legend-container')
|
||||
@combined_rubric_container= @$(@combined_rubric_sel)
|
||||
@toggle_rubric("")
|
||||
@rubric_collapse = @$(@rubric_collapse_sel)
|
||||
@rubric_collapse.click @toggle_rubric
|
||||
@hide_rubrics()
|
||||
@$(@previous_rubric_sel).click @previous_rubric
|
||||
@$(@next_rubric_sel).click @next_rubric
|
||||
if response.hide_reset
|
||||
@reset_button.hide()
|
||||
|
||||
message_post: (event)=>
|
||||
external_grader_message=$(event.target).parent().parent().parent()
|
||||
evaluation_scoring = $(event.target).parent()
|
||||
|
||||
fd = new FormData()
|
||||
feedback = evaluation_scoring.find('textarea.feedback-on-feedback')[0].value
|
||||
submission_id = external_grader_message.find('input.submission_id')[0].value
|
||||
grader_id = external_grader_message.find('input.grader_id')[0].value
|
||||
score = evaluation_scoring.find("input:radio[name='evaluation-score']:checked").val()
|
||||
feedback = @$(evaluation_scoring).find(@fof_sel)[0].value
|
||||
submission_id = @$(external_grader_message).find(@sub_id_sel)[0].value
|
||||
grader_id = @$(external_grader_message).find(@grader_id_sel)[0].value
|
||||
score = @$(evaluation_scoring).find("input:radio[name='evaluation-score']:checked").val()
|
||||
|
||||
fd.append('feedback', feedback)
|
||||
fd.append('submission_id', submission_id)
|
||||
@@ -244,7 +257,7 @@ class @CombinedOpenEnded
|
||||
contentType: false
|
||||
success: (response) =>
|
||||
@gentle_alert response.msg
|
||||
$('section.evaluation').slideToggle()
|
||||
@$('section.evaluation').slideToggle()
|
||||
@message_wrapper.html(response.message_html)
|
||||
|
||||
|
||||
@@ -256,11 +269,9 @@ class @CombinedOpenEnded
|
||||
@submit_button.unbind('click')
|
||||
@submit_button.show()
|
||||
@reset_button.hide()
|
||||
@next_problem_button.hide()
|
||||
@hide_file_upload()
|
||||
@next_problem_button.hide()
|
||||
@hint_area.attr('disabled', false)
|
||||
if @task_number>1 or @child_state!='initial'
|
||||
@show_status_current()
|
||||
|
||||
if @task_number==1 and @child_state=='assessing'
|
||||
@prompt_hide()
|
||||
@@ -269,12 +280,14 @@ class @CombinedOpenEnded
|
||||
if @child_type=="openended"
|
||||
@skip_button.hide()
|
||||
if @allow_reset=="True"
|
||||
@show_results_current
|
||||
@show_combined_rubric_current()
|
||||
@reset_button.show()
|
||||
@submit_button.hide()
|
||||
@answer_area.attr("disabled", true)
|
||||
@replace_text_inputs()
|
||||
@hint_area.attr('disabled', true)
|
||||
if @task_number<@task_count
|
||||
@gentle_alert "Your score did not meet the criteria to move to the next step."
|
||||
else if @child_state == 'initial'
|
||||
@answer_area.attr("disabled", false)
|
||||
@submit_button.prop('value', 'Submit')
|
||||
@@ -286,12 +299,14 @@ class @CombinedOpenEnded
|
||||
@hide_file_upload()
|
||||
@submit_button.prop('value', 'Submit assessment')
|
||||
@submit_button.click @save_assessment
|
||||
@submit_button.attr("disabled",true)
|
||||
if @child_type == "openended"
|
||||
@submit_button.hide()
|
||||
@queueing()
|
||||
if @task_number==1 and @task_count==1
|
||||
@grader_status = $('.grader-status')
|
||||
@grader_status.html("<p>Response submitted for scoring.</p>")
|
||||
@grader_status = @$(@grader_status_sel)
|
||||
@grader_status.html("<span class='grading'>Your response has been submitted. Please check back later for your grade.</span> ")
|
||||
else if @child_type == "selfassessment"
|
||||
@setup_score_selection()
|
||||
else if @child_state == 'post_assessment'
|
||||
if @child_type=="openended"
|
||||
@skip_button.show()
|
||||
@@ -304,6 +319,7 @@ class @CombinedOpenEnded
|
||||
else
|
||||
@submit_button.click @message_post
|
||||
else if @child_state == 'done'
|
||||
@show_combined_rubric_current()
|
||||
@rubric_wrapper.hide()
|
||||
@answer_area.attr("disabled", true)
|
||||
@replace_text_inputs()
|
||||
@@ -312,11 +328,8 @@ class @CombinedOpenEnded
|
||||
if @child_type=="openended"
|
||||
@skip_button.hide()
|
||||
if @task_number<@task_count
|
||||
@next_problem()
|
||||
@next_problem_button.show()
|
||||
else
|
||||
if @task_number==1 and @task_count==1
|
||||
@show_combined_rubric_current()
|
||||
@show_results_current()
|
||||
@reset_button.show()
|
||||
|
||||
|
||||
@@ -326,14 +339,32 @@ class @CombinedOpenEnded
|
||||
find_hint_elements: ->
|
||||
@hint_area = @$('textarea.post_assessment')
|
||||
|
||||
replace_answer: (response) =>
|
||||
if response.success
|
||||
@rubric_wrapper.html(response.rubric_html)
|
||||
@rubric_wrapper.show()
|
||||
@rub = new Rubric(@coe)
|
||||
@rub.initialize(@location)
|
||||
@child_state = 'assessing'
|
||||
@find_assessment_elements()
|
||||
@rebind()
|
||||
answer_area_div = @$(@answer_area_div_sel)
|
||||
answer_area_div.html(response.student_response)
|
||||
else
|
||||
@can_upload_files = pre_can_upload_files
|
||||
@gentle_alert response.error
|
||||
|
||||
save_answer: (event) =>
|
||||
@submit_button.attr("disabled",true)
|
||||
@submit_button.hide()
|
||||
event.preventDefault()
|
||||
@answer_area.attr("disabled", true)
|
||||
max_filesize = 2*1000*1000 #2MB
|
||||
pre_can_upload_files = @can_upload_files
|
||||
if @child_state == 'initial'
|
||||
files = ""
|
||||
if @can_upload_files == true
|
||||
files = $('.file-upload-box')[0].files[0]
|
||||
files = @$(@file_upload_box_sel)[0].files[0]
|
||||
if files != undefined
|
||||
if files.size > max_filesize
|
||||
@can_upload_files = false
|
||||
@@ -351,21 +382,11 @@ class @CombinedOpenEnded
|
||||
data: fd
|
||||
processData: false
|
||||
contentType: false
|
||||
async: false
|
||||
success: (response) =>
|
||||
if response.success
|
||||
@rubric_wrapper.html(response.rubric_html)
|
||||
@rubric_wrapper.show()
|
||||
Rubric.initialize(@location)
|
||||
@answer_area.html(response.student_response)
|
||||
@child_state = 'assessing'
|
||||
@find_assessment_elements()
|
||||
@rebind()
|
||||
else
|
||||
@can_upload_files = pre_can_upload_files
|
||||
@gentle_alert response.error
|
||||
@replace_answer(response)
|
||||
|
||||
$.ajaxWithPrefix("#{@ajax_url}/save_answer",settings)
|
||||
|
||||
else
|
||||
@errors_area.html(@out_of_sync_message)
|
||||
|
||||
@@ -373,7 +394,7 @@ class @CombinedOpenEnded
|
||||
#Previously, responses were submitted when hitting enter. Add in a modifier that ensures that ctrl+enter is needed.
|
||||
if event.which == 17 && @is_ctrl==false
|
||||
@is_ctrl=true
|
||||
else if @is_ctrl==true && event.which == 13 && @child_state == 'assessing' && Rubric.check_complete()
|
||||
else if @is_ctrl==true && event.which == 13 && @child_state == 'assessing' && @rub.check_complete()
|
||||
@save_assessment(event)
|
||||
|
||||
keyup_handler: (event) =>
|
||||
@@ -382,10 +403,12 @@ class @CombinedOpenEnded
|
||||
@is_ctrl=false
|
||||
|
||||
save_assessment: (event) =>
|
||||
@submit_button.attr("disabled",true)
|
||||
@submit_button.hide()
|
||||
event.preventDefault()
|
||||
if @child_state == 'assessing' && Rubric.check_complete()
|
||||
checked_assessment = Rubric.get_total_score()
|
||||
score_list = Rubric.get_score_list()
|
||||
if @child_state == 'assessing' && @rub.check_complete()
|
||||
checked_assessment = @rub.get_total_score()
|
||||
score_list = @rub.get_score_list()
|
||||
data = {'assessment' : checked_assessment, 'score_list' : score_list}
|
||||
$.postWithPrefix "#{@ajax_url}/save_assessment", data, (response) =>
|
||||
if response.success
|
||||
@@ -440,9 +463,10 @@ class @CombinedOpenEnded
|
||||
@hint_wrapper.html('')
|
||||
@message_wrapper.html('')
|
||||
@child_state = 'initial'
|
||||
@combined_open_ended.after(response.html).remove()
|
||||
@coe.after(response.html).remove()
|
||||
@allow_reset="False"
|
||||
@reinitialize(@element)
|
||||
@has_been_reset = true
|
||||
@rebind()
|
||||
@reset_button.hide()
|
||||
else
|
||||
@@ -459,7 +483,7 @@ class @CombinedOpenEnded
|
||||
@hint_wrapper.html('')
|
||||
@message_wrapper.html('')
|
||||
@child_state = 'initial'
|
||||
@combined_open_ended.after(response.html).remove()
|
||||
@coe.after(response.html).remove()
|
||||
@reinitialize(@element)
|
||||
@rebind()
|
||||
@next_problem_button.hide()
|
||||
@@ -467,18 +491,18 @@ class @CombinedOpenEnded
|
||||
@gentle_alert "Moved to next step."
|
||||
else
|
||||
@gentle_alert "Your score did not meet the criteria to move to the next step."
|
||||
@show_results_current()
|
||||
@show_combined_rubric_current()
|
||||
else
|
||||
@errors_area.html(response.error)
|
||||
else
|
||||
@errors_area.html(@out_of_sync_message)
|
||||
|
||||
gentle_alert: (msg) =>
|
||||
if @el.find('.open-ended-alert').length
|
||||
@el.find('.open-ended-alert').remove()
|
||||
if @$el.find(@oe_alert_sel).length
|
||||
@$el.find(@oe_alert_sel).remove()
|
||||
alert_elem = "<div class='open-ended-alert'>" + msg + "</div>"
|
||||
@el.find('.open-ended-action').after(alert_elem)
|
||||
@el.find('.open-ended-alert').css(opacity: 0).animate(opacity: 1, 700)
|
||||
@$el.find('.open-ended-action').after(alert_elem)
|
||||
@$el.find(@oe_alert_sel).css(opacity: 0).animate(opacity: 1, 700)
|
||||
|
||||
queueing: =>
|
||||
if @child_state=="assessing" and @child_type=="openended"
|
||||
@@ -500,8 +524,8 @@ class @CombinedOpenEnded
|
||||
@can_upload_files = true
|
||||
@file_upload_area.html('<input type="file" class="file-upload-box"><img class="file-upload-preview" src="#" alt="Uploaded image" />')
|
||||
@file_upload_area.show()
|
||||
$('.file-upload-preview').hide()
|
||||
$('.file-upload-box').change @preview_image
|
||||
@$(@file_upload_preview_sel).hide()
|
||||
@$(@file_upload_box_sel).change @preview_image
|
||||
else
|
||||
@gentle_alert 'File uploads are required for this question, but are not supported in this browser. Try the newest version of google chrome. Alternatively, if you have uploaded the image to the web, you can paste a link to it into the answer box.'
|
||||
|
||||
@@ -519,33 +543,66 @@ class @CombinedOpenEnded
|
||||
|
||||
# wrap this so that it can be mocked
|
||||
reload: ->
|
||||
location.reload()
|
||||
@reinitialize()
|
||||
|
||||
collapse_question: () =>
|
||||
collapse_question: (event) =>
|
||||
@prompt_container.slideToggle()
|
||||
@prompt_container.toggleClass('open')
|
||||
if @question_header.text() == "(Hide)"
|
||||
new_text = "(Show)"
|
||||
if @question_header.text() == "Hide Prompt"
|
||||
new_text = "Show Prompt"
|
||||
Logger.log 'oe_hide_question', {location: @location}
|
||||
else
|
||||
Logger.log 'oe_show_question', {location: @location}
|
||||
new_text = "(Hide)"
|
||||
new_text = "Hide Prompt"
|
||||
@question_header.text(new_text)
|
||||
return false
|
||||
|
||||
hide_rubrics: () =>
|
||||
rubrics = @$(@combined_rubric_sel)
|
||||
for rub in rubrics
|
||||
if @$(rub).data('status')=="shown"
|
||||
@$(rub).show()
|
||||
else
|
||||
@$(rub).hide()
|
||||
|
||||
next_rubric: =>
|
||||
@shift_rubric(1)
|
||||
return false
|
||||
|
||||
previous_rubric: =>
|
||||
@shift_rubric(-1)
|
||||
return false
|
||||
|
||||
shift_rubric: (i) =>
|
||||
rubrics = @$(@combined_rubric_sel)
|
||||
number = 0
|
||||
for rub in rubrics
|
||||
if @$(rub).data('status')=="shown"
|
||||
number = @$(rub).data('number')
|
||||
@$(rub).data('status','hidden')
|
||||
if i==1 and number < rubrics.length - 1
|
||||
number = number + i
|
||||
|
||||
if i==-1 and number>0
|
||||
number = number + i
|
||||
|
||||
@$(rubrics[number]).data('status', 'shown')
|
||||
@hide_rubrics()
|
||||
|
||||
prompt_show: () =>
|
||||
if @prompt_container.is(":hidden")==true
|
||||
@prompt_container.slideToggle()
|
||||
@prompt_container.toggleClass('open')
|
||||
@question_header.text("(Hide)")
|
||||
@question_header.text("Hide Prompt")
|
||||
|
||||
prompt_hide: () =>
|
||||
if @prompt_container.is(":visible")==true
|
||||
@prompt_container.slideToggle()
|
||||
@prompt_container.toggleClass('open')
|
||||
@question_header.text("(Show)")
|
||||
@question_header.text("Show Prompt")
|
||||
|
||||
log_feedback_click: (event) ->
|
||||
link_text = $(event.target).html()
|
||||
link_text = @$(event.target).html()
|
||||
if link_text == 'See full feedback'
|
||||
Logger.log 'oe_show_full_feedback', {}
|
||||
else if link_text == 'Respond to Feedback'
|
||||
@@ -553,32 +610,44 @@ class @CombinedOpenEnded
|
||||
else
|
||||
generated_event_type = link_text.toLowerCase().replace(" ","_")
|
||||
Logger.log "oe_" + generated_event_type, {}
|
||||
|
||||
log_feedback_selection: (event) ->
|
||||
target_selection = $(event.target).val()
|
||||
target_selection = @$(event.target).val()
|
||||
Logger.log 'oe_feedback_response_selected', {value: target_selection}
|
||||
|
||||
remove_attribute: (name) =>
|
||||
if $('.file-upload-preview').attr(name)
|
||||
$('.file-upload-preview')[0].removeAttribute(name)
|
||||
if @$(@file_upload_preview_sel).attr(name)
|
||||
@$(@file_upload_preview_sel)[0].removeAttribute(name)
|
||||
|
||||
preview_image: () =>
|
||||
if $('.file-upload-box')[0].files && $('.file-upload-box')[0].files[0]
|
||||
if @$(@file_upload_box_sel)[0].files && @$(@file_upload_box_sel)[0].files[0]
|
||||
reader = new FileReader()
|
||||
reader.onload = (e) =>
|
||||
max_dim = 150
|
||||
@remove_attribute('src')
|
||||
@remove_attribute('height')
|
||||
@remove_attribute('width')
|
||||
$('.file-upload-preview').attr('src', e.target.result)
|
||||
height_px = $('.file-upload-preview')[0].height
|
||||
width_px = $('.file-upload-preview')[0].width
|
||||
@$(@file_upload_preview_sel).attr('src', e.target.result)
|
||||
height_px = @$(@file_upload_preview_sel)[0].height
|
||||
width_px = @$(@file_upload_preview_sel)[0].width
|
||||
scale_factor = 0
|
||||
if height_px>width_px
|
||||
scale_factor = height_px/max_dim
|
||||
else
|
||||
scale_factor = width_px/max_dim
|
||||
$('.file-upload-preview')[0].width = width_px/scale_factor
|
||||
$('.file-upload-preview')[0].height = height_px/scale_factor
|
||||
$('.file-upload-preview').show()
|
||||
reader.readAsDataURL($('.file-upload-box')[0].files[0])
|
||||
@$(@file_upload_preview_sel)[0].width = width_px/scale_factor
|
||||
@$(@file_upload_preview_sel)[0].height = height_px/scale_factor
|
||||
@$(@file_upload_preview_sel).show()
|
||||
reader.readAsDataURL(@$(@file_upload_box_sel)[0].files[0])
|
||||
|
||||
toggle_rubric: (event) =>
|
||||
info_rubric_elements = @$(@info_rubric_elements_sel)
|
||||
info_rubric_elements.slideToggle()
|
||||
return false
|
||||
|
||||
setup_score_selection: () =>
|
||||
@$("input[class='score-selection']").change @graded_callback
|
||||
|
||||
graded_callback: () =>
|
||||
if @rub.check_complete()
|
||||
@submit_button.attr("disabled",false)
|
||||
@submit_button.show()
|
||||
|
||||
@@ -3,10 +3,20 @@
|
||||
# Can (and should be) expanded upon when our problem list
|
||||
# becomes more sophisticated
|
||||
class @PeerGrading
|
||||
|
||||
peer_grading_sel: '.peer-grading'
|
||||
peer_grading_container_sel: '.peer-grading-container'
|
||||
error_container_sel: '.error-container'
|
||||
message_container_sel: '.message-container'
|
||||
problem_button_sel: '.problem-button'
|
||||
problem_list_sel: '.problem-list'
|
||||
progress_bar_sel: '.progress-bar'
|
||||
|
||||
constructor: (element) ->
|
||||
@peer_grading_container = $('.peer-grading')
|
||||
@el = element
|
||||
@peer_grading_container = @$(@peer_grading_sel)
|
||||
@use_single_location = @peer_grading_container.data('use-single-location')
|
||||
@peer_grading_outer_container = $('.peer-grading-container')
|
||||
@peer_grading_outer_container = @$(@peer_grading_container_sel)
|
||||
@ajax_url = @peer_grading_container.data('ajax-url')
|
||||
|
||||
if @use_single_location.toLowerCase() == "true"
|
||||
@@ -14,23 +24,27 @@ class @PeerGrading
|
||||
@activate_problem()
|
||||
else
|
||||
#Otherwise, activate the panel view.
|
||||
@error_container = $('.error-container')
|
||||
@error_container = @$(@error_container_sel)
|
||||
@error_container.toggle(not @error_container.is(':empty'))
|
||||
|
||||
@message_container = $('.message-container')
|
||||
@message_container = @$(@message_container_sel)
|
||||
@message_container.toggle(not @message_container.is(':empty'))
|
||||
|
||||
@problem_button = $('.problem-button')
|
||||
@problem_button = @$(@problem_button_sel)
|
||||
@problem_button.click @show_results
|
||||
|
||||
@problem_list = $('.problem-list')
|
||||
@problem_list = @$(@problem_list_sel)
|
||||
@construct_progress_bar()
|
||||
|
||||
# locally scoped jquery.
|
||||
$: (selector) ->
|
||||
$(selector, @el)
|
||||
|
||||
construct_progress_bar: () =>
|
||||
problems = @problem_list.find('tr').next()
|
||||
problems.each( (index, element) =>
|
||||
problem = $(element)
|
||||
progress_bar = problem.find('.progress-bar')
|
||||
progress_bar = problem.find(@progress_bar_sel)
|
||||
bar_value = parseInt(problem.data('graded'))
|
||||
bar_max = parseInt(problem.data('required')) + bar_value
|
||||
progress_bar.progressbar({value: bar_value, max: bar_max})
|
||||
@@ -43,10 +57,10 @@ class @PeerGrading
|
||||
if response.success
|
||||
@peer_grading_outer_container.after(response.html).remove()
|
||||
backend = new PeerGradingProblemBackend(@ajax_url, false)
|
||||
new PeerGradingProblem(backend)
|
||||
new PeerGradingProblem(backend, @el)
|
||||
else
|
||||
@gentle_alert response.error
|
||||
|
||||
activate_problem: () =>
|
||||
backend = new PeerGradingProblemBackend(@ajax_url, false)
|
||||
new PeerGradingProblem(backend)
|
||||
new PeerGradingProblem(backend, @el)
|
||||
@@ -158,11 +158,47 @@ class @PeerGradingProblemBackend
|
||||
return response
|
||||
|
||||
class @PeerGradingProblem
|
||||
constructor: (backend) ->
|
||||
@prompt_wrapper = $('.prompt-wrapper')
|
||||
|
||||
prompt_wrapper_sel: '.prompt-wrapper'
|
||||
peer_grading_container_sel: '.peer-grading-container'
|
||||
submission_container_sel: '.submission-container'
|
||||
prompt_container_sel: '.prompt-container'
|
||||
rubric_container_sel: '.rubric-container'
|
||||
flag_student_container_sel: '.flag-student-container'
|
||||
answer_unknown_container_sel: '.answer-unknown-container'
|
||||
calibration_panel_sel: '.calibration-panel'
|
||||
grading_panel_sel: '.grading-panel'
|
||||
content_panel_sel: '.content-panel'
|
||||
grading_message_sel: '.grading-message'
|
||||
question_header_sel: '.question-header'
|
||||
flag_submission_confirmation_sel: '.flag-submission-confirmation'
|
||||
flag_submission_confirmation_button_sel: '.flag-submission-confirmation-button'
|
||||
flag_submission_removal_button_sel: '.flag-submission-removal-button'
|
||||
grading_wrapper_sel: '.grading-wrapper'
|
||||
calibration_feedback_sel: '.calibration-feedback'
|
||||
interstitial_page_sel: '.interstitial-page'
|
||||
calibration_interstitial_page_sel: '.calibration-interstitial-page'
|
||||
error_container_sel: '.error-container'
|
||||
feedback_area_sel: '.feedback-area'
|
||||
score_selection_container_sel: '.score-selection-container'
|
||||
rubric_selection_container_sel: '.rubric-selection-container'
|
||||
submit_button_sel: '.submit-button'
|
||||
action_button_sel: '.action-button'
|
||||
calibration_feedback_button_sel: '.calibration-feedback-button'
|
||||
interstitial_page_button_sel: '.interstitial-page-button'
|
||||
calibration_interstitial_page_button_sel: '.calibration-interstitial-page-button'
|
||||
flag_checkbox_sel: '.flag-checkbox'
|
||||
answer_unknown_checkbox_sel: '.answer-unknown-checkbox'
|
||||
calibration_text_sel: '.calibration-text'
|
||||
grading_text_sel: '.grading-text'
|
||||
calibration_feedback_wrapper_sel: '.calibration-feedback-wrapper'
|
||||
|
||||
constructor: (backend, el) ->
|
||||
@el = el
|
||||
@prompt_wrapper = $(@prompt_wrapper_sel)
|
||||
@backend = backend
|
||||
@is_ctrl = false
|
||||
|
||||
@el = $(@peer_grading_container_sel)
|
||||
|
||||
# get the location of the problem
|
||||
@location = $('.peer-grading').data('location')
|
||||
@@ -172,57 +208,55 @@ class @PeerGradingProblem
|
||||
return
|
||||
|
||||
# get the other elements we want to fill in
|
||||
@submission_container = $('.submission-container')
|
||||
@prompt_container = $('.prompt-container')
|
||||
@rubric_container = $('.rubric-container')
|
||||
@flag_student_container = $('.flag-student-container')
|
||||
@answer_unknown_container = $('.answer-unknown-container')
|
||||
@calibration_panel = $('.calibration-panel')
|
||||
@grading_panel = $('.grading-panel')
|
||||
@content_panel = $('.content-panel')
|
||||
@grading_message = $('.grading-message')
|
||||
@submission_container = @$(@submission_container_sel)
|
||||
@prompt_container = @$(@prompt_container_sel)
|
||||
@rubric_container = @$(@rubric_container_sel)
|
||||
@flag_student_container = @$(@flag_student_container_sel)
|
||||
@answer_unknown_container = @$(@answer_unknown_container_sel)
|
||||
@calibration_panel = @$(@calibration_panel_sel)
|
||||
@grading_panel = @$(@grading_panel_sel)
|
||||
@content_panel = @$(@content_panel_sel)
|
||||
@grading_message = @$(@grading_message_sel)
|
||||
@grading_message.hide()
|
||||
@question_header = $('.question-header')
|
||||
@question_header = @$(@question_header_sel)
|
||||
@question_header.click @collapse_question
|
||||
@flag_submission_confirmation = $('.flag-submission-confirmation')
|
||||
@flag_submission_confirmation_button = $('.flag-submission-confirmation-button')
|
||||
@flag_submission_removal_button = $('.flag-submission-removal-button')
|
||||
@flag_submission_confirmation = @$(@flag_submission_confirmation_sel)
|
||||
@flag_submission_confirmation_button = @$(@flag_submission_confirmation_button_sel)
|
||||
@flag_submission_removal_button = @$(@flag_submission_removal_button_sel)
|
||||
|
||||
@flag_submission_confirmation_button.click @close_dialog_box
|
||||
@flag_submission_removal_button.click @remove_flag
|
||||
|
||||
@grading_wrapper =$('.grading-wrapper')
|
||||
@calibration_feedback_panel = $('.calibration-feedback')
|
||||
@interstitial_page = $('.interstitial-page')
|
||||
@grading_wrapper = @$(@grading_wrapper_sel)
|
||||
@calibration_feedback_panel = @$(@calibration_feedback_sel)
|
||||
@interstitial_page = @$(@interstitial_page_sel)
|
||||
@interstitial_page.hide()
|
||||
|
||||
@calibration_interstitial_page = $('.calibration-interstitial-page')
|
||||
@calibration_interstitial_page = @$(@calibration_interstitial_page_sel)
|
||||
@calibration_interstitial_page.hide()
|
||||
|
||||
@error_container = $('.error-container')
|
||||
@error_container = @$(@error_container_sel)
|
||||
|
||||
@submission_key_input = $("input[name='submission-key']")
|
||||
@essay_id_input = $("input[name='essay-id']")
|
||||
@feedback_area = $('.feedback-area')
|
||||
@essay_id_input = @$("input[name='essay-id']")
|
||||
@feedback_area = @$(@feedback_area_sel)
|
||||
|
||||
@score_selection_container = $('.score-selection-container')
|
||||
@rubric_selection_container = $('.rubric-selection-container')
|
||||
@score_selection_container = @$(@score_selection_container_sel)
|
||||
@rubric_selection_container = @$(@rubric_selection_container_sel)
|
||||
@grade = null
|
||||
@calibration = null
|
||||
|
||||
@submit_button = $('.submit-button')
|
||||
@action_button = $('.action-button')
|
||||
@calibration_feedback_button = $('.calibration-feedback-button')
|
||||
@interstitial_page_button = $('.interstitial-page-button')
|
||||
@calibration_interstitial_page_button = $('.calibration-interstitial-page-button')
|
||||
@flag_student_checkbox = $('.flag-checkbox')
|
||||
@answer_unknown_checkbox = $('.answer-unknown-checkbox')
|
||||
@submit_button = @$(@submit_button_sel)
|
||||
@action_button = @$(@action_button_sel)
|
||||
@calibration_feedback_button = @$(@calibration_feedback_button_sel)
|
||||
@interstitial_page_button = @$(@interstitial_page_button_sel)
|
||||
@calibration_interstitial_page_button = @$(@calibration_interstitial_page_button_sel)
|
||||
@flag_student_checkbox = @$(@flag_checkbox_sel)
|
||||
@answer_unknown_checkbox = @$(@answer_unknown_checkbox_sel)
|
||||
|
||||
$(window).keydown @keydown_handler
|
||||
$(window).keyup @keyup_handler
|
||||
|
||||
@collapse_question()
|
||||
|
||||
Collapsible.setCollapsibles(@content_panel)
|
||||
|
||||
# Set up the click event handlers
|
||||
@@ -230,7 +264,7 @@ class @PeerGradingProblem
|
||||
@calibration_feedback_button.click =>
|
||||
@calibration_feedback_panel.hide()
|
||||
@grading_wrapper.show()
|
||||
@gentle_alert "Calibration essay saved. Fetched the next essay."
|
||||
@gentle_alert "Calibration essay saved. Fetching the next essay."
|
||||
@is_calibrated_check()
|
||||
|
||||
@interstitial_page_button.click =>
|
||||
@@ -251,6 +285,10 @@ class @PeerGradingProblem
|
||||
|
||||
@is_calibrated_check()
|
||||
|
||||
# locally scoped jquery.
|
||||
$: (selector) ->
|
||||
$(selector, @el)
|
||||
|
||||
|
||||
##########
|
||||
#
|
||||
@@ -269,8 +307,8 @@ class @PeerGradingProblem
|
||||
|
||||
construct_data: () ->
|
||||
data =
|
||||
rubric_scores: Rubric.get_score_list()
|
||||
score: Rubric.get_total_score()
|
||||
rubric_scores: @rub.get_score_list()
|
||||
score: @rub.get_total_score()
|
||||
location: @location
|
||||
submission_id: @essay_id_input.val()
|
||||
submission_key: @submission_key_input.val()
|
||||
@@ -282,10 +320,12 @@ class @PeerGradingProblem
|
||||
|
||||
submit_calibration_essay: ()=>
|
||||
data = @construct_data()
|
||||
@submit_button.hide()
|
||||
@backend.post('save_calibration_essay', data, @calibration_callback)
|
||||
|
||||
submit_grade: () =>
|
||||
data = @construct_data()
|
||||
@submit_button.hide()
|
||||
@backend.post('save_grade', data, @submission_callback)
|
||||
|
||||
|
||||
@@ -298,13 +338,15 @@ class @PeerGradingProblem
|
||||
remove_flag: () =>
|
||||
@flag_student_checkbox.removeAttr("checked")
|
||||
@close_dialog_box()
|
||||
@submit_button.attr('disabled', true)
|
||||
|
||||
close_dialog_box: () =>
|
||||
$( ".flag-submission-confirmation" ).dialog('close')
|
||||
$(@flag_submission_confirmation_sel).dialog('close')
|
||||
|
||||
flag_box_checked: () =>
|
||||
if @flag_student_checkbox.is(':checked')
|
||||
$( ".flag-submission-confirmation" ).dialog({ height: 400, width: 400 })
|
||||
@$(@flag_submission_confirmation_sel).dialog({ height: 400, width: 400 })
|
||||
@submit_button.attr('disabled', false)
|
||||
|
||||
# called after we perform an is_student_calibrated check
|
||||
calibration_check_callback: (response) =>
|
||||
@@ -344,7 +386,11 @@ class @PeerGradingProblem
|
||||
if response.success
|
||||
@is_calibrated_check()
|
||||
@grading_message.fadeIn()
|
||||
@grading_message.html("<p>Successfully saved your feedback. Fetched the next essay.</p>")
|
||||
message = "<p>Successfully saved your feedback. Fetching the next essay."
|
||||
if response.required_done
|
||||
message = message + " You have completed the required number of gradings."
|
||||
message = message + "</p>"
|
||||
@grading_message.html(message)
|
||||
else
|
||||
if response.error
|
||||
@render_error(response.error)
|
||||
@@ -353,12 +399,16 @@ class @PeerGradingProblem
|
||||
|
||||
# called after a grade is selected on the interface
|
||||
graded_callback: (event) =>
|
||||
ev = @$(event.target).parent().parent()
|
||||
ul = ev.parent().parent()
|
||||
ul.find(".rubric-label-selected").removeClass('rubric-label-selected')
|
||||
ev.addClass('rubric-label-selected')
|
||||
# check to see whether or not any categories have not been scored
|
||||
if Rubric.check_complete()
|
||||
if @rub.check_complete()
|
||||
# show button if we have scores for all categories
|
||||
@grading_message.hide()
|
||||
@show_submit_button()
|
||||
@grade = Rubric.get_total_score()
|
||||
@grade = @rub.get_total_score()
|
||||
|
||||
keydown_handler: (event) =>
|
||||
#Previously, responses were submitted when hitting enter. Add in a modifier that ensures that ctrl+enter is needed.
|
||||
@@ -395,18 +445,20 @@ class @PeerGradingProblem
|
||||
# Display the right text
|
||||
# both versions of the text are written into the template itself
|
||||
# we only need to show/hide the correct ones at the correct time
|
||||
@calibration_panel.find('.calibration-text').show()
|
||||
@grading_panel.find('.calibration-text').show()
|
||||
@calibration_panel.find('.grading-text').hide()
|
||||
@grading_panel.find('.grading-text').hide()
|
||||
@calibration_panel.find(@calibration_text_sel).show()
|
||||
@grading_panel.find(@calibration_text_sel).show()
|
||||
@calibration_panel.find(@grading_text_sel).hide()
|
||||
@grading_panel.find(@grading_text_sel).hide()
|
||||
@flag_student_container.hide()
|
||||
@answer_unknown_container.hide()
|
||||
|
||||
@feedback_area.val("")
|
||||
|
||||
@submit_button.show()
|
||||
@submit_button.unbind('click')
|
||||
@submit_button.click @submit_calibration_essay
|
||||
|
||||
@submit_button.attr('disabled', true)
|
||||
@scroll_to_top()
|
||||
else if response.error
|
||||
@render_error(response.error)
|
||||
else
|
||||
@@ -425,16 +477,20 @@ class @PeerGradingProblem
|
||||
# Display the correct text
|
||||
# both versions of the text are written into the template itself
|
||||
# we only need to show/hide the correct ones at the correct time
|
||||
@calibration_panel.find('.calibration-text').hide()
|
||||
@grading_panel.find('.calibration-text').hide()
|
||||
@calibration_panel.find('.grading-text').show()
|
||||
@grading_panel.find('.grading-text').show()
|
||||
@calibration_panel.find(@calibration_text_sel).hide()
|
||||
@grading_panel.find(@calibration_text_sel).hide()
|
||||
@calibration_panel.find(@grading_text_sel).show()
|
||||
@grading_panel.find(@grading_text_sel).show()
|
||||
@flag_student_container.show()
|
||||
@answer_unknown_container.show()
|
||||
@feedback_area.val("")
|
||||
|
||||
@flag_student_checkbox.removeAttr("checked")
|
||||
@submit_button.show()
|
||||
@submit_button.unbind('click')
|
||||
@submit_button.click @submit_grade
|
||||
@submit_button.attr('disabled', true)
|
||||
@scroll_to_top()
|
||||
else if response.error
|
||||
@render_error(response.error)
|
||||
else
|
||||
@@ -463,13 +519,14 @@ class @PeerGradingProblem
|
||||
@submit_button.hide()
|
||||
@action_button.hide()
|
||||
@calibration_feedback_panel.hide()
|
||||
Rubric.initialize(@location)
|
||||
@rub = new Rubric(@el)
|
||||
@rub.initialize(@location)
|
||||
|
||||
|
||||
render_calibration_feedback: (response) =>
|
||||
# display correct grade
|
||||
@calibration_feedback_panel.slideDown()
|
||||
calibration_wrapper = $('.calibration-feedback-wrapper')
|
||||
calibration_wrapper = @$(@calibration_feedback_wrapper_sel)
|
||||
calibration_wrapper.html("<p>The score you gave was: #{@grade}. The actual score is: #{response.actual_score}</p>")
|
||||
|
||||
score = parseInt(@grade)
|
||||
@@ -482,11 +539,11 @@ class @PeerGradingProblem
|
||||
|
||||
if response.actual_rubric != undefined
|
||||
calibration_wrapper.append("<div>Instructor Scored Rubric: #{response.actual_rubric}</div>")
|
||||
if response.actual_feedback!=undefined
|
||||
if response.actual_feedback.feedback!=undefined
|
||||
calibration_wrapper.append("<div>Instructor Feedback: #{response.actual_feedback}</div>")
|
||||
|
||||
# disable score selection and submission from the grading interface
|
||||
$("input[name='score-selection']").attr('disabled', true)
|
||||
@$("input[name='score-selection']").attr('disabled', true)
|
||||
@submit_button.hide()
|
||||
@calibration_feedback_button.show()
|
||||
|
||||
@@ -508,23 +565,30 @@ class @PeerGradingProblem
|
||||
@action_button.show()
|
||||
|
||||
show_submit_button: () =>
|
||||
@submit_button.attr('disabled', false)
|
||||
@submit_button.show()
|
||||
|
||||
setup_score_selection: (max_score) =>
|
||||
# And now hook up an event handler again
|
||||
$("input[class='score-selection']").change @graded_callback
|
||||
@$("input[class='score-selection']").change @graded_callback
|
||||
|
||||
gentle_alert: (msg) =>
|
||||
@grading_message.fadeIn()
|
||||
@grading_message.html("<p>" + msg + "</p>")
|
||||
|
||||
collapse_question: () =>
|
||||
collapse_question: (event) =>
|
||||
@prompt_container.slideToggle()
|
||||
@prompt_container.toggleClass('open')
|
||||
if @question_header.text() == "(Hide)"
|
||||
Logger.log 'peer_grading_hide_question', {location: @location}
|
||||
new_text = "(Show)"
|
||||
if @question_header.text() == "Hide Prompt"
|
||||
new_text = "Show Prompt"
|
||||
Logger.log 'oe_hide_question', {location: @location}
|
||||
else
|
||||
Logger.log 'peer_grading_show_question', {location: @location}
|
||||
new_text = "(Hide)"
|
||||
Logger.log 'oe_show_question', {location: @location}
|
||||
new_text = "Hide Prompt"
|
||||
@question_header.text(new_text)
|
||||
return false
|
||||
|
||||
scroll_to_top: () =>
|
||||
$('html, body').animate({
|
||||
scrollTop: $(".peer-grading").offset().top
|
||||
}, 200)
|
||||
|
||||
@@ -7,7 +7,9 @@ from xmodule.progress import Progress
|
||||
from xmodule.stringify import stringify_children
|
||||
import self_assessment_module
|
||||
import open_ended_module
|
||||
from functools import partial
|
||||
from .combined_open_ended_rubric import CombinedOpenEndedRubric, GRADER_TYPE_IMAGE_DICT, HUMAN_GRADER_TYPE, LEGEND_LIST
|
||||
from peer_grading_service import PeerGradingService, MockPeerGradingService, GradingServiceError
|
||||
|
||||
log = logging.getLogger("mitx.courseware")
|
||||
|
||||
@@ -31,8 +33,17 @@ ACCEPT_FILE_UPLOAD = False
|
||||
TRUE_DICT = ["True", True, "TRUE", "true"]
|
||||
|
||||
HUMAN_TASK_TYPE = {
|
||||
'selfassessment': "Self Assessment",
|
||||
'openended': "edX Assessment",
|
||||
'selfassessment': "Self",
|
||||
'openended': "edX",
|
||||
'ml_grading.conf' : "AI",
|
||||
'peer_grading.conf' : "Peer",
|
||||
}
|
||||
|
||||
HUMAN_STATES = {
|
||||
'intitial': "Not started.",
|
||||
'assessing': "Being scored.",
|
||||
'intermediate_done': "Scoring finished.",
|
||||
'done': "Complete.",
|
||||
}
|
||||
|
||||
# Default value that controls whether or not to skip basic spelling checks in the controller
|
||||
@@ -56,7 +67,6 @@ class CombinedOpenEndedV1Module():
|
||||
ajax actions implemented by combined open ended module are:
|
||||
'reset' -- resets the whole combined open ended module and returns to the first child moduleresource_string
|
||||
'next_problem' -- moves to the next child module
|
||||
'get_results' -- gets results from a given child module
|
||||
|
||||
Types of children. Task is synonymous with child module, so each combined open ended module
|
||||
incorporates multiple children (tasks):
|
||||
@@ -106,6 +116,11 @@ class CombinedOpenEndedV1Module():
|
||||
self.accept_file_upload = instance_state.get('accept_file_upload', ACCEPT_FILE_UPLOAD) in TRUE_DICT
|
||||
self.skip_basic_checks = instance_state.get('skip_spelling_checks', SKIP_BASIC_CHECKS) in TRUE_DICT
|
||||
|
||||
if system.open_ended_grading_interface:
|
||||
self.peer_gs = PeerGradingService(system.open_ended_grading_interface, system)
|
||||
else:
|
||||
self.peer_gs = MockPeerGradingService()
|
||||
|
||||
self.required_peer_grading = instance_state.get('required_peer_grading', 3)
|
||||
self.peer_grader_count = instance_state.get('peer_grader_count', 3)
|
||||
self.min_to_calibrate = instance_state.get('min_to_calibrate', 3)
|
||||
@@ -300,6 +315,7 @@ class CombinedOpenEndedV1Module():
|
||||
'accept_file_upload': self.accept_file_upload,
|
||||
'location': self.location,
|
||||
'legend_list': LEGEND_LIST,
|
||||
'human_state': HUMAN_STATES.get(self.state,"Not started.")
|
||||
}
|
||||
|
||||
return context
|
||||
@@ -334,6 +350,14 @@ class CombinedOpenEndedV1Module():
|
||||
self.update_task_states()
|
||||
return self.current_task.get_html(self.system)
|
||||
|
||||
def get_html_ajax(self, data):
|
||||
"""
|
||||
Get HTML in AJAX callback
|
||||
data - Needed to preserve AJAX structure
|
||||
Output: Dictionary with html attribute
|
||||
"""
|
||||
return {'html': self.get_html()}
|
||||
|
||||
def get_current_attributes(self, task_number):
|
||||
"""
|
||||
Gets the min and max score to attempt attributes of the specified task.
|
||||
@@ -419,6 +443,7 @@ class CombinedOpenEndedV1Module():
|
||||
grader_type = grader_types[0]
|
||||
else:
|
||||
grader_type = "IN"
|
||||
grader_types = ["IN"]
|
||||
|
||||
if grader_type in HUMAN_GRADER_TYPE:
|
||||
human_grader_name = HUMAN_GRADER_TYPE[grader_type]
|
||||
@@ -446,9 +471,22 @@ class CombinedOpenEndedV1Module():
|
||||
'feedback_dicts': feedback_dicts,
|
||||
'grader_ids': grader_ids,
|
||||
'submission_ids': submission_ids,
|
||||
'success' : True
|
||||
}
|
||||
return last_response_dict
|
||||
|
||||
def extract_human_name_from_task(self, task_xml):
|
||||
tree = etree.fromstring(task_xml)
|
||||
payload = tree.xpath("/openended/openendedparam/grader_payload")
|
||||
if len(payload)==0:
|
||||
task_name = "selfassessment"
|
||||
else:
|
||||
inner_payload = json.loads(payload[0].text)
|
||||
task_name = inner_payload['grader_settings']
|
||||
|
||||
human_task = HUMAN_TASK_TYPE[task_name]
|
||||
return human_task
|
||||
|
||||
def update_task_states(self):
|
||||
"""
|
||||
Updates the task state of the combined open ended module with the task state of the current child module.
|
||||
@@ -481,6 +519,51 @@ class CombinedOpenEndedV1Module():
|
||||
pass
|
||||
return return_html
|
||||
|
||||
def check_if_student_has_done_needed_grading(self):
|
||||
"""
|
||||
Checks with the ORA server to see if the student has completed the needed peer grading to be shown their grade.
|
||||
For example, if a student submits one response, and three peers grade their response, the student
|
||||
cannot see their grades and feedback unless they reciprocate.
|
||||
Output:
|
||||
success - boolean indicator of success
|
||||
allowed_to_submit - boolean indicator of whether student has done their needed grading or not
|
||||
error_message - If not success, explains why
|
||||
"""
|
||||
student_id = self.system.anonymous_student_id
|
||||
success = False
|
||||
allowed_to_submit = True
|
||||
try:
|
||||
response = self.peer_gs.get_data_for_location(self.location.url(), student_id)
|
||||
count_graded = response['count_graded']
|
||||
count_required = response['count_required']
|
||||
student_sub_count = response['student_sub_count']
|
||||
count_available = response['count_available']
|
||||
success = True
|
||||
except GradingServiceError:
|
||||
# This is a dev_facing_error
|
||||
log.error("Could not contact external open ended graders for location {0} and student {1}".format(
|
||||
self.location, student_id))
|
||||
# This is a student_facing_error
|
||||
error_message = "Could not contact the graders. Please notify course staff."
|
||||
return success, allowed_to_submit, error_message
|
||||
except KeyError:
|
||||
log.error("Invalid response from grading server for location {0} and student {1}".format(self.location, student_id))
|
||||
error_message = "Received invalid response from the graders. Please notify course staff."
|
||||
return success, allowed_to_submit, error_message
|
||||
if count_graded >= count_required or count_available==0:
|
||||
error_message = ""
|
||||
return success, allowed_to_submit, error_message
|
||||
else:
|
||||
allowed_to_submit = False
|
||||
# This is a student_facing_error
|
||||
error_string = ("<h4>Feedback not available yet</h4>"
|
||||
"<p>You need to peer grade {0} more submissions in order to see your feedback.</p>"
|
||||
"<p>You have graded responses from {1} students, and {2} students have graded your submissions. </p>"
|
||||
"<p>You have made {3} submissions.</p>")
|
||||
error_message = error_string.format(count_required - count_graded, count_graded, count_required,
|
||||
student_sub_count)
|
||||
return success, allowed_to_submit, error_message
|
||||
|
||||
def get_rubric(self, _data):
|
||||
"""
|
||||
Gets the results of a given grader via ajax.
|
||||
@@ -488,30 +571,39 @@ class CombinedOpenEndedV1Module():
|
||||
Output: Dictionary to be rendered via ajax that contains the result html.
|
||||
"""
|
||||
all_responses = []
|
||||
loop_up_to_task = self.current_task_number + 1
|
||||
for i in xrange(0, loop_up_to_task):
|
||||
all_responses.append(self.get_last_response(i))
|
||||
rubric_scores = [all_responses[i]['rubric_scores'] for i in xrange(0, len(all_responses)) if
|
||||
len(all_responses[i]['rubric_scores']) > 0 and all_responses[i]['grader_types'][
|
||||
0] in HUMAN_GRADER_TYPE.keys()]
|
||||
grader_types = [all_responses[i]['grader_types'] for i in xrange(0, len(all_responses)) if
|
||||
len(all_responses[i]['grader_types']) > 0 and all_responses[i]['grader_types'][
|
||||
0] in HUMAN_GRADER_TYPE.keys()]
|
||||
feedback_items = [all_responses[i]['feedback_items'] for i in xrange(0, len(all_responses)) if
|
||||
len(all_responses[i]['feedback_items']) > 0 and all_responses[i]['grader_types'][
|
||||
0] in HUMAN_GRADER_TYPE.keys()]
|
||||
rubric_html = self.rubric_renderer.render_combined_rubric(stringify_children(self.static_data['rubric']),
|
||||
rubric_scores,
|
||||
grader_types, feedback_items)
|
||||
success, can_see_rubric, error = self.check_if_student_has_done_needed_grading()
|
||||
if not can_see_rubric:
|
||||
return {'html' : self.system.render_template('{0}/combined_open_ended_hidden_results.html'.format(self.TEMPLATE_DIR), {'error' : error}), 'success' : True, 'hide_reset' : True}
|
||||
|
||||
contexts = []
|
||||
rubric_number = self.current_task_number
|
||||
if self.ready_to_reset:
|
||||
rubric_number+=1
|
||||
response = self.get_last_response(rubric_number)
|
||||
score_length = len(response['grader_types'])
|
||||
for z in xrange(score_length):
|
||||
if response['grader_types'][z] in HUMAN_GRADER_TYPE:
|
||||
try:
|
||||
feedback = response['feedback_dicts'][z].get('feedback', '')
|
||||
except TypeError:
|
||||
return {'success' : False}
|
||||
rubric_scores = [[response['rubric_scores'][z]]]
|
||||
grader_types = [[response['grader_types'][z]]]
|
||||
feedback_items = [[response['feedback_items'][z]]]
|
||||
rubric_html = self.rubric_renderer.render_combined_rubric(stringify_children(self.static_data['rubric']),
|
||||
rubric_scores,
|
||||
grader_types, feedback_items)
|
||||
contexts.append({
|
||||
'result': rubric_html,
|
||||
'task_name': 'Scored rubric',
|
||||
'feedback' : feedback
|
||||
})
|
||||
|
||||
response_dict = all_responses[-1]
|
||||
context = {
|
||||
'results': rubric_html,
|
||||
'task_name': 'Scored Rubric',
|
||||
'class_name': 'combined-rubric-container'
|
||||
'results': contexts,
|
||||
}
|
||||
html = self.system.render_template('{0}/combined_open_ended_results.html'.format(self.TEMPLATE_DIR), context)
|
||||
return {'html': html, 'success': True}
|
||||
return {'html': html, 'success': True, 'hide_reset' : False}
|
||||
|
||||
def get_legend(self, _data):
|
||||
"""
|
||||
@@ -525,59 +617,6 @@ class CombinedOpenEndedV1Module():
|
||||
html = self.system.render_template('{0}/combined_open_ended_legend.html'.format(self.TEMPLATE_DIR), context)
|
||||
return {'html': html, 'success': True}
|
||||
|
||||
def get_results(self, _data):
|
||||
"""
|
||||
Gets the results of a given grader via ajax.
|
||||
Input: AJAX data dictionary
|
||||
Output: Dictionary to be rendered via ajax that contains the result html.
|
||||
"""
|
||||
self.update_task_states()
|
||||
loop_up_to_task = self.current_task_number + 1
|
||||
all_responses = []
|
||||
for i in xrange(0, loop_up_to_task):
|
||||
all_responses.append(self.get_last_response(i))
|
||||
context_list = []
|
||||
for ri in all_responses:
|
||||
for i in xrange(0, len(ri['rubric_scores'])):
|
||||
feedback = ri['feedback_dicts'][i].get('feedback', '')
|
||||
rubric_data = self.rubric_renderer.render_rubric(stringify_children(self.static_data['rubric']),
|
||||
ri['rubric_scores'][i])
|
||||
if rubric_data['success']:
|
||||
rubric_html = rubric_data['html']
|
||||
else:
|
||||
rubric_html = ''
|
||||
context = {
|
||||
'rubric_html': rubric_html,
|
||||
'grader_type': ri['grader_type'],
|
||||
'feedback': feedback,
|
||||
'grader_id': ri['grader_ids'][i],
|
||||
'submission_id': ri['submission_ids'][i],
|
||||
}
|
||||
context_list.append(context)
|
||||
feedback_table = self.system.render_template('{0}/open_ended_result_table.html'.format(self.TEMPLATE_DIR), {
|
||||
'context_list': context_list,
|
||||
'grader_type_image_dict': GRADER_TYPE_IMAGE_DICT,
|
||||
'human_grader_types': HUMAN_GRADER_TYPE,
|
||||
'rows': 50,
|
||||
'cols': 50,
|
||||
})
|
||||
context = {
|
||||
'results': feedback_table,
|
||||
'task_name': "Feedback",
|
||||
'class_name': "result-container",
|
||||
}
|
||||
html = self.system.render_template('{0}/combined_open_ended_results.html'.format(self.TEMPLATE_DIR), context)
|
||||
return {'html': html, 'success': True}
|
||||
|
||||
def get_status_ajax(self, _data):
|
||||
"""
|
||||
Gets the results of a given grader via ajax.
|
||||
Input: AJAX data dictionary
|
||||
Output: Dictionary to be rendered via ajax that contains the result html.
|
||||
"""
|
||||
html = self.get_status(True)
|
||||
return {'html': html, 'success': True}
|
||||
|
||||
def handle_ajax(self, dispatch, data):
|
||||
"""
|
||||
This is called by courseware.module_render, to handle an AJAX call.
|
||||
@@ -592,10 +631,11 @@ class CombinedOpenEndedV1Module():
|
||||
handlers = {
|
||||
'next_problem': self.next_problem,
|
||||
'reset': self.reset,
|
||||
'get_results': self.get_results,
|
||||
'get_combined_rubric': self.get_rubric,
|
||||
'get_status': self.get_status_ajax,
|
||||
'get_legend': self.get_legend,
|
||||
'get_last_response': self.get_last_response_ajax,
|
||||
'get_current_state': self.get_current_state,
|
||||
'get_html': self.get_html_ajax,
|
||||
}
|
||||
|
||||
if dispatch not in handlers:
|
||||
@@ -605,6 +645,17 @@ class CombinedOpenEndedV1Module():
|
||||
d = handlers[dispatch](data)
|
||||
return json.dumps(d, cls=ComplexEncoder)
|
||||
|
||||
def get_current_state(self, data):
|
||||
return self.get_context()
|
||||
|
||||
def get_last_response_ajax(self, data):
|
||||
"""
|
||||
Get the last response via ajax callback
|
||||
data - Needed to preserve ajax callback structure
|
||||
Output: Last response dictionary
|
||||
"""
|
||||
return self.get_last_response(self.current_task_number)
|
||||
|
||||
def next_problem(self, _data):
|
||||
"""
|
||||
Called via ajax to advance to the next problem.
|
||||
@@ -623,10 +674,12 @@ class CombinedOpenEndedV1Module():
|
||||
if self.state != self.DONE:
|
||||
if not self.ready_to_reset:
|
||||
return self.out_of_sync_error(data)
|
||||
|
||||
if self.student_attempts >= self.max_attempts-1:
|
||||
if self.student_attempts==self.max_attempts-1:
|
||||
self.student_attempts +=1
|
||||
success, can_reset, error = self.check_if_student_has_done_needed_grading()
|
||||
if not can_reset:
|
||||
return {'error': error, 'success': False}
|
||||
if self.student_attempts >= self.max_attempts - 1:
|
||||
if self.student_attempts == self.max_attempts - 1:
|
||||
self.student_attempts += 1
|
||||
return {
|
||||
'success': False,
|
||||
# This is a student_facing_error
|
||||
@@ -638,7 +691,7 @@ class CombinedOpenEndedV1Module():
|
||||
self.student_attempts +=1
|
||||
self.state = self.INITIAL
|
||||
self.ready_to_reset = False
|
||||
for i in xrange(0, len(self.task_xml)):
|
||||
for i in xrange(len(self.task_xml)):
|
||||
self.current_task_number = i
|
||||
self.setup_next_task(reset=True)
|
||||
self.current_task.reset(self.system)
|
||||
@@ -673,9 +726,10 @@ class CombinedOpenEndedV1Module():
|
||||
Output: The status html to be rendered
|
||||
"""
|
||||
status = []
|
||||
for i in xrange(0, self.current_task_number + 1):
|
||||
task_data = self.get_last_response(i)
|
||||
task_data.update({'task_number': i + 1})
|
||||
for i in xrange(0, len(self.task_xml)):
|
||||
human_task_name = self.extract_human_name_from_task(self.task_xml[i])
|
||||
|
||||
task_data = {'task_number': i + 1, 'human_task' : human_task_name, 'current' : self.current_task_number==i}
|
||||
status.append(task_data)
|
||||
|
||||
context = {
|
||||
|
||||
@@ -206,20 +206,49 @@ class CombinedOpenEndedRubric(object):
|
||||
def render_combined_rubric(self, rubric_xml, scores, score_types, feedback_types):
|
||||
success, score_tuples = CombinedOpenEndedRubric.reformat_scores_for_rendering(scores, score_types,
|
||||
feedback_types)
|
||||
#Get all the categories in the rubric
|
||||
rubric_categories = self.extract_categories(rubric_xml)
|
||||
#Get a list of max scores, each entry belonging to a rubric category
|
||||
max_scores = map((lambda cat: cat['options'][-1]['points']), rubric_categories)
|
||||
actual_scores = []
|
||||
#Get the highest possible score across all categories
|
||||
max_score = max(max_scores)
|
||||
for i in xrange(0, len(rubric_categories)):
|
||||
category = rubric_categories[i]
|
||||
for j in xrange(0, len(category['options'])):
|
||||
#Loop through each category
|
||||
for i, category in enumerate(rubric_categories):
|
||||
#Loop through each option in the category
|
||||
for j in xrange(len(category['options'])):
|
||||
#Intialize empty grader types list
|
||||
rubric_categories[i]['options'][j]['grader_types'] = []
|
||||
for tuple in score_tuples:
|
||||
if tuple[1] == i and tuple[2] == j:
|
||||
for grader_type in tuple[3]:
|
||||
#Score tuples are a flat data structure with (category, option, grader_type_list) for selected graders
|
||||
for tup in score_tuples:
|
||||
if tup[1] == i and tup[2] == j:
|
||||
for grader_type in tup[3]:
|
||||
#Set the rubric grader type to the tuple grader types
|
||||
rubric_categories[i]['options'][j]['grader_types'].append(grader_type)
|
||||
#Grab the score and add it to the actual scores. J will be the score for the selected
|
||||
#grader type
|
||||
if len(actual_scores)<=i:
|
||||
#Initialize a new list in the list of lists
|
||||
actual_scores.append([j])
|
||||
else:
|
||||
#If a list in the list of lists for this position exists, append to it
|
||||
actual_scores[i] += [j]
|
||||
|
||||
actual_scores = [sum(i) / len(i) for i in actual_scores]
|
||||
correct = []
|
||||
#Define if the student is "correct" (1) "incorrect" (0) or "partially correct" (.5)
|
||||
for (i, a) in enumerate(actual_scores):
|
||||
if int(a) == max_scores[i]:
|
||||
correct.append(1)
|
||||
elif int(a)==0:
|
||||
correct.append(0)
|
||||
else:
|
||||
correct.append(.5)
|
||||
|
||||
html = self.system.render_template('{0}/open_ended_combined_rubric.html'.format(self.TEMPLATE_DIR),
|
||||
{'categories': rubric_categories,
|
||||
'max_scores': max_scores,
|
||||
'correct' : correct,
|
||||
'has_score': True,
|
||||
'view_only': True,
|
||||
'max_score': max_score,
|
||||
|
||||
@@ -11,6 +11,9 @@ log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class GradingServiceError(Exception):
|
||||
"""
|
||||
Exception for grading service. Shown when Open Response Assessment servers cannot be reached.
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
@@ -62,7 +65,6 @@ class GradingService(object):
|
||||
"""
|
||||
Make a get request to the grading controller
|
||||
"""
|
||||
log.debug(params)
|
||||
op = lambda: self.session.get(url,
|
||||
allow_redirects=allow_redirects,
|
||||
params=params)
|
||||
|
||||
@@ -641,6 +641,7 @@ class OpenEndedModule(openendedchild.OpenEndedChild):
|
||||
"""
|
||||
# Once we close the problem, we should not allow students
|
||||
# to save answers
|
||||
error_message = ""
|
||||
closed, msg = self.check_if_closed()
|
||||
if closed:
|
||||
return msg
|
||||
@@ -650,17 +651,11 @@ class OpenEndedModule(openendedchild.OpenEndedChild):
|
||||
|
||||
# add new history element with answer and empty score and hint.
|
||||
success, data = self.append_image_to_student_answer(data)
|
||||
error_message = ""
|
||||
if success:
|
||||
success, allowed_to_submit, error_message = self.check_if_student_can_submit()
|
||||
if allowed_to_submit:
|
||||
data['student_answer'] = OpenEndedModule.sanitize_html(data['student_answer'])
|
||||
self.new_history_entry(data['student_answer'])
|
||||
self.send_to_grader(data['student_answer'], system)
|
||||
self.change_state(self.ASSESSING)
|
||||
else:
|
||||
# Error message already defined
|
||||
success = False
|
||||
data['student_answer'] = OpenEndedModule.sanitize_html(data['student_answer'])
|
||||
self.new_history_entry(data['student_answer'])
|
||||
self.send_to_grader(data['student_answer'], system)
|
||||
self.change_state(self.ASSESSING)
|
||||
else:
|
||||
# This is a student_facing_error
|
||||
error_message = "There was a problem saving the image in your submission. Please try a different image, or try pasting a link to an image into the answer box."
|
||||
@@ -668,7 +663,7 @@ class OpenEndedModule(openendedchild.OpenEndedChild):
|
||||
return {
|
||||
'success': success,
|
||||
'error': error_message,
|
||||
'student_response': data['student_answer']
|
||||
'student_response': data['student_answer'].replace("\n","<br/>")
|
||||
}
|
||||
|
||||
def update_score(self, data, system):
|
||||
@@ -699,12 +694,12 @@ class OpenEndedModule(openendedchild.OpenEndedChild):
|
||||
score = self.latest_score()
|
||||
correct = 'correct' if self.is_submission_correct(score) else 'incorrect'
|
||||
if self.child_state == self.ASSESSING:
|
||||
eta_string = self.get_eta()
|
||||
eta_string = "Your response has been submitted. Please check back later for your grade."
|
||||
else:
|
||||
post_assessment = ""
|
||||
correct = ""
|
||||
previous_answer = self.initial_display
|
||||
|
||||
previous_answer = ""
|
||||
previous_answer = previous_answer.replace("\n","<br/>")
|
||||
context = {
|
||||
'prompt': self.child_prompt,
|
||||
'previous_answer': previous_answer,
|
||||
|
||||
@@ -58,7 +58,7 @@ class OpenEndedChild(object):
|
||||
'assessing': 'In progress',
|
||||
'post_assessment': 'Done',
|
||||
'done': 'Done',
|
||||
}
|
||||
}
|
||||
|
||||
def __init__(self, system, location, definition, descriptor, static_data,
|
||||
instance_state=None, shared_state=None, **kwargs):
|
||||
@@ -179,10 +179,11 @@ class OpenEndedChild(object):
|
||||
answer = autolink_html(answer)
|
||||
cleaner = Cleaner(style=True, links=True, add_nofollow=False, page_structure=True, safe_attrs_only=True,
|
||||
host_whitelist=open_ended_image_submission.TRUSTED_IMAGE_DOMAINS,
|
||||
whitelist_tags=set(['embed', 'iframe', 'a', 'img']))
|
||||
whitelist_tags=set(['embed', 'iframe', 'a', 'img', 'br']))
|
||||
clean_html = cleaner.clean_html(answer)
|
||||
clean_html = re.sub(r'</p>$', '', re.sub(r'^<p>', '', clean_html))
|
||||
except:
|
||||
clean_html = re.sub("\n","<br/>", clean_html)
|
||||
except Exception:
|
||||
clean_html = answer
|
||||
return clean_html
|
||||
|
||||
@@ -230,7 +231,7 @@ class OpenEndedChild(object):
|
||||
'max_score': self._max_score,
|
||||
'child_attempts': self.child_attempts,
|
||||
'child_created': False,
|
||||
}
|
||||
}
|
||||
return json.dumps(state)
|
||||
|
||||
def _allow_reset(self):
|
||||
@@ -332,7 +333,7 @@ class OpenEndedChild(object):
|
||||
try:
|
||||
image_data.seek(0)
|
||||
image_ok = open_ended_image_submission.run_image_tests(image_data)
|
||||
except:
|
||||
except Exception:
|
||||
log.exception("Could not create image and check it.")
|
||||
|
||||
if image_ok:
|
||||
@@ -345,7 +346,7 @@ class OpenEndedChild(object):
|
||||
success, s3_public_url = open_ended_image_submission.upload_to_s3(
|
||||
image_data, image_key, self.s3_interface
|
||||
)
|
||||
except:
|
||||
except Exception:
|
||||
log.exception("Could not upload image to S3.")
|
||||
|
||||
return success, image_ok, s3_public_url
|
||||
@@ -434,38 +435,6 @@ class OpenEndedChild(object):
|
||||
|
||||
return success, string
|
||||
|
||||
def check_if_student_can_submit(self):
|
||||
location = self.location_string
|
||||
|
||||
student_id = self.system.anonymous_student_id
|
||||
success = False
|
||||
allowed_to_submit = True
|
||||
response = {}
|
||||
# This is a student_facing_error
|
||||
error_string = ("You need to peer grade {0} more in order to make another submission. "
|
||||
"You have graded {1}, and {2} are required. You have made {3} successful peer grading submissions.")
|
||||
try:
|
||||
response = self.peer_gs.get_data_for_location(self.location_string, student_id)
|
||||
count_graded = response['count_graded']
|
||||
count_required = response['count_required']
|
||||
student_sub_count = response['student_sub_count']
|
||||
success = True
|
||||
except:
|
||||
# This is a dev_facing_error
|
||||
log.error("Could not contact external open ended graders for location {0} and student {1}".format(
|
||||
self.location_string, student_id))
|
||||
# This is a student_facing_error
|
||||
error_message = "Could not contact the graders. Please notify course staff."
|
||||
return success, allowed_to_submit, error_message
|
||||
if count_graded >= count_required:
|
||||
return success, allowed_to_submit, ""
|
||||
else:
|
||||
allowed_to_submit = False
|
||||
# This is a student_facing_error
|
||||
error_message = error_string.format(count_required - count_graded, count_graded, count_required,
|
||||
student_sub_count)
|
||||
return success, allowed_to_submit, error_message
|
||||
|
||||
def get_eta(self):
|
||||
if self.controller_qs:
|
||||
response = self.controller_qs.check_for_eta(self.location_string)
|
||||
|
||||
@@ -124,4 +124,4 @@ class MockPeerGradingService(object):
|
||||
]}
|
||||
|
||||
def get_data_for_location(self, problem_location, student_id):
|
||||
return {"version": 1, "count_graded": 3, "count_required": 3, "success": True, "student_sub_count": 1}
|
||||
return {"version": 1, "count_graded": 3, "count_required": 3, "success": True, "student_sub_count": 1, 'submissions_available' : 0}
|
||||
|
||||
@@ -61,6 +61,7 @@ class SelfAssessmentModule(openendedchild.OpenEndedChild):
|
||||
else:
|
||||
previous_answer = ''
|
||||
|
||||
previous_answer = previous_answer.replace("\n","<br/>")
|
||||
context = {
|
||||
'prompt': self.child_prompt,
|
||||
'previous_answer': previous_answer,
|
||||
@@ -184,14 +185,9 @@ class SelfAssessmentModule(openendedchild.OpenEndedChild):
|
||||
# add new history element with answer and empty score and hint.
|
||||
success, data = self.append_image_to_student_answer(data)
|
||||
if success:
|
||||
success, allowed_to_submit, error_message = self.check_if_student_can_submit()
|
||||
if allowed_to_submit:
|
||||
data['student_answer'] = SelfAssessmentModule.sanitize_html(data['student_answer'])
|
||||
self.new_history_entry(data['student_answer'])
|
||||
self.change_state(self.ASSESSING)
|
||||
else:
|
||||
# Error message already defined
|
||||
success = False
|
||||
data['student_answer'] = SelfAssessmentModule.sanitize_html(data['student_answer'])
|
||||
self.new_history_entry(data['student_answer'])
|
||||
self.change_state(self.ASSESSING)
|
||||
else:
|
||||
# This is a student_facing_error
|
||||
error_message = "There was a problem saving the image in your submission. Please try a different image, or try pasting a link to an image into the answer box."
|
||||
@@ -200,7 +196,7 @@ class SelfAssessmentModule(openendedchild.OpenEndedChild):
|
||||
'success': success,
|
||||
'rubric_html': self.get_rubric_html(system),
|
||||
'error': error_message,
|
||||
'student_response': data['student_answer'],
|
||||
'student_response': data['student_answer'].replace("\n","<br/>")
|
||||
}
|
||||
|
||||
def save_assessment(self, data, _system):
|
||||
@@ -272,8 +268,6 @@ class SelfAssessmentModule(openendedchild.OpenEndedChild):
|
||||
try:
|
||||
rubric_scores = json.loads(latest_post_assessment)
|
||||
except:
|
||||
# This is a dev_facing_error
|
||||
log.error("Cannot parse rubric scores in self assessment module from {0}".format(latest_post_assessment))
|
||||
rubric_scores = []
|
||||
return [rubric_scores]
|
||||
|
||||
|
||||
@@ -46,7 +46,6 @@ class PeerGradingFields(object):
|
||||
)
|
||||
due = Date(
|
||||
help="Due date that should be displayed.",
|
||||
default=None,
|
||||
scope=Scope.settings)
|
||||
graceperiod = Timedelta(
|
||||
help="Amount of grace to give on the due date.",
|
||||
@@ -189,9 +188,8 @@ class PeerGradingModule(PeerGradingFields, XModule):
|
||||
|
||||
return json.dumps(d, cls=ComplexEncoder)
|
||||
|
||||
def query_data_for_location(self):
|
||||
def query_data_for_location(self, location):
|
||||
student_id = self.system.anonymous_student_id
|
||||
location = self.link_to_location
|
||||
success = False
|
||||
response = {}
|
||||
|
||||
@@ -229,7 +227,7 @@ class PeerGradingModule(PeerGradingFields, XModule):
|
||||
count_graded = self.student_data_for_location['count_graded']
|
||||
count_required = self.student_data_for_location['count_required']
|
||||
except:
|
||||
success, response = self.query_data_for_location()
|
||||
success, response = self.query_data_for_location(self.location)
|
||||
if not success:
|
||||
log.exception(
|
||||
"No instance data found and could not get data from controller for loc {0} student {1}".format(
|
||||
@@ -312,17 +310,26 @@ class PeerGradingModule(PeerGradingFields, XModule):
|
||||
error: if there was an error in the submission, this is the error message
|
||||
"""
|
||||
|
||||
required = set(['location', 'submission_id', 'submission_key', 'score', 'feedback', 'rubric_scores[]', 'submission_flagged', 'answer_unknown'])
|
||||
success, message = self._check_required(data, required)
|
||||
required = ['location', 'submission_id', 'submission_key', 'score', 'feedback', 'submission_flagged', 'answer_unknown']
|
||||
if data.get("submission_flagged", False) in ["false", False, "False", "FALSE"]:
|
||||
required.append("rubric_scores[]")
|
||||
success, message = self._check_required(data, set(required))
|
||||
if not success:
|
||||
return self._err_response(message)
|
||||
|
||||
data_dict = {k:data.get(k) for k in required}
|
||||
data_dict['rubric_scores'] = data.getlist('rubric_scores[]')
|
||||
if 'rubric_scores[]' in required:
|
||||
data_dict['rubric_scores'] = data.getlist('rubric_scores[]')
|
||||
data_dict['grader_id'] = self.system.anonymous_student_id
|
||||
|
||||
try:
|
||||
response = self.peer_gs.save_grade(**data_dict)
|
||||
success, location_data = self.query_data_for_location(data_dict['location'])
|
||||
#Don't check for success above because the response = statement will raise the same Exception as the one
|
||||
#that will cause success to be false.
|
||||
response.update({'required_done' : False})
|
||||
if 'count_graded' in location_data and 'count_required' in location_data and int(location_data['count_graded'])>=int(location_data['count_required']):
|
||||
response['required_done'] = True
|
||||
return response
|
||||
except GradingServiceError:
|
||||
# This is a dev_facing_error
|
||||
@@ -502,7 +509,7 @@ class PeerGradingModule(PeerGradingFields, XModule):
|
||||
error_text = "Could not get list of problems to peer grade. Please notify course staff."
|
||||
log.error(error_text)
|
||||
success = False
|
||||
except:
|
||||
except Exception:
|
||||
log.exception("Could not contact peer grading service.")
|
||||
success = False
|
||||
|
||||
@@ -513,20 +520,24 @@ class PeerGradingModule(PeerGradingFields, XModule):
|
||||
'''
|
||||
try:
|
||||
return modulestore().get_instance(self.system.course_id, location)
|
||||
except:
|
||||
except Exception:
|
||||
# the linked problem doesn't exist
|
||||
log.error("Problem {0} does not exist in this course".format(location))
|
||||
raise
|
||||
|
||||
good_problem_list = []
|
||||
for problem in problem_list:
|
||||
problem_location = problem['location']
|
||||
descriptor = _find_corresponding_module_for_location(problem_location)
|
||||
try:
|
||||
descriptor = _find_corresponding_module_for_location(problem_location)
|
||||
except Exception:
|
||||
continue
|
||||
if descriptor:
|
||||
problem['due'] = descriptor.lms.due
|
||||
grace_period = descriptor.lms.graceperiod
|
||||
try:
|
||||
problem_timeinfo = TimeInfo(problem['due'], grace_period)
|
||||
except:
|
||||
except Exception:
|
||||
log.error("Malformed due date or grace period string for location {0}".format(problem_location))
|
||||
raise
|
||||
if self._closed(problem_timeinfo):
|
||||
@@ -537,13 +548,14 @@ class PeerGradingModule(PeerGradingFields, XModule):
|
||||
# if we can't find the due date, assume that it doesn't have one
|
||||
problem['due'] = None
|
||||
problem['closed'] = False
|
||||
good_problem_list.append(problem)
|
||||
|
||||
ajax_url = self.ajax_url
|
||||
html = self.system.render_template('peer_grading/peer_grading.html', {
|
||||
'course_id': self.system.course_id,
|
||||
'ajax_url': ajax_url,
|
||||
'success': success,
|
||||
'problem_list': problem_list,
|
||||
'problem_list': good_problem_list,
|
||||
'error_text': error_text,
|
||||
# Checked above
|
||||
'staff_access': False,
|
||||
|
||||
@@ -73,6 +73,7 @@ class OpenEndedChildTest(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.test_system = get_test_system()
|
||||
self.test_system.open_ended_grading_interface = None
|
||||
self.openendedchild = OpenEndedChild(self.test_system, self.location,
|
||||
self.definition, self.descriptor, self.static_data, self.metadata)
|
||||
|
||||
@@ -203,7 +204,7 @@ class OpenEndedModuleTest(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.test_system = get_test_system()
|
||||
|
||||
self.test_system.open_ended_grading_interface = None
|
||||
self.test_system.location = self.location
|
||||
self.mock_xqueue = MagicMock()
|
||||
self.mock_xqueue.send_to_queue.return_value = (None, "Message")
|
||||
@@ -410,6 +411,7 @@ class CombinedOpenEndedModuleTest(unittest.TestCase):
|
||||
full_definition = definition_template.format(prompt=prompt, rubric=rubric, task1=task_xml1, task2=task_xml2)
|
||||
descriptor = Mock(data=full_definition)
|
||||
test_system = get_test_system()
|
||||
test_system.open_ended_grading_interface = None
|
||||
combinedoe_container = CombinedOpenEndedModule(
|
||||
test_system,
|
||||
descriptor,
|
||||
@@ -536,6 +538,7 @@ class OpenEndedModuleXmlTest(unittest.TestCase, DummyModulestore):
|
||||
|
||||
def setUp(self):
|
||||
self.test_system = get_test_system()
|
||||
self.test_system.open_ended_grading_interface = None
|
||||
self.test_system.xqueue['interface'] = Mock(
|
||||
send_to_queue=Mock(side_effect=[1, "queued"])
|
||||
)
|
||||
@@ -569,9 +572,9 @@ class OpenEndedModuleXmlTest(unittest.TestCase, DummyModulestore):
|
||||
module = self.get_module_from_location(self.problem_location, COURSE)
|
||||
|
||||
#Simulate a student saving an answer
|
||||
module.handle_ajax("save_answer", {"student_answer": self.answer})
|
||||
status = module.handle_ajax("get_status", {})
|
||||
self.assertTrue(isinstance(status, basestring))
|
||||
html = module.handle_ajax("get_html", {})
|
||||
module.handle_ajax("save_answer", {"student_answer": self.answer, "can_upload_files" : False, "student_file" : None})
|
||||
html = module.handle_ajax("get_html", {})
|
||||
|
||||
#Mock a student submitting an assessment
|
||||
assessment_dict = MockQueryDict()
|
||||
@@ -579,8 +582,7 @@ class OpenEndedModuleXmlTest(unittest.TestCase, DummyModulestore):
|
||||
module.handle_ajax("save_assessment", assessment_dict)
|
||||
task_one_json = json.loads(module.task_states[0])
|
||||
self.assertEqual(json.loads(task_one_json['child_history'][0]['post_assessment']), assessment)
|
||||
status = module.handle_ajax("get_status", {})
|
||||
self.assertTrue(isinstance(status, basestring))
|
||||
rubric = module.handle_ajax("get_combined_rubric", {})
|
||||
|
||||
#Move to the next step in the problem
|
||||
module.handle_ajax("next_problem", {})
|
||||
@@ -617,7 +619,6 @@ class OpenEndedModuleXmlTest(unittest.TestCase, DummyModulestore):
|
||||
module.handle_ajax("save_assessment", assessment_dict)
|
||||
task_one_json = json.loads(module.task_states[0])
|
||||
self.assertEqual(json.loads(task_one_json['child_history'][0]['post_assessment']), assessment)
|
||||
module.handle_ajax("get_status", {})
|
||||
|
||||
#Move to the next step in the problem
|
||||
try:
|
||||
@@ -660,15 +661,11 @@ class OpenEndedModuleXmlTest(unittest.TestCase, DummyModulestore):
|
||||
|
||||
#Get html and other data client will request
|
||||
module.get_html()
|
||||
legend = module.handle_ajax("get_legend", {})
|
||||
self.assertTrue(isinstance(legend, basestring))
|
||||
|
||||
module.handle_ajax("get_status", {})
|
||||
module.handle_ajax("skip_post_assessment", {})
|
||||
self.assertTrue(isinstance(legend, basestring))
|
||||
|
||||
#Get all results
|
||||
module.handle_ajax("get_results", {})
|
||||
module.handle_ajax("get_combined_rubric", {})
|
||||
|
||||
#reset the problem
|
||||
module.handle_ajax("reset", {})
|
||||
@@ -686,6 +683,7 @@ class OpenEndedModuleXmlAttemptTest(unittest.TestCase, DummyModulestore):
|
||||
|
||||
def setUp(self):
|
||||
self.test_system = get_test_system()
|
||||
self.test_system.open_ended_grading_interface = None
|
||||
self.test_system.xqueue['interface'] = Mock(
|
||||
send_to_queue=Mock(side_effect=[1, "queued"])
|
||||
)
|
||||
@@ -702,8 +700,6 @@ class OpenEndedModuleXmlAttemptTest(unittest.TestCase, DummyModulestore):
|
||||
|
||||
#Simulate a student saving an answer
|
||||
module.handle_ajax("save_answer", {"student_answer": self.answer})
|
||||
status = module.handle_ajax("get_status", {})
|
||||
self.assertTrue(isinstance(status, basestring))
|
||||
|
||||
#Mock a student submitting an assessment
|
||||
assessment_dict = MockQueryDict()
|
||||
@@ -711,8 +707,6 @@ class OpenEndedModuleXmlAttemptTest(unittest.TestCase, DummyModulestore):
|
||||
module.handle_ajax("save_assessment", assessment_dict)
|
||||
task_one_json = json.loads(module.task_states[0])
|
||||
self.assertEqual(json.loads(task_one_json['child_history'][0]['post_assessment']), assessment)
|
||||
status = module.handle_ajax("get_status", {})
|
||||
self.assertTrue(isinstance(status, basestring))
|
||||
|
||||
#Move to the next step in the problem
|
||||
module.handle_ajax("next_problem", {})
|
||||
|
||||
@@ -61,7 +61,7 @@ class PeerGradingModuleTest(unittest.TestCase, DummyModulestore):
|
||||
Try getting data from the external grading service
|
||||
@return:
|
||||
"""
|
||||
success, data = self.peer_grading.query_data_for_location()
|
||||
success, data = self.peer_grading.query_data_for_location(self.problem_location.url())
|
||||
self.assertEqual(success, True)
|
||||
|
||||
def test_get_score(self):
|
||||
|
||||
@@ -93,7 +93,6 @@ def peer_grading_notifications(course, user):
|
||||
log.info(
|
||||
"Problem with getting notifications from peer grading service for course {0} user {1}.".format(course_id,
|
||||
student_id))
|
||||
|
||||
if pending_grading:
|
||||
img_path = "/static/images/grading_notification.png"
|
||||
|
||||
@@ -154,7 +153,7 @@ def combined_notifications(course, user):
|
||||
last_time_viewed)
|
||||
notifications = json.loads(controller_response)
|
||||
if notifications['success']:
|
||||
if notifications['overall_need_to_check']:
|
||||
if notifications['staff_needs_to_grade'] or notifications['student_needs_to_peer_grade']:
|
||||
pending_grading = True
|
||||
except:
|
||||
#Non catastrophic error, so no real action
|
||||
|
||||
@@ -103,7 +103,6 @@ The standard chunk of Lorem Ipsum used since the 1500s is reproduced below for t
|
||||
|
||||
|
||||
else if cmd == 'save_grade'
|
||||
console.log("eval: #{data.score} pts, Feedback: #{data.feedback}")
|
||||
response =
|
||||
@mock('get_next', {location: data.location})
|
||||
# get_problem_list
|
||||
@@ -147,12 +146,14 @@ The standard chunk of Lorem Ipsum used since the 1500s is reproduced below for t
|
||||
|
||||
|
||||
class @StaffGrading
|
||||
grading_message_sel: '.grading-message'
|
||||
|
||||
constructor: (backend) ->
|
||||
AjaxPrefix.addAjaxPrefix(jQuery, -> "")
|
||||
@backend = backend
|
||||
|
||||
# all the jquery selectors
|
||||
|
||||
@el = $('.staff-grading')
|
||||
@problem_list_container = $('.problem-list-container')
|
||||
@problem_list = $('.problem-list')
|
||||
|
||||
@@ -224,12 +225,12 @@ class @StaffGrading
|
||||
setup_score_selection: =>
|
||||
@score_selection_container.html(@rubric)
|
||||
$('input[class="score-selection"]').change => @graded_callback()
|
||||
Rubric.initialize(@location)
|
||||
|
||||
@rub = new Rubric(@el)
|
||||
@rub.initialize(@location)
|
||||
|
||||
graded_callback: () =>
|
||||
# show button if we have scores for all categories
|
||||
if Rubric.check_complete()
|
||||
if @rub.check_complete()
|
||||
@state = state_graded
|
||||
@submit_button.show()
|
||||
|
||||
@@ -237,7 +238,7 @@ class @StaffGrading
|
||||
#Previously, responses were submitted when hitting enter. Add in a modifier that ensures that ctrl+enter is needed.
|
||||
if event.which == 17 && @is_ctrl==false
|
||||
@is_ctrl=true
|
||||
else if @is_ctrl==true && event.which == 13 && !@list_view && Rubric.check_complete()
|
||||
else if @is_ctrl==true && event.which == 13 && !@list_view && @rub.check_complete()
|
||||
@submit_and_get_next()
|
||||
|
||||
keyup_handler: (event) =>
|
||||
@@ -252,7 +253,7 @@ class @StaffGrading
|
||||
# always clear out errors and messages on transition.
|
||||
@error_msg = ''
|
||||
@message = ''
|
||||
|
||||
|
||||
if response.success
|
||||
if response.problem_list
|
||||
@problems = response.problem_list
|
||||
@@ -264,6 +265,7 @@ class @StaffGrading
|
||||
@error(response.error)
|
||||
|
||||
@render_view()
|
||||
@scroll_to_top()
|
||||
|
||||
get_next_submission: (location) ->
|
||||
@location = location
|
||||
@@ -272,13 +274,14 @@ class @StaffGrading
|
||||
|
||||
skip_and_get_next: () =>
|
||||
data =
|
||||
score: Rubric.get_total_score()
|
||||
rubric_scores: Rubric.get_score_list()
|
||||
score: @rub.get_total_score()
|
||||
rubric_scores: @rub.get_score_list()
|
||||
feedback: @feedback_area.val()
|
||||
submission_id: @submission_id
|
||||
location: @location
|
||||
skipped: true
|
||||
submission_flagged: false
|
||||
@gentle_alert "Skipped the submission."
|
||||
@backend.post('save_grade', data, @ajax_callback)
|
||||
|
||||
get_problem_list: () ->
|
||||
@@ -287,15 +290,21 @@ class @StaffGrading
|
||||
|
||||
submit_and_get_next: () ->
|
||||
data =
|
||||
score: Rubric.get_total_score()
|
||||
rubric_scores: Rubric.get_score_list()
|
||||
score: @rub.get_total_score()
|
||||
rubric_scores: @rub.get_score_list()
|
||||
feedback: @feedback_area.val()
|
||||
submission_id: @submission_id
|
||||
location: @location
|
||||
submission_flagged: @flag_submission_checkbox.is(':checked')
|
||||
|
||||
@gentle_alert "Grades saved. Fetching the next submission to grade."
|
||||
@backend.post('save_grade', data, @ajax_callback)
|
||||
|
||||
gentle_alert: (msg) =>
|
||||
@grading_message = $(@grading_message_sel)
|
||||
@grading_message.html("")
|
||||
@grading_message.fadeIn()
|
||||
@grading_message.html("<p>" + msg + "</p>")
|
||||
|
||||
error: (msg) ->
|
||||
@error_msg = msg
|
||||
@state = state_error
|
||||
@@ -466,6 +475,15 @@ class @StaffGrading
|
||||
new_text = "(Hide)"
|
||||
@question_header.text(new_text)
|
||||
|
||||
scroll_to_top: () =>
|
||||
#This try/catch is needed because jasmine fails with it
|
||||
try
|
||||
$('html, body').animate({
|
||||
scrollTop: $(".staff-grading").offset().top
|
||||
}, 200)
|
||||
catch error
|
||||
console.log("Scrolling error.")
|
||||
|
||||
|
||||
|
||||
# for now, just create an instance and load it...
|
||||
|
||||
@@ -23,7 +23,11 @@
|
||||
</section>
|
||||
|
||||
<section class="rubric-wrapper">
|
||||
<h3>Rubric</h3>
|
||||
<div class="visibility-control visibility-control-rubric">
|
||||
<div class="inner">
|
||||
</div>
|
||||
<span class="section-header section-header-rubric">Rubric</span>
|
||||
</div>
|
||||
<div class="rubric-container">
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,56 +1,85 @@
|
||||
.rubric-header {
|
||||
background-color: #fafafa;
|
||||
border-radius: 5px;
|
||||
|
||||
.rubric-collapse {
|
||||
margin-right: $baseline/2;
|
||||
}
|
||||
}
|
||||
|
||||
.button {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.rubric {
|
||||
margin: 0px 0px;
|
||||
margin: 0;
|
||||
color: #3C3C3C;
|
||||
|
||||
tr {
|
||||
margin:0px 0px;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
td {
|
||||
height: 100%;
|
||||
border: 1px black solid;
|
||||
text-align: center;
|
||||
height: 100%;
|
||||
border: 1px black solid;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
th {
|
||||
padding: 5px;
|
||||
margin: 5px;
|
||||
text-align: center;
|
||||
margin: $baseline/4;
|
||||
padding: $baseline/4;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.points-header th {
|
||||
padding: 0px;
|
||||
padding: 0px;
|
||||
}
|
||||
.rubric-label
|
||||
{
|
||||
position: relative;
|
||||
font-size: .9em;
|
||||
display: block;
|
||||
|
||||
.rubric-label {
|
||||
position: relative;
|
||||
display: block;
|
||||
font-size: .9em;
|
||||
|
||||
.choicegroup-correct {
|
||||
//nothing
|
||||
}
|
||||
|
||||
.choicegroup-incorrect {
|
||||
display:none;
|
||||
}
|
||||
}
|
||||
|
||||
.grade {
|
||||
position: absolute;
|
||||
bottom:0px;
|
||||
right:0px;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
}
|
||||
.selected-grade,
|
||||
.selected-grade .rubric-label {
|
||||
background: #666;
|
||||
color: white;
|
||||
}
|
||||
input[type=radio]:checked + .rubric-label {
|
||||
|
||||
input[type=radio]:checked + .rubric-label {
|
||||
background: white;
|
||||
color: $base-font-color;
|
||||
white-space:nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
.wrappable {
|
||||
white-space:normal;
|
||||
white-space:normal;
|
||||
}
|
||||
|
||||
input[class='score-selection'] {
|
||||
position: relative;
|
||||
font-size: 16px;
|
||||
position: relative;
|
||||
font-size: 16px;
|
||||
}
|
||||
ul.rubric-list
|
||||
{
|
||||
list-style-type: none;
|
||||
padding:0;
|
||||
margin:0;
|
||||
|
||||
ul.rubric-list {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style-type: none;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,49 +1,52 @@
|
||||
div.staff-grading,
|
||||
div.peer-grading{
|
||||
border: 1px solid lightgray;
|
||||
|
||||
textarea.feedback-area {
|
||||
margin: 0;
|
||||
height: 75px;
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
ul.rubric-list{
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style-type: none;
|
||||
padding:0;
|
||||
margin:0;
|
||||
|
||||
li {
|
||||
&.rubric-list-item{
|
||||
margin-bottom: 0px;
|
||||
padding: 0px;
|
||||
}
|
||||
&.rubric-list-item{
|
||||
margin-bottom: 0;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin : 0 0 0 10px;
|
||||
margin: 0 0 0 $baseline/2;
|
||||
}
|
||||
|
||||
h2{
|
||||
a
|
||||
{
|
||||
h2 {
|
||||
a {
|
||||
text-size: .5em;
|
||||
}
|
||||
}
|
||||
|
||||
div {
|
||||
margin: 0px;
|
||||
margin: 0;
|
||||
|
||||
&.submission-container{
|
||||
overflow-y: auto;
|
||||
height: 150px;
|
||||
background: #F6F6F6;
|
||||
border: 1px solid #ddd;
|
||||
@include clearfix;
|
||||
@include clearfix;
|
||||
overflow-y: auto;
|
||||
max-height: 300px;
|
||||
height: auto;
|
||||
border: 1px solid #ddd;
|
||||
background: #f6f6f6;
|
||||
}
|
||||
}
|
||||
|
||||
label {
|
||||
margin: 0px;
|
||||
margin: 0;
|
||||
padding: 2px;
|
||||
min-width: 50px;
|
||||
background-color: white;
|
||||
text-size: 1.5em;
|
||||
}
|
||||
|
||||
@@ -58,143 +61,161 @@ div.peer-grading{
|
||||
display: none;
|
||||
}
|
||||
|
||||
.problem-list
|
||||
{
|
||||
text-align: center;
|
||||
.problem-list {
|
||||
width: 100%;
|
||||
table-layout: auto;
|
||||
width:100%;
|
||||
th
|
||||
{
|
||||
text-align: center;
|
||||
|
||||
th {
|
||||
padding: 2px;
|
||||
}
|
||||
td
|
||||
{
|
||||
padding:2px;
|
||||
|
||||
td {
|
||||
padding: 2px;
|
||||
}
|
||||
td.problem-name
|
||||
{
|
||||
text-align:left;
|
||||
|
||||
td.problem-name {
|
||||
text-align: left;
|
||||
}
|
||||
.ui-progressbar
|
||||
{
|
||||
height:1em;
|
||||
margin:0px;
|
||||
padding:0px;
|
||||
|
||||
.ui-progressbar {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
height: 1em;
|
||||
}
|
||||
}
|
||||
|
||||
.prompt-information-container,
|
||||
.rubric-wrapper,
|
||||
.calibration-feedback-wrapper,
|
||||
.grading-container
|
||||
{
|
||||
padding: 2px;
|
||||
.grading-container {
|
||||
padding: $baseline/2 0;
|
||||
}
|
||||
.error-container
|
||||
{
|
||||
background-color: #FFCCCC;
|
||||
|
||||
.error-container {
|
||||
margin-left: 0;
|
||||
padding: 2px;
|
||||
margin-left: 0px;
|
||||
background-color: #ffcccc;
|
||||
}
|
||||
.submission-wrapper
|
||||
{
|
||||
h3
|
||||
{
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
p
|
||||
{
|
||||
margin-left:2px;
|
||||
}
|
||||
|
||||
.submission-wrapper {
|
||||
padding: 2px;
|
||||
padding-bottom: 15px;
|
||||
|
||||
h3 {
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
p {
|
||||
margin-left: 2px;
|
||||
}
|
||||
}
|
||||
.meta-info-wrapper
|
||||
{
|
||||
background-color: #eee;
|
||||
.meta-info-wrapper {
|
||||
padding:2px;
|
||||
div
|
||||
{
|
||||
display : inline;
|
||||
background-color: #eee;
|
||||
|
||||
div {
|
||||
display: inline;
|
||||
}
|
||||
}
|
||||
.message-container,
|
||||
.grading-message
|
||||
{
|
||||
background-color: $yellow;
|
||||
.grading-message {
|
||||
margin-left: 0;
|
||||
padding: 2px;
|
||||
margin-left:0px;
|
||||
background-color: $yellow;
|
||||
}
|
||||
|
||||
.breadcrumbs
|
||||
{
|
||||
margin-top:2px;
|
||||
margin-left:0px;
|
||||
margin-bottom:2px;
|
||||
.breadcrumbs {
|
||||
margin: $baseline/2 $baseline/4;
|
||||
font-size: .8em;
|
||||
}
|
||||
|
||||
.instructions-panel
|
||||
{
|
||||
|
||||
margin-right:2px;
|
||||
> div
|
||||
{
|
||||
padding: 2px;
|
||||
margin-bottom: 5px;
|
||||
background: #eee;
|
||||
width:47.6%;
|
||||
h3
|
||||
{
|
||||
text-align:center;
|
||||
text-transform:uppercase;
|
||||
color: #777;
|
||||
}
|
||||
p
|
||||
{
|
||||
color: #777;
|
||||
}
|
||||
}
|
||||
.calibration-panel
|
||||
{
|
||||
float:left;
|
||||
}
|
||||
.grading-panel
|
||||
{
|
||||
float:right;
|
||||
}
|
||||
.current-state
|
||||
{
|
||||
background: #1D9DD9;
|
||||
h3, p
|
||||
{
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
.instructions-panel {
|
||||
@include clearfix;
|
||||
padding: $baseline/2;
|
||||
background-color: #eee;
|
||||
font-size: .8em;
|
||||
|
||||
> div {
|
||||
margin-bottom: 5px;
|
||||
padding: $baseline/2;
|
||||
width: 49%;
|
||||
background: #eee;
|
||||
|
||||
h3 {
|
||||
color: #777;
|
||||
text-align: center;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
p{
|
||||
color: #777;
|
||||
}
|
||||
}
|
||||
.calibration-panel {
|
||||
display: inline-block;
|
||||
width: 20%;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.grading-panel {
|
||||
display: inline-block;
|
||||
width: 20%;
|
||||
border-radius: 3px;
|
||||
}
|
||||
.current-state {
|
||||
background: #fff;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.collapsible {
|
||||
margin-left: 0;
|
||||
|
||||
.collapsible
|
||||
{
|
||||
margin-left: 0px;
|
||||
header
|
||||
{
|
||||
margin-top:2px;
|
||||
margin-bottom:2px;
|
||||
header {
|
||||
margin-top: 2px;
|
||||
margin-bottom: 2px;
|
||||
font-size: 1.2em;
|
||||
}
|
||||
}
|
||||
|
||||
.interstitial-page
|
||||
{
|
||||
.interstitial-page {
|
||||
text-align: center;
|
||||
input[type=button]
|
||||
{
|
||||
margin-top: 20px;
|
||||
|
||||
input[type=button] {
|
||||
margin-top: $baseline;
|
||||
}
|
||||
}
|
||||
padding: 15px;
|
||||
border: none;
|
||||
}
|
||||
|
||||
div.peer-grading {
|
||||
border-radius: $baseline/2;
|
||||
padding: 0;
|
||||
|
||||
.peer-grading-tools {
|
||||
padding: $baseline;
|
||||
}
|
||||
|
||||
.error-container {
|
||||
margin: $baseline;
|
||||
border-radius: $baseline/4;
|
||||
padding: $baseline/2;
|
||||
}
|
||||
|
||||
.interstitial-page, .calibration -feedback, .calibration-interstitial-page {
|
||||
padding: $baseline;
|
||||
}
|
||||
|
||||
.prompt-wrapper {
|
||||
padding: $baseline;
|
||||
}
|
||||
|
||||
.grading-wrapper {
|
||||
padding: $baseline;
|
||||
}
|
||||
}
|
||||
|
||||
div.staff-grading {
|
||||
padding: $baseline;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,28 +1,60 @@
|
||||
<%! from django.utils.translation import ugettext as _ %>
|
||||
<section id="combined-open-ended" class="combined-open-ended" data-location="${location}" data-ajax-url="${ajax_url}" data-allow_reset="${allow_reset}" data-state="${state}" data-task-count="${task_count}" data-task-number="${task_number}" data-accept-file-upload = "${accept_file_upload}">
|
||||
<div class="status-container">
|
||||
${status|n}
|
||||
<div class="name">
|
||||
<h2>${display_name}</h2>
|
||||
<div class="progress-container">
|
||||
</div>
|
||||
</div>
|
||||
<h2>${display_name}</h2>
|
||||
|
||||
<div class="item-container">
|
||||
<h4>Prompt <a href="#" class="question-header">(Hide)</a> </h4>
|
||||
<div class="problem-container">
|
||||
% for item in items:
|
||||
<div class="item">${item['content'] | n}</div>
|
||||
% endfor
|
||||
<div class="problemwrapper">
|
||||
<div class="status-bar">
|
||||
<table class="statustable">
|
||||
<tr>
|
||||
<td class="problemtype-container">
|
||||
<div class="problemtype">
|
||||
${_("Open Response")}
|
||||
</div>
|
||||
</td>
|
||||
<td class="assessments-container">
|
||||
<div class="assessment-text">
|
||||
${_("Assessments:")}
|
||||
</div>
|
||||
<div class="status-container">
|
||||
${status|n}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<input type="button" value="${_("Reset")}" class="reset-button" name="reset"/>
|
||||
<input type="button" value="${_("Next Step")}" class="next-step-button" name="reset"/>
|
||||
</div>
|
||||
<div class="item-container">
|
||||
<div class="visibility-control visibility-control-prompt">
|
||||
<div class="inner">
|
||||
</div>
|
||||
<a href="" class="section-header section-header-prompt question-header">${_("Hide Prompt")}</a>
|
||||
</div>
|
||||
<div class="problem-container">
|
||||
% for item in items:
|
||||
<div class="item">${item['content'] | n}</div>
|
||||
% endfor
|
||||
</div>
|
||||
<div class="oe-tools response-tools">
|
||||
<span class="oe-tools-label"></span>
|
||||
<input type="button" value="${_('Try Again')}" class="reset-button" name="reset"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<section class="legend-container">
|
||||
</section>
|
||||
<div class="combined-rubric-container">
|
||||
</div>
|
||||
<div class="combined-rubric-container">
|
||||
</div>
|
||||
<div class="oe-tools problem-tools">
|
||||
<!--<span class="oe-tools-label">Once you have completed this form of assessment, you may continue. </span>-->
|
||||
<input type="button" value="${_('Next Step')}" class="next-step-button" name="reset"/>
|
||||
</div>
|
||||
|
||||
<div class="result-container">
|
||||
<section class="legend-container">
|
||||
</section>
|
||||
|
||||
<div class="result-container">
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
<div class="combined-rubric-container" data-status="shown" data-number="1">
|
||||
<div class="visibility-control visibility-control-rubric">
|
||||
<div class="inner">
|
||||
</div>
|
||||
<span class="section-header section-header-rubric">Submitted Rubric</span>
|
||||
</div>
|
||||
<div class="written-feedback">
|
||||
${error}
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,4 +1,37 @@
|
||||
<div class="${class_name}">
|
||||
<h4>${task_name}</h4>
|
||||
${results | n}
|
||||
</div>
|
||||
<%! from django.utils.translation import ugettext as _ %>
|
||||
% for (i,result) in enumerate(results):
|
||||
% if 'task_name' in result and 'result' in result:
|
||||
<div class="combined-rubric-container"
|
||||
%if i>0:
|
||||
data-status="hidden" data-number="${i}">
|
||||
% else:
|
||||
data-status="shown" data-number="${i}">
|
||||
% endif
|
||||
<div class="visibility-control visibility-control-rubric">
|
||||
<div class="inner">
|
||||
</div>
|
||||
<span class="section-header section-header-rubric">${_("Submitted Rubric")}</span>
|
||||
</div>
|
||||
<div class="oe-tools rubric-header">
|
||||
<span class="oe-tools-label"></span>
|
||||
<button class="rubric-collapse" href="#">${_("Toggle Full Rubric")}</button>
|
||||
<span class="oe-tools-scores">
|
||||
<span class="oe-tools-scores-label"></span>
|
||||
% if len(results)>1:
|
||||
<button href="#" alt="Previous" class="rubric-button rubric-previous-button"><i class="icon-chevron-left"></i></button>
|
||||
% endif
|
||||
${result['task_name']} from grader ${i+1}
|
||||
% if len(results)>1:
|
||||
<button href="#" alt="Next" class="rubric-button rubric-next-button"><i class="icon-chevron-right"></i></button>
|
||||
% endif
|
||||
</span>
|
||||
</div>
|
||||
${result['result'] | n}
|
||||
<div class="written-feedback">
|
||||
${result['feedback'] | n}
|
||||
</div>
|
||||
</div>
|
||||
%endif
|
||||
|
||||
% endfor
|
||||
|
||||
|
||||
@@ -1,23 +1,14 @@
|
||||
<%! from django.utils.translation import ugettext as _ %>
|
||||
<div class="status-elements">
|
||||
<section id="combined-open-ended-status" class="combined-open-ended-status">
|
||||
<div class="statusitem">
|
||||
${_("Status")}
|
||||
</div>
|
||||
%for i in xrange(0,len(status_list)):
|
||||
<%status=status_list[i]%>
|
||||
%if i==len(status_list)-1:
|
||||
%if status['current']:
|
||||
<div class="statusitem statusitem-current" data-status-number="${i}">
|
||||
%else:
|
||||
<div class="statusitem" data-status-number="${i}">
|
||||
%endif
|
||||
%if status['grader_type'] in grader_type_image_dict and render_via_ajax:
|
||||
<% grader_image = grader_type_image_dict[status['grader_type']]%>
|
||||
<img src="${grader_image}" title=${status['human_grader_type']}>
|
||||
%else:
|
||||
${status['human_task']}
|
||||
%endif
|
||||
(${status['human_state']})
|
||||
${status['human_task']}
|
||||
</div>
|
||||
%endfor
|
||||
</section>
|
||||
|
||||
@@ -4,7 +4,11 @@
|
||||
<div class="prompt">
|
||||
${prompt|n}
|
||||
</div>
|
||||
<h4>${_("Response")}</h4>
|
||||
<div class="visibility-control visibility-control-response">
|
||||
<div class="inner">
|
||||
</div>
|
||||
<span class="section-header section-header-response">${_("Response")}</span>
|
||||
</div>
|
||||
<textarea rows="${rows}" cols="${cols}" name="answer" class="answer short-form-response" id="input_${id}">${previous_answer|h}</textarea>
|
||||
|
||||
<div class="message-wrapper"></div>
|
||||
@@ -12,7 +16,7 @@
|
||||
% if state == 'initial':
|
||||
<span class="unanswered" style="display:inline-block;" id="status_${id}">${_("Unanswered")}</span>
|
||||
% elif state == 'assessing':
|
||||
<span class="grading" id="status_${id}">${_("Submitted for grading.")}
|
||||
<span class="grading" id="status_${id}">
|
||||
% if eta_message is not None:
|
||||
${eta_message}
|
||||
% endif
|
||||
@@ -27,8 +31,8 @@
|
||||
|
||||
<div class="file-upload"></div>
|
||||
|
||||
<input type="button" value="${_("Submit")}" class="submit-button" name="show"/>
|
||||
<input name="skip" class="skip-button" type="button" value="${_("Skip Post-Assessment")}"/>
|
||||
<input type="button" value="${_('Submit')}" class="submit-button" name="show"/>
|
||||
<input name="skip" class="skip-button" type="button" value="${_('Skip Post-Assessment')}"/>
|
||||
|
||||
<div class="open-ended-action"></div>
|
||||
|
||||
|
||||
@@ -1,24 +1,32 @@
|
||||
<div class="rubric">
|
||||
% for i in range(len(categories)):
|
||||
<% category = categories[i] %>
|
||||
<span class="rubric-category">${category['description']}</span> <br/>
|
||||
<span class="rubric-category">${category['description']}</span>
|
||||
<ul class="rubric-list">
|
||||
% for j in range(len(category['options'])):
|
||||
<% option = category['options'][j] %>
|
||||
<li class="rubric-list-item">
|
||||
%if len(category['options'][j]['grader_types'])>0:
|
||||
<li class="rubric-list-item">
|
||||
%else:
|
||||
<li class="rubric-list-item rubric-info-item">
|
||||
%endif
|
||||
<div class="rubric-label">
|
||||
%for grader_type in category['options'][j]['grader_types']:
|
||||
% if grader_type in grader_type_image_dict:
|
||||
<% grader_image = grader_type_image_dict[grader_type] %>
|
||||
% if grader_type in human_grader_types:
|
||||
<% human_title = human_grader_types[grader_type] %>
|
||||
% else:
|
||||
<% human_title = grader_type %>
|
||||
% endif
|
||||
<img src="${grader_image}" title="${human_title}"/>
|
||||
% endif
|
||||
%endfor
|
||||
${option['points']} points : ${option['text']}
|
||||
%if len(category['options'][j]['grader_types'])>0:
|
||||
%if correct[i]==1:
|
||||
<label class="choicegroup_correct wrapper-score-selection"></label>
|
||||
%elif correct[i]==.5:
|
||||
<label class="choicegroup_partialcorrect wrapper-score-selection"></label>
|
||||
%else:
|
||||
<label class="choicegroup_incorrect wrapper-score-selection"></label>
|
||||
%endif
|
||||
<span class="wrappable"> ${option['points']} points : ${option['text']}</span>
|
||||
</label>
|
||||
%else:
|
||||
<label class="rubric-elements-info">
|
||||
<span class="wrapper-score-selection"> </span>
|
||||
<span class="wrappable"> ${option['points']} points : ${option['text']}</span>
|
||||
</label>
|
||||
%endif
|
||||
</div>
|
||||
</li>
|
||||
% endfor
|
||||
|
||||
@@ -1,11 +1,17 @@
|
||||
<%! from django.utils.translation import ugettext as _ %>
|
||||
<% from random import randint %>
|
||||
<form class="rubric-template" id="inputtype_${id}" xmlns="http://www.w3.org/1999/html">
|
||||
<h3>${_("Rubric")}</h3>
|
||||
<p>${_("Select the criteria you feel best represents this submission in each category.")}</p>
|
||||
<div class="visibility-control visibility-control-rubric">
|
||||
<div class="inner">
|
||||
</div>
|
||||
<span class="section-header section-header-rubric">${_("Rubric")}</span>
|
||||
</div>
|
||||
<p>Select the criteria you feel best represents this submission in each category.</p>
|
||||
<div class="rubric">
|
||||
% for i in range(len(categories)):
|
||||
<% category = categories[i] %>
|
||||
<span class="rubric-category">${category['description']}</span> <br/>
|
||||
<% m = randint(0,1000) %>
|
||||
<span class="rubric-category">${category['description']}</span>
|
||||
<ul class="rubric-list">
|
||||
% for j in range(len(category['options'])):
|
||||
<% option = category['options'][j] %>
|
||||
@@ -14,8 +20,8 @@
|
||||
%else:
|
||||
<li class="rubric-list-item">
|
||||
% endif
|
||||
<label class="rubric-label" for="score-${i}-${j}">
|
||||
<input type="radio" class="score-selection" data-category="${i}" name="score-selection-${i}" id="score-${i}-${j}" value="${option['points']}"/>
|
||||
<label class="rubric-label" for="score-${i}-${j}-${m}">
|
||||
<span class="wrapper-score-selection"><input type="radio" class="score-selection" data-category="${i}" name="score-selection-${i}" id="score-${i}-${j}-${m}" value="${option['points']}"/></span>
|
||||
<span class="wrappable"> ${option['points']} points : ${option['text']}</span>
|
||||
</label>
|
||||
</li>
|
||||
|
||||
@@ -5,20 +5,22 @@
|
||||
<div class="prompt">
|
||||
${prompt}
|
||||
</div>
|
||||
|
||||
<h4>${_("Response")}</h4>
|
||||
<div class="visibility-control visibility-control-response">
|
||||
<div class="inner">
|
||||
</div>
|
||||
<span class="section-header section-header-response">${_("Response")}</span>
|
||||
</div>
|
||||
<div>
|
||||
<textarea name="answer" class="answer short-form-response" cols="70" rows="20">${previous_answer|n}</textarea>
|
||||
</div>
|
||||
|
||||
<div class="open-ended-action"></div>
|
||||
<div class="message-wrapper"></div>
|
||||
<div class="grader-status"></div>
|
||||
|
||||
<div class="rubric-wrapper">${initial_rubric}</div>
|
||||
|
||||
<div class="hint-wrapper"></div>
|
||||
|
||||
<div class="message-wrapper"></div>
|
||||
|
||||
<div class="file-upload"></div>
|
||||
<input type="button" value="${_("Submit")}" class="submit-button" name="show"/>
|
||||
<input type="button" value="${_('Submit')}" class="submit-button" name="show"/>
|
||||
|
||||
<div class="open-ended-action"></div>
|
||||
<span id="answer_${id}"></span>
|
||||
</section>
|
||||
|
||||
@@ -19,75 +19,71 @@
|
||||
|
||||
<div class="staff-grading" data-ajax_url="${ajax_url}">
|
||||
<h1>${_("Staff grading")}</h1>
|
||||
<div class="breadcrumbs">
|
||||
</div>
|
||||
<div class="error-container">
|
||||
</div>
|
||||
<div class="message-container">
|
||||
</div>
|
||||
<div class="breadcrumbs"></div>
|
||||
<div class="error-container"></div>
|
||||
<div class="message-container"></div>
|
||||
|
||||
<! -- Problem List View -->
|
||||
<section class="problem-list-container">
|
||||
<h2>${_("Instructions")}</h2>
|
||||
<div class="instructions">
|
||||
<p>${_("This is the list of problems that currently need to be graded in order to train the machine learning models. Each problem needs to be trained separately, and we have indicated the number of student submissions that need to be graded in order for a model to be generated. You can grade more than the minimum required number of submissions--this will improve the accuracy of machine learning, though with diminishing returns. You can see the current accuracy of machine learning while grading.")}</p>
|
||||
</div>
|
||||
<h2>${_("Instructions")}</h2>
|
||||
<div class="instructions">
|
||||
<p>${_("This is the list of problems that currently need to be graded in order to train the machine learning models. Each problem needs to be trained separately, and we have indicated the number of student submissions that need to be graded in order for a model to be generated. You can grade more than the minimum required number of submissions--this will improve the accuracy of machine learning, though with diminishing returns. You can see the current accuracy of machine learning while grading.")}</p>
|
||||
</div>
|
||||
|
||||
<h2>${_("Problem List")}</h2>
|
||||
<table class="problem-list">
|
||||
</table>
|
||||
<h2>${_("Problem List")}</h2>
|
||||
<table class="problem-list">
|
||||
</table>
|
||||
</section>
|
||||
|
||||
<!-- Grading View -->
|
||||
|
||||
<section class="prompt-wrapper">
|
||||
<h2 class="prompt-name"></h2>
|
||||
<div class="meta-info-wrapper">
|
||||
<div class="problem-meta-info-container">
|
||||
</div>
|
||||
<div class="ml-error-info-container">
|
||||
</div>
|
||||
</div>
|
||||
<div class="prompt-information-container">
|
||||
<div class="grading-message"></div>
|
||||
<h2 class="prompt-name">
|
||||
</h2>
|
||||
<div class="meta-info-wrapper">
|
||||
<div class="problem-meta-info-container">
|
||||
</div>
|
||||
<div class="ml-error-info-container">
|
||||
</div>
|
||||
</div>
|
||||
<div class="prompt-information-container">
|
||||
<h3>${_('Prompt')} <a href="#" class="question-header">${_("(Hide)")}</a></h3>
|
||||
<div class="prompt-container">
|
||||
</div>
|
||||
<div class="prompt-container">
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="action-button">
|
||||
<input type=button value="${_("Submit")}" class="action-button" name="show" />
|
||||
<input type=button value="${_("Submit")}" class="action-button" name="show" />
|
||||
</div>
|
||||
|
||||
<section class="grading-wrapper">
|
||||
<div class="grading-container">
|
||||
<div class="submission-wrapper">
|
||||
<h3>${_("Student Response")}</h3>
|
||||
<div class="submission-container">
|
||||
</div>
|
||||
</div>
|
||||
<div class="evaluation">
|
||||
<p class="score-selection-container">
|
||||
</p>
|
||||
<p class="grade-selection-container">
|
||||
</p>
|
||||
<h3>${_("Written Feedback")}</h3>
|
||||
<textarea name="feedback" placeholder="${_("Feedback for student (optional)")}" class="feedback-area" cols="70" >
|
||||
</textarea>
|
||||
<p>
|
||||
${_("Flag as inappropriate content for later review")} <input class="flag-checkbox" type="checkbox" />
|
||||
</p>
|
||||
</div>
|
||||
<div class="submission">
|
||||
<input type="button" value="${_("Submit")}" class="submit-button" name="show"/>
|
||||
<input type="button" value="${_("Skip")}" class="skip-button" name="skip"/>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<div class="grading-container">
|
||||
<div class="submission-wrapper">
|
||||
<h3>${_("Student Response")}</h3>
|
||||
<div class="submission-container">
|
||||
</div>
|
||||
</div>
|
||||
<div class="evaluation">
|
||||
<p class="score-selection-container">
|
||||
</p>
|
||||
<p class="grade-selection-container">
|
||||
</p>
|
||||
<h3>${_("Written Feedback")}</h3>
|
||||
<textarea name="feedback" placeholder="${_("Feedback for student (optional)")}"
|
||||
class="feedback-area" cols="70" ></textarea>
|
||||
<p>
|
||||
${_("Flag as inappropriate content for later review")} <input class="flag-checkbox" type="checkbox" />
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="submission">
|
||||
<input type="button" value="${_("Submit")}" class="submit-button" name="show"/>
|
||||
<input type="button" value="${_("Skip")}" class="skip-button" name="skip"/>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -2,59 +2,61 @@
|
||||
<section class="container peer-grading-container">
|
||||
<div class="peer-grading" data-ajax-url="${ajax_url}" data-use-single-location="${use_single_location}">
|
||||
<div class="error-container">${error_text}</div>
|
||||
<h1>${_("Peer Grading")}</h1>
|
||||
<h2>${_("Instructions")}</h2>
|
||||
<p>${_("Here are a list of problems that need to be peer graded for this course.")}</p>
|
||||
% if success:
|
||||
% if len(problem_list) == 0:
|
||||
<div class="message-container">
|
||||
${_("Nothing to grade!")}
|
||||
</div>
|
||||
%else:
|
||||
<div class="problem-list-container">
|
||||
<table class="problem-list">
|
||||
<tr>
|
||||
<th>${_("Problem Name")}</th>
|
||||
<th>${_("Due date")}</th>
|
||||
<th>${_("Graded")}</th>
|
||||
<th>${_("Available")}</th>
|
||||
<th>${_("Required")}</th>
|
||||
<th>${_("Progress")}</th>
|
||||
<div class="peer-grading-tools">
|
||||
<h1 class="peer-grading-title">${_("Peer Grading")}</h1>
|
||||
<h2 class="peer-grading-instructions">${_("Instructions")}</h2>
|
||||
<p>${_("Here are a list of problems that need to be peer graded for this course.")}</p>
|
||||
% if success:
|
||||
% if len(problem_list) == 0:
|
||||
<div class="message-container">
|
||||
${_("You currently do not having any peer grading to do. In order to have peer grading to do, you need to have submitted a response to a peer grading problem. The instructor also needs to score the essays that are used to help you better understand the grading criteria.")}
|
||||
</div>
|
||||
%else:
|
||||
<div class="problem-list-container">
|
||||
<table class="problem-list">
|
||||
<tr>
|
||||
<th>${_("Problem Name")}</th>
|
||||
<th>${_("Due date")}</th>
|
||||
<th>${_("Graded")}</th>
|
||||
<th>${_("Available")}</th>
|
||||
<th>${_("Required")}</th>
|
||||
<th>${_("Progress")}</th>
|
||||
</tr>
|
||||
%for problem in problem_list:
|
||||
<tr data-graded="${problem['num_graded']}" data-required="${problem['num_required']}">
|
||||
<td class="problem-name">
|
||||
%if problem['closed']:
|
||||
${problem['problem_name']}
|
||||
%else:
|
||||
<a href="#problem" data-location="${problem['location']}" class="problem-button">${problem['problem_name']}</a>
|
||||
%endif
|
||||
</td>
|
||||
<td>
|
||||
% if problem['due']:
|
||||
${problem['due']}
|
||||
% else:
|
||||
${_("No due date")}
|
||||
% endif
|
||||
</td>
|
||||
<td>
|
||||
${problem['num_graded']}
|
||||
</td>
|
||||
<td>
|
||||
${problem['num_pending']}
|
||||
</td>
|
||||
<td>
|
||||
${problem['num_required']}
|
||||
</td>
|
||||
<td>
|
||||
<div class="progress-bar">
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
%for problem in problem_list:
|
||||
<tr data-graded="${problem['num_graded']}" data-required="${problem['num_required']}">
|
||||
<td class="problem-name">
|
||||
%if problem['closed']:
|
||||
${problem['problem_name']}
|
||||
%else:
|
||||
<a href="#problem" data-location="${problem['location']}" class="problem-button">${problem['problem_name']}</a>
|
||||
%endif
|
||||
</td>
|
||||
<td>
|
||||
% if problem['due']:
|
||||
${problem['due']}
|
||||
% else:
|
||||
${_("No due date")}
|
||||
% endif
|
||||
</td>
|
||||
<td>
|
||||
${problem['num_graded']}
|
||||
</td>
|
||||
<td>
|
||||
${problem['num_pending']}
|
||||
</td>
|
||||
<td>
|
||||
${problem['num_required']}
|
||||
</td>
|
||||
<td>
|
||||
<div class="progress-bar">
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
%endfor
|
||||
</table>
|
||||
</div>
|
||||
%endfor
|
||||
</table>
|
||||
</div>
|
||||
%endif
|
||||
%endif
|
||||
%endif
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -4,98 +4,95 @@
|
||||
<div class="error-container"></div>
|
||||
|
||||
<section class="content-panel">
|
||||
<div class="instructions-panel">
|
||||
<div class="calibration-panel">
|
||||
<h3>${_("Learning to Grade")}</h3>
|
||||
<div class="instructions-panel">
|
||||
<div class="calibration-panel">
|
||||
<h3>${_("Learning to Grade")}</h3>
|
||||
</div>
|
||||
<div class="grading-panel">
|
||||
<h3>${_("Peer Grading")}</h3>
|
||||
</div>
|
||||
</div>
|
||||
<div class="grading-panel">
|
||||
<h3>${_("Peer Grading")}</h3>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="prompt-wrapper">
|
||||
<h2>${_('Prompt')} <a href="#" class="question-header">${_('(Hide)')}</a></h2>
|
||||
<div class="prompt-information-container">
|
||||
<section>
|
||||
<div class="prompt-container">
|
||||
<div class="prompt-wrapper">
|
||||
<div class="visibility-control visibility-control-prompt">
|
||||
<div class="inner">
|
||||
</div>
|
||||
<a href="" class="section-header section-header-prompt question-header">${_('Hide Prompt')}</a>
|
||||
</div>
|
||||
<div class="prompt-information-container">
|
||||
<section>
|
||||
<div class="prompt-container">
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
<section class="grading-wrapper">
|
||||
<div class="grading-message">
|
||||
</div>
|
||||
<h2>${_("Student Response")}</h2>
|
||||
<div class="grading-container">
|
||||
<div class="submission-wrapper">
|
||||
<h3></h3>
|
||||
<div class="submission-container">
|
||||
</div>
|
||||
<input type="hidden" name="submission-key" value="" />
|
||||
<input type="hidden" name="essay-id" value="" />
|
||||
</div>
|
||||
<div class="evaluation">
|
||||
<p class="rubric-selection-container"></p>
|
||||
<p class="score-selection-container"></p>
|
||||
<h3>${_("Written Feedback")}</h3>
|
||||
<p>${_("Please include some written feedback as well.")}</p>
|
||||
<textarea name="feedback" placeholder="Feedback for student" class="feedback-area" cols="70" ></textarea>
|
||||
<div class="flag-student-container"> ${_("This submission has explicit or pornographic content : ")}
|
||||
<input type="checkbox" class="flag-checkbox" value="student_is_flagged">
|
||||
</div>
|
||||
<div class="answer-unknown-container"> ${_("I do not know how to grade this question : ")}
|
||||
<input type="checkbox" class="answer-unknown-checkbox" value="answer_is_unknown">
|
||||
</div>
|
||||
</div>
|
||||
<div class="submission">
|
||||
<input type="button" value="${_("Submit")}" class="submit-button" name="show"/>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
<!-- Calibration feedback: Shown after a calibration is sent -->
|
||||
<section class="calibration-feedback">
|
||||
<h2>${_("How did I do?")}</h2>
|
||||
<div class="calibration-feedback-wrapper">
|
||||
</div>
|
||||
<input type="button" class="calibration-feedback-button" value="${_("Continue")}" name="calibration-feedback-button" />
|
||||
</section>
|
||||
|
||||
</div>
|
||||
<!-- Interstitial Page: Shown between calibration and grading steps -->
|
||||
<section class="interstitial-page">
|
||||
<h1>${_("Ready to grade!")}</h1>
|
||||
<p>${_("You have finished learning to grade, which means that you are now ready to start grading.")}</p>
|
||||
<input type="button" class="interstitial-page-button" value="${_("Start Grading!")}" name="interstitial-page-button" />
|
||||
</section>
|
||||
|
||||
<!-- Calibration Interstitial Page: Shown before calibration -->
|
||||
<section class="calibration-interstitial-page">
|
||||
<h1>${_("Learning to grade")}</h1>
|
||||
<p>${_("You have not yet finished learning to grade this problem.")}</p>
|
||||
<p>${_("You will now be shown a series of instructor-scored essays, and will be asked to score them yourself.")}</p>
|
||||
<p>${_("Once you can score the essays similarly to an instructor, you will be ready to grade your peers.")}</p>
|
||||
<input type="button" class="calibration-interstitial-page-button" value="${_("Start learning to grade")}" name="calibration-interstitial-page-button" />
|
||||
</section>
|
||||
|
||||
<section class="grading-wrapper">
|
||||
<h2>${_("Student Response")}</h2>
|
||||
|
||||
<div class="grading-container">
|
||||
<div class="submission-wrapper">
|
||||
<h3></h3>
|
||||
<div class="submission-container">
|
||||
<!-- Flag submission confirmation dialog -->
|
||||
<section class="flag-submission-confirmation">
|
||||
<h4>${_("Are you sure that you want to flag this submission?")}</h4>
|
||||
<p>
|
||||
${_("You are about to flag a submission. You should only flag a submission that contains explicit or offensive content. If the submission is not addressed to the question or is incorrect, you should give it a score of zero and accompanying feedback instead of flagging it.")}
|
||||
</p>
|
||||
<div>
|
||||
<input type="button" class="flag-submission-removal-button" value="${_("Remove Flag")}" name="calibration-interstitial-page-button" />
|
||||
<input type="button" class="flag-submission-confirmation-button" value="${_("Keep Flag")}" name="calibration-interstitial-page-button" />
|
||||
</div>
|
||||
<input type="hidden" name="submission-key" value="" />
|
||||
<input type="hidden" name="essay-id" value="" />
|
||||
</div>
|
||||
<div class="evaluation">
|
||||
<p class="rubric-selection-container"></p>
|
||||
<p class="score-selection-container">
|
||||
</p>
|
||||
<h3>${_("Written Feedback")}</h3>
|
||||
<p>${_("Please include some written feedback as well.")}</p>
|
||||
<textarea name="feedback" placeholder="Feedback for student"
|
||||
class="feedback-area" cols="70" ></textarea>
|
||||
<div class="flag-student-container"> ${_("This submission has explicit or pornographic content : ")}<input type="checkbox" class="flag-checkbox" value="student_is_flagged"> </div>
|
||||
<div class="answer-unknown-container"> ${_("I do not know how to grade this question : ")}<input type="checkbox" class="answer-unknown-checkbox" value="answer_is_unknown"></div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
<div class="submission">
|
||||
<input type="button" value="${_("Submit")}" class="submit-button" name="show"/>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="grading-message">
|
||||
</div>
|
||||
|
||||
</section>
|
||||
</section>
|
||||
<!-- Calibration feedback: Shown after a calibration is sent -->
|
||||
<section class="calibration-feedback">
|
||||
<h2>${_("How did I do?")}</h2>
|
||||
<div class="calibration-feedback-wrapper">
|
||||
</div>
|
||||
<input type="button" class="calibration-feedback-button" value="${_("Continue")}" name="calibration-feedback-button" />
|
||||
</section>
|
||||
|
||||
<!-- Interstitial Page: Shown between calibration and grading steps -->
|
||||
<section class="interstitial-page">
|
||||
<h1>${_("Ready to grade!")}</h1>
|
||||
<p>${_("You have finished learning to grade, which means that you are now ready to start grading.")}</p>
|
||||
<input type="button" class="interstitial-page-button" value="${_("Start Grading!")}" name="interstitial-page-button" />
|
||||
</section>
|
||||
|
||||
<!-- Calibration Interstitial Page: Shown before calibration -->
|
||||
<section class="calibration-interstitial-page">
|
||||
<h1>${_("Learning to grade")}</h1>
|
||||
<p>${_("You have not yet finished learning to grade this problem.")}</p>
|
||||
<p>${_("You will now be shown a series of instructor-scored essays, and will be asked to score them yourself.")}</p>
|
||||
<p>${_("Once you can score the essays similarly to an instructor, you will be ready to grade your peers.")}</p>
|
||||
<input type="button" class="calibration-interstitial-page-button" value="${_("Start learning to grade")}" name="calibration-interstitial-page-button" />
|
||||
</section>
|
||||
|
||||
<!-- Flag submission confirmation dialog -->
|
||||
<section class="flag-submission-confirmation">
|
||||
<h4>${_("Are you sure that you want to flag this submission?")}</h4>
|
||||
<p>
|
||||
${_("You are about to flag a submission. You should only flag a submission that contains explicit or offensive content. If the submission is not addressed to the question or is incorrect, you should give it a score of zero and accompanying feedback instead of flagging it.")}
|
||||
</p>
|
||||
<div>
|
||||
<input type="button" class="flag-submission-removal-button" value="${_("Remove Flag")}" name="calibration-interstitial-page-button" />
|
||||
<input type="button" class="flag-submission-confirmation-button" value="${_("Keep Flag")}" name="calibration-interstitial-page-button" />
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
<input type="button" value="${_("Go Back")}" class="action-button" name="back" />
|
||||
<input type="button" value="${_("Go Back")}" class="action-button" name="back" />
|
||||
</div>
|
||||
</section>
|
||||
|
||||
Reference in New Issue
Block a user