From 8a0270ea2b3d48f08535d22505c02b7433a56cd3 Mon Sep 17 00:00:00 2001 From: Calen Pennington Date: Fri, 20 Jul 2012 15:20:39 -0400 Subject: [PATCH] Allow for modular css from XModules, and split capa module css out as a test --- cms/envs/common.py | 96 ++++-- cms/static/sass/.gitignore | 1 + cms/static/sass/base-style.scss | 2 + common/djangoapps/xmodule_modifiers.py | 2 + common/lib/xmodule/xmodule/capa_module.py | 1 + .../lib/xmodule/xmodule/css/capa/display.scss | 264 ++++++++++++++++ common/lib/xmodule/xmodule/x_module.py | 91 +++--- common/templates/xmodule_display.html | 2 +- common/templates/xmodule_edit.html | 2 +- lms/envs/common.py | 54 +++- lms/static/sass/.gitignore | 1 + lms/static/sass/course.scss | 3 +- .../course/old/courseware/_courseware.scss | 136 -------- .../sass/course/old/courseware/_problems.scss | 292 ------------------ 14 files changed, 426 insertions(+), 521 deletions(-) create mode 100644 common/lib/xmodule/xmodule/css/capa/display.scss delete mode 100644 lms/static/sass/course/old/courseware/_problems.scss diff --git a/cms/envs/common.py b/cms/envs/common.py index 8a7422255a..582cb75abf 100644 --- a/cms/envs/common.py +++ b/cms/envs/common.py @@ -27,6 +27,7 @@ import errno import glob2 import lms.envs.common import hashlib +from collections import defaultdict from path import path ############################ FEATURE CONFIGURATION ############################# @@ -176,6 +177,69 @@ MESSAGE_STORAGE = 'django.contrib.messages.storage.session.SessionStorage' STATICFILES_STORAGE = 'pipeline.storage.PipelineCachedStorage' +# Load javascript and css from all of the available descriptors, and +# prep it for use in pipeline js +from xmodule.x_module import XModuleDescriptor +from xmodule.raw_module import RawDescriptor +js_file_dir = PROJECT_ROOT / "static" / "coffee" / "module" +css_file_dir = PROJECT_ROOT / "static" / "sass" / "module" +module_styles_path = css_file_dir / "_module-styles.scss" + +for dir_ in (js_file_dir, css_file_dir): + try: + os.makedirs(dir_) + except OSError as exc: + if exc.errno == errno.EEXIST: + pass + else: + raise + +js_fragments = set() +css_fragments = defaultdict(set) +for descriptor in XModuleDescriptor.load_classes() + [RawDescriptor]: + descriptor_js = descriptor.get_javascript() + module_js = descriptor.module_class.get_javascript() + + for filetype in ('coffee', 'js'): + for idx, fragment in enumerate(descriptor_js.get(filetype, []) + module_js.get(filetype, [])): + js_fragments.add((idx, filetype, fragment)) + + for class_ in (descriptor, descriptor.module_class): + fragments = class_.get_css() + for filetype in ('sass', 'scss', 'css'): + for idx, fragment in enumerate(fragments.get(filetype, [])): + css_fragments[idx, filetype, fragment].add(class_.__name__) + +module_js_sources = [] +for idx, filetype, fragment in sorted(js_fragments): + path = js_file_dir / "{idx}-{hash}.{type}".format( + idx=idx, + hash=hashlib.md5(fragment).hexdigest(), + type=filetype) + with open(path, 'w') as js_file: + js_file.write(fragment) + module_js_sources.append(path.replace(PROJECT_ROOT / "static/", "")) + +css_imports = defaultdict(set) +for (idx, filetype, fragment), classes in sorted(css_fragments.items()): + fragment_name = "{idx}-{hash}.{type}".format( + idx=idx, + hash=hashlib.md5(fragment).hexdigest(), + type=filetype) + # Prepend _ so that sass just includes the files into a single file + with open(css_file_dir / '_' + fragment_name, 'w') as js_file: + js_file.write(fragment) + + for class_ in classes: + css_imports[class_].add(fragment_name) + +with open(module_styles_path, 'w') as module_styles: + for class_, fragment_names in css_imports.items(): + imports = "\n".join('@import "{0}";'.format(name) for name in fragment_names) + module_styles.write(""".xmodule_{class_} {{ {imports} }}""".format( + class_=class_, imports=imports + )) + PIPELINE_CSS = { 'base-style': { 'source_filenames': ['sass/base-style.scss'], @@ -185,38 +249,6 @@ PIPELINE_CSS = { PIPELINE_ALWAYS_RECOMPILE = ['sass/base-style.scss'] -# Load javascript from all of the available descriptors, and -# prep it for use in pipeline js -from xmodule.x_module import XModuleDescriptor -from xmodule.raw_module import RawDescriptor -js_file_dir = PROJECT_ROOT / "static" / "coffee" / "module" -try: - os.makedirs(js_file_dir) -except OSError as exc: - if exc.errno == errno.EEXIST: - pass - else: - raise - -fragments = set() -for descriptor in XModuleDescriptor.load_classes() + [RawDescriptor]: - descriptor_js = descriptor.get_javascript() - module_js = descriptor.module_class.get_javascript() - - for filetype in ('coffee', 'js'): - for idx, fragment in enumerate(descriptor_js.get(filetype, []) + module_js.get(filetype, [])): - fragments.add((idx, filetype, fragment)) - -module_js_sources = [] -for idx, filetype, fragment in sorted(fragments): - path = os.path.join(js_file_dir, "{idx}-{hash}.{type}".format( - idx=idx, - hash=hashlib.md5(fragment).hexdigest(), - type=filetype)) - with open(path, 'w') as js_file: - js_file.write(fragment) - module_js_sources.append(path.replace(PROJECT_ROOT / "static/", "")) - PIPELINE_JS = { 'main': { 'source_filenames': [ diff --git a/cms/static/sass/.gitignore b/cms/static/sass/.gitignore index b3a5267117..c8578e8cd3 100644 --- a/cms/static/sass/.gitignore +++ b/cms/static/sass/.gitignore @@ -1 +1,2 @@ *.css +module diff --git a/cms/static/sass/base-style.scss b/cms/static/sass/base-style.scss index 6d45331576..35c02a4758 100644 --- a/cms/static/sass/base-style.scss +++ b/cms/static/sass/base-style.scss @@ -4,3 +4,5 @@ @import 'base', 'layout', 'content-types'; @import 'calendar'; @import 'section', 'unit'; + +@import 'module/module-styles.scss'; diff --git a/common/djangoapps/xmodule_modifiers.py b/common/djangoapps/xmodule_modifiers.py index a9314f4b43..d0d1e0be15 100644 --- a/common/djangoapps/xmodule_modifiers.py +++ b/common/djangoapps/xmodule_modifiers.py @@ -14,6 +14,7 @@ def wrap_xmodule(get_html, module, template): module: An XModule template: A template that takes the variables: content: the results of get_html, + class_: the module class name module_name: the js_module_name of the module """ @@ -21,6 +22,7 @@ def wrap_xmodule(get_html, module, template): def _get_html(): return render_to_string(template, { 'content': get_html(), + 'class_': module.__class__.__name__, 'module_name': module.js_module_name }) return _get_html diff --git a/common/lib/xmodule/xmodule/capa_module.py b/common/lib/xmodule/xmodule/capa_module.py index 980e1386c3..263e062887 100644 --- a/common/lib/xmodule/xmodule/capa_module.py +++ b/common/lib/xmodule/xmodule/capa_module.py @@ -75,6 +75,7 @@ class CapaModule(XModule): 'js': [resource_string(__name__, 'js/src/capa/imageinput.js'), resource_string(__name__, 'js/src/capa/schematic.js')]} js_module_name = "Problem" + css = {'scss': [resource_string(__name__, 'css/capa/display.scss')]} def __init__(self, system, location, definition, instance_state=None, shared_state=None, **kwargs): XModule.__init__(self, system, location, definition, instance_state, shared_state, **kwargs) diff --git a/common/lib/xmodule/xmodule/css/capa/display.scss b/common/lib/xmodule/xmodule/css/capa/display.scss new file mode 100644 index 0000000000..2088e8baa3 --- /dev/null +++ b/common/lib/xmodule/xmodule/css/capa/display.scss @@ -0,0 +1,264 @@ +h2 { +margin-top: 0; +margin-bottom: 15px; +width: flex-grid(2, 9); +padding-right: flex-gutter(9); +border-right: 1px dashed #ddd; +@include box-sizing(border-box); +display: table-cell; +vertical-align: top; + +&.problem-header { + section.staff { + margin-top: 30px; + font-size: 80%; + } +} + +@media screen and (max-width:1120px) { + display: block; + width: auto; + border-right: 0; +} + +@media print { + display: block; + width: auto; + border-right: 0; +} +} + +section.problem { +display: table-cell; +width: flex-grid(7, 9); +padding-left: flex-gutter(9); + +@media screen and (max-width:1120px) { + display: block; + width: auto; + padding: 0; +} + +@media print { + display: block; + width: auto; + padding: 0; + + canvas, img { + page-break-inside: avoid; + } +} + +div { + p.status { + text-indent: -9999px; + margin: -1px 0 0 10px; + } + + &.unanswered { + p.status { + @include inline-block(); + background: url('../images/unanswered-icon.png') center center no-repeat; + height: 14px; + width: 14px; + } + } + + &.correct, &.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; + } + } + + &.incorrect, &.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 { + @include inline-block(); + margin-bottom: 0; + margin-left: 10px; + + &:before { + content: "Answer: "; + font-weight: bold; + display: inline; + + } + &:empty { + &:before { + display: none; + } + } + } + + div.equation { + clear: both; + padding: 6px; + background: #eee; + + span { + margin-bottom: 0; + } + } + + 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; + } + + &.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; + } + } +} + +ul { + list-style: disc outside none; + margin-bottom: lh(); + margin-left: .75em; + margin-left: .75rem; +} + +ol { + list-style: decimal outside none; + margin-bottom: lh(); + margin-left: .75em; + margin-left: .75rem; +} + +dl { + line-height: 1.4em; +} + +dl dt { + font-weight: bold; +} + +dl dd { + margin-bottom: 0; +} + +dd { + margin-left: .5em; + margin-left: .5rem; +} + +li { + line-height: 1.4em; + margin-bottom: lh(.5); + + &:last-child { + margin-bottom: 0; + } +} + +p { + margin-bottom: lh(); +} + +table { + margin-bottom: lh(); + width: 100%; + // border: 1px solid #ddd; + border-collapse: collapse; + + th { + // border-bottom: 2px solid #ccc; + font-weight: bold; + text-align: left; + } + + td { + // border: 1px solid #ddd; + } + + caption, th, td { + padding: .25em .75em .25em 0; + padding: .25rem .75rem .25rem 0; + } + + caption { + background: #f1f1f1; + margin-bottom: .75em; + margin-bottom: .75rem; + padding: .75em 0; + padding: .75rem 0; + } + + tr, td, th { + vertical-align: middle; + } + +} + +hr { + background: #ddd; + border: none; + clear: both; + color: #ddd; + float: none; + height: 1px; + margin: 0 0 .75rem; + width: 100%; +} + +.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; + border: 1px solid #ccc; + padding: lh(); +} +} diff --git a/common/lib/xmodule/xmodule/x_module.py b/common/lib/xmodule/xmodule/x_module.py index fa904367f0..c504320f7c 100644 --- a/common/lib/xmodule/xmodule/x_module.py +++ b/common/lib/xmodule/xmodule/x_module.py @@ -64,7 +64,50 @@ class Plugin(object): in pkg_resources.iter_entry_points(cls.entry_point)] -class XModule(object): +class HTMLSnippet(object): + """ + A base class defining an interface for an object that is able to present an + html snippet, along with associated javascript and css + """ + + js = {} + js_module_name = None + + css = {} + + @classmethod + def get_javascript(cls): + """ + Return a dictionary containing some of the following keys: + coffee: A list of coffeescript fragments that should be compiled and + placed on the page + js: A list of javascript fragments that should be included on the page + + All of these will be loaded onto the page in the CMS + """ + return cls.js + + @classmethod + def get_css(cls): + """ + Return a dictionary containing some of the following keys: + css: A list of css fragments that should be applied to the html contents + of the snippet + sass: A list of sass fragments that should be applied to the html contents + of the snippet + scss: A list of scss fragments that should be applied to the html contents + of the snippet + """ + return cls.css + + def get_html(self): + """ + Return the html used to edit this module + """ + raise NotImplementedError("get_html() must be provided by specific modules") + + +class XModule(HTMLSnippet): ''' Implements a generic learning module. Subclasses must at a minimum provide a definition for get_html in order to be displayed to users. @@ -77,9 +120,6 @@ class XModule(object): # if the icon class depends on the data in the module icon_class = 'other' - js = {} - js_module_name = None - def __init__(self, system, location, definition, instance_state=None, shared_state=None, **kwargs): ''' Construct a new xmodule @@ -196,28 +236,8 @@ class XModule(object): get is a dictionary-like object ''' return "" - # ================================== HTML INTERFACE DEFINITIONS ====================== - @classmethod - def get_javascript(cls): - """ - Return a dictionary containing some of the following keys: - coffee: A list of coffeescript fragments that should be compiled and - placed on the page - js: A list of javascript fragments that should be included on the page - - All of these will be loaded onto the page in the LMS - """ - return cls.js - - def get_html(self): - ''' HTML, as shown in the browser. This is the only method that must be implemented - ''' - raise NotImplementedError("get_html must be defined for all XModules that appear on the screen. Not defined in %s" % self.__class__.__name__) - - - -class XModuleDescriptor(Plugin): +class XModuleDescriptor(Plugin, HTMLSnippet): """ An XModuleDescriptor is a specification for an element of a course. This could be a problem, an organizational element (a group of content), or a segment of video, @@ -228,8 +248,6 @@ class XModuleDescriptor(Plugin): and can generate XModules (which do know about student state). """ entry_point = "xmodule.v1" - js = {} - js_module_name = None module_class = XModule # A list of metadata that this module can inherit from its parent module @@ -404,25 +422,6 @@ class XModuleDescriptor(Plugin): """ raise NotImplementedError('Modules must implement export_to_xml to enable xml export') - # ================================== HTML INTERFACE DEFINITIONS ====================== - @classmethod - def get_javascript(cls): - """ - Return a dictionary containing some of the following keys: - coffee: A list of coffeescript fragments that should be compiled and - placed on the page - js: A list of javascript fragments that should be included on the page - - All of these will be loaded onto the page in the CMS - """ - return cls.js - - def get_html(self): - """ - Return the html used to edit this module - """ - raise NotImplementedError("get_html() must be provided by specific modules") - # =============================== Testing =================================== def get_sample_state(self): """ diff --git a/common/templates/xmodule_display.html b/common/templates/xmodule_display.html index 09af18ebb8..7fd7a08cb2 100644 --- a/common/templates/xmodule_display.html +++ b/common/templates/xmodule_display.html @@ -1,3 +1,3 @@ -
+
${content}
diff --git a/common/templates/xmodule_edit.html b/common/templates/xmodule_edit.html index 1828c82987..25341b8902 100644 --- a/common/templates/xmodule_edit.html +++ b/common/templates/xmodule_edit.html @@ -1,3 +1,3 @@ -
+
${content}
diff --git a/lms/envs/common.py b/lms/envs/common.py index 19d87e8eb7..643c43a561 100644 --- a/lms/envs/common.py +++ b/lms/envs/common.py @@ -24,6 +24,7 @@ import tempfile import glob2 import errno import hashlib +from collections import defaultdict import djcelery from path import path @@ -336,31 +337,60 @@ main_vendor_js = [ from xmodule.x_module import XModuleDescriptor from xmodule.hidden_module import HiddenDescriptor js_file_dir = PROJECT_ROOT / "static" / "coffee" / "module" -try: - os.makedirs(js_file_dir) -except OSError as exc: - if exc.errno == errno.EEXIST: - pass - else: - raise +css_file_dir = PROJECT_ROOT / "static" / "sass" / "module" +module_styles_path = css_file_dir / "_module-styles.scss" -fragments = set() +for dir_ in (js_file_dir, css_file_dir): + try: + os.makedirs(dir_) + except OSError as exc: + if exc.errno == errno.EEXIST: + pass + else: + raise + +js_fragments = set() +css_fragments = defaultdict(set) for descriptor in XModuleDescriptor.load_classes() + [HiddenDescriptor]: module_js = descriptor.module_class.get_javascript() for filetype in ('coffee', 'js'): for idx, fragment in enumerate(module_js.get(filetype, [])): - fragments.add((idx, filetype, fragment)) + js_fragments.add((idx, filetype, fragment)) + + module_css = descriptor.module_class.get_css() + for filetype in ('sass', 'scss', 'css'): + for idx, fragment in enumerate(module_css.get(filetype, [])): + css_fragments[idx, filetype, fragment].add(descriptor.module_class.__name__) module_js_sources = [] -for idx, filetype, fragment in sorted(fragments): - path = os.path.join(js_file_dir, "{idx}-{hash}.{type}".format( +for idx, filetype, fragment in sorted(js_fragments): + path = js_file_dir / "{idx}-{hash}.{type}".format( idx=idx, hash=hashlib.md5(fragment).hexdigest(), - type=filetype)) + type=filetype) with open(path, 'w') as js_file: js_file.write(fragment) module_js_sources.append(path.replace(PROJECT_ROOT / "static/", "")) +css_imports = defaultdict(set) +for (idx, filetype, fragment), classes in sorted(css_fragments.items()): + fragment_name = "{idx}-{hash}.{type}".format( + idx=idx, + hash=hashlib.md5(fragment).hexdigest(), + type=filetype) + # Prepend _ so that sass just includes the files into a single file + with open(css_file_dir / '_' + fragment_name, 'w') as js_file: + js_file.write(fragment) + + for class_ in classes: + css_imports[class_].add(fragment_name) + +with open(module_styles_path, 'w') as module_styles: + for class_, fragment_names in css_imports.items(): + imports = "\n".join('@import "{0}";'.format(name) for name in fragment_names) + module_styles.write(""".xmodule_{class_} {{ {imports} }}""".format( + class_=class_, imports=imports + )) PIPELINE_JS = { 'application': { diff --git a/lms/static/sass/.gitignore b/lms/static/sass/.gitignore index b3a5267117..c8578e8cd3 100644 --- a/lms/static/sass/.gitignore +++ b/lms/static/sass/.gitignore @@ -1 +1,2 @@ *.css +module diff --git a/lms/static/sass/course.scss b/lms/static/sass/course.scss index 81d1e34a0e..0f78da572f 100644 --- a/lms/static/sass/course.scss +++ b/lms/static/sass/course.scss @@ -20,4 +20,5 @@ @import 'course/old/courseware/sidebar'; @import 'course/old/courseware/video'; @import 'course/old/courseware/amplifier'; -@import 'course/old/courseware/problems'; + +@import 'module/module-styles.scss'; diff --git a/lms/static/sass/course/old/courseware/_courseware.scss b/lms/static/sass/course/old/courseware/_courseware.scss index 8de09d0adb..d7911f49ed 100644 --- a/lms/static/sass/course/old/courseware/_courseware.scss +++ b/lms/static/sass/course/old/courseware/_courseware.scss @@ -49,142 +49,6 @@ div.course-wrapper { } } - .problem-set { - position: relative; - @extend .clearfix; - - h2 { - margin-top: 0; - margin-bottom: 15px; - width: flex-grid(2, 9); - padding-right: flex-gutter(9); - border-right: 1px dashed #ddd; - @include box-sizing(border-box); - display: table-cell; - vertical-align: top; - - &.problem-header { - section.staff { - margin-top: 30px; - font-size: 80%; - } - } - - @media screen and (max-width:1120px) { - display: block; - width: auto; - border-right: 0; - } - - @media print { - display: block; - width: auto; - border-right: 0; - } - } - - section.problem { - display: table-cell; - width: flex-grid(7, 9); - padding-left: flex-gutter(9); - - @media screen and (max-width:1120px) { - display: block; - width: auto; - padding: 0; - } - - @media print { - display: block; - width: auto; - padding: 0; - - canvas, img { - page-break-inside: avoid; - } - } - - 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; - } - - &.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; - } - } - } - - div { - > span { - display: block; - margin-bottom: lh(.5); - - &[answer] { - border-top: 1px solid #ededed; - border-bottom: 1px solid #ededed; - background: #f3f3f3; - margin: 0 (-(lh())); - padding: lh(.5) lh(); - } - } - } - - input[type="text"] { - display: inline-block; - width: 50%; - } - - center { - display: block; - margin: lh() 0; - border: 1px solid #ccc; - padding: lh(); - } - - section.action { - margin-top: lh(); - - input[type="button"] { - padding: lh(.4) lh(); - text-shadow: 0 -1px 0 #666; - } - } - } - - section.problems-wrapper, div#seq_content { - @extend .problem-set; - } - - section.problems-wrapper { - display: table; - width: 100%; - - @media screen and (max-width:1120px) { - display: block; - width: auto; - } - } - div#seq_content { h1 { background: none; diff --git a/lms/static/sass/course/old/courseware/_problems.scss b/lms/static/sass/course/old/courseware/_problems.scss deleted file mode 100644 index dc66b2e743..0000000000 --- a/lms/static/sass/course/old/courseware/_problems.scss +++ /dev/null @@ -1,292 +0,0 @@ -section.problem-set { - position: relative; - @extend .clearfix; - - h2 { - margin-top: 0; - margin-bottom: 15px; - width: flex-grid(2, 9); - padding-right: flex-gutter(9); - border-right: 1px dashed #ddd; - @include box-sizing(border-box); - display: table-cell; - vertical-align: top; - - &.problem-header { - section.staff { - margin-top: 30px; - font-size: 80%; - } - } - - @media screen and (max-width:1120px) { - display: block; - width: auto; - border-right: 0; - } - - @media print { - display: block; - width: auto; - border-right: 0; - } - } - - section.problem { - display: table-cell; - width: flex-grid(7, 9); - padding-left: flex-gutter(9); - - @media screen and (max-width:1120px) { - display: block; - width: auto; - padding: 0; - } - - @media print { - display: block; - width: auto; - padding: 0; - - canvas, img { - page-break-inside: avoid; - } - } - - div { - p.status { - text-indent: -9999px; - margin: -1px 0 0 10px; - } - - &.unanswered { - p.status { - @include inline-block(); - background: url('../images/unanswered-icon.png') center center no-repeat; - height: 14px; - width: 14px; - } - } - - &.correct, &.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; - } - } - - &.incorrect, &.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 { - @include inline-block(); - margin-bottom: 0; - margin-left: 10px; - - &:before { - content: "Answer: "; - font-weight: bold; - display: inline; - - } - &:empty { - &:before { - display: none; - } - } - } - - div.equation { - clear: both; - padding: 6px; - background: #eee; - - span { - margin-bottom: 0; - } - } - - 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; - } - - &.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; - } - } - } - - ul { - list-style: disc outside none; - margin-bottom: lh(); - margin-left: .75em; - margin-left: .75rem; - } - - ol { - list-style: decimal outside none; - margin-bottom: lh(); - margin-left: .75em; - margin-left: .75rem; - } - - dl { - line-height: 1.4em; - } - - dl dt { - font-weight: bold; - } - - dl dd { - margin-bottom: 0; - } - - dd { - margin-left: .5em; - margin-left: .5rem; - } - - li { - line-height: 1.4em; - margin-bottom: lh(.5); - - &:last-child { - margin-bottom: 0; - } - } - - p { - margin-bottom: lh(); - } - - table { - margin-bottom: lh(); - width: 100%; - // border: 1px solid #ddd; - border-collapse: collapse; - - th { - // border-bottom: 2px solid #ccc; - font-weight: bold; - text-align: left; - } - - td { - // border: 1px solid #ddd; - } - - caption, th, td { - padding: .25em .75em .25em 0; - padding: .25rem .75rem .25rem 0; - } - - caption { - background: #f1f1f1; - margin-bottom: .75em; - margin-bottom: .75rem; - padding: .75em 0; - padding: .75rem 0; - } - - tr, td, th { - vertical-align: middle; - } - - } - - hr { - background: #ddd; - border: none; - clear: both; - color: #ddd; - float: none; - height: 1px; - margin: 0 0 .75rem; - width: 100%; - } - - .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; - border: 1px solid #ccc; - padding: lh(); - } - } - - section.action { - margin-top: lh(.5); - - input[type="button"] { - padding: lh(.4) lh(); - text-shadow: 0 -1px 0 #666; - } - } -} - -section.problems-wrapper, div#seq_content { - @extend .problem-set; -} - -section.problems-wrapper { - display: table; - width: 100%; - - @media screen and (max-width:1120px) { - display: block; - width: auto; - } -}