Commit 2dfca626 by Marco Morales

Merge pull request #8151 from edx/marco/capa-styling

Updated styling for basic capa problems (multiple choice, dropdown, checkboxes, numerical input and text input) including support for mobile app experience. 
parents 13dbfb86 aa5e2f49
...@@ -351,7 +351,7 @@ ...@@ -351,7 +351,7 @@
</p> </p>
<p>What Apple device competed with the portable CD player?</p> <p>What Apple device competed with the portable CD player?</p>
<span><form class="choicegroup capa_inputtype" id="inputtype_i4x-AndyA-ABT101-problem-46d2b65d793549e2876729d55df9a2cb_2_1"> <span><form class="choicegroup capa_inputtype" id="inputtype_i4x-AndyA-ABT101-problem-46d2b65d793549e2876729d55df9a2cb_2_1">
<div class="indicator_container"> <div class="indicator-container">
<span class="unanswered" style="display:inline-block;" id="status_i4x-AndyA-ABT101-problem-46d2b65d793549e2876729d55df9a2cb_2_1"></span> <span class="unanswered" style="display:inline-block;" id="status_i4x-AndyA-ABT101-problem-46d2b65d793549e2876729d55df9a2cb_2_1"></span>
</div> </div>
......
...@@ -69,7 +69,7 @@ registry = TagRegistry() # pylint: disable=invalid-name ...@@ -69,7 +69,7 @@ registry = TagRegistry() # pylint: disable=invalid-name
class Status(object): class Status(object):
""" """
Problem status Problem status
attributes: classname, display_name attributes: classname, display_name, display_tooltip
""" """
css_classes = { css_classes = {
# status: css class # status: css class
...@@ -77,7 +77,7 @@ class Status(object): ...@@ -77,7 +77,7 @@ class Status(object):
'incomplete': 'incorrect', 'incomplete': 'incorrect',
'queued': 'processing', 'queued': 'processing',
} }
__slots__ = ('classname', '_status', 'display_name') __slots__ = ('classname', '_status', 'display_name', 'display_tooltip')
def __init__(self, status, gettext_func=unicode): def __init__(self, status, gettext_func=unicode):
self.classname = self.css_classes.get(status, status) self.classname = self.css_classes.get(status, status)
...@@ -90,7 +90,16 @@ class Status(object): ...@@ -90,7 +90,16 @@ class Status(object):
'unsubmitted': _('unanswered'), 'unsubmitted': _('unanswered'),
'queued': _('processing'), 'queued': _('processing'),
} }
tooltips = {
# Translators: these are tooltips that indicate the state of an assessment question
'correct': _('This is correct.'),
'incorrect': _('This is incorrect.'),
'unanswered': _('This is unanswered.'),
'unsubmitted': _('This is unanswered.'),
'queued': _('This is being processed.'),
}
self.display_name = names.get(status, unicode(status)) self.display_name = names.get(status, unicode(status))
self.display_tooltip = tooltips.get(status, u'')
self._status = status or '' self._status = status or ''
def __str__(self): def __str__(self):
......
<form class="choicegroup capa_inputtype" id="inputtype_${id}"> <form class="choicegroup capa_inputtype" id="inputtype_${id}">
<div class="indicator_container">
% if input_type == 'checkbox' or not value:
<span class="status ${status.classname if show_correctness != 'never' else 'unanswered'}"
id="status_${id}"
aria-describedby="inputtype_${id}">
<span class="sr">
%for choice_id, choice_description in choices:
% if choice_id in value:
${choice_description},
%endif
%endfor
-
${status.display_name}
</span>
</span>
% endif
</div>
<fieldset role="${input_type}group" aria-label="${label}"> <fieldset role="${input_type}group" aria-label="${label}">
% for choice_id, choice_description in choices: % for choice_id, choice_description in choices:
<label for="input_${id}_${choice_id}" <label for="input_${id}_${choice_id}"
## If the student has selected this choice... ## If the student has selected this choice...
...@@ -58,7 +39,21 @@ ...@@ -58,7 +39,21 @@
% endfor % endfor
<span id="answer_${id}"></span> <span id="answer_${id}"></span>
</fieldset> </fieldset>
<div class="indicator-container">
% if input_type == 'checkbox' or not value:
<span class="status ${status.classname if show_correctness != 'never' else 'unanswered'}" id="status_${id}" aria-describedby="inputtype_${id}" data-tooltip="${status.display_tooltip}">
<span class="sr">
%for choice_id, choice_description in choices:
% if choice_id in value:
${choice_description},
%endif
%endfor
-
${status.display_name}
</span>
</span>
% endif
</div>
% if show_correctness == "never" and (value or status not in ['unsubmitted']): % if show_correctness == "never" and (value or status not in ['unsubmitted']):
<div class="capa_alert">${submitted_message}</div> <div class="capa_alert">${submitted_message}</div>
%endif %endif
......
...@@ -9,11 +9,6 @@ ...@@ -9,11 +9,6 @@
<section id="choicetextinput_${id}" class="choicetextinput"> <section id="choicetextinput_${id}" class="choicetextinput">
<form class="choicetextgroup capa_inputtype" id="inputtype_${id}"> <form class="choicetextgroup capa_inputtype" id="inputtype_${id}">
<div class="script_placeholder" data-src="${STATIC_URL}js/capa/choicetextinput.js"/> <div class="script_placeholder" data-src="${STATIC_URL}js/capa/choicetextinput.js"/>
<div class="indicator_container">
% if input_type == 'checkbox' or not element_checked:
<span class="status ${status.classname}" id="status_${id}"></span>
% endif
</div>
<fieldset aria-label="${label}"> <fieldset aria-label="${label}">
% for choice_id, choice_description in choices: % for choice_id, choice_description in choices:
...@@ -62,6 +57,13 @@ ...@@ -62,6 +57,13 @@
<span id="answer_${id}"></span> <span id="answer_${id}"></span>
</fieldset> </fieldset>
<input class= "choicetextvalue" type="hidden" name="input_${id}{}" id="input_${id}" value="${value|h}" /> <input class= "choicetextvalue" type="hidden" name="input_${id}{}" id="input_${id}" value="${value|h}" />
<div class="indicator-container">
% if input_type == 'checkbox' or not element_checked:
<span class="status ${status.classname}" id="status_${id}"></span>
% endif
</div>
% if show_correctness == "never" and (value or status not in ['unsubmitted']): % if show_correctness == "never" and (value or status not in ['unsubmitted']):
<div class="capa_alert">${_(submitted_message)}</div> <div class="capa_alert">${_(submitted_message)}</div>
%endif %endif
......
...@@ -10,9 +10,11 @@ ...@@ -10,9 +10,11 @@
% endif % endif
/> />
<p class="status" id="${id}_status"> <span class="status" id="${id}_status" data-tooltip="${status.display_tooltip}">
<span class="sr">
${status.display_name} ${status.display_name}
</p> </span>
</span>
<div id="input_${id}_preview" class="equation"> <div id="input_${id}_preview" class="equation">
\[\] \[\]
......
...@@ -13,12 +13,13 @@ ...@@ -13,12 +13,13 @@
</select> </select>
<span id="answer_${id}"></span> <span id="answer_${id}"></span>
<div class="indicator-container">
<span class="status ${status.classname}" <span class="status ${status.classname}"
id="status_${id}" id="status_${id}"
aria-describedby="input_${id}"> aria-describedby="input_${id}" data-tooltip="${status.display_tooltip}">
<span class="sr">${value|h} - ${status.display_name}</span> <span class="sr">${value|h} - ${status.display_name}</span>
</span> </span>
</div>
% if msg: % if msg:
<span class="message">${msg|n}</span> <span class="message">${msg|n}</span>
% endif % endif
......
...@@ -27,10 +27,11 @@ ...@@ -27,10 +27,11 @@
/> />
${trailing_text | h} ${trailing_text | h}
<p class="status" <span class="status"
%if status != 'unsubmitted': %if status != 'unsubmitted':
%endif %endif
aria-describedby="input_${id}"> aria-describedby="input_${id}" data-tooltip="${status.display_tooltip}">
<span class="sr">
%if value: %if value:
${value|h} ${value|h}
% else: % else:
...@@ -38,7 +39,8 @@ ...@@ -38,7 +39,8 @@
%endif %endif
- -
${status.display_name} ${status.display_name}
</p> </span>
</span>
<p id="answer_${id}" class="answer"></p> <p id="answer_${id}" class="answer"></p>
......
...@@ -144,7 +144,7 @@ class ChoiceGroupTemplateTest(TemplateTestCase): ...@@ -144,7 +144,7 @@ class ChoiceGroupTemplateTest(TemplateTestCase):
# Should mark the entire problem correct # Should mark the entire problem correct
xml = self.render_to_xml(self.context) 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) self.assert_has_xpath(xml, xpath, self.context)
# Should NOT mark individual options # Should NOT mark individual options
...@@ -172,7 +172,7 @@ class ChoiceGroupTemplateTest(TemplateTestCase): ...@@ -172,7 +172,7 @@ class ChoiceGroupTemplateTest(TemplateTestCase):
for test_conditions in conditions: for test_conditions in conditions:
self.context.update(test_conditions) self.context.update(test_conditions)
xml = self.render_to_xml(self.context) 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) self.assert_has_xpath(xml, xpath, self.context)
# Should NOT mark individual options # Should NOT mark individual options
...@@ -204,7 +204,7 @@ class ChoiceGroupTemplateTest(TemplateTestCase): ...@@ -204,7 +204,7 @@ class ChoiceGroupTemplateTest(TemplateTestCase):
for test_conditions in conditions: for test_conditions in conditions:
self.context.update(test_conditions) self.context.update(test_conditions)
xml = self.render_to_xml(self.context) 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) self.assert_has_xpath(xml, xpath, self.context)
# Should NOT mark individual options # Should NOT mark individual options
...@@ -234,7 +234,7 @@ class ChoiceGroupTemplateTest(TemplateTestCase): ...@@ -234,7 +234,7 @@ class ChoiceGroupTemplateTest(TemplateTestCase):
self.assert_has_xpath(xml, xpath, self.context) self.assert_has_xpath(xml, xpath, self.context)
# Should NOT mark the whole problem # 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) self.assert_no_xpath(xml, xpath, self.context)
def test_option_marked_incorrect(self): def test_option_marked_incorrect(self):
...@@ -255,7 +255,7 @@ class ChoiceGroupTemplateTest(TemplateTestCase): ...@@ -255,7 +255,7 @@ class ChoiceGroupTemplateTest(TemplateTestCase):
self.assert_has_xpath(xml, xpath, self.context) self.assert_has_xpath(xml, xpath, self.context)
# Should NOT mark the whole problem # 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) self.assert_no_xpath(xml, xpath, self.context)
def test_never_show_correctness(self): def test_never_show_correctness(self):
...@@ -289,10 +289,10 @@ class ChoiceGroupTemplateTest(TemplateTestCase): ...@@ -289,10 +289,10 @@ class ChoiceGroupTemplateTest(TemplateTestCase):
xml = self.render_to_xml(self.context) xml = self.render_to_xml(self.context)
# Should NOT mark the entire problem correct/incorrect # 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) 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) self.assert_no_xpath(xml, xpath, self.context)
# Should NOT mark individual options # Should NOT mark individual options
...@@ -388,9 +388,9 @@ class TextlineTemplateTest(TemplateTestCase): ...@@ -388,9 +388,9 @@ class TextlineTemplateTest(TemplateTestCase):
xpath = "//div[@class='%s ']" % div_class xpath = "//div[@class='%s ']" % div_class
self.assert_has_xpath(xml, xpath, self.context) self.assert_has_xpath(xml, xpath, self.context)
# Expect that we get a <p> with class="status" # Expect that we get a <span> with class="status"
# (used to by CSS to draw the green check / red x) # (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) status_mark, exact=False)
def test_label(self): def test_label(self):
...@@ -848,7 +848,7 @@ class ChoiceTextGroupTemplateTest(TemplateTestCase): ...@@ -848,7 +848,7 @@ class ChoiceTextGroupTemplateTest(TemplateTestCase):
# Should mark the entire problem correct # Should mark the entire problem correct
xml = self.render_to_xml(self.context) 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) self.assert_has_xpath(xml, xpath, self.context)
# Should NOT mark individual options # Should NOT mark individual options
...@@ -875,7 +875,7 @@ class ChoiceTextGroupTemplateTest(TemplateTestCase): ...@@ -875,7 +875,7 @@ class ChoiceTextGroupTemplateTest(TemplateTestCase):
for test_conditions in conditions: for test_conditions in conditions:
self.context.update(test_conditions) self.context.update(test_conditions)
xml = self.render_to_xml(self.context) 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) self.assert_has_xpath(xml, xpath, self.context)
# Should NOT mark individual options # Should NOT mark individual options
...@@ -907,7 +907,7 @@ class ChoiceTextGroupTemplateTest(TemplateTestCase): ...@@ -907,7 +907,7 @@ class ChoiceTextGroupTemplateTest(TemplateTestCase):
for test_conditions in conditions: for test_conditions in conditions:
self.context.update(test_conditions) self.context.update(test_conditions)
xml = self.render_to_xml(self.context) 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) self.assert_has_xpath(xml, xpath, self.context)
# Should NOT mark individual options # Should NOT mark individual options
...@@ -937,7 +937,7 @@ class ChoiceTextGroupTemplateTest(TemplateTestCase): ...@@ -937,7 +937,7 @@ class ChoiceTextGroupTemplateTest(TemplateTestCase):
self.assert_has_xpath(xml, xpath, self.context) self.assert_has_xpath(xml, xpath, self.context)
# Should NOT mark the whole problem # 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) self.assert_no_xpath(xml, xpath, self.context)
def test_option_marked_incorrect(self): def test_option_marked_incorrect(self):
...@@ -957,7 +957,7 @@ class ChoiceTextGroupTemplateTest(TemplateTestCase): ...@@ -957,7 +957,7 @@ class ChoiceTextGroupTemplateTest(TemplateTestCase):
self.assert_has_xpath(xml, xpath, self.context) self.assert_has_xpath(xml, xpath, self.context)
# Should NOT mark the whole problem # 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) self.assert_no_xpath(xml, xpath, self.context)
def test_label(self): def test_label(self):
......
// 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); $annotation-yellow: rgba(255,255,10,0.3);
$color-copy-tip: rgb(100,100,100); $color-copy-tip: rgb(100,100,100);
$color-success: rgb(0, 136, 1); $correct: $green-d1;
$color-fail: rgb(212, 64, 64); $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 { h2 {
margin-top: 0; margin-top: 0;
margin-bottom: ($baseline*0.75); margin-bottom: ($baseline*0.75);
...@@ -24,12 +70,12 @@ h2 { ...@@ -24,12 +70,12 @@ h2 {
.feedback-hint-correct { .feedback-hint-correct {
margin-top: ($baseline/2); margin-top: ($baseline/2);
color: $color-success; color: $correct;
} }
.feedback-hint-incorrect { .feedback-hint-incorrect {
margin-top: ($baseline/2); margin-top: ($baseline/2);
color: $color-fail; color: $incorrect;
} }
.feedback-hint-text { .feedback-hint-text {
...@@ -55,10 +101,9 @@ h2 { ...@@ -55,10 +101,9 @@ h2 {
display: block; display: block;
} }
iframe[seamless]{ iframe[seamless]{
overflow: hidden; overflow: hidden;
padding: 0px; padding: 0;
border: 0px none transparent; border: 0px none transparent;
background-color: transparent; background-color: transparent;
} }
...@@ -68,13 +113,16 @@ iframe[seamless]{ ...@@ -68,13 +113,16 @@ iframe[seamless]{
} }
div.problem-progress { div.problem-progress {
@include padding-left($baseline/4);
@extend %t-ultralight;
display: inline-block; display: inline-block;
padding-left: ($baseline/4); color: $gray-d1;
color: #666;
font-weight: 100; font-weight: 100;
font-size: em(16); font-size: em(16);
} }
// +Problem - Base
// ====================
div.problem { div.problem {
@media print { @media print {
display: block; display: block;
...@@ -89,7 +137,11 @@ div.problem { ...@@ -89,7 +137,11 @@ div.problem {
.inline { .inline {
display: inline; display: inline;
} }
}
// +Problem - Choice Group
// ====================
div.problem {
.choicegroup { .choicegroup {
@include clearfix(); @include clearfix();
min-width: 100px; min-width: 100px;
...@@ -97,51 +149,98 @@ div.problem { ...@@ -97,51 +149,98 @@ div.problem {
width: 100px; width: 100px;
label { label {
@include float(left); @include box-sizing(border-box);
display: inline-block;
clear: both; 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 { &.choicegroup_correct {
&:after { @include status-icon($correct, "\f00c");
margin-left: ($baseline*0.75); border: 2px solid $correct;
content: url('../images/correct-icon.png');
// keep green for correct answers on hover.
&:hover {
border-color: $correct;
} }
} }
&.choicegroup_incorrect { &.choicegroup_incorrect {
&:after { @include status-icon($incorrect, "\f00d");
margin-left: ($baseline*0.75); border: 2px solid $incorrect;
content: url('../images/incorrect-icon.png');
// keep red for incorrect answers on hover.
&:hover {
border-color: $incorrect;
} }
} }
&:hover {
border: 2px solid $blue;
}
} }
.indicator_container { .indicator-container {
@include float(left); display: inline-block;
min-height: 1px;
width: 25px; width: 25px;
height: 1px;
@include margin-right(15px);
} }
fieldset { fieldset {
@include box-sizing(border-box); @include box-sizing(border-box);
margin: 0px 0px $baseline;
@include padding-left($baseline);
@include border-left(1px solid #ddd);
} }
input[type="radio"], input[type="radio"],
input[type="checkbox"] { input[type="checkbox"] {
@include float(left); @include margin(($baseline/4) ($baseline/2) ($baseline/4) ($baseline/4));
@include margin(4px, 8px, 0, 0);
} }
text { text {
@include margin-left(25px);
display: inline; 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 { ol.enumerate {
li { li {
&:before { &:before {
...@@ -187,17 +286,22 @@ div.problem { ...@@ -187,17 +286,22 @@ div.problem {
} }
} }
// known classes using this div: .indicator-container, moved to section above
div { div {
// TO-DO: Styling used by advanced capa problem types. Should be synced up to use .status class
p { p {
&.answer { &.answer {
margin-top: -2px; margin-top: -2px;
} }
&.status { &.status {
margin: 8px 0 0 $baseline/2; @include margin(8px, 0, 0, ($baseline/2));
text-indent: 100%; text-indent: 100%;
white-space: nowrap; white-space: nowrap;
overflow: hidden; overflow: hidden;
} }
span.clarification i { span.clarification i {
font-style: normal; font-style: normal;
&:hover { &:hover {
...@@ -224,7 +328,7 @@ div.problem { ...@@ -224,7 +328,7 @@ div.problem {
} }
input { input {
border-color: green; border-color: $correct;
} }
} }
...@@ -241,7 +345,7 @@ div.problem { ...@@ -241,7 +345,7 @@ div.problem {
} }
} }
&.incorrect, &.incomplete, &.ui-icon-close { &.ui-icon-close {
p.status { p.status {
display: inline-block; display: inline-block;
width: 20px; width: 20px;
...@@ -250,7 +354,21 @@ div.problem { ...@@ -250,7 +354,21 @@ div.problem {
} }
input { 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 { ...@@ -260,14 +378,14 @@ div.problem {
} }
p.answer { p.answer {
@include margin-left($baseline/2);
display: inline-block; display: inline-block;
margin-bottom: 0; margin-bottom: 0;
margin-left: $baseline/2;
&:before { &:before {
@extend %t-strong;
display: inline; display: inline;
content: "Answer: "; content: "Answer: ";
font-weight: bold;
} }
&:empty { &:empty {
...@@ -287,8 +405,8 @@ div.problem { ...@@ -287,8 +405,8 @@ div.problem {
} }
img.loading { img.loading {
@include padding-left($baseline/2);
display: inline-block; display: inline-block;
padding-left: ($baseline/2);
} }
span { span {
...@@ -312,8 +430,9 @@ div.problem { ...@@ -312,8 +430,9 @@ div.problem {
} }
} }
//TO-DO: review and deprecate all these styles within span {}
span { span {
&.unanswered, &.ui-icon-bullet { &.ui-icon-bullet {
display: inline-block; display: inline-block;
position: relative; position: relative;
top: 4px; top: 4px;
...@@ -331,7 +450,7 @@ div.problem { ...@@ -331,7 +450,7 @@ div.problem {
background: url('../images/spinner.gif') center center no-repeat; background: url('../images/spinner.gif') center center no-repeat;
} }
&.correct, &.ui-icon-check { &.ui-icon-check {
display: inline-block; display: inline-block;
position: relative; position: relative;
top: 3px; top: 3px;
...@@ -349,7 +468,7 @@ div.problem { ...@@ -349,7 +468,7 @@ div.problem {
background: url('../images/partially-correct-icon.png') center center no-repeat; background: url('../images/partially-correct-icon.png') center center no-repeat;
} }
&.incorrect, &.incomplete, &.ui-icon-close { &.incomplete, &.ui-icon-close {
display: inline-block; display: inline-block;
position: relative; position: relative;
top: 3px; top: 3px;
...@@ -360,8 +479,8 @@ div.problem { ...@@ -360,8 +479,8 @@ div.problem {
} }
.reload { .reload {
float:right; @include float(right);
margin: $baseline/2; margin: ($baseline/2);
} }
...@@ -457,15 +576,6 @@ div.problem { ...@@ -457,15 +576,6 @@ div.problem {
} }
} }
form.option-input {
margin: -$baseline/2 0 $baseline;
padding-bottom: $baseline;
select {
margin-right: flex-gutter();
}
}
ul { ul {
margin-bottom: lh(); margin-bottom: lh();
margin-left: .75em; margin-left: .75em;
...@@ -485,7 +595,8 @@ div.problem { ...@@ -485,7 +595,8 @@ div.problem {
} }
dl dt { dl dt {
font-weight: bold; @extend %t-strong;
} }
dl dd { dl dd {
...@@ -531,8 +642,8 @@ div.problem { ...@@ -531,8 +642,8 @@ div.problem {
} }
th { th {
@extend %t-strong;
text-align: left; text-align: left;
font-weight: bold;
} }
td { td {
...@@ -584,6 +695,93 @@ div.problem { ...@@ -584,6 +695,93 @@ div.problem {
white-space: pre; 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 { .CodeMirror {
border: 1px solid black; border: 1px solid black;
...@@ -634,47 +832,20 @@ div.problem { ...@@ -634,47 +832,20 @@ div.problem {
.CodeMirror-scroll { .CodeMirror-scroll {
margin-right: 0px; margin-right: 0px;
} }
}
hr { // +Problem - Actions
float: none; // ====================
clear: both; div.problem .action {
margin: 0 0 .75rem;
width: 100%;
height: 1px;
border: none;
background: #ddd;
color: #ddd;
}
.hidden {
display: none;
visibility: hidden;
}
#{$all-text-inputs} {
display: inline;
width: auto;
}
// this supports a deprecated element and should be removed once the center tag is removed
center {
display: block;
margin: lh() 0;
padding: lh();
border: 1px solid $gray-l3;
}
div.action {
margin-top: $baseline; margin-top: $baseline;
.save, .check, .show, .reset, .hint-button { .save, .check, .show, .reset, .hint-button {
@include margin-right($baseline/2);
margin-bottom: ($baseline/2);
height: ($baseline*2); height: ($baseline*2);
vertical-align: middle; vertical-align: middle;
text-transform: uppercase;
font-weight: 600; font-weight: 600;
@media print {
display: none;
}
} }
.save { .save {
...@@ -695,20 +866,52 @@ div.problem { ...@@ -695,20 +866,52 @@ div.problem {
// border-radius: 3px; // border-radius: 3px;
// padding: 8px 12px; // padding: 8px 12px;
// margin-top: ($baseline/2); // margin-top: ($baseline/2);
@include margin-left($baseline/2);
display: inline-block; display: inline-block;
margin-top: 8px; margin-top: 8px;
@include margin-left($baseline/2); color: $gray-d1;
color: #666;
font-style: italic; font-style: italic;
-webkit-font-smoothing: antialiased; -webkit-font-smoothing: antialiased;
} }
}
// +Problem - Misc, Unclassified Mess Part 2
// ====================
div.problem {
hr {
float: none;
clear: both;
margin: 0 0 .75rem;
width: 100%;
height: 1px;
border: none;
background: #ddd;
color: #ddd;
}
.hidden {
display: none;
visibility: hidden;
}
#{$all-text-inputs} {
display: inline;
width: auto;
}
// this supports a deprecated element and should be removed once the center tag is removed
center {
display: block;
margin: lh() 0;
padding: lh();
border: 1px solid $gray-l3;
} }
.detailed-solution { .detailed-solution {
> p:first-child { > p:first-child {
@extend %t-strong;
color: #aaa; color: #aaa;
text-transform: uppercase; text-transform: uppercase;
font-weight: bold;
font-style: normal; font-style: normal;
font-size: 0.9em; font-size: 0.9em;
} }
...@@ -720,9 +923,9 @@ div.problem { ...@@ -720,9 +923,9 @@ div.problem {
.detailed-targeted-feedback { .detailed-targeted-feedback {
> p:first-child { > p:first-child {
color: red; @extend %t-strong;
color: $incorrect;
text-transform: uppercase; text-transform: uppercase;
font-weight: bold;
font-style: normal; font-style: normal;
font-size: 0.9em; font-size: 0.9em;
} }
...@@ -734,9 +937,9 @@ div.problem { ...@@ -734,9 +937,9 @@ div.problem {
.detailed-targeted-feedback-correct { .detailed-targeted-feedback-correct {
> p:first-child { > p:first-child {
color: green; @extend %t-strong;
color: $correct;
text-transform: uppercase; text-transform: uppercase;
font-weight: bold;
font-style: normal; font-style: normal;
font-size: 0.9em; font-size: 0.9em;
} }
...@@ -777,11 +980,11 @@ div.problem { ...@@ -777,11 +980,11 @@ div.problem {
border: 1px solid $gray-l3; border: 1px solid $gray-l3;
h3 { h3 {
@extend %t-strong;
padding: 9px; padding: 9px;
border-bottom: 1px solid #e3e3e3; border-bottom: 1px solid #e3e3e3;
background: #eee; background: #eee;
text-shadow: 0 1px 0 $white; text-shadow: 0 1px 0 $white;
font-weight: bold;
font-size: em(16); font-size: em(16);
} }
...@@ -818,9 +1021,9 @@ div.problem { ...@@ -818,9 +1021,9 @@ div.problem {
margin-bottom: 12px; margin-bottom: 12px;
h3 { h3 {
@extend %t-strong;
color: #aaa; color: #aaa;
text-transform: uppercase; text-transform: uppercase;
font-weight: bold;
font-style: normal; font-style: normal;
font-size: 0.9em; font-size: 0.9em;
} }
...@@ -877,7 +1080,7 @@ div.problem { ...@@ -877,7 +1080,7 @@ div.problem {
} }
.shortform { .shortform {
font-weight: bold; @extend %t-strong;
} }
.longform { .longform {
...@@ -951,7 +1154,12 @@ div.problem { ...@@ -951,7 +1154,12 @@ div.problem {
} }
} }
} }
}
// +Problem - Rubric
// ====================
div.problem {
.rubric { .rubric {
tr { tr {
margin: ($baseline/2) 0; margin: ($baseline/2) 0;
...@@ -1004,16 +1212,20 @@ div.problem { ...@@ -1004,16 +1212,20 @@ div.problem {
display: none; display: none;
} }
} }
}
// +Problem - Annotation
// ====================
div.problem {
.annotation-input { .annotation-input {
margin: 0 0 1em 0; margin: 0 0 1em 0;
border: 1px solid $gray-l3; border: 1px solid $gray-l3;
border-radius: 1em; border-radius: 1em;
.annotation-header { .annotation-header {
@extend %t-strong;
padding: .5em 1em; padding: .5em 1em;
border-bottom: 1px solid $gray-l3; border-bottom: 1px solid $gray-l3;
font-weight: bold;
} }
.annotation-body { padding: .5em 1em; } .annotation-body { padding: .5em 1em; }
...@@ -1094,16 +1306,20 @@ div.problem { ...@@ -1094,16 +1306,20 @@ div.problem {
pre { background-color: $gray-l3; color: $black; } pre { background-color: $gray-l3; color: $black; }
&:before { &:before {
@extend %t-strong;
display: block; display: block;
content: "debug input value"; content: "debug input value";
text-transform: uppercase; text-transform: uppercase;
font-weight: bold;
font-size: 1.5em; font-size: 1.5em;
} }
} }
} }
}
.choicetextgroup{ // +Problem - Choice Text Group
// ====================
div.problem {
.choicetextgroup {
@extend .choicegroup; @extend .choicegroup;
input[type="text"]{ input[type="text"]{
...@@ -1114,7 +1330,7 @@ div.problem { ...@@ -1114,7 +1330,7 @@ div.problem {
@extend label.choicegroup_correct; @extend label.choicegroup_correct;
input[type="text"] { input[type="text"] {
border-color: green; border-color: $correct;
} }
} }
......
...@@ -323,7 +323,7 @@ describe 'Problem', -> ...@@ -323,7 +323,7 @@ describe 'Problem', ->
<div><p></p><span><section id="choicetextinput_1_2_1" class="choicetextinput"> <div><p></p><span><section id="choicetextinput_1_2_1" class="choicetextinput">
<form class="choicetextgroup capa_inputtype" id="inputtype_1_2_1"> <form class="choicetextgroup capa_inputtype" id="inputtype_1_2_1">
<div class="indicator_container"> <div class="indicator-container">
<span class="unanswered" style="display:inline-block;" id="status_1_2_1"></span> <span class="unanswered" style="display:inline-block;" id="status_1_2_1"></span>
</div> </div>
<fieldset> <fieldset>
......
...@@ -468,9 +468,9 @@ class @Problem ...@@ -468,9 +468,9 @@ class @Problem
# They should set handlers on each <input> to reset the whole. # They should set handlers on each <input> to reset the whole.
formulaequationinput: (element) -> formulaequationinput: (element) ->
$(element).find('input').on 'input', -> $(element).find('input').on 'input', ->
$p = $(element).find('p.status') $p = $(element).find('span.status')
`// Translators: the word unanswered here is about answering a problem the student must solve.` `// Translators: the word unanswered here is about answering a problem the student must solve.`
$p.parent().removeClass().addClass "unanswered" $p.parent().removeClass().addClass "unsubmitted"
choicegroup: (element) -> choicegroup: (element) ->
$element = $(element) $element = $(element)
...@@ -496,9 +496,9 @@ class @Problem ...@@ -496,9 +496,9 @@ class @Problem
textline: (element) -> textline: (element) ->
$(element).find('input').on 'input', -> $(element).find('input').on 'input', ->
$p = $(element).find('p.status') $p = $(element).find('span.status')
`// Translators: the word unanswered here is about answering a problem the student must solve.` `// Translators: the word unanswered here is about answering a problem the student must solve.`
$p.parent().removeClass("correct incorrect").addClass "unanswered" $p.parent().removeClass("correct incorrect").addClass "unsubmitted"
inputtypeSetupMethods: inputtypeSetupMethods:
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
// * +Content - Screenreader Text - Extend // * +Content - Screenreader Text - Extend
// * +Content - Text Wrap - Extend // * +Content - Text Wrap - Extend
// * +Content - Text Truncate - Extend // * +Content - Text Truncate - Extend
// * +Icon - Font-Awesome - Extend
// +Font Sizing - Mixin // +Font Sizing - Mixin
// ==================== // ====================
...@@ -428,3 +429,11 @@ ...@@ -428,3 +429,11 @@
text-overflow: ellipsis; text-overflow: ellipsis;
} }
// * +Icon - Font-Awesome - Extend
// ====================
%use-font-awesome {
display: inline-block;
font-family: FontAwesome;
-webkit-font-smoothing: antialiased;
speak: none;
}
...@@ -66,7 +66,7 @@ class ProblemPage(PageObject): ...@@ -66,7 +66,7 @@ class ProblemPage(PageObject):
""" """
Is there a "correct" status showing? Is there a "correct" status showing?
""" """
return self.q(css="div.problem div.capa_inputtype.textline div.correct p.status").is_present() return self.q(css="div.problem div.capa_inputtype.textline div.correct span.status").is_present()
def click_clarification(self, index=0): def click_clarification(self, index=0):
""" """
......
...@@ -176,11 +176,11 @@ Feature: LMS.Answer problems ...@@ -176,11 +176,11 @@ Feature: LMS.Answer problems
Scenario: I can view and hide the answer if the problem has it: Scenario: I can view and hide the answer if the problem has it:
Given I am viewing a "numerical" that shows the answer "always" Given I am viewing a "numerical" that shows the answer "always"
When I press the button with the label "Show Answer" When I press the button with the label "SHOW ANSWER"
Then the Show/Hide button label is "Hide Answer" Then the Show/Hide button label is "HIDE ANSWER"
And I should see "4.14159" somewhere in the page And I should see "4.14159" somewhere in the page
When I press the button with the label "Hide Answer" When I press the button with the label "HIDE ANSWER"
Then the Show/Hide button label is "Show Answer" Then the Show/Hide button label is "SHOW ANSWER"
And I should not see "4.14159" anywhere on the page And I should not see "4.14159" anywhere on the page
Scenario: I can see my score on a problem when I answer it and after I reset it Scenario: I can see my score on a problem when I answer it and after I reset it
......
...@@ -84,7 +84,7 @@ PROBLEM_DICT = { ...@@ -84,7 +84,7 @@ PROBLEM_DICT = {
'answer': 'correct string'}, 'answer': 'correct string'},
'correct': ['div.correct'], 'correct': ['div.correct'],
'incorrect': ['div.incorrect'], 'incorrect': ['div.incorrect'],
'unanswered': ['div.unanswered']}, 'unanswered': ['div.unanswered', 'div.unsubmitted']},
'numerical': { 'numerical': {
'factory': NumericalResponseXMLFactory(), 'factory': NumericalResponseXMLFactory(),
...@@ -95,7 +95,7 @@ PROBLEM_DICT = { ...@@ -95,7 +95,7 @@ PROBLEM_DICT = {
'math_display': True}, 'math_display': True},
'correct': ['div.correct'], 'correct': ['div.correct'],
'incorrect': ['div.incorrect'], 'incorrect': ['div.incorrect'],
'unanswered': ['div.unanswered']}, 'unanswered': ['div.unanswered', 'div.unsubmitted']},
'formula': { 'formula': {
'factory': FormulaResponseXMLFactory(), 'factory': FormulaResponseXMLFactory(),
...@@ -108,7 +108,7 @@ PROBLEM_DICT = { ...@@ -108,7 +108,7 @@ PROBLEM_DICT = {
'answer': 'x^2+2*x+y'}, 'answer': 'x^2+2*x+y'},
'correct': ['div.correct'], 'correct': ['div.correct'],
'incorrect': ['div.incorrect'], 'incorrect': ['div.incorrect'],
'unanswered': ['div.unanswered']}, 'unanswered': ['div.unanswered', 'div.unsubmitted']},
'script': { 'script': {
'factory': CustomResponseXMLFactory(), 'factory': CustomResponseXMLFactory(),
...@@ -129,7 +129,7 @@ PROBLEM_DICT = { ...@@ -129,7 +129,7 @@ PROBLEM_DICT = {
""")}, """)},
'correct': ['div.correct'], 'correct': ['div.correct'],
'incorrect': ['div.incorrect'], 'incorrect': ['div.incorrect'],
'unanswered': ['div.unanswered']}, 'unanswered': ['div.unanswered', 'div.unsubmitted']},
'code': { 'code': {
'factory': CodeResponseXMLFactory(), 'factory': CodeResponseXMLFactory(),
......
...@@ -28,7 +28,7 @@ h1.top-header { ...@@ -28,7 +28,7 @@ h1.top-header {
.light-button, a.light-button, // only used in askbot as classes .light-button, a.light-button, // only used in askbot as classes
.gray-button { .gray-button {
@include button(simple, #eee); @include button(simple, $gray-l5);
@extend .button-reset; @extend .button-reset;
font-size: em(13); font-size: em(13);
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment