Make discussion js work for cms as well as lms so that inline discussion xmodules load
This commit is contained in:
@@ -23,12 +23,9 @@ import sys
|
||||
import tempfile
|
||||
import os.path
|
||||
import os
|
||||
import errno
|
||||
import glob2
|
||||
import lms.envs.common
|
||||
import hashlib
|
||||
from collections import defaultdict
|
||||
from path import path
|
||||
from xmodule.static_content import write_descriptor_styles, write_descriptor_js, write_module_js, write_module_styles
|
||||
|
||||
############################ FEATURE CONFIGURATION #############################
|
||||
|
||||
@@ -194,67 +191,27 @@ 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
|
||||
from xmodule.error_module import ErrorDescriptor
|
||||
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"
|
||||
from rooted_paths import rooted_glob, remove_root
|
||||
|
||||
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
|
||||
write_descriptor_styles(PROJECT_ROOT / "static/sass/descriptor", [RawDescriptor, ErrorDescriptor])
|
||||
write_module_styles(PROJECT_ROOT / "static/sass/module", [RawDescriptor, ErrorDescriptor])
|
||||
|
||||
js_fragments = set()
|
||||
css_fragments = defaultdict(set)
|
||||
for _, descriptor in XModuleDescriptor.load_classes() + [(None, RawDescriptor), (None, ErrorDescriptor)]:
|
||||
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
|
||||
))
|
||||
descriptor_js = remove_root(
|
||||
PROJECT_ROOT / 'static',
|
||||
write_descriptor_js(
|
||||
PROJECT_ROOT / "static/coffee/descriptor",
|
||||
[RawDescriptor, ErrorDescriptor]
|
||||
)
|
||||
)
|
||||
module_js = remove_root(
|
||||
PROJECT_ROOT / 'static',
|
||||
write_module_js(
|
||||
PROJECT_ROOT / "static/coffee/module",
|
||||
[RawDescriptor, ErrorDescriptor]
|
||||
)
|
||||
)
|
||||
|
||||
PIPELINE_CSS = {
|
||||
'base-style': {
|
||||
@@ -267,23 +224,18 @@ PIPELINE_ALWAYS_RECOMPILE = ['sass/base-style.scss']
|
||||
|
||||
PIPELINE_JS = {
|
||||
'main': {
|
||||
'source_filenames': [
|
||||
pth.replace(COMMON_ROOT / 'static/', '')
|
||||
for pth
|
||||
in glob2.glob(COMMON_ROOT / 'static/coffee/src/**/*.coffee')
|
||||
] + [
|
||||
pth.replace(PROJECT_ROOT / 'static/', '')
|
||||
for pth
|
||||
in glob2.glob(PROJECT_ROOT / 'static/coffee/src/**/*.coffee')
|
||||
] + ['js/base.js'],
|
||||
'source_filenames': sorted(
|
||||
rooted_glob(COMMON_ROOT / 'static/', 'coffee/src/**/*.coffee') +
|
||||
rooted_glob(PROJECT_ROOT / 'static/', 'coffee/src/**/*.coffee')
|
||||
) + ['js/base.js'],
|
||||
'output_filename': 'js/cms-application.js',
|
||||
},
|
||||
'module-js': {
|
||||
'source_filenames': module_js_sources,
|
||||
'source_filenames': descriptor_js + module_js,
|
||||
'output_filename': 'js/cms-modules.js',
|
||||
},
|
||||
'spec': {
|
||||
'source_filenames': [pth.replace(PROJECT_ROOT / 'static/', '') for pth in glob2.glob(PROJECT_ROOT / 'static/coffee/spec/**/*.coffee')],
|
||||
'source_filenames': sorted(rooted_glob(PROJECT_ROOT / 'static/', 'coffee/spec/**/*.coffee')),
|
||||
'output_filename': 'js/cms-spec.js'
|
||||
}
|
||||
}
|
||||
|
||||
1
cms/static/coffee/.gitignore
vendored
1
cms/static/coffee/.gitignore
vendored
@@ -1,2 +1,3 @@
|
||||
*.js
|
||||
descriptor
|
||||
module
|
||||
|
||||
1
cms/static/sass/.gitignore
vendored
1
cms/static/sass/.gitignore
vendored
@@ -1,2 +1,3 @@
|
||||
*.css
|
||||
descriptor
|
||||
module
|
||||
|
||||
@@ -8,3 +8,4 @@
|
||||
@import 'section', 'unit', 'index';
|
||||
|
||||
@import 'module/module-styles.scss';
|
||||
@import 'descriptor/module-styles.scss';
|
||||
|
||||
18
common/lib/rooted_paths.py
Normal file
18
common/lib/rooted_paths.py
Normal file
@@ -0,0 +1,18 @@
|
||||
import glob2
|
||||
|
||||
|
||||
def rooted_glob(root, glob):
|
||||
"""
|
||||
Returns the results of running `glob` rooted in the directory `root`.
|
||||
All returned paths are relative to `root`.
|
||||
|
||||
Uses glob2 globbing
|
||||
"""
|
||||
return remove_root(root, glob2.glob('{root}/{glob}'.format(root=root, glob=glob)))
|
||||
|
||||
|
||||
def remove_root(root, paths):
|
||||
"""
|
||||
Returns `paths` made relative to `root`
|
||||
"""
|
||||
return [pth.replace(root + '/', '') for pth in paths]
|
||||
@@ -17,7 +17,7 @@ class @Video
|
||||
@embed()
|
||||
else
|
||||
window.onYouTubePlayerAPIReady = =>
|
||||
$('.course-content .video').each ->
|
||||
@el.each ->
|
||||
$(this).data('video').embed()
|
||||
|
||||
youtubeId: (speed)->
|
||||
|
||||
107
common/lib/xmodule/xmodule/static_content.py
Normal file
107
common/lib/xmodule/xmodule/static_content.py
Normal file
@@ -0,0 +1,107 @@
|
||||
"""
|
||||
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(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(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(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(""".xmodule_{class_} {{ {imports} }}""".format(
|
||||
class_=class_, imports=imports
|
||||
))
|
||||
|
||||
|
||||
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
|
||||
@@ -21,10 +21,7 @@ Longer TODO:
|
||||
import sys
|
||||
import os
|
||||
import tempfile
|
||||
import glob2
|
||||
import errno
|
||||
import hashlib
|
||||
from collections import defaultdict
|
||||
from xmodule.static_content import write_module_styles, write_module_js
|
||||
|
||||
import djcelery
|
||||
from path import path
|
||||
@@ -412,6 +409,33 @@ MIDDLEWARE_CLASSES = (
|
||||
|
||||
STATICFILES_STORAGE = 'pipeline.storage.PipelineCachedStorage'
|
||||
|
||||
from xmodule.hidden_module import HiddenDescriptor
|
||||
from rooted_paths import rooted_glob, remove_root
|
||||
|
||||
write_module_styles(PROJECT_ROOT / 'static/sass/module', [HiddenDescriptor])
|
||||
module_js = remove_root(
|
||||
PROJECT_ROOT / 'static',
|
||||
write_module_js(PROJECT_ROOT / 'static/coffee/module', [HiddenDescriptor])
|
||||
)
|
||||
|
||||
courseware_js = (
|
||||
[
|
||||
'coffee/src/' + pth + '.coffee'
|
||||
for pth in ['courseware', 'histogram', 'navigation', 'time']
|
||||
] +
|
||||
sorted(rooted_glob(PROJECT_ROOT / 'static', 'coffee/src/modules/**/*.coffee'))
|
||||
)
|
||||
|
||||
main_vendor_js = [
|
||||
'js/vendor/jquery.min.js',
|
||||
'js/vendor/jquery-ui.min.js',
|
||||
'js/vendor/jquery.cookie.js',
|
||||
'js/vendor/jquery.qtip.min.js',
|
||||
'js/vendor/swfobject/swfobject.js',
|
||||
]
|
||||
|
||||
discussion_js = sorted(rooted_glob(PROJECT_ROOT / 'static', 'coffee/src/discussion/**/*.coffee'))
|
||||
|
||||
PIPELINE_CSS = {
|
||||
'application': {
|
||||
'source_filenames': ['sass/application.scss'],
|
||||
@@ -428,99 +452,14 @@ PIPELINE_CSS = {
|
||||
}
|
||||
|
||||
PIPELINE_ALWAYS_RECOMPILE = ['sass/application.scss', 'sass/ie.scss', 'sass/course.scss']
|
||||
|
||||
courseware_only_js = [
|
||||
PROJECT_ROOT / 'static/coffee/src/' + pth + '.coffee'
|
||||
for pth
|
||||
in ['courseware', 'histogram', 'navigation', 'time']
|
||||
]
|
||||
courseware_only_js += [
|
||||
pth for pth
|
||||
in glob2.glob(PROJECT_ROOT / 'static/coffee/src/modules/**/*.coffee')
|
||||
]
|
||||
|
||||
main_vendor_js = [
|
||||
'js/vendor/jquery.min.js',
|
||||
'js/vendor/jquery-ui.min.js',
|
||||
'js/vendor/jquery.cookie.js',
|
||||
'js/vendor/jquery.qtip.min.js',
|
||||
'js/vendor/swfobject/swfobject.js',
|
||||
]
|
||||
|
||||
discussion_js = sorted(glob2.glob(PROJECT_ROOT / 'static/coffee/src/discussion/**/*.coffee'))
|
||||
|
||||
# Load javascript from all of the available xmodules, and
|
||||
# prep it for use in pipeline js
|
||||
from xmodule.x_module import XModuleDescriptor
|
||||
from xmodule.hidden_module import HiddenDescriptor
|
||||
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() + [(None, HiddenDescriptor)]:
|
||||
module_js = descriptor.module_class.get_javascript()
|
||||
for filetype in ('coffee', 'js'):
|
||||
for idx, fragment in enumerate(module_js.get(filetype, [])):
|
||||
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(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_JS = {
|
||||
'application': {
|
||||
# Application will contain all paths not in courseware_only_js
|
||||
'source_filenames': [
|
||||
pth.replace(COMMON_ROOT / 'static/', '')
|
||||
for pth
|
||||
in sorted(glob2.glob(COMMON_ROOT / 'static/coffee/src/**/*.coffee'))
|
||||
] + [
|
||||
pth.replace(PROJECT_ROOT / 'static/', '')
|
||||
for pth in sorted(glob2.glob(PROJECT_ROOT / 'static/coffee/src/**/*.coffee'))\
|
||||
if pth not in courseware_only_js and pth not in discussion_js
|
||||
] + [
|
||||
'source_filenames': sorted(
|
||||
set(rooted_glob(COMMON_ROOT / 'static', 'coffee/src/**/*.coffee') +
|
||||
rooted_glob(PROJECT_ROOT / 'static', 'coffee/src/**/*.coffee')) -
|
||||
set(courseware_js + discussion_js)
|
||||
) + [
|
||||
'js/form.ext.js',
|
||||
'js/my_courses_dropdown.js',
|
||||
'js/toggle_login_modal.js',
|
||||
@@ -530,7 +469,7 @@ PIPELINE_JS = {
|
||||
'output_filename': 'js/lms-application.js'
|
||||
},
|
||||
'courseware': {
|
||||
'source_filenames': [pth.replace(PROJECT_ROOT / 'static/', '') for pth in courseware_only_js],
|
||||
'source_filenames': courseware_js,
|
||||
'output_filename': 'js/lms-courseware.js'
|
||||
},
|
||||
'main_vendor': {
|
||||
@@ -538,15 +477,15 @@ PIPELINE_JS = {
|
||||
'output_filename': 'js/lms-main_vendor.js',
|
||||
},
|
||||
'module-js': {
|
||||
'source_filenames': module_js_sources,
|
||||
'source_filenames': module_js,
|
||||
'output_filename': 'js/lms-modules.js',
|
||||
},
|
||||
'spec': {
|
||||
'source_filenames': [pth.replace(PROJECT_ROOT / 'static/', '') for pth in glob2.glob(PROJECT_ROOT / 'static/coffee/spec/**/*.coffee')],
|
||||
'source_filenames': sorted(rooted_glob(PROJECT_ROOT / 'static/', 'coffee/spec/**/*.coffee')),
|
||||
'output_filename': 'js/lms-spec.js'
|
||||
},
|
||||
'discussion' : {
|
||||
'source_filenames': [pth.replace(PROJECT_ROOT / 'static/', '') for pth in discussion_js],
|
||||
'discussion': {
|
||||
'source_filenames': discussion_js,
|
||||
'output_filename': 'js/discussion.js'
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user