108 lines
3.3 KiB
Python
108 lines
3.3 KiB
Python
"""
|
|
This module has utility functions for gathering up the static content
|
|
that is defined by XModules and XModuleDescriptors (javascript and css)
|
|
"""
|
|
|
|
import hashlib
|
|
import os
|
|
import errno
|
|
from collections import defaultdict
|
|
|
|
from .x_module import XModuleDescriptor
|
|
|
|
|
|
def write_module_styles(output_root, extra_descriptors):
|
|
return _write_styles('.xmodule_display', output_root, _list_modules(extra_descriptors))
|
|
|
|
|
|
def write_module_js(output_root, extra_descriptors):
|
|
return _write_js(output_root, _list_modules(extra_descriptors))
|
|
|
|
|
|
def write_descriptor_styles(output_root, extra_descriptors):
|
|
return _write_styles('.xmodule_edit', output_root, _list_descriptors(extra_descriptors))
|
|
|
|
|
|
def write_descriptor_js(output_root, extra_descriptors):
|
|
return _write_js(output_root, _list_descriptors(extra_descriptors))
|
|
|
|
|
|
def _list_descriptors(extra_descriptors):
|
|
return [
|
|
desc for desc in [
|
|
desc for (_, desc) in XModuleDescriptor.load_classes()
|
|
] + extra_descriptors
|
|
]
|
|
|
|
|
|
def _list_modules(extra_descriptors):
|
|
return [
|
|
desc.module_class
|
|
for desc
|
|
in _list_descriptors(extra_descriptors)
|
|
]
|
|
|
|
|
|
def _ensure_dir(dir_):
|
|
try:
|
|
os.makedirs(dir_)
|
|
except OSError as exc:
|
|
if exc.errno == errno.EEXIST:
|
|
pass
|
|
else:
|
|
raise
|
|
|
|
|
|
def _write_styles(selector, output_root, classes):
|
|
_ensure_dir(output_root)
|
|
|
|
css_fragments = defaultdict(set)
|
|
for class_ in classes:
|
|
class_css = class_.get_css()
|
|
for filetype in ('sass', 'scss', 'css'):
|
|
for idx, fragment in enumerate(class_css.get(filetype, [])):
|
|
css_fragments[idx, filetype, fragment].add(class_.__name__)
|
|
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(output_root / '_' + fragment_name, 'w') as css_file:
|
|
css_file.write(fragment)
|
|
|
|
for class_ in classes:
|
|
css_imports[class_].add(fragment_name)
|
|
|
|
with open(output_root / '_module-styles.scss', '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("""{selector}.xmodule_{class_} {{ {imports} }}""".format(
|
|
class_=class_, imports=imports, selector=selector
|
|
))
|
|
|
|
|
|
def _write_js(output_root, classes):
|
|
_ensure_dir(output_root)
|
|
|
|
js_fragments = set()
|
|
for class_ in classes:
|
|
module_js = class_.get_javascript()
|
|
for filetype in ('coffee', 'js'):
|
|
for idx, fragment in enumerate(module_js.get(filetype, [])):
|
|
js_fragments.add((idx, filetype, fragment))
|
|
|
|
module_js = []
|
|
for idx, filetype, fragment in sorted(js_fragments):
|
|
path = output_root / "{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.append(path)
|
|
|
|
return module_js
|