Allow for modular css from XModules, and split capa module css out as a test

This commit is contained in:
Calen Pennington
2012-07-20 15:20:39 -04:00
parent 0a79130b11
commit 8a0270ea2b
14 changed files with 426 additions and 521 deletions

View File

@@ -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

View File

@@ -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)

View 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();
}
}

View File

@@ -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):
"""

View File

@@ -1,3 +1,3 @@
<section class="xmodule_display" data-type="${module_name}">
<section class="xmodule_display xmodule_${class_}" data-type="${module_name}">
${content}
</section>

View File

@@ -1,3 +1,3 @@
<section class="xmodule_edit" data-type="${module_name}">
<section class="xmodule_edit xmodule_${class_}" data-type="${module_name}">
${content}
</section>