Commit 3fa636e0 by Calen Pennington

Move module javascript into common/lib/xmodule. Still TODO: run jasmine tests in that directory

parent 1395e5d5
......@@ -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)
......
[
{
"content": "Video 1",
"type": "video",
"title": "Video 1"
}, {
"content": "Video 2",
"type": "video",
"title": "Video 2"
}, {
"content": "Sample Problem",
"type": "problem",
"title": "Sample Problem"
}
]
class @Raw
constructor: (@element) ->
@edit_box = $(".edit-box", @element)
save: -> @edit_box.val()
class @HTML
class @RawDescriptor
constructor: (@element) ->
@edit_box = $(".edit-box", @element)
......
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'
......
......@@ -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')
......
/**
* 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);
\ No newline at end of file
......@@ -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;
......
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