Allow for modular css from XModules, and split capa module css out as a test
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
264
common/lib/xmodule/xmodule/css/capa/display.scss
Normal file
264
common/lib/xmodule/xmodule/css/capa/display.scss
Normal file
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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):
|
||||
"""
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
<section class="xmodule_display" data-type="${module_name}">
|
||||
<section class="xmodule_display xmodule_${class_}" data-type="${module_name}">
|
||||
${content}
|
||||
</section>
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
<section class="xmodule_edit" data-type="${module_name}">
|
||||
<section class="xmodule_edit xmodule_${class_}" data-type="${module_name}">
|
||||
${content}
|
||||
</section>
|
||||
|
||||
Reference in New Issue
Block a user