Commit 12cc4a19 by Calen Pennington

Merge pull request #1224 from cpennington/lms-xblock-js-execution

Add an XBlock javascript runtime, and use it to run XModules
parents 3605ebd0 61a03197
...@@ -42,7 +42,7 @@ def add_a_multi_step_component(step, is_advanced, category): ...@@ -42,7 +42,7 @@ def add_a_multi_step_component(step, is_advanced, category):
def see_a_multi_step_component(step, category): def see_a_multi_step_component(step, category):
# Wait for all components to finish rendering # Wait for all components to finish rendering
selector = 'li.component section.xmodule_display' selector = 'li.component section.xblock-student_view'
world.wait_for(lambda _: len(world.css_find(selector)) == len(step.hashes)) world.wait_for(lambda _: len(world.css_find(selector)) == len(step.hashes))
for idx, step_hash in enumerate(step.hashes): for idx, step_hash in enumerate(step.hashes):
......
...@@ -8,7 +8,7 @@ from django.core.urlresolvers import reverse ...@@ -8,7 +8,7 @@ from django.core.urlresolvers import reverse
from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import login_required
from mitxmako.shortcuts import render_to_response, render_to_string from mitxmako.shortcuts import render_to_response, render_to_string
from xmodule_modifiers import replace_static_urls, wrap_xmodule from xmodule_modifiers import replace_static_urls, wrap_xblock
from xmodule.error_module import ErrorDescriptor from xmodule.error_module import ErrorDescriptor
from xmodule.errortracker import exc_info_to_str from xmodule.errortracker import exc_info_to_str
from xmodule.exceptions import NotFoundError, ProcessingError from xmodule.exceptions import NotFoundError, ProcessingError
...@@ -77,7 +77,7 @@ def preview_component(request, location): ...@@ -77,7 +77,7 @@ def preview_component(request, location):
component = modulestore().get_item(location) component = modulestore().get_item(location)
# Wrap the generated fragment in the xmodule_editor div so that the javascript # Wrap the generated fragment in the xmodule_editor div so that the javascript
# can bind to it correctly # can bind to it correctly
component.runtime.wrappers.append(partial(wrap_xmodule, 'xmodule_edit.html')) component.runtime.wrappers.append(wrap_xblock)
try: try:
content = component.render('studio_view').content content = component.render('studio_view').content
...@@ -105,11 +105,6 @@ def preview_module_system(request, preview_id, descriptor): ...@@ -105,11 +105,6 @@ def preview_module_system(request, preview_id, descriptor):
course_id = get_course_for_item(descriptor.location).location.course_id course_id = get_course_for_item(descriptor.location).location.course_id
if descriptor.location.category == 'static_tab':
wrapper_template = 'xmodule_tab_display.html'
else:
wrapper_template = 'xmodule_display.html'
return ModuleSystem( return ModuleSystem(
static_url=settings.STATIC_URL, static_url=settings.STATIC_URL,
ajax_url=reverse('preview_dispatch', args=[preview_id, descriptor.location.url(), '']).rstrip('/'), ajax_url=reverse('preview_dispatch', args=[preview_id, descriptor.location.url(), '']).rstrip('/'),
...@@ -129,7 +124,7 @@ def preview_module_system(request, preview_id, descriptor): ...@@ -129,7 +124,7 @@ def preview_module_system(request, preview_id, descriptor):
# Set up functions to modify the fragment produced by student_view # Set up functions to modify the fragment produced by student_view
wrappers=( wrappers=(
# This wrapper wraps the module in the template specified above # This wrapper wraps the module in the template specified above
partial(wrap_xmodule, wrapper_template), partial(wrap_xblock, display_name_only=descriptor.location.category == 'static_tab'),
# This wrapper replaces urls in the output that start with /static # This wrapper replaces urls in the output that start with /static
# with the correct course-specific url for the static content # with the correct course-specific url for the static content
......
...@@ -16,6 +16,7 @@ requirejs.config({ ...@@ -16,6 +16,7 @@ requirejs.config({
"jquery.fileupload": "xmodule_js/common_static/js/vendor/jQuery-File-Upload/js/jquery.fileupload", "jquery.fileupload": "xmodule_js/common_static/js/vendor/jQuery-File-Upload/js/jquery.fileupload",
"jquery.iframe-transport": "xmodule_js/common_static/js/vendor/jQuery-File-Upload/js/jquery.iframe-transport", "jquery.iframe-transport": "xmodule_js/common_static/js/vendor/jQuery-File-Upload/js/jquery.iframe-transport",
"jquery.inputnumber": "xmodule_js/common_static/js/vendor/html5-input-polyfills/number-polyfill", "jquery.inputnumber": "xmodule_js/common_static/js/vendor/html5-input-polyfills/number-polyfill",
"jquery.immediateDescendents": "xmodule_js/common_static/coffee/src/jquery.immediateDescendents",
"datepair": "xmodule_js/common_static/js/vendor/timepicker/datepair", "datepair": "xmodule_js/common_static/js/vendor/timepicker/datepair",
"date": "xmodule_js/common_static/js/vendor/date", "date": "xmodule_js/common_static/js/vendor/date",
"underscore": "xmodule_js/common_static/js/vendor/underscore-min", "underscore": "xmodule_js/common_static/js/vendor/underscore-min",
...@@ -25,6 +26,7 @@ requirejs.config({ ...@@ -25,6 +26,7 @@ requirejs.config({
"tinymce": "xmodule_js/common_static/js/vendor/tiny_mce/tiny_mce", "tinymce": "xmodule_js/common_static/js/vendor/tiny_mce/tiny_mce",
"jquery.tinymce": "xmodule_js/common_static/js/vendor/tiny_mce/jquery.tinymce", "jquery.tinymce": "xmodule_js/common_static/js/vendor/tiny_mce/jquery.tinymce",
"xmodule": "xmodule_js/src/xmodule", "xmodule": "xmodule_js/src/xmodule",
"xblock": "xmodule_js/common_static/coffee/src/xblock",
"utility": "xmodule_js/common_static/js/src/utility", "utility": "xmodule_js/common_static/js/src/utility",
"sinon": "xmodule_js/common_static/js/vendor/sinon-1.7.1", "sinon": "xmodule_js/common_static/js/vendor/sinon-1.7.1",
"squire": "xmodule_js/common_static/js/vendor/Squire", "squire": "xmodule_js/common_static/js/vendor/Squire",
...@@ -129,6 +131,14 @@ requirejs.config({ ...@@ -129,6 +131,14 @@ requirejs.config({
deps: ["jasmine"], deps: ["jasmine"],
exports: "AsyncSpec" exports: "AsyncSpec"
}, },
"xblock/core": {
exports: "XBlock",
deps: ["jquery", "jquery.immediateDescendents"]
},
"xblock/runtime.v1": {
exports: "XBlock",
deps: ["xblock/core"]
},
"coffee/src/main": { "coffee/src/main": {
deps: ["coffee/src/ajax_prefix"] deps: ["coffee/src/ajax_prefix"]
......
...@@ -16,6 +16,7 @@ requirejs.config({ ...@@ -16,6 +16,7 @@ requirejs.config({
"jquery.fileupload": "xmodule_js/common_static/js/vendor/jQuery-File-Upload/js/jquery.fileupload", "jquery.fileupload": "xmodule_js/common_static/js/vendor/jQuery-File-Upload/js/jquery.fileupload",
"jquery.iframe-transport": "xmodule_js/common_static/js/vendor/jQuery-File-Upload/js/jquery.iframe-transport", "jquery.iframe-transport": "xmodule_js/common_static/js/vendor/jQuery-File-Upload/js/jquery.iframe-transport",
"jquery.inputnumber": "xmodule_js/common_static/js/vendor/html5-input-polyfills/number-polyfill", "jquery.inputnumber": "xmodule_js/common_static/js/vendor/html5-input-polyfills/number-polyfill",
"jquery.immediateDescendents": "xmodule_js/common_static/coffee/src/jquery.immediateDescendents",
"datepair": "xmodule_js/common_static/js/vendor/timepicker/datepair", "datepair": "xmodule_js/common_static/js/vendor/timepicker/datepair",
"date": "xmodule_js/common_static/js/vendor/date", "date": "xmodule_js/common_static/js/vendor/date",
"underscore": "xmodule_js/common_static/js/vendor/underscore-min", "underscore": "xmodule_js/common_static/js/vendor/underscore-min",
...@@ -25,6 +26,7 @@ requirejs.config({ ...@@ -25,6 +26,7 @@ requirejs.config({
"tinymce": "xmodule_js/common_static/js/vendor/tiny_mce/tiny_mce", "tinymce": "xmodule_js/common_static/js/vendor/tiny_mce/tiny_mce",
"jquery.tinymce": "xmodule_js/common_static/js/vendor/tiny_mce/jquery.tinymce", "jquery.tinymce": "xmodule_js/common_static/js/vendor/tiny_mce/jquery.tinymce",
"xmodule": "xmodule_js/src/xmodule", "xmodule": "xmodule_js/src/xmodule",
"xblock": "xmodule_js/common_static/coffee/src/xblock",
"utility": "xmodule_js/common_static/js/src/utility", "utility": "xmodule_js/common_static/js/src/utility",
"sinon": "xmodule_js/common_static/js/vendor/sinon-1.7.1", "sinon": "xmodule_js/common_static/js/vendor/sinon-1.7.1",
"squire": "xmodule_js/common_static/js/vendor/Squire", "squire": "xmodule_js/common_static/js/vendor/Squire",
...@@ -129,6 +131,14 @@ requirejs.config({ ...@@ -129,6 +131,14 @@ requirejs.config({
deps: ["jasmine"], deps: ["jasmine"],
exports: "AsyncSpec" exports: "AsyncSpec"
}, },
"xblock/core": {
exports: "XBlock",
deps: ["jquery", "jquery.immediateDescendents"]
},
"xblock/runtime.v1": {
exports: "XBlock",
deps: ["xblock/core"]
},
"coffee/src/main": { "coffee/src/main": {
deps: ["coffee/src/ajax_prefix"] deps: ["coffee/src/ajax_prefix"]
......
...@@ -19,7 +19,7 @@ define ["coffee/src/views/module_edit", "xmodule"], (ModuleEdit) -> ...@@ -19,7 +19,7 @@ define ["coffee/src/views/module_edit", "xmodule"], (ModuleEdit) ->
<a href="#" class="delete-button"><span class="delete-icon white"></span>Delete</a> <a href="#" class="delete-button"><span class="delete-icon white"></span>Delete</a>
</div> </div>
<span class="drag-handle"></span> <span class="drag-handle"></span>
<section class="xmodule_display xmodule_stub" data-type="StubModule"> <section class="xblock xblock-student_view xmodule_display xmodule_stub" data-type="StubModule">
<div id="stub-module-content"/> <div id="stub-module-content"/>
</section> </section>
</li> </li>
...@@ -66,10 +66,9 @@ define ["coffee/src/views/module_edit", "xmodule"], (ModuleEdit) -> ...@@ -66,10 +66,9 @@ define ["coffee/src/views/module_edit", "xmodule"], (ModuleEdit) ->
describe "loadDisplay", -> describe "loadDisplay", ->
beforeEach -> beforeEach ->
spyOn(XModule, 'loadModule') spyOn(XBlock, 'initializeBlock')
@moduleEdit.loadDisplay() @moduleEdit.loadDisplay()
it "loads the .xmodule-display inside the module editor", -> it "loads the .xmodule-display inside the module editor", ->
expect(XModule.loadModule).toHaveBeenCalled() expect(XBlock.initializeBlock).toHaveBeenCalled()
expect(XModule.loadModule.mostRecentCall.args[0]).toBe($('.xmodule_display')) expect(XBlock.initializeBlock.mostRecentCall.args[0]).toBe($('.xblock-student_view'))
define ["backbone", "jquery", "underscore", "gettext", "xmodule", define ["backbone", "jquery", "underscore", "gettext", "xblock/runtime.v1",
"js/views/feedback_notification", "js/views/metadata", "js/collections/metadata" "js/views/feedback_notification", "js/views/metadata", "js/collections/metadata"
"jquery.inputnumber"], "jquery.inputnumber", "xmodule"],
(Backbone, $, _, gettext, XModule, NotificationView, MetadataView, MetadataCollection) -> (Backbone, $, _, gettext, XBlock, NotificationView, MetadataView, MetadataCollection) ->
class ModuleEdit extends Backbone.View class ModuleEdit extends Backbone.View
tagName: 'li' tagName: 'li'
className: 'component' className: 'component'
...@@ -21,11 +21,11 @@ define ["backbone", "jquery", "underscore", "gettext", "xmodule", ...@@ -21,11 +21,11 @@ define ["backbone", "jquery", "underscore", "gettext", "xmodule",
$component_editor: => @$el.find('.component-editor') $component_editor: => @$el.find('.component-editor')
loadDisplay: -> loadDisplay: ->
XModule.loadModule(@$el.find('.xmodule_display')) XBlock.initializeBlock(@$el.find('.xblock-student_view'))
loadEdit: -> loadEdit: ->
if not @module if not @module
@module = XModule.loadModule(@$el.find('.xmodule_edit')) @module = XBlock.initializeBlock(@$el.find('.xblock-studio_view'))
# At this point, metadata-edit.html will be loaded, and the metadata (as JSON) is available. # At this point, metadata-edit.html will be loaded, and the metadata (as JSON) is available.
metadataEditor = @$el.find('.metadata_edit') metadataEditor = @$el.find('.metadata_edit')
metadataData = metadataEditor.data('metadata') metadataData = metadataEditor.data('metadata')
......
...@@ -54,6 +54,8 @@ lib_paths: ...@@ -54,6 +54,8 @@ lib_paths:
- xmodule_js/common_static/js/vendor/date.js - xmodule_js/common_static/js/vendor/date.js
- xmodule_js/common_static/js/vendor/domReady.js - xmodule_js/common_static/js/vendor/domReady.js
- xmodule_js/common_static/js/vendor/jquery.smooth-scroll.min.js - xmodule_js/common_static/js/vendor/jquery.smooth-scroll.min.js
- xmodule_js/common_static/coffee/src/jquery.immediateDescendents.js
- xmodule_js/common_static/coffee/src/xblock
# Paths to source JavaScript files # Paths to source JavaScript files
src_paths: src_paths:
......
...@@ -49,6 +49,7 @@ lib_paths: ...@@ -49,6 +49,7 @@ lib_paths:
- xmodule_js/common_static/js/vendor/jasmine.async.js - xmodule_js/common_static/js/vendor/jasmine.async.js
- xmodule_js/common_static/js/vendor/CodeMirror/codemirror.js - xmodule_js/common_static/js/vendor/CodeMirror/codemirror.js
- xmodule_js/src/xmodule.js - xmodule_js/src/xmodule.js
- xmodule_js/common_static/coffee/src/jquery.immediateDescendents.js
- xmodule_js/common_static/js/test/i18n.js - xmodule_js/common_static/js/test/i18n.js
# Paths to source JavaScript files # Paths to source JavaScript files
......
...@@ -54,6 +54,7 @@ var require = { ...@@ -54,6 +54,7 @@ var require = {
"jquery.fileupload": "js/vendor/jQuery-File-Upload/js/jquery.fileupload", "jquery.fileupload": "js/vendor/jQuery-File-Upload/js/jquery.fileupload",
"jquery.iframe-transport": "js/vendor/jQuery-File-Upload/js/jquery.iframe-transport", "jquery.iframe-transport": "js/vendor/jQuery-File-Upload/js/jquery.iframe-transport",
"jquery.inputnumber": "js/vendor/html5-input-polyfills/number-polyfill", "jquery.inputnumber": "js/vendor/html5-input-polyfills/number-polyfill",
"jquery.immediateDescendents": "coffee/src/jquery.immediateDescendents",
"datepair": "js/vendor/timepicker/datepair", "datepair": "js/vendor/timepicker/datepair",
"date": "js/vendor/date", "date": "js/vendor/date",
"tzAbbr": "js/vendor/tzAbbr", "tzAbbr": "js/vendor/tzAbbr",
...@@ -64,6 +65,7 @@ var require = { ...@@ -64,6 +65,7 @@ var require = {
"tinymce": "js/vendor/tiny_mce/tiny_mce", "tinymce": "js/vendor/tiny_mce/tiny_mce",
"jquery.tinymce": "js/vendor/tiny_mce/jquery.tinymce", "jquery.tinymce": "js/vendor/tiny_mce/jquery.tinymce",
"xmodule": "/xmodule/xmodule", "xmodule": "/xmodule/xmodule",
"xblock": "coffee/src/xblock",
"utility": "js/src/utility", "utility": "js/src/utility",
"draggabilly": "js/vendor/draggabilly.pkgd", "draggabilly": "js/vendor/draggabilly.pkgd",
...@@ -159,6 +161,14 @@ var require = { ...@@ -159,6 +161,14 @@ var require = {
"mathjax": { "mathjax": {
exports: "MathJax" exports: "MathJax"
}, },
"xblock/core": {
exports: "XBlock",
deps: ["jquery", "jquery.immediateDescendents"]
},
"xblock/runtime.v1": {
exports: "XBlock",
deps: ["xblock/core"]
},
"coffee/src/main": { "coffee/src/main": {
deps: ["coffee/src/ajax_prefix"] deps: ["coffee/src/ajax_prefix"]
......
<section class="xmodule_display xmodule_${class_}" data-type="${module_name}">
${display_name}
</section>
...@@ -115,6 +115,7 @@ def wait_for_js_variable_truthy(variable): ...@@ -115,6 +115,7 @@ def wait_for_js_variable_truthy(variable):
def wait_for_xmodule(): def wait_for_xmodule():
"Wait until the XModule Javascript has loaded on the page." "Wait until the XModule Javascript has loaded on the page."
world.wait_for_js_variable_truthy("XModule") world.wait_for_js_variable_truthy("XModule")
world.wait_for_js_variable_truthy("XBlock")
@world.absorb @world.absorb
......
...@@ -14,6 +14,7 @@ from xblock.fragment import Fragment ...@@ -14,6 +14,7 @@ from xblock.fragment import Fragment
from xmodule.seq_module import SequenceModule from xmodule.seq_module import SequenceModule
from xmodule.vertical_module import VerticalModule from xmodule.vertical_module import VerticalModule
from xmodule.x_module import shim_xmodule_js, XModuleDescriptor, XModule
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
...@@ -28,32 +29,50 @@ def wrap_fragment(fragment, new_content): ...@@ -28,32 +29,50 @@ def wrap_fragment(fragment, new_content):
return wrapper_frag return wrapper_frag
def wrap_xmodule(template, block, view, frag, context): # pylint: disable=unused-argument def wrap_xblock(block, view, frag, context, display_name_only=False): # pylint: disable=unused-argument
""" """
Wraps the results of get_html in a standard <section> with identifying Wraps the results of rendering an XBlock view in a standard <section> with identifying
data so that the appropriate javascript module can be loaded onto it. data so that the appropriate javascript module can be loaded onto it.
get_html: An XModule.get_html method or an XModuleDescriptor.get_html method :param block: An XBlock (that may be an XModule or XModuleDescriptor)
module: An XModule :param view: The name of the view that rendered the fragment being wrapped
template: A template that takes the variables: :param frag: The :class:`Fragment` to be wrapped
content: the results of get_html, :param context: The context passed to the view being rendered
display_name: the display name of the xmodule, if available (None otherwise) :param display_name_only: If true, don't render the fragment content at all.
class_: the module class name Instead, just render the `display_name` of `block`
module_name: the js_module_name of the module
""" """
# If XBlock generated this class, then use the first baseclass # If any mixins have been applied, then use the unmixed class
# as the name (since that's the original, unmixed class)
class_name = getattr(block, 'unmixed_class', block.__class__).__name__ class_name = getattr(block, 'unmixed_class', block.__class__).__name__
data = {}
css_classes = ['xblock', 'xblock-' + view]
if isinstance(block, (XModule, XModuleDescriptor)):
if view == 'student_view':
# The block is acting as an XModule
css_classes.append('xmodule_display')
elif view == 'studio_view':
# The block is acting as an XModuleDescriptor
css_classes.append('xmodule_edit')
css_classes.append('xmodule_' + class_name)
data['type'] = block.js_module_name
shim_xmodule_js(frag)
if frag.js_init_fn:
data['init'] = frag.js_init_fn
data['runtime-version'] = frag.js_init_version
data['usage-id'] = block.scope_ids.usage_id
data['block-type'] = block.scope_ids.block_type
template_context = { template_context = {
'content': frag.content, 'content': block.display_name if display_name_only else frag.content,
'display_name': block.display_name, 'classes': css_classes,
'class_': class_name, 'data_attributes': ' '.join('data-{}="{}"'.format(key, value) for key, value in data.items()),
'module_name': block.js_module_name,
} }
return wrap_fragment(frag, render_to_string(template, template_context)) return wrap_fragment(frag, render_to_string('xblock_wrapper.html', template_context))
def replace_jump_to_id_urls(course_id, jump_to_id_base_url, block, view, frag, context): # pylint: disable=unused-argument def replace_jump_to_id_urls(course_id, jump_to_id_base_url, block, view, frag, context): # pylint: disable=unused-argument
......
<section class='xmodule_display xmodule_AnnotatableModule' data-type='Annotatable'> <section class='xblock xblock-student_view xmodule_display xmodule_AnnotatableModule' data-type='Annotatable'>
<div class="annotatable-wrapper"> <div class="annotatable-wrapper">
<div class="annotatable-header"> <div class="annotatable-header">
<div class="annotatable-title">First Annotation Exercise</div> <div class="annotatable-title">First Annotation Exercise</div>
......
<section class="course-content"> <section class="course-content">
<section class="xmodule_display xmodule_CombinedOpenEndedModule" data-type="CombinedOpenEnded"> <section class="xblock xblock-student_view xmodule_display xmodule_CombinedOpenEndedModule" data-type="CombinedOpenEnded">
<section id="combined-open-ended" class="combined-open-ended" data-ajax-url="/courses/MITx/6.002x/2012_Fall/modx/i4x://MITx/6.002x/combinedopenended/CombinedOE" data-allow_reset="False" data-state="assessing" data-task-count="2" data-task-number="1"> <section id="combined-open-ended" class="combined-open-ended" data-ajax-url="/courses/MITx/6.002x/2012_Fall/modx/i4x://MITx/6.002x/combinedopenended/CombinedOE" data-allow_reset="False" data-state="assessing" data-task-count="2" data-task-number="1">
<h2>Problem 1</h2> <h2>Problem 1</h2>
<div class="status-container"> <div class="status-container">
......
<li id="vert-0" data-id="i4x://Me/19.002/crowdsource_hinter/crowdsource_hinter_def7a1142dd0"> <li id="vert-0" data-id="i4x://Me/19.002/crowdsource_hinter/crowdsource_hinter_def7a1142dd0">
<section class="xmodule_display xmodule_CrowdsourceHinterModule" data-type="Hinter" id="hinter-root"> <section class="xblock xblock-student_view xmodule_display xmodule_CrowdsourceHinterModule" data-type="Hinter" id="hinter-root">
<section class="xmodule_display xmodule_CapaModule" data-type="Problem" id="problem"> <section class="xblock xblock-student_view xmodule_display xmodule_CapaModule" data-type="Problem" id="problem">
<section id="problem_i4x-Me-19_002-problem-Numerical_Input" class="problems-wrapper" data-problem-id="i4x://Me/19.002/problem/Numerical_Input" data-url="/courses/Me/19.002/Test/modx/i4x://Me/19.002/problem/Numerical_Input" data-progress_status="done" data-progress_detail="1/1"> <section id="problem_i4x-Me-19_002-problem-Numerical_Input" class="problems-wrapper" data-problem-id="i4x://Me/19.002/problem/Numerical_Input" data-url="/courses/Me/19.002/Test/modx/i4x://Me/19.002/problem/Numerical_Input" data-progress_status="done" data-progress_detail="1/1">
......
<section class='xmodule_display xmodule_CapaModule' data-type='Problem'> <section class='xblock xblock-student_view xmodule_display xmodule_CapaModule' data-type='Problem'>
<section id='problem_1' <section id='problem_1'
class='problems-wrapper' class='problems-wrapper'
data-problem-id='i4x://edX/101/problem/Problem1' data-problem-id='i4x://edX/101/problem/Problem1'
......
...@@ -2,7 +2,7 @@ describe 'Annotatable', -> ...@@ -2,7 +2,7 @@ describe 'Annotatable', ->
beforeEach -> beforeEach ->
loadFixtures 'annotatable.html' loadFixtures 'annotatable.html'
describe 'constructor', -> describe 'constructor', ->
el = $('.xmodule_display.xmodule_AnnotatableModule') el = $('.xblock-student_view.xmodule_AnnotatableModule')
beforeEach -> beforeEach ->
@annotatable = new Annotatable(el) @annotatable = new Annotatable(el)
it 'works', -> it 'works', ->
......
...@@ -25,7 +25,7 @@ describe 'Problem', -> ...@@ -25,7 +25,7 @@ describe 'Problem', ->
it 'set the element from html', -> it 'set the element from html', ->
@problem999 = new Problem (" @problem999 = new Problem ("
<section class='xmodule_display xmodule_CapaModule' data-type='Problem'> <section class='xblock xblock-student_view xmodule_display xmodule_CapaModule' data-type='Problem'>
<section id='problem_999' <section id='problem_999'
class='problems-wrapper' class='problems-wrapper'
data-problem-id='i4x://edX/999/problem/Quiz' data-problem-id='i4x://edX/999/problem/Quiz'
...@@ -36,14 +36,14 @@ describe 'Problem', -> ...@@ -36,14 +36,14 @@ describe 'Problem', ->
expect(@problem999.element_id).toBe 'problem_999' expect(@problem999.element_id).toBe 'problem_999'
it 'set the element from loadFixtures', -> it 'set the element from loadFixtures', ->
@problem1 = new Problem($('.xmodule_display')) @problem1 = new Problem($('.xblock-student_view'))
expect(@problem1.element_id).toBe 'problem_1' expect(@problem1.element_id).toBe 'problem_1'
describe 'bind', -> describe 'bind', ->
beforeEach -> beforeEach ->
spyOn window, 'update_schematics' spyOn window, 'update_schematics'
MathJax.Hub.getAllJax.andReturn [@stubbedJax] MathJax.Hub.getAllJax.andReturn [@stubbedJax]
@problem = new Problem($('.xmodule_display')) @problem = new Problem($('.xblock-student_view'))
it 'set mathjax typeset', -> it 'set mathjax typeset', ->
expect(MathJax.Hub.Queue).toHaveBeenCalled() expect(MathJax.Hub.Queue).toHaveBeenCalled()
...@@ -78,7 +78,7 @@ describe 'Problem', -> ...@@ -78,7 +78,7 @@ describe 'Problem', ->
describe 'renderProgressState', -> describe 'renderProgressState', ->
beforeEach -> beforeEach ->
@problem = new Problem($('.xmodule_display')) @problem = new Problem($('.xblock-student_view'))
#@renderProgressState = @problem.renderProgressState #@renderProgressState = @problem.renderProgressState
describe 'with a status of "none"', -> describe 'with a status of "none"', ->
...@@ -97,7 +97,7 @@ describe 'Problem', -> ...@@ -97,7 +97,7 @@ describe 'Problem', ->
describe 'render', -> describe 'render', ->
beforeEach -> beforeEach ->
@problem = new Problem($('.xmodule_display')) @problem = new Problem($('.xblock-student_view'))
@bind = @problem.bind @bind = @problem.bind
spyOn @problem, 'bind' spyOn @problem, 'bind'
...@@ -130,7 +130,7 @@ describe 'Problem', -> ...@@ -130,7 +130,7 @@ describe 'Problem', ->
describe 'check', -> describe 'check', ->
beforeEach -> beforeEach ->
@problem = new Problem($('.xmodule_display')) @problem = new Problem($('.xblock-student_view'))
@problem.answers = 'foo=1&bar=2' @problem.answers = 'foo=1&bar=2'
it 'log the problem_check event', -> it 'log the problem_check event', ->
...@@ -177,7 +177,7 @@ describe 'Problem', -> ...@@ -177,7 +177,7 @@ describe 'Problem', ->
describe 'reset', -> describe 'reset', ->
beforeEach -> beforeEach ->
@problem = new Problem($('.xmodule_display')) @problem = new Problem($('.xblock-student_view'))
it 'log the problem_reset event', -> it 'log the problem_reset event', ->
@problem.answers = 'foo=1&bar=2' @problem.answers = 'foo=1&bar=2'
...@@ -198,7 +198,7 @@ describe 'Problem', -> ...@@ -198,7 +198,7 @@ describe 'Problem', ->
describe 'show', -> describe 'show', ->
beforeEach -> beforeEach ->
@problem = new Problem($('.xmodule_display')) @problem = new Problem($('.xblock-student_view'))
@problem.el.prepend '<div id="answer_1_1" /><div id="answer_1_2" />' @problem.el.prepend '<div id="answer_1_1" /><div id="answer_1_2" />'
describe 'when the answer has not yet shown', -> describe 'when the answer has not yet shown', ->
...@@ -331,7 +331,7 @@ describe 'Problem', -> ...@@ -331,7 +331,7 @@ describe 'Problem', ->
describe 'save', -> describe 'save', ->
beforeEach -> beforeEach ->
@problem = new Problem($('.xmodule_display')) @problem = new Problem($('.xblock-student_view'))
@problem.answers = 'foo=1&bar=2' @problem.answers = 'foo=1&bar=2'
it 'log the problem_save event', -> it 'log the problem_save event', ->
...@@ -353,7 +353,7 @@ describe 'Problem', -> ...@@ -353,7 +353,7 @@ describe 'Problem', ->
describe 'refreshMath', -> describe 'refreshMath', ->
beforeEach -> beforeEach ->
@problem = new Problem($('.xmodule_display')) @problem = new Problem($('.xblock-student_view'))
$('#input_example_1').val 'E=mc^2' $('#input_example_1').val 'E=mc^2'
@problem.refreshMath target: $('#input_example_1').get(0) @problem.refreshMath target: $('#input_example_1').get(0)
...@@ -363,7 +363,7 @@ describe 'Problem', -> ...@@ -363,7 +363,7 @@ describe 'Problem', ->
describe 'updateMathML', -> describe 'updateMathML', ->
beforeEach -> beforeEach ->
@problem = new Problem($('.xmodule_display')) @problem = new Problem($('.xblock-student_view'))
@stubbedJax.root.toMathML.andReturn '<MathML>' @stubbedJax.root.toMathML.andReturn '<MathML>'
describe 'when there is no exception', -> describe 'when there is no exception', ->
...@@ -383,7 +383,7 @@ describe 'Problem', -> ...@@ -383,7 +383,7 @@ describe 'Problem', ->
describe 'refreshAnswers', -> describe 'refreshAnswers', ->
beforeEach -> beforeEach ->
@problem = new Problem($('.xmodule_display')) @problem = new Problem($('.xblock-student_view'))
@problem.el.html ''' @problem.el.html '''
<textarea class="CodeMirror" /> <textarea class="CodeMirror" />
<input id="input_1_1" name="input_1_1" class="schematic" value="one" /> <input id="input_1_1" name="input_1_1" class="schematic" value="one" />
......
...@@ -32,4 +32,4 @@ class @Conditional ...@@ -32,4 +32,4 @@ class @Conditional
else else
$(element).show() $(element).show()
XModule.loadModules @el XBlock.initializeBlocks @el
...@@ -92,7 +92,7 @@ class @Sequence ...@@ -92,7 +92,7 @@ class @Sequence
@el.trigger "sequence:change" @el.trigger "sequence:change"
@mark_active new_position @mark_active new_position
@$('#seq_content').html @contents.eq(new_position - 1).text() @$('#seq_content').html @contents.eq(new_position - 1).text()
XModule.loadModules(@$('#seq_content')) XBlock.initializeBlocks(@$('#seq_content'))
MathJax.Hub.Queue(["Typeset", MathJax.Hub, "seq_content"]) # NOTE: Actually redundant. Some other MathJax call also being performed MathJax.Hub.Queue(["Typeset", MathJax.Hub, "seq_content"]) # NOTE: Actually redundant. Some other MathJax call also being performed
window.update_schematics() # For embedded circuit simulator exercises in 6.002x window.update_schematics() # For embedded circuit simulator exercises in 6.002x
......
@XModule = @XModule = {}
@XBlockToXModuleShim = (runtime, element) ->
### ###
Load a single module (either an edit module or a display module) Load a single module (either an edit module or a display module)
from the supplied element, which should have a data-type attribute from the supplied element, which should have a data-type attribute
specifying the class to load specifying the class to load
### ###
loadModule: (element) ->
moduleType = $(element).data('type') moduleType = $(element).data('type')
if moduleType == 'None' if moduleType == 'None'
return return
...@@ -25,20 +26,6 @@ ...@@ -25,20 +26,6 @@
else else
throw error throw error
###
Load all modules on the page of the specified type.
If container is provided, only load modules inside that element
Type is one of 'display' or 'edit'
###
loadModules: (container) ->
selector = ".xmodule_edit, .xmodule_display"
if container?
modules = $(container).find(selector)
else
modules = $(selector)
modules.each((idx, element) -> XModule.loadModule element)
class @XModule.Descriptor class @XModule.Descriptor
......
...@@ -85,6 +85,14 @@ class HTMLSnippet(object): ...@@ -85,6 +85,14 @@ class HTMLSnippet(object):
.format(self.__class__)) .format(self.__class__))
def shim_xmodule_js(fragment):
"""
Set up the XBlock -> XModule shim on the supplied :class:`xblock.fragment.Fragment`
"""
if not fragment.js_init_fn:
fragment.initialize_js('XBlockToXModuleShim')
class XModuleMixin(XBlockMixin): class XModuleMixin(XBlockMixin):
""" """
Fields and methods used by XModules internally. Fields and methods used by XModules internally.
...@@ -92,6 +100,29 @@ class XModuleMixin(XBlockMixin): ...@@ -92,6 +100,29 @@ class XModuleMixin(XBlockMixin):
Adding this Mixin to an :class:`XBlock` allows it to cooperate with old-style :class:`XModules` Adding this Mixin to an :class:`XBlock` allows it to cooperate with old-style :class:`XModules`
""" """
# Attributes for inspection of the descriptor
# This indicates whether the xmodule is a problem-type.
# It should respond to max_score() and grade(). It can be graded or ungraded
# (like a practice problem).
has_score = False
# Class level variable
# True if this descriptor always requires recalculation of grades, for
# example if the score can change via an extrnal service, not just when the
# student interacts with the module on the page. A specific example is
# FoldIt, which posts grade-changing updates through a separate API.
always_recalculate_grades = False
# The default implementation of get_icon_class returns the icon_class
# attribute of the class
#
# This attribute can be overridden by subclasses, and
# the function can also be overridden if the icon class depends on the data
# in the module
icon_class = 'other'
display_name = String( display_name = String(
display_name="Display Name", display_name="Display Name",
help="This name appears in the horizontal navigation at the top of the page.", help="This name appears in the horizontal navigation at the top of the page.",
...@@ -335,13 +366,6 @@ class XModule(XModuleMixin, HTMLSnippet, XBlock): # pylint: disable=abstract-me ...@@ -335,13 +366,6 @@ class XModule(XModuleMixin, HTMLSnippet, XBlock): # pylint: disable=abstract-me
See the HTML module for a simple example. See the HTML module for a simple example.
""" """
# The default implementation of get_icon_class returns the icon_class
# attribute of the class
#
# This attribute can be overridden by subclasses, and
# the function can also be overridden if the icon class depends on the data
# in the module
icon_class = 'other'
has_score = descriptor_attr('has_score') has_score = descriptor_attr('has_score')
_field_data_cache = descriptor_attr('_field_data_cache') _field_data_cache = descriptor_attr('_field_data_cache')
...@@ -516,20 +540,6 @@ class XModuleDescriptor(XModuleMixin, HTMLSnippet, ResourceTemplates, XBlock): ...@@ -516,20 +540,6 @@ class XModuleDescriptor(XModuleMixin, HTMLSnippet, ResourceTemplates, XBlock):
entry_point = "xmodule.v1" entry_point = "xmodule.v1"
module_class = XModule module_class = XModule
# Attributes for inspection of the descriptor
# This indicates whether the xmodule is a problem-type.
# It should respond to max_score() and grade(). It can be graded or ungraded
# (like a practice problem).
has_score = False
# Class level variable
# True if this descriptor always requires recalculation of grades, for
# example if the score can change via an extrnal service, not just when the
# student interacts with the module on the page. A specific example is
# FoldIt, which posts grade-changing updates through a separate API.
always_recalculate_grades = False
# VS[compat]. Backwards compatibility code that can go away after # VS[compat]. Backwards compatibility code that can go away after
# importing 2012 courses. # importing 2012 courses.
...@@ -862,9 +872,13 @@ class DescriptorSystem(ConfigurableFragmentWrapper, Runtime): # pylint: disable ...@@ -862,9 +872,13 @@ class DescriptorSystem(ConfigurableFragmentWrapper, Runtime): # pylint: disable
return result return result
def render(self, block, view_name, context=None): def render(self, block, view_name, context=None):
if isinstance(block, (XModule, XModuleDescriptor)) and view_name == 'student_view': if view_name == 'student_view':
assert block.xmodule_runtime is not None assert block.xmodule_runtime is not None
return block.xmodule_runtime.render(block._xmodule, view_name, context) if isinstance(block, (XModule, XModuleDescriptor)):
to_render = block._xmodule
else:
to_render = block
return block.xmodule_runtime.render(to_render, view_name, context)
else: else:
return super(DescriptorSystem, self).render(block, view_name, context) return super(DescriptorSystem, self).render(block, view_name, context)
......
describe "$.immediateDescendents", ->
beforeEach ->
setFixtures """
<div>
<div class='xblock' id='child'>
<div class='xblock' id='nested'/>
</div>
<div>
<div class='xblock' id='grandchild'/>
</div>
</div>
"""
@descendents = $('#jasmine-fixtures').immediateDescendents(".xblock").get()
it "finds non-immediate children", ->
expect(@descendents).toContain($('#grandchild').get(0))
it "finds immediate children", ->
expect(@descendents).toContain($('#child').get(0))
it "skips nested descendents", ->
expect(@descendents).not.toContain($('#nested').get(0))
it "finds 2 children", ->
expect(@descendents.length).toBe(2)
\ No newline at end of file
describe "XBlock", ->
beforeEach ->
setFixtures """
<div>
<div class='xblock' id='vA' data-runtime-version="A" data-init="initFnA" data-name="a-name"/>
<div>
<div class='xblock' id='vZ' data-runtime-version="Z" data-init="initFnZ"/>
</div>
<div class='xblock' id='missing-version' data-init='initFnA' data-name='no-version'/>
<div class='xblock' id='missing-init' data-runtime-version="A" data-name='no-init'/>
</div>
"""
describe "initializeBlock", ->
beforeEach ->
XBlock.runtime.vA = jasmine.createSpy().andReturn('runtimeA')
XBlock.runtime.vZ = jasmine.createSpy().andReturn('runtimeZ')
window.initFnA = jasmine.createSpy()
window.initFnZ = jasmine.createSpy()
@fakeChildren = ['list', 'of', 'children']
spyOn(XBlock, 'initializeBlocks').andReturn(@fakeChildren)
@vABlock = XBlock.initializeBlock($('#vA')[0])
@vZBlock = XBlock.initializeBlock($('#vZ')[0])
@missingVersionBlock = XBlock.initializeBlock($('#missing-version')[0])
@missingInitBlock = XBlock.initializeBlock($('#missing-init')[0])
it "loads the right runtime version", ->
expect(XBlock.runtime.vA).toHaveBeenCalledWith($('#vA')[0], @fakeChildren)
expect(XBlock.runtime.vZ).toHaveBeenCalledWith($('#vZ')[0], @fakeChildren)
it "loads the right init function", ->
expect(window.initFnA).toHaveBeenCalledWith('runtimeA', $('#vA')[0])
expect(window.initFnZ).toHaveBeenCalledWith('runtimeZ', $('#vZ')[0])
it "loads when missing versions", ->
expect(@missingVersionBlock.element).toBe($('#missing-version'))
expect(@missingVersionBlock.name).toBe('no-version')
it "loads when missing init fn", ->
expect(@missingInitBlock.element).toBe($('#missing-init'))
expect(@missingInitBlock.name).toBe('no-init')
it "adds names to blocks", ->
expect(@vABlock.name).toBe('a-name')
it "leaves leaves missing names undefined", ->
expect(@vZBlock.name).toBeUndefined()
it "attaches the element to the block", ->
expect(@vABlock.element).toBe($('#vA')[0])
expect(@vZBlock.element).toBe($('#vZ')[0])
expect(@missingVersionBlock.element).toBe($('#missing-version')[0])
expect(@missingInitBlock.element).toBe($('#missing-init')[0])
describe "initializeBlocks", ->
it "initializes children", ->
spyOn(XBlock, 'initializeBlock')
XBlock.initializeBlocks($('#jasmine-fixtures'))
expect(XBlock.initializeBlock).toHaveBeenCalledWith($('#vA')[0])
expect(XBlock.initializeBlock).toHaveBeenCalledWith($('#vZ')[0])
describe "XBlock.runtime.v1", ->
beforeEach ->
setFixtures """
<div class='xblock' data-usage-id='fake-usage-id'/>
"""
@children = [
{name: 'childA'},
{name: 'childB'}
]
@element = $('.xblock')[0]
@runtime = XBlock.runtime.v1(@element, @children)
it "provides a handler url", ->
expect(@runtime.handlerUrl('foo')).toBe('/xblock/handler/fake-usage-id/foo')
it "provides a list of children", ->
expect(@runtime.children).toBe(@children)
it "maps children by name", ->
expect(@runtime.childMap.childA).toBe(@children[0])
expect(@runtime.childMap.childB).toBe(@children[1])
# Find all the children of an element that match the selector, but only
# the first instance found down any path. For example, we'll find all
# the ".xblock" elements below us, but not the ones that are themselves
# contained somewhere inside ".xblock" elements.
jQuery.fn.immediateDescendents = (selector) ->
@children().map ->
elem = jQuery(this)
if elem.is(selector)
this
else
elem.immediateDescendents(selector).get()
@XBlock =
runtime: {}
initializeBlock: (element) ->
$element = $(element)
children = @initializeBlocks($element)
version = $element.data("runtime-version")
initFnName = $element.data("init")
if version? and initFnName?
runtime = @runtime["v#{version}"](element, children)
initFn = window[initFnName]
block = initFn(runtime, element) ? {}
else
elementTag = $('<div>').append($element.clone()).html();
console.log("Block #{elementTag} is missing data-runtime-version or data-init, and can't be initialized")
block = {}
block.element = element
block.name = $element.data("name")
block
initializeBlocks: (element) ->
$(element).immediateDescendents(".xblock").map((idx, elem) =>
@initializeBlock elem
).toArray()
@XBlock.runtime.v1 = (element, children) ->
childMap = {}
$.each children, (idx, child) ->
childMap[child.name] = child
return {
handlerUrl: (handlerName) ->
usageId = $(element).data("usage-id")
"/xblock/handler/#{usageId}/#{handlerName}"
children: children
childMap: childMap
}
...@@ -35,6 +35,7 @@ lib_paths: ...@@ -35,6 +35,7 @@ lib_paths:
- js/vendor/jquery.timeago.js - js/vendor/jquery.timeago.js
- coffee/src/ajax_prefix.js - coffee/src/ajax_prefix.js
- js/test/add_ajax_prefix.js - js/test/add_ajax_prefix.js
- coffee/src/jquery.immediateDescendents.js
# Paths to source JavaScript files # Paths to source JavaScript files
src_paths: src_paths:
......
<section class="xmodule_display xmodule_${class_}" data-type="${module_name}"> <section class="${' '.join(classes)}" ${data_attributes}>
${content} ${content}
</section> </section>
<section class="xmodule_edit xmodule_${class_}" data-type="${module_name}">
${content}
</section>
...@@ -25,7 +25,7 @@ from xmodule.modulestore import Location ...@@ -25,7 +25,7 @@ from xmodule.modulestore import Location
from xmodule.modulestore.django import modulestore from xmodule.modulestore.django import modulestore
from xmodule.modulestore.exceptions import ItemNotFoundError from xmodule.modulestore.exceptions import ItemNotFoundError
from xmodule.x_module import ModuleSystem from xmodule.x_module import ModuleSystem
from xmodule_modifiers import replace_course_urls, replace_jump_to_id_urls, replace_static_urls, add_histogram, wrap_xmodule from xmodule_modifiers import replace_course_urls, replace_jump_to_id_urls, replace_static_urls, add_histogram, wrap_xblock
import static_replace import static_replace
from psychometrics.psychoanalyze import make_psychometrics_data_update_handler from psychometrics.psychoanalyze import make_psychometrics_data_update_handler
...@@ -340,7 +340,7 @@ def get_module_for_descriptor_internal(user, descriptor, field_data_cache, cours ...@@ -340,7 +340,7 @@ def get_module_for_descriptor_internal(user, descriptor, field_data_cache, cours
# Wrap the output display in a single div to allow for the XModule # Wrap the output display in a single div to allow for the XModule
# javascript to be bound correctly # javascript to be bound correctly
if wrap_xmodule_display is True: if wrap_xmodule_display is True:
block_wrappers.append(partial(wrap_xmodule, 'xmodule_display.html')) block_wrappers.append(wrap_xblock)
# TODO (cpennington): When modules are shared between courses, the static # TODO (cpennington): When modules are shared between courses, the static
# prefix is going to have to be specific to the module, not the directory # prefix is going to have to be specific to the module, not the directory
......
...@@ -299,7 +299,7 @@ class TestHtmlModifiers(ModuleStoreTestCase): ...@@ -299,7 +299,7 @@ class TestHtmlModifiers(ModuleStoreTestCase):
) )
result_fragment = module.render('student_view') result_fragment = module.render('student_view')
self.assertIn('section class="xmodule_display xmodule_HtmlModule"', result_fragment.content) self.assertIn('section class="xblock xblock-student_view xmodule_display xmodule_HtmlModule"', result_fragment.content)
def test_xmodule_display_wrapper_disabled(self): def test_xmodule_display_wrapper_disabled(self):
module = render.get_module( module = render.get_module(
...@@ -312,7 +312,7 @@ class TestHtmlModifiers(ModuleStoreTestCase): ...@@ -312,7 +312,7 @@ class TestHtmlModifiers(ModuleStoreTestCase):
) )
result_fragment = module.render('student_view') result_fragment = module.render('student_view')
self.assertNotIn('section class="xmodule_display xmodule_HtmlModule"', result_fragment.content) self.assertNotIn('section class="xblock xblock-student_view xmodule_display xmodule_HtmlModule"', result_fragment.content)
def test_static_link_rewrite(self): def test_static_link_rewrite(self):
module = render.get_module( module = render.get_module(
......
...@@ -11,7 +11,7 @@ from django.utils.html import escape ...@@ -11,7 +11,7 @@ from django.utils.html import escape
from django.http import Http404 from django.http import Http404
from django.conf import settings from django.conf import settings
from xmodule_modifiers import wrap_xmodule from xmodule_modifiers import wrap_xblock
from xmodule.html_module import HtmlDescriptor from xmodule.html_module import HtmlDescriptor
from xmodule.modulestore import MONGO_MODULESTORE_TYPE from xmodule.modulestore import MONGO_MODULESTORE_TYPE
from xmodule.modulestore.django import modulestore from xmodule.modulestore.django import modulestore
...@@ -164,7 +164,7 @@ def _section_send_email(course_id, access, course): ...@@ -164,7 +164,7 @@ def _section_send_email(course_id, access, course):
""" Provide data for the corresponding bulk email section """ """ Provide data for the corresponding bulk email section """
html_module = HtmlDescriptor(course.system, DictFieldData({'data': ''}), ScopeIds(None, None, None, None)) html_module = HtmlDescriptor(course.system, DictFieldData({'data': ''}), ScopeIds(None, None, None, None))
fragment = course.system.render(html_module, 'studio_view') fragment = course.system.render(html_module, 'studio_view')
fragment = wrap_xmodule('xmodule_edit.html', html_module, 'studio_view', fragment, None) fragment = wrap_xblock(html_module, 'studio_view', fragment, None)
email_editor = fragment.content email_editor = fragment.content
section_data = { section_data = {
'section_key': 'send_email', 'section_key': 'send_email',
......
...@@ -23,7 +23,7 @@ from django.core.urlresolvers import reverse ...@@ -23,7 +23,7 @@ from django.core.urlresolvers import reverse
from django.core.mail import send_mail from django.core.mail import send_mail
from django.utils import timezone from django.utils import timezone
from xmodule_modifiers import wrap_xmodule from xmodule_modifiers import wrap_xblock
import xmodule.graders as xmgraders import xmodule.graders as xmgraders
from xmodule.modulestore import MONGO_MODULESTORE_TYPE from xmodule.modulestore import MONGO_MODULESTORE_TYPE
from xmodule.modulestore.django import modulestore from xmodule.modulestore.django import modulestore
...@@ -832,8 +832,8 @@ def instructor_dashboard(request, course_id): ...@@ -832,8 +832,8 @@ def instructor_dashboard(request, course_id):
# HTML editor for email # HTML editor for email
if idash_mode == 'Email' and is_studio_course: if idash_mode == 'Email' and is_studio_course:
html_module = HtmlDescriptor(course.system, DictFieldData({'data': html_message}), ScopeIds(None, None, None, None)) html_module = HtmlDescriptor(course.system, DictFieldData({'data': html_message}), ScopeIds(None, None, None, None))
fragment = course.system.render(html_module, 'studio_view') fragment = html_module.render('studio_view')
fragment = wrap_xmodule('xmodule_edit.html', html_module, 'studio_view', fragment, None) fragment = wrap_xblock(html_module, 'studio_view', fragment, None)
email_editor = fragment.content email_editor = fragment.content
# Enable instructor email only if the following conditions are met: # Enable instructor email only if the following conditions are met:
......
...@@ -17,7 +17,7 @@ describe 'Courseware', -> ...@@ -17,7 +17,7 @@ describe 'Courseware', ->
spyOn(window, 'Histogram') spyOn(window, 'Histogram')
spyOn(window, 'Problem') spyOn(window, 'Problem')
spyOn(window, 'Video') spyOn(window, 'Video')
spyOn(XModule, 'loadModules') spyOn(XBlock, 'initializeBlocks')
setFixtures """ setFixtures """
<div class="course-content"> <div class="course-content">
<div id="video_1" class="video" data-streams="1.0:abc1234"></div> <div id="video_1" class="video" data-streams="1.0:abc1234"></div>
...@@ -30,7 +30,7 @@ describe 'Courseware', -> ...@@ -30,7 +30,7 @@ describe 'Courseware', ->
@courseware.render() @courseware.render()
it 'ensure that the XModules have been loaded', -> it 'ensure that the XModules have been loaded', ->
expect(XModule.loadModules).toHaveBeenCalled() expect(XBlock.initializeBlocks).toHaveBeenCalled()
it 'detect the histrogram element and convert it', -> it 'detect the histrogram element and convert it', ->
expect(window.Histogram).toHaveBeenCalledWith('3', [[0, 1]]) expect(window.Histogram).toHaveBeenCalledWith('3', [[0, 1]])
...@@ -11,7 +11,7 @@ class @Courseware ...@@ -11,7 +11,7 @@ class @Courseware
new Courseware new Courseware
render: -> render: ->
XModule.loadModules() XBlock.initializeBlocks($('.course-content'))
$('.course-content .histogram').each -> $('.course-content .histogram').each ->
id = $(this).attr('id').replace(/histogram_/, '') id = $(this).attr('id').replace(/histogram_/, '')
try try
......
...@@ -12,7 +12,7 @@ std_ajax_err = -> window.InstructorDashboard.util.std_ajax_err.apply this, argum ...@@ -12,7 +12,7 @@ std_ajax_err = -> window.InstructorDashboard.util.std_ajax_err.apply this, argum
class SendEmail class SendEmail
constructor: (@$container) -> constructor: (@$container) ->
# gather elements # gather elements
@$emailEditor = XModule.loadModule($('.xmodule_edit')); @$emailEditor = XBlock.initializeBlock($('.xblock-studio_view'));
@$send_to = @$container.find("select[name='send_to']'") @$send_to = @$container.find("select[name='send_to']'")
@$subject = @$container.find("input[name='subject']'") @$subject = @$container.find("input[name='subject']'")
@$btn_send = @$container.find("input[name='send']'") @$btn_send = @$container.find("input[name='send']'")
......
...@@ -38,6 +38,8 @@ lib_paths: ...@@ -38,6 +38,8 @@ lib_paths:
- xmodule_js/common_static/js/vendor/jquery.cookie.js - xmodule_js/common_static/js/vendor/jquery.cookie.js
- xmodule_js/common_static/js/vendor/flot/jquery.flot.js - xmodule_js/common_static/js/vendor/flot/jquery.flot.js
- xmodule_js/common_static/js/vendor/CodeMirror/codemirror.js - xmodule_js/common_static/js/vendor/CodeMirror/codemirror.js
- xmodule_js/common_static/coffee/src/jquery.immediateDescendents.js
- xmodule_js/common_static/coffee/src/xblock
- xmodule_js/src/capa/ - xmodule_js/src/capa/
- xmodule_js/src/video/ - xmodule_js/src/video/
- xmodule_js/src/xmodule.js - xmodule_js/src/xmodule.js
......
...@@ -546,7 +546,7 @@ function goto( mode) ...@@ -546,7 +546,7 @@ function goto( mode)
<input type="submit" name="action" value="Send email"> <input type="submit" name="action" value="Send email">
</div> </div>
<script type="text/javascript"> <script type="text/javascript">
var emailEditor = XModule.loadModule($('.xmodule_edit')); var emailEditor = XBlock.initializeBlock($('.xblock-studio_view'));
document.idashform.onsubmit = function() { document.idashform.onsubmit = function() {
this.message.value = emailEditor.save()['data']; this.message.value = emailEditor.save()['data'];
return true; return true;
......
...@@ -64,7 +64,7 @@ namespace :'test:js' do ...@@ -64,7 +64,7 @@ namespace :'test:js' do
end end
desc "Run the JavaScript tests in your default browser" desc "Run the JavaScript tests in your default browser"
task :dev, [:env] => [:clean_test_files, :'assets:coffee'] do |t, args| task :dev, [:env] => [:clean_test_files, :'assets:coffee:_watch'] do |t, args|
if args[:env].nil? if args[:env].nil?
puts "Error: No test suite specified. Try one of these instead:" puts "Error: No test suite specified. Try one of these instead:"
print_js_test_cmds('dev') print_js_test_cmds('dev')
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
-e git+https://github.com/eventbrite/zendesk.git@d53fe0e81b623f084e91776bcf6369f8b7b63879#egg=zendesk -e git+https://github.com/eventbrite/zendesk.git@d53fe0e81b623f084e91776bcf6369f8b7b63879#egg=zendesk
# Our libraries: # Our libraries:
-e git+https://github.com/edx/XBlock.git@cee38a15f#egg=XBlock -e git+https://github.com/edx/XBlock.git@74c1a2e9#egg=XBlock
-e git+https://github.com/edx/codejail.git@0a1b468#egg=codejail -e git+https://github.com/edx/codejail.git@0a1b468#egg=codejail
-e git+https://github.com/edx/diff-cover.git@v0.2.6#egg=diff_cover -e git+https://github.com/edx/diff-cover.git@v0.2.6#egg=diff_cover
-e git+https://github.com/edx/js-test-tool.git@v0.1.4#egg=js_test_tool -e git+https://github.com/edx/js-test-tool.git@v0.1.4#egg=js_test_tool
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment