Commit 69290c18 by Calen Pennington

Live editing of html modules implemented, but no saving to the backend

parent 1b7b7e91
......@@ -10,6 +10,7 @@ import os.path
from StringIO import StringIO
from mako.template import Template
from mako.lookup import TemplateLookup
from collections import defaultdict
from django.core.management.base import BaseCommand
from keystore.django import keystore
......@@ -42,9 +43,7 @@ class Command(BaseCommand):
# Simple lists
'chapter': 'Week',
'course': 'Course',
'sequential': 'LectureSequence',
'vertical': 'ProblemSet',
'section': {
'section': defaultdict(lambda: 'Section', {
'Lab': 'Lab',
'Lecture Sequence': 'LectureSequence',
'Homework': 'Homework',
......@@ -52,8 +51,13 @@ class Command(BaseCommand):
'Video': 'VideoSegment',
'Midterm': 'Exam',
'Final': 'Exam',
None: 'Section',
},
'Problems': 'ProblemSet',
}),
'videosequence': 'VideoSequence',
'problemset': 'ProblemSet',
'vertical': 'Section',
'sequential': 'Section',
'tab': 'Section',
# True types
'video': 'VideoSegment',
'html': 'HTML',
......@@ -78,6 +82,8 @@ class Command(BaseCommand):
e.set('url', 'i4x://mit.edu/6002xs12/{category}/{name}'.format(
category=category,
name=name))
else:
print "Skipping element with tag", e.tag
def handle_skip(e):
......@@ -150,6 +156,9 @@ class Command(BaseCommand):
'sequential': handle_list,
'vertical': handle_list,
'section': handle_list,
'videosequence': handle_list,
'problemset': handle_list,
'tab': handle_list,
# True types
'video': handle_video,
'html': handle_html,
......
......@@ -17,4 +17,4 @@ def index(request):
def edit_item(request):
item_id = request.GET['id']
item = keystore().get_item(item_id)
return HttpResponse("<section>Problem content</section>")
return HttpResponse(item.get_html())
......@@ -21,6 +21,7 @@ Longer TODO:
import sys
import tempfile
import os.path
from path import path
############################ FEATURE CONFIGURATION #############################
......@@ -154,11 +155,30 @@ PIPELINE_CSS = {
PIPELINE_ALWAYS_RECOMPILE = ['sass/base-style.scss']
from x_module import XModuleDescriptor
js_file_dir = tempfile.mkdtemp('js', dir=PROJECT_ROOT / "static")
module_js_sources = []
for xmodule in XModuleDescriptor.load_classes():
js = xmodule.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=xmodule.__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 = {
'main': {
'source_filenames': ['coffee/main.coffee'],
'output_filename': 'js/main.js',
},
'module-js': {
'source_filenames': module_js_sources,
'output_filename': 'js/modules.js',
}
}
PIPELINE_COMPILERS = [
......
bind_edit_links = ->
$('a.module-edit').click ->
edit_item($(this).attr('id'))
return false
edit_item = (id) ->
$.get('/edit_item', {id: id}, (data) ->
$('#module-html').empty().append(data)
bind_edit_links()
$('section.edit-pane').show()
$('body').addClass('content')
window['construct_html']('module-html')
)
$ ->
$('section.main-content').children().hide()
$('.editable').inlineEdit()
......@@ -20,12 +34,6 @@ $ ->
$(this).parent().parent().hide()
return false
edit_item = (id) ->
$.get('/edit_item', {id: id}, (data) ->
$('section.edit-pane').empty().append(data)
$('section.edit-pane').show()
$('body').addClass('content')
)
setHeight = ->
windowHeight = $(this).height()
......@@ -55,10 +63,6 @@ $ ->
$(document).ready(setHeight)
$(window).bind('resize', setHeight)
$('a.module-edit').click ->
edit_item($(this).attr('id'))
return false
$('.video-new a').click ->
$('section.edit-pane').show()
return false
......@@ -66,3 +70,6 @@ $ ->
$('.problem-new a').click ->
$('section.edit-pane').show()
return false
bind_edit_links()
......@@ -23,7 +23,7 @@
<%block name="content"></%block>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script type="text/javascript" src="${ STATIC_URL}/js/jquery.min.js"></script>
<script type="text/javascript" src="${ STATIC_URL }/js/markitup/jquery.markitup.js"></script>
<script type="text/javascript" src="${ STATIC_URL }/js/markitup/sets/wiki/set.js"></script>
% if settings.MITX_FEATURES['USE_DJANGO_PIPELINE']:
......@@ -31,6 +31,8 @@
% else:
<script src="${ STATIC_URL }/js/main.js"></script>
% endif
<%static:js group='module-js'/>
<script src="${ STATIC_URL }/js/jquery.inlineedit.js"></script>
<script src="${ STATIC_URL }/js/jquery.leanModal.min.js"></script>
<script src="${ STATIC_URL }/js/jquery.tablednd.js"></script>
......
......@@ -7,14 +7,9 @@
<%include file="widgets/navigation.html"/>
<section class="main-content">
<%include file="widgets/week-edit.html"/>
<%include file="widgets/week-new.html"/>
<%include file="widgets/sequnce-edit.html"/>
<%include file="widgets/video-edit.html"/>
<%include file="widgets/video-new.html"/>
<%include file="widgets/problem-edit.html"/>
<%include file="widgets/problem-new.html"/>
<section class="edit-pane"/>
<section class="edit-pane">
<div id="module-html"/>
</section>
</section>
</section>
......
<%namespace name='static' file='../static_content.html'/>
<section class="html-edit">
<header>
<a href="#" class="cancel">Cancel</a>
<a href="#" class="save-update">Save &amp; Update</a>
</header>
<section>
<header>
<h1 class="editable">${module.name}</h1>
<section>
<textarea name="" id="edit-box" rows="8" cols="40">${module.definition['data']['text']}</textarea>
<div id="edit-preview" class="preview">${module.definition['data']['text']}</div>
</section>
<a href="" class="save-update">Save &amp; Update</a>
</section>
</section>
......@@ -6,7 +6,7 @@
<section>
<header>
<h1 class="editable">New Problem</h1>
<h1 class="editable">${module.name}</h1>
<section class="author">
<div>
<h2>Last modified:</h2>
......
<section class="sequence-edit">
<header>
<div class="week">
<h2><a href="">Week 1</a></h2>
<ul>
<li>
<p class="editable"><strong>Goal title:</strong> This is the goal body and is where the goal will be further explained</p>
</li>
</ul>
</div>
<div>
<h1 class="editable">Lecture sequence</h1>
<p><strong>Group type:</strong> Ordered Sequence</p>
<h1 class="editable">${module.name}</h1>
<p><strong>Module Type:</strong>${module.type}</p>
</div>
</header>
......@@ -51,72 +43,12 @@
<ol>
<li>
<ol>
% for child in module.get_children():
<li>
<a href="" class="problem-edit">Problem title 11</a>
<a href="#" class="draggable">handle</a>
</li>
<li>
<a href="#" class="sequence-edit">Problem Group</a>
<a href="#" class="draggable">handle</a>
</li>
<li>
<a href="#" class="problem-edit">Problem title 14</a>
<a href="#" class="draggable">handle</a>
</li>
<li>
<a href="#" class="video-edit">Video 3</a>
<a href="#" class="draggable">handle</a>
</li>
<li class="group">
<header>
<h3>
<a href="#" class="problem-edit">Problem group</a>
<a href="#" class="draggable">handle</a>
</h3>
</header>
<ol>
<li>
<a href="#" class="problem-edit">Problem title 11</a>
<a href="#" class="draggable">handle</a>
</li>
<li>
<a href="#" class="problem-edit">Problem title 11</a>
<a href="#" class="draggable">handle</a>
</li>
<li>
<a href="#" class="problem-edit">Problem title 11</a>
<a href="#" class="draggable">handle</a>
</li>
</ol>
</li>
<li>
<a href="#" class="problem-edit">Problem title 13</a>
<a href="#" class="draggable">handle</a>
</li>
<li>
<a href="#" class="problem-edit">Problem title 14</a>
<a href="#" class="draggable">handle</a>
</li>
<li>
<a href="#" class="video-edit">Video 3</a>
<a href="#" class="draggable">handle</a>
</li>
<li>
<a href="" class="problem-edit">Problem title 11</a>
<a href="#" class="draggable">handle</a>
</li>
<li>
<a href="#" class="sequence-edit">Problem Group</a>
<a href="#" class="draggable">handle</a>
</li>
<li>
<a href="#" class="problem-edit">Problem title 14</a>
<a href="#" class="draggable">handle</a>
</li>
<li>
<a href="#" class="video-edit">Video 3</a>
<a href="#" class="module-edit" id="${child.url}">${child.name}</a>
<a href="#" class="draggable">handle</a>
</li>
%endfor
</ol>
</li>
......
......@@ -10,7 +10,8 @@ import StringIO
from datetime import timedelta
from lxml import etree
from x_module import XModule, XModuleDescriptor
from x_module import XModule
from mako_module import MakoModuleDescriptor
from progress import Progress
from capa.capa_problem import LoncapaProblem
from capa.responsetypes import StudentInputError
......@@ -63,8 +64,14 @@ class ComplexEncoder(json.JSONEncoder):
return json.JSONEncoder.default(self, obj)
class ModuleDescriptor(XModuleDescriptor):
pass
class CapaModuleDescriptor(MakoModuleDescriptor):
"""
Module implementing problems in the LON-CAPA format,
as implemented by capa.capa_problem
"""
mako_template = 'widgets/problem-edit.html'
class Module(XModule):
......
import json
import logging
from x_module import XModule, XModuleDescriptor
from x_module import XModule
from mako_module import MakoModuleDescriptor
from lxml import etree
log = logging.getLogger("mitx.courseware")
#-----------------------------------------------------------------------------
class ModuleDescriptor(XModuleDescriptor):
pass
class HtmlModuleDescriptor(MakoModuleDescriptor):
"""
Module for putting raw html in a course
"""
mako_template = "widgets/html-edit.html"
# TODO (cpennington): Make this into a proper module
js = {'coffee': ["""
window.construct_html = (id) ->
$('#' + id + " #edit-box").on('input', ->
$('#' + id + ' #edit-preview').empty().append($(this).val())
)
"""]}
class Module(XModule):
id_attribute = 'filename'
......
from x_module import XModuleDescriptor
from mitxmako.shortcuts import render_to_string
class MakoModuleDescriptor(XModuleDescriptor):
"""
Module descriptor intended as a mixin that uses a mako template
to specify the module html.
Expects the descriptor to have the `mako_template` attribute set
with the name of the template to render, and it will pass
the descriptor as the `module` parameter to that template
"""
def get_html(self):
return render_to_string(self.mako_template, {
'module': self
})
......@@ -3,7 +3,8 @@ import logging
from lxml import etree
from x_module import XModule, XModuleDescriptor
from x_module import XModule
from mako_module import MakoModuleDescriptor
from xmodule.progress import Progress
log = logging.getLogger("mitx.common.lib.seq_module")
......@@ -12,9 +13,6 @@ log = logging.getLogger("mitx.common.lib.seq_module")
# OBSOLETE: This obsoletes 'type'
class_priority = ['video', 'problem']
class ModuleDescriptor(XModuleDescriptor):
pass
class Module(XModule):
''' Layout module which lays out content in a temporal sequence
'''
......@@ -117,5 +115,5 @@ class Module(XModule):
self.rendered = False
class SectionDescriptor(XModuleDescriptor):
pass
class SectionDescriptor(MakoModuleDescriptor):
mako_template = 'widgets/sequence-edit.html'
......@@ -19,6 +19,9 @@ setup(
"TutorialIndex = seq_module:SectionDescriptor",
"Exam = seq_module:SectionDescriptor",
"VideoSegment = video_module:VideoSegmentDescriptor",
"ProblemSet = seq_module:SectionDescriptor",
"Problem = capa_module:CapaModuleDescriptor",
"HTML = html_module:HtmlModuleDescriptor",
]
}
)
......@@ -3,7 +3,6 @@ import pkg_resources
import logging
from keystore import Location
from progress import Progress
log = logging.getLogger('mitx.' + __name__)
......@@ -30,6 +29,12 @@ class Plugin(object):
return classes[0].load()
@classmethod
def load_classes(cls):
return [class_.load()
for class_
in pkg_resources.iter_entry_points(cls.entry_point)]
class XModule(object):
''' Implements a generic learning module.
......@@ -154,6 +159,7 @@ class XModuleDescriptor(Plugin):
and can generate XModules (which do know about student state).
"""
entry_point = "xmodule.v1"
js = {}
@staticmethod
def load_from_json(json_data, system):
......@@ -178,6 +184,19 @@ class XModuleDescriptor(Plugin):
"""
return cls(system=system, **json_data)
@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 CMS
"""
return cls.js
def __init__(self,
system,
definition=None,
......@@ -221,21 +240,27 @@ class XModuleDescriptor(Plugin):
else:
return [child for child in self._child_instances if child.type in categories]
def get_html(self):
"""
Return the html used to edit this module
"""
raise NotImplementedError("get_html() must be provided by specific modules")
def get_xml(self):
''' For conversions between JSON and legacy XML representations.
'''
if self.xml:
if self.xml:
return self.xml
else:
else:
raise NotImplementedError("JSON->XML Translation not implemented")
def get_json(self):
''' For conversions between JSON and legacy XML representations.
'''
if self.json:
if self.json:
raise NotImplementedError
return self.json # TODO: Return context as well -- files, etc.
else:
return self.json # TODO: Return context as well -- files, etc.
else:
raise NotImplementedError("XML->JSON Translation not implemented")
#def handle_cms_json(self):
......
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