Move module javascript into common/lib/xmodule. Still TODO: run jasmine tests in that directory
This commit is contained in:
@@ -98,7 +98,7 @@ def edit_item(request):
|
||||
item = modulestore().get_item(item_location)
|
||||
return render_to_response('unit.html', {
|
||||
'contents': item.get_html(),
|
||||
'js_module': item.js_module_name(),
|
||||
'js_module': item.__class__.__name__,
|
||||
'category': item.category,
|
||||
'name': item.name,
|
||||
'previews': get_module_previews(item),
|
||||
|
||||
@@ -177,6 +177,8 @@ PIPELINE_CSS = {
|
||||
|
||||
PIPELINE_ALWAYS_RECOMPILE = ['sass/base-style.scss']
|
||||
|
||||
# Load javascript 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
|
||||
js_file_dir = PROJECT_ROOT / "static" / "coffee" / "module"
|
||||
|
||||
@@ -8,6 +8,7 @@ import re
|
||||
|
||||
from datetime import timedelta
|
||||
from lxml import etree
|
||||
from pkg_resources import resource_string
|
||||
|
||||
from xmodule.x_module import XModule
|
||||
from xmodule.raw_module import RawDescriptor
|
||||
@@ -70,6 +71,8 @@ class CapaModule(XModule):
|
||||
'''
|
||||
icon_class = 'problem'
|
||||
|
||||
js = {'coffee': [resource_string(__name__, 'js/src/capa/display.coffee')]}
|
||||
|
||||
def __init__(self, system, location, definition, instance_state=None, shared_state=None, **kwargs):
|
||||
XModule.__init__(self, system, location, definition, instance_state, shared_state, **kwargs)
|
||||
|
||||
|
||||
15
common/lib/xmodule/xmodule/js/fixtures/items.json
Normal file
15
common/lib/xmodule/xmodule/js/fixtures/items.json
Normal file
@@ -0,0 +1,15 @@
|
||||
[
|
||||
{
|
||||
"content": "Video 1",
|
||||
"type": "video",
|
||||
"title": "Video 1"
|
||||
}, {
|
||||
"content": "Video 2",
|
||||
"type": "video",
|
||||
"title": "Video 2"
|
||||
}, {
|
||||
"content": "Sample Problem",
|
||||
"type": "problem",
|
||||
"title": "Sample Problem"
|
||||
}
|
||||
]
|
||||
@@ -1,5 +0,0 @@
|
||||
class @Raw
|
||||
constructor: (@element) ->
|
||||
@edit_box = $(".edit-box", @element)
|
||||
|
||||
save: -> @edit_box.val()
|
||||
@@ -1,4 +1,4 @@
|
||||
class @HTML
|
||||
class @RawDescriptor
|
||||
constructor: (@element) ->
|
||||
@edit_box = $(".edit-box", @element)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
class @Video
|
||||
constructor: (@id, videos) ->
|
||||
constructor: (@id, videos, @caption_url_base) ->
|
||||
window.player = null
|
||||
@el = $("#video_#{@id}")
|
||||
@parseVideos videos
|
||||
@@ -7,7 +7,7 @@ class @VideoCaption extends Subview
|
||||
.bind('DOMMouseScroll', @onMovement)
|
||||
|
||||
captionURL: ->
|
||||
"/static/subs/#{@youtubeId}.srt.sjson"
|
||||
"#{@captionURLBase}/#{@youtubeId}.srt.sjson"
|
||||
|
||||
render: ->
|
||||
@$('.video-wrapper').after """
|
||||
@@ -25,7 +25,7 @@ class @VideoPlayer extends Subview
|
||||
|
||||
render: ->
|
||||
@control = new VideoControl el: @$('.video-controls')
|
||||
@caption = new VideoCaption el: @el, youtubeId: @video.youtubeId('1.0'), currentSpeed: @currentSpeed()
|
||||
@caption = new VideoCaption el: @el, youtubeId: @video.youtubeId('1.0'), currentSpeed: @currentSpeed(), captionURLBase: @video.caption_url_base
|
||||
unless onTouchBasedDevice()
|
||||
@volumeControl = new VideoVolumeControl el: @$('.secondary-controls')
|
||||
@speedControl = new VideoSpeedControl el: @$('.secondary-controls'), speeds: @video.speeds, currentSpeed: @currentSpeed()
|
||||
@@ -12,8 +12,7 @@ class RawDescriptor(MakoModuleDescriptor, XmlDescriptor):
|
||||
"""
|
||||
mako_template = "widgets/raw-edit.html"
|
||||
|
||||
js = {'coffee': [resource_string(__name__, 'js/module/raw.coffee')]}
|
||||
js_module = 'Raw'
|
||||
js = {'coffee': [resource_string(__name__, 'js/src/raw/edit.coffee')]}
|
||||
|
||||
def get_context(self):
|
||||
return {
|
||||
|
||||
@@ -8,6 +8,7 @@ from xmodule.xml_module import XmlDescriptor
|
||||
from xmodule.x_module import XModule
|
||||
from xmodule.progress import Progress
|
||||
from xmodule.exceptions import NotFoundError
|
||||
from pkg_resources import resource_string
|
||||
|
||||
log = logging.getLogger("mitx.common.lib.seq_module")
|
||||
|
||||
@@ -19,6 +20,7 @@ class_priority = ['video', 'problem']
|
||||
class SequenceModule(XModule):
|
||||
''' Layout module which lays out content in a temporal sequence
|
||||
'''
|
||||
js = {'coffee': [resource_string(__name__, 'js/src/sequence/display.coffee')]}
|
||||
|
||||
def __init__(self, system, location, definition, instance_state=None, shared_state=None, **kwargs):
|
||||
XModule.__init__(self, system, location, definition, instance_state, shared_state, **kwargs)
|
||||
|
||||
@@ -2,6 +2,7 @@ import json
|
||||
import logging
|
||||
|
||||
from lxml import etree
|
||||
from pkg_resources import resource_string, resource_listdir
|
||||
|
||||
from xmodule.x_module import XModule
|
||||
from xmodule.raw_module import RawDescriptor
|
||||
@@ -13,6 +14,13 @@ class VideoModule(XModule):
|
||||
video_time = 0
|
||||
icon_class = 'video'
|
||||
|
||||
js = {'coffee':
|
||||
[resource_string(__name__, 'js/src/video/display.coffee')] +
|
||||
[resource_string(__name__, 'js/src/video/display/' + filename)
|
||||
for filename
|
||||
in resource_listdir(__name__, 'js/src/video/display')
|
||||
]}
|
||||
|
||||
def __init__(self, system, location, definition, instance_state=None, shared_state=None, **kwargs):
|
||||
XModule.__init__(self, system, location, definition, instance_state, shared_state, **kwargs)
|
||||
xmltree = etree.fromstring(self.definition['data'])
|
||||
|
||||
@@ -77,6 +77,8 @@ class XModule(object):
|
||||
# if the icon class depends on the data in the module
|
||||
icon_class = 'other'
|
||||
|
||||
js = {}
|
||||
|
||||
def __init__(self, system, location, definition, instance_state=None, shared_state=None, **kwargs):
|
||||
'''
|
||||
Construct a new xmodule
|
||||
@@ -179,11 +181,6 @@ class XModule(object):
|
||||
'''
|
||||
return None
|
||||
|
||||
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__)
|
||||
|
||||
def get_progress(self):
|
||||
''' Return a progress.Progress object that represents how far the student has gone
|
||||
in this module. Must be implemented to get correct progress tracking behavior in
|
||||
@@ -198,6 +195,25 @@ 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):
|
||||
"""
|
||||
@@ -211,7 +227,6 @@ class XModuleDescriptor(Plugin):
|
||||
"""
|
||||
entry_point = "xmodule.v1"
|
||||
js = {}
|
||||
js_module = None
|
||||
|
||||
# A list of metadata that this module can inherit from its parent module
|
||||
inheritable_metadata = (
|
||||
@@ -398,13 +413,6 @@ class XModuleDescriptor(Plugin):
|
||||
"""
|
||||
return cls.js
|
||||
|
||||
def js_module_name(self):
|
||||
"""
|
||||
Return the name of the javascript class to instantiate when
|
||||
this module descriptor is loaded for editing
|
||||
"""
|
||||
return self.js_module
|
||||
|
||||
def get_html(self):
|
||||
"""
|
||||
Return the html used to edit this module
|
||||
|
||||
@@ -22,6 +22,7 @@ import sys
|
||||
import os
|
||||
import tempfile
|
||||
import glob2
|
||||
import errno
|
||||
|
||||
import djcelery
|
||||
from path import path
|
||||
@@ -327,6 +328,37 @@ main_vendor_js = [
|
||||
'js/vendor/jquery.qtip.min.js',
|
||||
]
|
||||
|
||||
# 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"
|
||||
try:
|
||||
os.makedirs(js_file_dir)
|
||||
except OSError as exc:
|
||||
if exc.errno == errno.EEXIST:
|
||||
pass
|
||||
else:
|
||||
raise
|
||||
|
||||
module_js_sources = []
|
||||
for descriptor in XModuleDescriptor.load_classes() + [HiddenDescriptor]:
|
||||
module = getattr(descriptor, 'module_class', None)
|
||||
if module is None:
|
||||
continue
|
||||
|
||||
js = module.get_javascript()
|
||||
for filetype in ('coffee', 'js'):
|
||||
for idx, fragment in enumerate(js.get(filetype, [])):
|
||||
path = os.path.join(js_file_dir, "{name}.{idx}.{type}".format(
|
||||
name=module.__name__,
|
||||
idx=idx,
|
||||
type=filetype))
|
||||
with open(path, 'w') as js_file:
|
||||
js_file.write(fragment)
|
||||
module_js_sources.append(path.replace(PROJECT_ROOT / "static/", ""))
|
||||
|
||||
|
||||
PIPELINE_JS = {
|
||||
'application': {
|
||||
# Application will contain all paths not in courseware_only_js
|
||||
@@ -350,6 +382,10 @@ PIPELINE_JS = {
|
||||
'source_filenames': main_vendor_js,
|
||||
'output_filename': 'js/main_vendor.js',
|
||||
},
|
||||
'module-js': {
|
||||
'source_filenames': module_js_sources,
|
||||
'output_filename': 'js/modules.js',
|
||||
},
|
||||
'spec': {
|
||||
'source_filenames': [pth.replace(PROJECT_ROOT / 'static/', '') for pth in glob2.glob(PROJECT_ROOT / 'static/coffee/spec/**/*.coffee')],
|
||||
'output_filename': 'js/spec.js'
|
||||
|
||||
1
lms/static/coffee/.gitignore
vendored
1
lms/static/coffee/.gitignore
vendored
@@ -1 +1,2 @@
|
||||
*.js
|
||||
module
|
||||
|
||||
@@ -18,7 +18,7 @@ class @Courseware
|
||||
render: ->
|
||||
$('.course-content .video').each ->
|
||||
id = $(this).attr('id').replace(/video_/, '')
|
||||
new Video id, $(this).data('streams')
|
||||
new Video id, $(this).data('streams'), $(this).data('caption-url-base')
|
||||
$('.course-content .problems-wrapper').each ->
|
||||
id = $(this).data('problem-id')
|
||||
new Problem id, $(this).attr('id'), $(this).data('url')
|
||||
|
||||
11
lms/static/js/vendor/jquery.scrollTo-1.4.2-min.js
vendored
Normal file
11
lms/static/js/vendor/jquery.scrollTo-1.4.2-min.js
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* jQuery.ScrollTo - Easy element scrolling using jQuery.
|
||||
* Copyright (c) 2007-2009 Ariel Flesler - aflesler(at)gmail(dot)com | http://flesler.blogspot.com
|
||||
* Dual licensed under MIT and GPL.
|
||||
* Date: 5/25/2009
|
||||
* @author Ariel Flesler
|
||||
* @version 1.4.2
|
||||
*
|
||||
* http://flesler.blogspot.com/2007/10/jqueryscrollto.html
|
||||
*/
|
||||
;(function(d){var k=d.scrollTo=function(a,i,e){d(window).scrollTo(a,i,e)};k.defaults={axis:'xy',duration:parseFloat(d.fn.jquery)>=1.3?0:1};k.window=function(a){return d(window)._scrollable()};d.fn._scrollable=function(){return this.map(function(){var a=this,i=!a.nodeName||d.inArray(a.nodeName.toLowerCase(),['iframe','#document','html','body'])!=-1;if(!i)return a;var e=(a.contentWindow||a).document||a.ownerDocument||a;return d.browser.safari||e.compatMode=='BackCompat'?e.body:e.documentElement})};d.fn.scrollTo=function(n,j,b){if(typeof j=='object'){b=j;j=0}if(typeof b=='function')b={onAfter:b};if(n=='max')n=9e9;b=d.extend({},k.defaults,b);j=j||b.speed||b.duration;b.queue=b.queue&&b.axis.length>1;if(b.queue)j/=2;b.offset=p(b.offset);b.over=p(b.over);return this._scrollable().each(function(){var q=this,r=d(q),f=n,s,g={},u=r.is('html,body');switch(typeof f){case'number':case'string':if(/^([+-]=)?\d+(\.\d+)?(px|%)?$/.test(f)){f=p(f);break}f=d(f,this);case'object':if(f.is||f.style)s=(f=d(f)).offset()}d.each(b.axis.split(''),function(a,i){var e=i=='x'?'Left':'Top',h=e.toLowerCase(),c='scroll'+e,l=q[c],m=k.max(q,i);if(s){g[c]=s[h]+(u?0:l-r.offset()[h]);if(b.margin){g[c]-=parseInt(f.css('margin'+e))||0;g[c]-=parseInt(f.css('border'+e+'Width'))||0}g[c]+=b.offset[h]||0;if(b.over[h])g[c]+=f[i=='x'?'width':'height']()*b.over[h]}else{var o=f[h];g[c]=o.slice&&o.slice(-1)=='%'?parseFloat(o)/100*m:o}if(/^\d+$/.test(g[c]))g[c]=g[c]<=0?0:Math.min(g[c],m);if(!a&&b.queue){if(l!=g[c])t(b.onAfterFirst);delete g[c]}});t(b.onAfter);function t(a){r.animate(g,j,b.easing,a&&function(){a.call(this,n,b)})}}).end()};k.max=function(a,i){var e=i=='x'?'Width':'Height',h='scroll'+e;if(!d(a).is('html,body'))return a[h]-d(a)[e.toLowerCase()]();var c='client'+e,l=a.ownerDocument.documentElement,m=a.ownerDocument.body;return Math.max(l[h],m[h])-Math.min(l[c],m[c])};function p(a){return typeof a=='object'?a:{top:a,left:a}}})(jQuery);
|
||||
@@ -20,6 +20,7 @@
|
||||
{% load compressed %}
|
||||
{# static files #}
|
||||
{% compressed_js 'application' %}
|
||||
{% compressed_js 'module-js' %}
|
||||
|
||||
{# spec files #}
|
||||
{% compressed_js 'spec' %}
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
<%include file="footer.html" />
|
||||
|
||||
<%static:js group='application'/>
|
||||
<%static:js group='module-js'/>
|
||||
|
||||
<%block name="js_extra"/>
|
||||
</body>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<h1> ${name} </h1>
|
||||
% endif
|
||||
|
||||
<div id="video_${id}" class="video" data-streams="${streams}">
|
||||
<div id="video_${id}" class="video" data-streams="${streams}" data-caption-url-base="/static/subs">
|
||||
<div class="tc-wrapper">
|
||||
<article class="video-wrapper">
|
||||
<section class="video-player">
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
$('.course-content .video').each(function() {
|
||||
var id;
|
||||
id = $(this).attr('id').replace(/video_/, '');
|
||||
return new Video(id, $(this).data('streams'));
|
||||
return new Video(id, $(this).data('streams'), $(this).data('caption-url'));
|
||||
});
|
||||
$('.course-content .problems-wrapper').each(function() {
|
||||
var id;
|
||||
|
||||
Reference in New Issue
Block a user