\[\]
diff --git a/common/lib/capa/capa/templates/optioninput.html b/common/lib/capa/capa/templates/optioninput.html
index f804e771cc..a4f25d801b 100644
--- a/common/lib/capa/capa/templates/optioninput.html
+++ b/common/lib/capa/capa/templates/optioninput.html
@@ -13,12 +13,13 @@
-
- ${value|h} - ${status.display_name}
-
-
+
+
+ ${value|h} - ${status.display_name}
+
+
% if msg:
${msg|n}
% endif
diff --git a/common/lib/capa/capa/templates/textline.html b/common/lib/capa/capa/templates/textline.html
index 8a9826b0a5..b37fb0d67e 100644
--- a/common/lib/capa/capa/templates/textline.html
+++ b/common/lib/capa/capa/templates/textline.html
@@ -27,18 +27,20 @@
/>
${trailing_text | h}
-
- %if value:
- ${value|h}
- % else:
- ${label}
- %endif
- -
- ${status.display_name}
-
+ aria-describedby="input_${id}" data-tooltip="${status.display_tooltip}">
+
+ %if value:
+ ${value|h}
+ % else:
+ ${label}
+ %endif
+ -
+ ${status.display_name}
+
+
diff --git a/common/lib/capa/capa/tests/test_input_templates.py b/common/lib/capa/capa/tests/test_input_templates.py
index 09ae25476d..5af21fd5e2 100644
--- a/common/lib/capa/capa/tests/test_input_templates.py
+++ b/common/lib/capa/capa/tests/test_input_templates.py
@@ -144,7 +144,7 @@ class ChoiceGroupTemplateTest(TemplateTestCase):
# Should mark the entire problem correct
xml = self.render_to_xml(self.context)
- xpath = "//div[@class='indicator_container']/span[@class='status correct']"
+ xpath = "//div[@class='indicator-container']/span[@class='status correct']"
self.assert_has_xpath(xml, xpath, self.context)
# Should NOT mark individual options
@@ -172,7 +172,7 @@ class ChoiceGroupTemplateTest(TemplateTestCase):
for test_conditions in conditions:
self.context.update(test_conditions)
xml = self.render_to_xml(self.context)
- xpath = "//div[@class='indicator_container']/span[@class='status incorrect']"
+ xpath = "//div[@class='indicator-container']/span[@class='status incorrect']"
self.assert_has_xpath(xml, xpath, self.context)
# Should NOT mark individual options
@@ -204,7 +204,7 @@ class ChoiceGroupTemplateTest(TemplateTestCase):
for test_conditions in conditions:
self.context.update(test_conditions)
xml = self.render_to_xml(self.context)
- xpath = "//div[@class='indicator_container']/span[@class='status unanswered']"
+ xpath = "//div[@class='indicator-container']/span[@class='status unanswered']"
self.assert_has_xpath(xml, xpath, self.context)
# Should NOT mark individual options
@@ -234,7 +234,7 @@ class ChoiceGroupTemplateTest(TemplateTestCase):
self.assert_has_xpath(xml, xpath, self.context)
# Should NOT mark the whole problem
- xpath = "//div[@class='indicator_container']/span"
+ xpath = "//div[@class='indicator-container']/span"
self.assert_no_xpath(xml, xpath, self.context)
def test_option_marked_incorrect(self):
@@ -255,7 +255,7 @@ class ChoiceGroupTemplateTest(TemplateTestCase):
self.assert_has_xpath(xml, xpath, self.context)
# Should NOT mark the whole problem
- xpath = "//div[@class='indicator_container']/span"
+ xpath = "//div[@class='indicator-container']/span"
self.assert_no_xpath(xml, xpath, self.context)
def test_never_show_correctness(self):
@@ -289,10 +289,10 @@ class ChoiceGroupTemplateTest(TemplateTestCase):
xml = self.render_to_xml(self.context)
# Should NOT mark the entire problem correct/incorrect
- xpath = "//div[@class='indicator_container']/span[@class='status correct']"
+ xpath = "//div[@class='indicator-container']/span[@class='status correct']"
self.assert_no_xpath(xml, xpath, self.context)
- xpath = "//div[@class='indicator_container']/span[@class='status incorrect']"
+ xpath = "//div[@class='indicator-container']/span[@class='status incorrect']"
self.assert_no_xpath(xml, xpath, self.context)
# Should NOT mark individual options
@@ -388,9 +388,9 @@ class TextlineTemplateTest(TemplateTestCase):
xpath = "//div[@class='%s ']" % div_class
self.assert_has_xpath(xml, xpath, self.context)
- # Expect that we get a
with class="status"
+ # Expect that we get a with class="status"
# (used to by CSS to draw the green check / red x)
- self.assert_has_text(xml, "//p[@class='status']",
+ self.assert_has_text(xml, "//span[@class='status']/span[@class='sr']",
status_mark, exact=False)
def test_label(self):
@@ -848,7 +848,7 @@ class ChoiceTextGroupTemplateTest(TemplateTestCase):
# Should mark the entire problem correct
xml = self.render_to_xml(self.context)
- xpath = "//div[@class='indicator_container']/span[@class='status correct']"
+ xpath = "//div[@class='indicator-container']/span[@class='status correct']"
self.assert_has_xpath(xml, xpath, self.context)
# Should NOT mark individual options
@@ -875,7 +875,7 @@ class ChoiceTextGroupTemplateTest(TemplateTestCase):
for test_conditions in conditions:
self.context.update(test_conditions)
xml = self.render_to_xml(self.context)
- xpath = "//div[@class='indicator_container']/span[@class='status incorrect']"
+ xpath = "//div[@class='indicator-container']/span[@class='status incorrect']"
self.assert_has_xpath(xml, xpath, self.context)
# Should NOT mark individual options
@@ -907,7 +907,7 @@ class ChoiceTextGroupTemplateTest(TemplateTestCase):
for test_conditions in conditions:
self.context.update(test_conditions)
xml = self.render_to_xml(self.context)
- xpath = "//div[@class='indicator_container']/span[@class='status unanswered']"
+ xpath = "//div[@class='indicator-container']/span[@class='status unanswered']"
self.assert_has_xpath(xml, xpath, self.context)
# Should NOT mark individual options
@@ -937,7 +937,7 @@ class ChoiceTextGroupTemplateTest(TemplateTestCase):
self.assert_has_xpath(xml, xpath, self.context)
# Should NOT mark the whole problem
- xpath = "//div[@class='indicator_container']/span"
+ xpath = "//div[@class='indicator-container']/span"
self.assert_no_xpath(xml, xpath, self.context)
def test_option_marked_incorrect(self):
@@ -957,7 +957,7 @@ class ChoiceTextGroupTemplateTest(TemplateTestCase):
self.assert_has_xpath(xml, xpath, self.context)
# Should NOT mark the whole problem
- xpath = "//div[@class='indicator_container']/span"
+ xpath = "//div[@class='indicator-container']/span"
self.assert_no_xpath(xml, xpath, self.context)
def test_label(self):
diff --git a/common/lib/xmodule/xmodule/css/capa/display.scss b/common/lib/xmodule/xmodule/css/capa/display.scss
index 727630b79b..02e4b45ebf 100644
--- a/common/lib/xmodule/xmodule/css/capa/display.scss
+++ b/common/lib/xmodule/xmodule/css/capa/display.scss
@@ -1,8 +1,54 @@
+// capa - styling
+// ====================
+
+// Table of Contents
+// * +Variables - Capa
+// * +Extends - Capa
+// * +Mixins - Status Icon - Capa
+// * +Resets - Deprecate Please
+// * +Problem - Base
+// * +Problem - Choice Group
+// * +Problem - Misc, Unclassified Mess
+// * +Problem - Text Input, Numerical Input
+// * +Problem - Option Input (Dropdown)
+// * +Problem - CodeMirror
+// * +Problem - Misc, Unclassified Mess Part 2
+// * +Problem - Rubric
+// * +Problem - Annotation
+// * +Problem - Choice Text Group
+
+// +Variables - Capa
+// ====================
$annotation-yellow: rgba(255,255,10,0.3);
$color-copy-tip: rgb(100,100,100);
-$color-success: rgb(0, 136, 1);
-$color-fail: rgb(212, 64, 64);
+$correct: $green-d1;
+$incorrect: $red;
+// +Extends - Capa
+// ====================
+// Duplicated from _mixins.scss due to xmodule compilation, inheritance issues
+%use-font-awesome {
+ font-family: FontAwesome;
+ -webkit-font-smoothing: antialiased;
+ display: inline-block;
+ speak: none;
+}
+
+// +Mixins - Status Icon - Capa
+// ====================
+@mixin status-icon($color: $gray, $fontAwesomeIcon: "\f00d"){
+
+ &:after {
+ @extend %use-font-awesome;
+ @include margin-left(17px);
+ color: $color;
+ font-size: 1.2em;
+ content: $fontAwesomeIcon;
+ }
+}
+
+// +Resets - Deprecate Please
+// ====================
h2 {
margin-top: 0;
margin-bottom: ($baseline*0.75);
@@ -24,12 +70,12 @@ h2 {
.feedback-hint-correct {
margin-top: ($baseline/2);
- color: $color-success;
+ color: $correct;
}
.feedback-hint-incorrect {
margin-top: ($baseline/2);
- color: $color-fail;
+ color: $incorrect;
}
.feedback-hint-text {
@@ -55,10 +101,9 @@ h2 {
display: block;
}
-
iframe[seamless]{
overflow: hidden;
- padding: 0px;
+ padding: 0;
border: 0px none transparent;
background-color: transparent;
}
@@ -68,13 +113,16 @@ iframe[seamless]{
}
div.problem-progress {
+ @include padding-left($baseline/4);
+ @extend %t-ultralight;
display: inline-block;
- padding-left: ($baseline/4);
- color: #666;
+ color: $gray-d1;
font-weight: 100;
font-size: em(16);
}
+// +Problem - Base
+// ====================
div.problem {
@media print {
display: block;
@@ -89,7 +137,11 @@ div.problem {
.inline {
display: inline;
}
+}
+// +Problem - Choice Group
+// ====================
+div.problem {
.choicegroup {
@include clearfix();
min-width: 100px;
@@ -97,51 +149,98 @@ div.problem {
width: 100px;
label {
- @include float(left);
+ @include box-sizing(border-box);
+ display: inline-block;
clear: both;
- margin-bottom: ($baseline/4);
+ margin-bottom: ($baseline/2);
+ border: 2px solid $gray-l4;
+ border-radius: 3px;
+ padding: ($baseline/2);
+ width: 100%;
&.choicegroup_correct {
- &:after {
- margin-left: ($baseline*0.75);
- content: url('../images/correct-icon.png');
+ @include status-icon($correct, "\f00c");
+ border: 2px solid $correct;
+
+ // keep green for correct answers on hover.
+ &:hover {
+ border-color: $correct;
}
}
&.choicegroup_incorrect {
- &:after {
- margin-left: ($baseline*0.75);
- content: url('../images/incorrect-icon.png');
+ @include status-icon($incorrect, "\f00d");
+ border: 2px solid $incorrect;
+
+ // keep red for incorrect answers on hover.
+ &:hover {
+ border-color: $incorrect;
}
}
+
+ &:hover {
+ border: 2px solid $blue;
+ }
}
- .indicator_container {
- @include float(left);
+ .indicator-container {
+ display: inline-block;
+ min-height: 1px;
width: 25px;
- height: 1px;
- @include margin-right(15px);
}
fieldset {
@include box-sizing(border-box);
- margin: 0px 0px $baseline;
- @include padding-left($baseline);
- @include border-left(1px solid #ddd);
}
input[type="radio"],
input[type="checkbox"] {
- @include float(left);
- @include margin(4px, 8px, 0, 0);
+ @include margin(($baseline/4) ($baseline/2) ($baseline/4) ($baseline/4));
}
text {
+ @include margin-left(25px);
display: inline;
- margin-left: 25px;
}
}
+}
+// +Problem - Status Indicators
+// ====================
+// Summary status indicators shown after the input area
+div.problem {
+
+ .indicator-container {
+
+ .status {
+ width: $baseline;
+ height: $baseline;
+
+ // CASE: correct answer
+ &.correct {
+ @include status-icon($correct, "\f00c");
+ }
+
+ // CASE: incorrect answer
+ &.incorrect {
+ @include status-icon($incorrect, "\f00d");
+ }
+
+ // CASE: unanswered
+ &.unanswered {
+ @include status-icon($gray-l4, "\f128");
+ }
+
+ // CASE: processing
+ &.processing {
+ }
+ }
+ }
+}
+
+// +Problem - Misc, Unclassified Mess
+// ====================
+div.problem {
ol.enumerate {
li {
&:before {
@@ -187,17 +286,22 @@ div.problem {
}
}
+ // known classes using this div: .indicator-container, moved to section above
div {
+
+ // TO-DO: Styling used by advanced capa problem types. Should be synced up to use .status class
p {
&.answer {
margin-top: -2px;
}
+
&.status {
- margin: 8px 0 0 $baseline/2;
+ @include margin(8px, 0, 0, ($baseline/2));
text-indent: 100%;
white-space: nowrap;
overflow: hidden;
}
+
span.clarification i {
font-style: normal;
&:hover {
@@ -224,7 +328,7 @@ div.problem {
}
input {
- border-color: green;
+ border-color: $correct;
}
}
@@ -241,7 +345,7 @@ div.problem {
}
}
- &.incorrect, &.incomplete, &.ui-icon-close {
+ &.ui-icon-close {
p.status {
display: inline-block;
width: 20px;
@@ -250,7 +354,21 @@ div.problem {
}
input {
- border-color: red;
+ border-color: $incorrect;
+ }
+ }
+
+ &.incorrect, &.incomplete {
+
+ p.status {
+ display: inline-block;
+ width: 20px;
+ height: 20px;
+ background: url('../images/incorrect-icon.png') center center no-repeat;
+ }
+
+ input {
+ border-color: $incorrect;
}
}
@@ -260,14 +378,14 @@ div.problem {
}
p.answer {
+ @include margin-left($baseline/2);
display: inline-block;
margin-bottom: 0;
- margin-left: $baseline/2;
&:before {
+ @extend %t-strong;
display: inline;
content: "Answer: ";
- font-weight: bold;
}
&:empty {
@@ -287,8 +405,8 @@ div.problem {
}
img.loading {
+ @include padding-left($baseline/2);
display: inline-block;
- padding-left: ($baseline/2);
}
span {
@@ -303,7 +421,7 @@ div.problem {
background: #f1f1f1;
}
}
- }
+ }
// Hides equation previews in symbolic response problems when printing
[id^='display'].equation {
@@ -312,8 +430,9 @@ div.problem {
}
}
+ //TO-DO: review and deprecate all these styles within span {}
span {
- &.unanswered, &.ui-icon-bullet {
+ &.ui-icon-bullet {
display: inline-block;
position: relative;
top: 4px;
@@ -331,7 +450,7 @@ div.problem {
background: url('../images/spinner.gif') center center no-repeat;
}
- &.correct, &.ui-icon-check {
+ &.ui-icon-check {
display: inline-block;
position: relative;
top: 3px;
@@ -349,7 +468,7 @@ div.problem {
background: url('../images/partially-correct-icon.png') center center no-repeat;
}
- &.incorrect, &.incomplete, &.ui-icon-close {
+ &.incomplete, &.ui-icon-close {
display: inline-block;
position: relative;
top: 3px;
@@ -360,8 +479,8 @@ div.problem {
}
.reload {
- float:right;
- margin: $baseline/2;
+ @include float(right);
+ margin: ($baseline/2);
}
@@ -457,15 +576,6 @@ div.problem {
}
}
- form.option-input {
- margin: -$baseline/2 0 $baseline;
- padding-bottom: $baseline;
-
- select {
- margin-right: flex-gutter();
- }
- }
-
ul {
margin-bottom: lh();
margin-left: .75em;
@@ -485,7 +595,8 @@ div.problem {
}
dl dt {
- font-weight: bold;
+ @extend %t-strong;
+
}
dl dd {
@@ -531,8 +642,8 @@ div.problem {
}
th {
+ @extend %t-strong;
text-align: left;
- font-weight: bold;
}
td {
@@ -584,6 +695,93 @@ div.problem {
white-space: pre;
}
}
+}
+
+// +Problem - Text Input, Numerical Input
+// ====================
+.problem {
+ .capa_inputtype.textline, .inputtype.formulaequationinput {
+
+ input {
+ @include box-sizing(border-box);
+ border: 2px solid $gray-l4;
+ border-radius: 3px;
+ min-width: 160px;
+ height: 46px;
+ }
+
+ > .incorrect, .correct, .unanswered {
+
+ .status {
+ display: inline-block;
+ margin-top: ($baseline/2);
+ background: none;
+ }
+ }
+
+ // CASE: incorrect answer
+ > .incorrect {
+
+ input {
+ border: 2px solid $incorrect;
+ }
+
+ .status {
+ @include status-icon($incorrect, "\f00d");
+ }
+ }
+
+ // CASE: correct answer
+ > .correct {
+
+ input {
+ border: 2px solid $correct;
+ }
+
+ .status {
+ @include status-icon($correct, "\f00c");
+ }
+ }
+
+ // CASE: unanswered
+ > .unanswered {
+
+ input {
+ border: 2px solid $gray-l4;
+ }
+
+ .status {
+ @include status-icon($gray-l4, "\f128");
+ }
+ }
+ }
+}
+
+
+// +Problem - Option Input (Dropdown)
+// ====================
+.problem {
+ .inputtype.option-input {
+ margin: (-$baseline/2) 0 $baseline;
+ padding-bottom: $baseline;
+
+ select {
+ @include margin-right($baseline/2);
+ }
+
+ .indicator-container {
+ display: inline-block;
+
+ .status.correct:after, .status.incorrect:after {
+ @include margin-left(0);
+ }
+ }
+ }
+}
+
+// +Problem - CodeMirror
+// ====================
+div.problem {
.CodeMirror {
border: 1px solid black;
@@ -634,7 +832,52 @@ div.problem {
.CodeMirror-scroll {
margin-right: 0px;
}
+}
+// +Problem - Actions
+// ====================
+div.problem .action {
+ margin-top: $baseline;
+
+ .save, .check, .show, .reset, .hint-button {
+ @include margin-right($baseline/2);
+ margin-bottom: ($baseline/2);
+ height: ($baseline*2);
+ vertical-align: middle;
+ text-transform: uppercase;
+ font-weight: 600;
+ }
+
+ .save {
+ @extend .blue-button !optional;
+ }
+
+ .show {
+
+ .show-label {
+ font-weight: 600;
+ font-size: 1.0em;
+ }
+ }
+
+ .submission_feedback {
+ // background: #F3F3F3;
+ // border: 1px solid #ddd;
+ // border-radius: 3px;
+ // padding: 8px 12px;
+ // margin-top: ($baseline/2);
+ @include margin-left($baseline/2);
+ display: inline-block;
+ margin-top: 8px;
+ color: $gray-d1;
+ font-style: italic;
+ -webkit-font-smoothing: antialiased;
+ }
+}
+
+// +Problem - Misc, Unclassified Mess Part 2
+// ====================
+div.problem {
hr {
float: none;
clear: both;
@@ -663,52 +906,12 @@ div.problem {
padding: lh();
border: 1px solid $gray-l3;
}
-
- div.action {
- margin-top: $baseline;
-
- .save, .check, .show, .reset, .hint-button {
- height: ($baseline*2);
- vertical-align: middle;
- font-weight: 600;
-
- @media print {
- display: none;
- }
- }
-
- .save {
- @extend .blue-button !optional;
- }
-
- .show {
-
- .show-label {
- font-weight: 600;
- font-size: 1.0em;
- }
- }
-
- .submission_feedback {
- // background: #F3F3F3;
- // border: 1px solid #ddd;
- // border-radius: 3px;
- // padding: 8px 12px;
- // margin-top: ($baseline/2);
- display: inline-block;
- margin-top: 8px;
- @include margin-left($baseline/2);
- color: #666;
- font-style: italic;
- -webkit-font-smoothing: antialiased;
- }
- }
-
+
.detailed-solution {
> p:first-child {
+ @extend %t-strong;
color: #aaa;
text-transform: uppercase;
- font-weight: bold;
font-style: normal;
font-size: 0.9em;
}
@@ -720,9 +923,9 @@ div.problem {
.detailed-targeted-feedback {
> p:first-child {
- color: red;
+ @extend %t-strong;
+ color: $incorrect;
text-transform: uppercase;
- font-weight: bold;
font-style: normal;
font-size: 0.9em;
}
@@ -734,9 +937,9 @@ div.problem {
.detailed-targeted-feedback-correct {
> p:first-child {
- color: green;
+ @extend %t-strong;
+ color: $correct;
text-transform: uppercase;
- font-weight: bold;
font-style: normal;
font-size: 0.9em;
}
@@ -777,11 +980,11 @@ div.problem {
border: 1px solid $gray-l3;
h3 {
+ @extend %t-strong;
padding: 9px;
border-bottom: 1px solid #e3e3e3;
background: #eee;
text-shadow: 0 1px 0 $white;
- font-weight: bold;
font-size: em(16);
}
@@ -818,9 +1021,9 @@ div.problem {
margin-bottom: 12px;
h3 {
+ @extend %t-strong;
color: #aaa;
text-transform: uppercase;
- font-weight: bold;
font-style: normal;
font-size: 0.9em;
}
@@ -877,7 +1080,7 @@ div.problem {
}
.shortform {
- font-weight: bold;
+ @extend %t-strong;
}
.longform {
@@ -951,7 +1154,12 @@ div.problem {
}
}
}
+}
+
+// +Problem - Rubric
+// ====================
+div.problem {
.rubric {
tr {
margin: ($baseline/2) 0;
@@ -1004,16 +1212,20 @@ div.problem {
display: none;
}
}
+}
+// +Problem - Annotation
+// ====================
+div.problem {
.annotation-input {
margin: 0 0 1em 0;
border: 1px solid $gray-l3;
border-radius: 1em;
.annotation-header {
+ @extend %t-strong;
padding: .5em 1em;
border-bottom: 1px solid $gray-l3;
- font-weight: bold;
}
.annotation-body { padding: .5em 1em; }
@@ -1094,16 +1306,20 @@ div.problem {
pre { background-color: $gray-l3; color: $black; }
&:before {
+ @extend %t-strong;
display: block;
content: "debug input value";
text-transform: uppercase;
- font-weight: bold;
font-size: 1.5em;
}
}
}
+}
- .choicetextgroup{
+// +Problem - Choice Text Group
+// ====================
+div.problem {
+ .choicetextgroup {
@extend .choicegroup;
input[type="text"]{
@@ -1114,7 +1330,7 @@ div.problem {
@extend label.choicegroup_correct;
input[type="text"] {
- border-color: green;
+ border-color: $correct;
}
}
diff --git a/common/lib/xmodule/xmodule/js/spec/capa/display_spec.coffee b/common/lib/xmodule/xmodule/js/spec/capa/display_spec.coffee
index 892864f631..a8d881c6e6 100644
--- a/common/lib/xmodule/xmodule/js/spec/capa/display_spec.coffee
+++ b/common/lib/xmodule/xmodule/js/spec/capa/display_spec.coffee
@@ -323,7 +323,7 @@ describe 'Problem', ->