diff --git a/.eslintignore b/.eslintignore index fd5205ea5f..e0e659a325 100644 --- a/.eslintignore +++ b/.eslintignore @@ -50,7 +50,6 @@ common/lib/xmodule/xmodule/js/src/conditional/display.js common/lib/xmodule/xmodule/js/src/discussion/display.js common/lib/xmodule/xmodule/js/src/html/display.js common/lib/xmodule/xmodule/js/src/html/edit.js -common/lib/xmodule/xmodule/js/src/javascript_loader.js common/lib/xmodule/xmodule/js/src/problem/edit.js common/lib/xmodule/xmodule/js/src/raw/edit/json.js common/lib/xmodule/xmodule/js/src/raw/edit/metadata-only.js diff --git a/common/lib/xmodule/xmodule/annotatable_module.py b/common/lib/xmodule/xmodule/annotatable_module.py index d08bd7c377..338a5fe067 100644 --- a/common/lib/xmodule/xmodule/annotatable_module.py +++ b/common/lib/xmodule/xmodule/annotatable_module.py @@ -48,11 +48,11 @@ class AnnotatableFields(object): class AnnotatableModule(AnnotatableFields, XModule): js = { 'coffee': [ - resource_string(__name__, 'js/src/javascript_loader.coffee'), resource_string(__name__, 'js/src/html/display.coffee'), resource_string(__name__, 'js/src/annotatable/display.coffee'), ], 'js': [ + resource_string(__name__, 'js/src/javascript_loader.js'), resource_string(__name__, 'js/src/collapsible.js'), ] } diff --git a/common/lib/xmodule/xmodule/capa_module.py b/common/lib/xmodule/xmodule/capa_module.py index 42e52e5bc9..d97feaf30b 100644 --- a/common/lib/xmodule/xmodule/capa_module.py +++ b/common/lib/xmodule/xmodule/capa_module.py @@ -31,9 +31,9 @@ class CapaModule(CapaMixin, XModule): js = { 'coffee': [ resource_string(__name__, 'js/src/capa/display.coffee'), - resource_string(__name__, 'js/src/javascript_loader.coffee'), ], 'js': [ + resource_string(__name__, 'js/src/javascript_loader.js'), resource_string(__name__, 'js/src/collapsible.js'), resource_string(__name__, 'js/src/capa/imageinput.js'), resource_string(__name__, 'js/src/capa/schematic.js'), diff --git a/common/lib/xmodule/xmodule/conditional_module.py b/common/lib/xmodule/xmodule/conditional_module.py index 4fb13e8519..538550b04b 100644 --- a/common/lib/xmodule/xmodule/conditional_module.py +++ b/common/lib/xmodule/xmodule/conditional_module.py @@ -114,10 +114,10 @@ class ConditionalModule(ConditionalFields, XModule, StudioEditableModule): js = { 'coffee': [ - resource_string(__name__, 'js/src/javascript_loader.coffee'), resource_string(__name__, 'js/src/conditional/display.coffee'), ], 'js': [ + resource_string(__name__, 'js/src/javascript_loader.js'), resource_string(__name__, 'js/src/collapsible.js'), ] } diff --git a/common/lib/xmodule/xmodule/html_module.py b/common/lib/xmodule/xmodule/html_module.py index c93351dbaa..a3ed311c20 100644 --- a/common/lib/xmodule/xmodule/html_module.py +++ b/common/lib/xmodule/xmodule/html_module.py @@ -92,10 +92,10 @@ class HtmlModuleMixin(HtmlBlock, XModule): """ js = { 'coffee': [ - resource_string(__name__, 'js/src/javascript_loader.coffee'), resource_string(__name__, 'js/src/html/display.coffee'), ], 'js': [ + resource_string(__name__, 'js/src/javascript_loader.js'), resource_string(__name__, 'js/src/collapsible.js'), resource_string(__name__, 'js/src/html/imageModal.js'), resource_string(__name__, 'js/common_static/js/vendor/draggabilly.js'), diff --git a/common/lib/xmodule/xmodule/imageannotation_module.py b/common/lib/xmodule/xmodule/imageannotation_module.py index 7d999aabab..e9d68ebac1 100644 --- a/common/lib/xmodule/xmodule/imageannotation_module.py +++ b/common/lib/xmodule/xmodule/imageannotation_module.py @@ -92,11 +92,11 @@ class ImageAnnotationModule(AnnotatableFields, XModule): '''Image Annotation Module''' js = { 'coffee': [ - resource_string(__name__, 'js/src/javascript_loader.coffee'), resource_string(__name__, 'js/src/html/display.coffee'), resource_string(__name__, 'js/src/annotatable/display.coffee'), ], 'js': [ + resource_string(__name__, 'js/src/javascript_loader.js'), resource_string(__name__, 'js/src/collapsible.js'), ] } diff --git a/common/lib/xmodule/xmodule/js/src/.gitignore b/common/lib/xmodule/xmodule/js/src/.gitignore index 0d20de51a2..4baebb5a27 100644 --- a/common/lib/xmodule/xmodule/js/src/.gitignore +++ b/common/lib/xmodule/xmodule/js/src/.gitignore @@ -13,3 +13,4 @@ !time.js !collapsible.js !xmodule.js +!javascript_loader.js diff --git a/common/lib/xmodule/xmodule/js/src/javascript_loader.coffee b/common/lib/xmodule/xmodule/js/src/javascript_loader.coffee deleted file mode 100644 index a687da3538..0000000000 --- a/common/lib/xmodule/xmodule/js/src/javascript_loader.coffee +++ /dev/null @@ -1,70 +0,0 @@ -class @JavascriptLoader - - # Set of library functions that provide common interface for javascript loading - # for all module types. All functionality provided by JavascriptLoader should take - # place at module scope, i.e. don't run jQuery over entire page - - # executeModuleScripts: - # Scan the module ('el') for "script_placeholder"s, then: - # 1) Fetch each script from server - # 2) Explicitly attach the script to the of document - # 3) Explicitly wait for each script to be loaded - # 4) Return to callback function when all scripts loaded - @executeModuleScripts: (el, callback=null) -> - - placeholders = el.find(".script_placeholder") - - if placeholders.length == 0 - callback() if callback? - return - - # TODO: Verify the execution order of multiple placeholders - completed = (false for i in [1..placeholders.length]) - callbackCalled = false - - # This is required for IE8 support. - completionHandlerGeneratorIE = (index) => - return () -> - if (this.readyState == 'complete' || this.readyState == 'loaded') - #completionHandlerGenerator.call(self, index)() - completionHandlerGenerator(index)() - - completionHandlerGenerator = (index) => - return () => - allComplete = true - completed[index] = true - for flag in completed - if not flag - allComplete = false - break - if allComplete and not callbackCalled - callbackCalled = true - callback() if callback? - - # Keep a map of what sources we're loaded from, and don't do it twice. - loaded = {} - placeholders.each (index, placeholder) -> - # TODO: Check if the script already exists in DOM. If so, (1) copy it - # into memory; (2) delete the DOM script element; (3) reappend it. - # This would prevent memory bloat and save a network request. - src = $(placeholder).attr("data-src") - if src not of loaded - loaded[src] = true - s = document.createElement('script') - s.setAttribute('src', src) - s.setAttribute('type', "text/javascript") - - s.onload = completionHandlerGenerator(index) - - # s.onload does not fire in IE8; this does. - s.onreadystatechange = completionHandlerGeneratorIE(index) - - # Need to use the DOM elements directly or the scripts won't execute - # properly. - $('head')[0].appendChild(s) - else - # just call the completion callback directly, without reloading the file - completionHandlerGenerator(index)() - $(placeholder).remove() - - diff --git a/common/lib/xmodule/xmodule/js/src/javascript_loader.js b/common/lib/xmodule/xmodule/js/src/javascript_loader.js new file mode 100644 index 0000000000..1b31217f5d --- /dev/null +++ b/common/lib/xmodule/xmodule/js/src/javascript_loader.js @@ -0,0 +1,89 @@ +(function() { + 'use strict'; + this.JavascriptLoader = (function() { + function JavascriptLoader() { + } + + /** + * Set of library functions that provide common interface for javascript loading + * for all module types. All functionality provided by JavascriptLoader should take + * place at module scope, i.e. don't run jQuery over entire page. + * + * executeModuleScripts: + * Scan the module ('el') for "script_placeholder"s, then: + * + * 1) Fetch each script from server + * 2) Explicitly attach the script to the of document + * 3) Explicitly wait for each script to be loaded + * 4) Return to callback function when all scripts loaded + */ + JavascriptLoader.executeModuleScripts = function(el, callback) { + var callbackCalled, completed, completionHandlerGenerator, loaded, placeholders; + if (!callback) { + callback = null; // eslint-disable-line no-param-reassign + } + placeholders = el.find('.script_placeholder'); + if (placeholders.length === 0) { + if (callback !== null) { + callback(); + } + return []; + } + // TODO: Verify the execution order of multiple placeholders + completed = (function() { + var i, ref, results; + results = []; + for (i = 1, ref = placeholders.length; ref >= 1 ? i <= ref : i >= ref; ref >= 1 ? ++i : --i) { + results.push(false); + } + return results; + }()); + callbackCalled = false; + completionHandlerGenerator = function(index) { + return function() { + var allComplete, flag, i, len; + allComplete = true; + completed[index] = true; + for (i = 0, len = completed.length; i < len; i++) { + flag = completed[i]; + if (!flag) { + allComplete = false; + break; + } + } + if (allComplete && !callbackCalled) { + callbackCalled = true; + if (callback !== null) { + return callback(); + } + } + return undefined; + }; + }; + // Keep a map of what sources we're loaded from, and don't do it twice. + loaded = {}; + return placeholders.each(function(index, placeholder) { + var s, src; + // TODO: Check if the script already exists in DOM. If so, (1) copy it + // into memory; (2) delete the DOM script element; (3) reappend it. + // This would prevent memory bloat and save a network request. + src = $(placeholder).attr('data-src'); + if (!(src in loaded)) { + loaded[src] = true; + s = document.createElement('script'); + s.setAttribute('src', src); + s.setAttribute('type', 'text/javascript'); + s.onload = completionHandlerGenerator(index); + // Need to use the DOM elements directly or the scripts won't execute properly. + $('head')[0].appendChild(s); + } else { + // just call the completion callback directly, without reloading the file + completionHandlerGenerator(index)(); + } + return $(placeholder).remove(); + }); + }; + + return JavascriptLoader; + }()); +}).call(this); diff --git a/common/lib/xmodule/xmodule/poll_module.py b/common/lib/xmodule/xmodule/poll_module.py index e703f74812..9b86d01ab2 100644 --- a/common/lib/xmodule/xmodule/poll_module.py +++ b/common/lib/xmodule/xmodule/poll_module.py @@ -42,8 +42,8 @@ class PollFields(object): class PollModule(PollFields, XModule): """Poll Module""" js = { - 'coffee': [resource_string(__name__, 'js/src/javascript_loader.coffee')], 'js': [ + resource_string(__name__, 'js/src/javascript_loader.js'), resource_string(__name__, 'js/src/poll/poll.js'), resource_string(__name__, 'js/src/poll/poll_main.js') ] diff --git a/common/lib/xmodule/xmodule/videoannotation_module.py b/common/lib/xmodule/xmodule/videoannotation_module.py index 1daf6bc32d..945d676594 100644 --- a/common/lib/xmodule/xmodule/videoannotation_module.py +++ b/common/lib/xmodule/xmodule/videoannotation_module.py @@ -86,11 +86,11 @@ class VideoAnnotationModule(AnnotatableFields, XModule): '''Video Annotation Module''' js = { 'coffee': [ - resource_string(__name__, 'js/src/javascript_loader.coffee'), resource_string(__name__, 'js/src/html/display.coffee'), resource_string(__name__, 'js/src/annotatable/display.coffee'), ], 'js': [ + resource_string(__name__, 'js/src/javascript_loader.js'), resource_string(__name__, 'js/src/collapsible.js'), ] } diff --git a/common/lib/xmodule/xmodule/word_cloud_module.py b/common/lib/xmodule/xmodule/word_cloud_module.py index 23ce97584c..b2fd468692 100644 --- a/common/lib/xmodule/xmodule/word_cloud_module.py +++ b/common/lib/xmodule/xmodule/word_cloud_module.py @@ -91,8 +91,8 @@ class WordCloudFields(object): class WordCloudModule(WordCloudFields, XModule): """WordCloud Xmodule""" js = { - 'coffee': [resource_string(__name__, 'js/src/javascript_loader.coffee')], 'js': [ + resource_string(__name__, 'js/src/javascript_loader.js'), resource_string(__name__, 'js/src/word_cloud/d3.min.js'), resource_string(__name__, 'js/src/word_cloud/d3.layout.cloud.js'), resource_string(__name__, 'js/src/word_cloud/word_cloud.js'),