Merge pull request #135 from MITx/cpennington/cms-editing
Roundtrip HTML module editing working in the CMS
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
from mitxmako.shortcuts import render_to_response
|
||||
from keystore.django import keystore
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django_future.csrf import ensure_csrf_cookie
|
||||
from django.http import HttpResponse
|
||||
import json
|
||||
|
||||
|
||||
@ensure_csrf_cookie
|
||||
def index(request):
|
||||
# TODO (cpennington): These need to be read in from the active user
|
||||
org = 'mit.edu'
|
||||
@@ -11,3 +14,20 @@ def index(request):
|
||||
course = keystore().get_item(['i4x', org, course, 'Course', name])
|
||||
weeks = course.get_children()
|
||||
return render_to_response('index.html', {'weeks': weeks})
|
||||
|
||||
|
||||
def edit_item(request):
|
||||
item_id = request.GET['id']
|
||||
item = keystore().get_item(item_id)
|
||||
return render_to_response('unit.html', {
|
||||
'contents': item.get_html(),
|
||||
'type': item.type,
|
||||
'name': item.name,
|
||||
})
|
||||
|
||||
|
||||
def save_item(request):
|
||||
item_id = request.POST['id']
|
||||
data = json.loads(request.POST['data'])
|
||||
keystore().update_item(item_id, data)
|
||||
return HttpResponse(json.dumps({}))
|
||||
|
||||
@@ -21,6 +21,9 @@ Longer TODO:
|
||||
|
||||
import sys
|
||||
import tempfile
|
||||
import os.path
|
||||
import os
|
||||
import errno
|
||||
from path import path
|
||||
|
||||
############################ FEATURE CONFIGURATION #############################
|
||||
@@ -154,7 +157,38 @@ PIPELINE_CSS = {
|
||||
|
||||
PIPELINE_ALWAYS_RECOMPILE = ['sass/base-style.scss']
|
||||
|
||||
from x_module import XModuleDescriptor
|
||||
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 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', 'coffee/unit.coffee'],
|
||||
'output_filename': 'js/main.js',
|
||||
},
|
||||
'module-js': {
|
||||
'source_filenames': module_js_sources,
|
||||
'output_filename': 'js/modules.js',
|
||||
}
|
||||
}
|
||||
|
||||
PIPELINE_COMPILERS = [
|
||||
|
||||
2
cms/static/coffee/.gitignore
vendored
Normal file
2
cms/static/coffee/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
*.js
|
||||
module
|
||||
78
cms/static/coffee/main.coffee
Normal file
78
cms/static/coffee/main.coffee
Normal file
@@ -0,0 +1,78 @@
|
||||
class @CMS
|
||||
@bind = =>
|
||||
$('a.module-edit').click ->
|
||||
CMS.edit_item($(this).attr('id'))
|
||||
return false
|
||||
|
||||
@edit_item = (id) =>
|
||||
$.get('/edit_item', {id: id}, (data) =>
|
||||
$('#module-html').empty().append(data)
|
||||
CMS.bind()
|
||||
$('section.edit-pane').show()
|
||||
$('body').addClass('content')
|
||||
new Unit('unit-wrapper', id)
|
||||
)
|
||||
|
||||
$ ->
|
||||
$.ajaxSetup
|
||||
headers : { 'X-CSRFToken': $.cookie 'csrftoken' }
|
||||
$('section.main-content').children().hide()
|
||||
$('.editable').inlineEdit()
|
||||
$('.editable-textarea').inlineEdit({control: 'textarea'})
|
||||
|
||||
heighest = 0
|
||||
$('.cal ol > li').each ->
|
||||
heighest = if $(this).height() > heighest then $(this).height() else heighest
|
||||
|
||||
$('.cal ol > li').css('height',heighest + 'px')
|
||||
|
||||
$('.add-new-section').click -> return false
|
||||
|
||||
$('.new-week .close').click ->
|
||||
$(this).parents('.new-week').hide()
|
||||
$('p.add-new-week').show()
|
||||
return false
|
||||
|
||||
$('.save-update').click ->
|
||||
$(this).parent().parent().hide()
|
||||
return false
|
||||
|
||||
|
||||
setHeight = ->
|
||||
windowHeight = $(this).height()
|
||||
contentHeight = windowHeight - 29
|
||||
|
||||
$('section.main-content > section').css('min-height', contentHeight)
|
||||
$('body.content .cal').css('height', contentHeight)
|
||||
|
||||
$('.edit-week').click ->
|
||||
$('body').addClass('content')
|
||||
$('body.content .cal').css('height', contentHeight)
|
||||
$('section.edit-pane').show()
|
||||
return false
|
||||
|
||||
$('a.week-edit').click ->
|
||||
$('body').addClass('content')
|
||||
$('body.content .cal').css('height', contentHeight)
|
||||
$('section.edit-pane').show()
|
||||
return false
|
||||
|
||||
$('a.sequence-edit').click ->
|
||||
$('body').addClass('content')
|
||||
$('body.content .cal').css('height', contentHeight)
|
||||
$('section.edit-pane').show()
|
||||
return false
|
||||
|
||||
$(document).ready(setHeight)
|
||||
$(window).bind('resize', setHeight)
|
||||
|
||||
$('.video-new a').click ->
|
||||
$('section.edit-pane').show()
|
||||
return false
|
||||
|
||||
$('.problem-new a').click ->
|
||||
$('section.edit-pane').show()
|
||||
return false
|
||||
|
||||
CMS.bind()
|
||||
|
||||
15
cms/static/coffee/unit.coffee
Normal file
15
cms/static/coffee/unit.coffee
Normal file
@@ -0,0 +1,15 @@
|
||||
class @Unit
|
||||
constructor: (@element_id, @module_id) ->
|
||||
@module = new window[$("##{@element_id}").attr('class')] 'module-html'
|
||||
|
||||
$("##{@element_id} .save-update").click (event) =>
|
||||
event.preventDefault()
|
||||
$.post("save_item", {
|
||||
id: @module_id
|
||||
data: JSON.stringify(@module.save())
|
||||
})
|
||||
|
||||
$("##{@element_id} .cancel").click (event) =>
|
||||
event.preventDefault()
|
||||
CMS.edit_item(@module_id)
|
||||
|
||||
47
cms/static/js/jquery.cookie.js
Normal file
47
cms/static/js/jquery.cookie.js
Normal file
@@ -0,0 +1,47 @@
|
||||
/*!
|
||||
* jQuery Cookie Plugin
|
||||
* https://github.com/carhartl/jquery-cookie
|
||||
*
|
||||
* Copyright 2011, Klaus Hartl
|
||||
* Dual licensed under the MIT or GPL Version 2 licenses.
|
||||
* http://www.opensource.org/licenses/mit-license.php
|
||||
* http://www.opensource.org/licenses/GPL-2.0
|
||||
*/
|
||||
(function($) {
|
||||
$.cookie = function(key, value, options) {
|
||||
|
||||
// key and at least value given, set cookie...
|
||||
if (arguments.length > 1 && (!/Object/.test(Object.prototype.toString.call(value)) || value === null || value === undefined)) {
|
||||
options = $.extend({}, options);
|
||||
|
||||
if (value === null || value === undefined) {
|
||||
options.expires = -1;
|
||||
}
|
||||
|
||||
if (typeof options.expires === 'number') {
|
||||
var days = options.expires, t = options.expires = new Date();
|
||||
t.setDate(t.getDate() + days);
|
||||
}
|
||||
|
||||
value = String(value);
|
||||
|
||||
return (document.cookie = [
|
||||
encodeURIComponent(key), '=', options.raw ? value : encodeURIComponent(value),
|
||||
options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE
|
||||
options.path ? '; path=' + options.path : '',
|
||||
options.domain ? '; domain=' + options.domain : '',
|
||||
options.secure ? '; secure' : ''
|
||||
].join(''));
|
||||
}
|
||||
|
||||
// key and possibly options given, get cookie...
|
||||
options = value || {};
|
||||
var decode = options.raw ? function(s) { return s; } : decodeURIComponent;
|
||||
|
||||
var pairs = document.cookie.split('; ');
|
||||
for (var i = 0, pair; pair = pairs[i] && pairs[i].split('='); i++) {
|
||||
if (decode(pair[0]) === key) return decode(pair[1] || ''); // IE saves cookies with empty string as "c; ", e.g. without "=" as opposed to EOMB, thus pair[1] may be undefined
|
||||
}
|
||||
return null;
|
||||
};
|
||||
})(jQuery);
|
||||
4
cms/static/js/jquery.min.js
vendored
Normal file
4
cms/static/js/jquery.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@@ -1,85 +0,0 @@
|
||||
$(document).ready(function(){
|
||||
$('section.main-content').children().hide();
|
||||
|
||||
$(function(){
|
||||
$('.editable').inlineEdit();
|
||||
$('.editable-textarea').inlineEdit({control: 'textarea'});
|
||||
});
|
||||
|
||||
var heighest = 0;
|
||||
$('.cal ol > li').each(function(){
|
||||
heighest = ($(this).height() > heighest) ? $(this).height() : heighest;
|
||||
|
||||
});
|
||||
|
||||
$('.cal ol > li').css('height',heighest + 'px');
|
||||
|
||||
$('.add-new-section').click(function() {
|
||||
return false;
|
||||
});
|
||||
|
||||
$('.new-week .close').click( function(){
|
||||
$(this).parents('.new-week').hide();
|
||||
$('p.add-new-week').show();
|
||||
return false;
|
||||
});
|
||||
|
||||
$('.save-update').click(function(){
|
||||
$(this).parent().parent().hide();
|
||||
return false;
|
||||
});
|
||||
|
||||
setHeight = function(){
|
||||
var windowHeight = $(this).height();
|
||||
var contentHeight = windowHeight - 29;
|
||||
|
||||
$('section.main-content > section').css('min-height', contentHeight);
|
||||
$('body.content .cal').css('height', contentHeight);
|
||||
|
||||
$('.edit-week').click( function() {
|
||||
$('body').addClass('content');
|
||||
$('body.content .cal').css('height', contentHeight);
|
||||
$('section.week-new').show();
|
||||
return false;
|
||||
});
|
||||
|
||||
$('.cal ol li header h1 a').click( function() {
|
||||
$('body').addClass('content');
|
||||
$('body.content .cal').css('height', contentHeight);
|
||||
$('section.week-edit').show();
|
||||
return false;
|
||||
});
|
||||
|
||||
$('a.sequence-edit').click(function(){
|
||||
$('body').addClass('content');
|
||||
$('body.content .cal').css('height', contentHeight);
|
||||
$('section.sequence-edit').show();
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
$(document).ready(setHeight);
|
||||
$(window).bind('resize', setHeight);
|
||||
|
||||
$('.video-new a').click(function(){
|
||||
$('section.video-new').show();
|
||||
return false;
|
||||
});
|
||||
|
||||
$('a.video-edit').click(function(){
|
||||
$('section.video-edit').show();
|
||||
return false;
|
||||
});
|
||||
|
||||
$('.problem-new a').click(function(){
|
||||
$('section.problem-new').show();
|
||||
return false;
|
||||
});
|
||||
|
||||
$('a.problem-edit').click(function(){
|
||||
$('section.problem-edit').show();
|
||||
return false;
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
Sass Watch:
|
||||
|
||||
sass --watch cms/static/sass:cms/static/css -r ./cms/static/sass/bourbon/lib/bourbon.rb
|
||||
sass --watch cms/static/sass:cms/static/sass -r ./cms/static/sass/bourbon/lib/bourbon.rb
|
||||
|
||||
@@ -111,3 +111,7 @@ input[type="submit"], .button {
|
||||
display: block;
|
||||
float: right;
|
||||
}
|
||||
|
||||
textarea {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
@@ -1,18 +1,15 @@
|
||||
section.video-new, section.video-edit, section.problem-new, section.problem-edit {
|
||||
position: absolute;
|
||||
top: 72px;
|
||||
right: 0;
|
||||
section.video-new,
|
||||
section.video-edit,
|
||||
section.problem-new,
|
||||
section.problem-edit,
|
||||
section.html-edit {
|
||||
background: #fff;
|
||||
width: flex-grid(6);
|
||||
@include box-shadow(0 0 6px #666);
|
||||
border: 1px solid #333;
|
||||
border-right: 0;
|
||||
z-index: 4;
|
||||
|
||||
> header {
|
||||
background: #666;
|
||||
background: #eee;
|
||||
@include clearfix;
|
||||
color: #fff;
|
||||
padding: 6px;
|
||||
border-bottom: 1px solid #333;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
|
||||
@@ -1,20 +1,23 @@
|
||||
section.problem-new, section.problem-edit {
|
||||
section#unit-wrapper {
|
||||
> header {
|
||||
border-bottom: 2px solid #333;
|
||||
@include clearfix();
|
||||
padding: 6px 20px;
|
||||
|
||||
h1 {
|
||||
font-size: 18px;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 1px;
|
||||
float: left;
|
||||
}
|
||||
|
||||
p {
|
||||
float: right;
|
||||
}
|
||||
}
|
||||
> section {
|
||||
textarea {
|
||||
@include box-sizing(border-box);
|
||||
display: block;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
div.preview {
|
||||
background: #eee;
|
||||
@include box-sizing(border-box);
|
||||
height: 40px;
|
||||
padding: 10px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
a.save {
|
||||
padding: 20px;
|
||||
a.save-update {
|
||||
@extend .button;
|
||||
@include inline-block();
|
||||
margin-top: 20px;
|
||||
@@ -22,3 +25,47 @@ section.problem-new, section.problem-edit {
|
||||
}
|
||||
}
|
||||
|
||||
section.problem-new,
|
||||
section.problem-edit,
|
||||
section.html-edit {
|
||||
textarea {
|
||||
@include box-sizing(border-box);
|
||||
display: block;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
|
||||
div.preview {
|
||||
background: #eee;
|
||||
@include box-sizing(border-box);
|
||||
min-height: 40px;
|
||||
padding: 10px;
|
||||
width: 100%;
|
||||
margin-top: 10px;
|
||||
|
||||
h1 {
|
||||
font-size: 24px;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 20px;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 18;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
ul {
|
||||
padding-left: 20px;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
p {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,11 +23,18 @@
|
||||
|
||||
<%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']:
|
||||
<%static:js group='main'/>
|
||||
% 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.cookie.js"></script>
|
||||
<script src="${ STATIC_URL }/js/jquery.leanModal.min.js"></script>
|
||||
<script src="${ STATIC_URL }/js/jquery.tablednd.js"></script>
|
||||
</body>
|
||||
|
||||
@@ -7,13 +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">
|
||||
<div id="module-html"/>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
</section>
|
||||
|
||||
19
cms/templates/unit.html
Normal file
19
cms/templates/unit.html
Normal file
@@ -0,0 +1,19 @@
|
||||
<section id="unit-wrapper" class="${type}">
|
||||
<header>
|
||||
<h1 class="editable">${name}</h1>
|
||||
<p>Unit type: ${type}</p>
|
||||
<!-- <div class="actions"> -->
|
||||
<!-- <a href="#" class="cancel">Cancel</a> -->
|
||||
<!-- <a href="#" class="save-update">Save & Update</a> -->
|
||||
<!-- </div> -->
|
||||
</header>
|
||||
<section>
|
||||
${contents}
|
||||
</section>
|
||||
<section>
|
||||
<div class="actions">
|
||||
<a href="" class="save-update">Save & Update</a>
|
||||
<a href="#" class="cancel">Cancel</a>
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
@@ -1,242 +0,0 @@
|
||||
<ul class="tabs">
|
||||
<li class="active">English (main)</li>
|
||||
<li>French</li>
|
||||
<li>English v2</li>
|
||||
<li>+</li>
|
||||
</ul>
|
||||
<textarea class="captions">
|
||||
{
|
||||
"start": [
|
||||
0, 2770, 5700, 7620, 10320, 12130, 13430, 15170, 17940, 20890, 22840, 26200, 28980, 30170, 32040, 33240, 36420, 37570, 41760, 44270, 48120, 50810, 52960, 54070, 56480, 58600, 59550, 62520, 67680, 69990, 74280, 77605, 81320, 85050, 88430, 92750, 96010, 99440, 103160, 106650, 110050, 114240, 118800, 120980, 122290, 125040, 127900, 130990, 133170, 134580, 139410, 143180, 144530, 147640, 150800, 153220, 156570, 161000, 162010, 162930, 164090, 165490, 167650, 170630, 172020, 174760, 178480, 181840, 185840, 188620, 194160, 196110, 199370, 201360, 204140, 209970, 211850, 215030, 218890, 221730, 225370, 228790, 231690, 234080, 236300, 237970, 240450, 244010, 247670, 251910, 253230, 260149, 263330, 266380, 269470, 273570, 278240, 280050, 282810, 288060, 292410, 297300, 298950, 300860, 302500, 304350, 309620, 312950, 318710, 322870, 323810, 328380, 332840, 334440, 338640, 341540, 345490, 348900, 350730, 354480, 357640, 362310, 365020, 366890, 368900, 373200, 374240, 379410, 381580, 381990, 385680, 389080, 390750, 393970, 395960, 397340, 401000, 403210, 405650, 408880, 411730, 415490, 421350, 425630, 427520, 430490, 435320, 436860, 439460, 443300, 447010, 450740, 453820, 456610, 460140, 463730, 466700, 471200, 472450, 475260, 476330, 480650, 483650, 486320, 489080, 491940, 496690, 501990, 502740, 507000, 511650, 513220, 517330, 519169, 524159, 528140, 529960, 531270, 535340, 541590, 543710, 545170, 550960, 551810, 555140, 556230, 557750, 560530, 564300, 566800, 567600, 569910, 573170, 578610, 580490, 585520, 586500, 589880, 591750, 596120, 597290, 600290, 602940, 606490, 608560, 610690, 612600, 613970, 616670, 621260, 622310, 624520, 626750, 629550, 632500, 635510, 637470, 638900, 640370, 644200, 647470, 648740, 652700, 653950 ],
|
||||
"end": [
|
||||
2770, 5700, 7620, 10320, 12130, 13430, 15170, 17940, 20890, 22840, 26200, 28980, 30170, 32040, 33240, 36420, 37570, 41760, 44269, 48120, 50809, 52960, 54070, 56480, 58599, 59550, 62519, 67680, 69990, 74280, 77605, 81320, 85050, 88429, 92750, 96010, 99440, 103160, 106649, 110050, 114240, 118800, 120980, 122290, 125040, 127900, 130990, 133170, 134579, 139410, 143180, 144530, 147640, 150799, 153220, 156570, 161000, 162010, 162929, 164090, 165490, 167650, 170630, 172019, 174760, 178480, 181840, 185840, 188620, 194160, 196109, 199370, 201360, 204140, 209970, 211850, 215030, 218890, 221730, 225369, 228790, 231690, 234079, 236300, 237970, 240450, 244010, 247670, 251910, 253230, 260149, 263330, 266380, 269469, 273570, 278240, 280050, 282810, 288060, 292410, 297300, 298950, 300860, 302500, 304350, 309620, 312950, 318710, 322870, 323810, 328380, 332840, 334440, 338640, 341539, 345490, 348900, 350729, 354480, 357640, 362310, 365020, 366890, 368900, 373200, 374240, 379410, 381580, 381990, 385680, 389080, 390750, 393970, 395960, 397340, 401000, 403210, 405650, 408880, 411730, 415490, 421350, 425630, 427520, 430490, 435320, 436860, 439460, 443299, 447010, 450740, 453820, 456610, 460140, 463729, 466700, 471200, 472450, 475260, 476330, 480650, 483650, 486320, 489080, 491940, 496690, 501990, 502740, 507000, 511650, 513220, 517330, 519169, 524159, 528140, 529960, 531270, 535340, 541590, 543710, 545170, 550959, 551810, 555140, 556230, 557750, 560530, 564300, 566800, 567599, 569910, 573170, 578610, 580490, 585520, 586500, 589880, 591750, 596120, 597290, 600290, 602939, 606490, 608560, 610689, 612600, 613970, 616670, 621260, 622310, 624520, 626750, 629550, 632500, 635510, 637470, 638900, 640370, 644200, 647470, 648740, 652700, 653950, 655050 ],
|
||||
"text": [
|
||||
"SUBJECT 1: The various methods\nI'm going to show you--",
|
||||
"in particular, the first method\none and method two for",
|
||||
"solving non-linear equations--",
|
||||
"are really just particular\nways of solving a pair of",
|
||||
"equations where at least\none of each have some",
|
||||
"non-linearity to them.",
|
||||
"So let's start with the\ngraphical method.",
|
||||
"And my circuit is on the\nright-hand side.",
|
||||
"And I'm showing you the same\nvoltage source resistor--",
|
||||
"the Thevenin pattern--",
|
||||
"connected to Device D. And\nbelow that, I have the",
|
||||
"equation iD equals ae\nraised to bvD, which",
|
||||
"is the device equation.",
|
||||
"So as before, let me\ngo ahead and do all",
|
||||
"the first few steps.",
|
||||
"I go ahead and write the\nnode equation at vD.",
|
||||
"And I got that.",
|
||||
"I go in and substitute, as I\nalways do, in the node method",
|
||||
"for the current, using\nthe device relation.",
|
||||
"And just for fun here, let me\nkeep that separate for now.",
|
||||
"In the analytical method, notice\nthat you ended up with",
|
||||
"these two equations, and\nyou had to solve",
|
||||
"for these two unknowns.",
|
||||
"And we did that using\nanalytical methods.",
|
||||
"In this video, I'm going to\nsolve these using the",
|
||||
"graphical method.",
|
||||
"In order to do so here's what\nI'm going to do I want to",
|
||||
"start by rearranging the terms\nin my equation 1 to make it a",
|
||||
"little bit more convenient\nto draw the graph.",
|
||||
"So notice in equation 2, I\nhave iD equals something.",
|
||||
"And then I have an expression\nin vD and iD.",
|
||||
"So what I'd like to do is let\nme start by taking this",
|
||||
"equation here and expressing it\nin more of a standard form",
|
||||
"so I can get something symmetric\nto equation 2.",
|
||||
"So let me express this by\npulling iD to the left-hand",
|
||||
"side all by itself, and so I\nget something like this.",
|
||||
"So I get iD on the left-hand\nside, and then I'm going to",
|
||||
"move vD minus V divided by\nr do the right hand side.",
|
||||
"So let's start with minus V\ndivided by R, and when I move",
|
||||
"that to the right-hand side, it\nbecomes V divided by R. And",
|
||||
"then when I move vD over R to\nthe right-hand side, I get",
|
||||
"minus vD over R. And I've simply\nnot done much here.",
|
||||
"I just have done some\nrearranging of the terms in",
|
||||
"equation 1.",
|
||||
"And since I haven't done\nanything unique and different,",
|
||||
"I'm just going to label\nthis as 1 prime.",
|
||||
"So I just got this from equation\n1, and I just labeled",
|
||||
"that as 1 prime.",
|
||||
"Continuing with the method--",
|
||||
"and now I'm summarizing for you\nequations 1 prime and 2--",
|
||||
"we want both of them for iD on\nthe left-hand side expressed",
|
||||
"as a function of vD.",
|
||||
"And in equation 2,\nit is non-linear.",
|
||||
"So the graphical method can\nbe summarized as follows.",
|
||||
"To start, I want you to\nnotice something.",
|
||||
"Essentially all we're trying to\ndo is find a solution, find",
|
||||
"a value for vD and iD that\nsatisfies both equations, 1",
|
||||
"prime and 2.",
|
||||
"that's all we're trying to do.",
|
||||
"It's just math here.",
|
||||
"There's no circuits here.",
|
||||
"We're just doing some relatively\nsimple math.",
|
||||
"We just have to figure out what\niD and vD are, and we'll",
|
||||
"use the graphical method.",
|
||||
"So to do the graphical method,\nwhat I'm going to do is I'm",
|
||||
"going to plot the two equations\nin a pair of graphs.",
|
||||
"And let me first start by\nplotting equation 2.",
|
||||
"And in equation 2, I'm going\nto plot iD equals a",
|
||||
"raised to ae bvD.",
|
||||
"I'm going to plot iD equals\na times e raised to bvD.",
|
||||
"That's my equation 2.",
|
||||
"And this is the plot\nthat I get for it.",
|
||||
"It's a plot that I had before.",
|
||||
"So that's my equation 2.",
|
||||
"Notice that this plot here is\nsimply the constraint on iD",
|
||||
"and vD imposed by the device.",
|
||||
"This little circuit here\ncontaining the Thevenin",
|
||||
"equivalent and connected to\nthe device, equation 2 is",
|
||||
"simply the constraint imposed\nby the device.",
|
||||
"The device properties are such\nthat it is going to constrain",
|
||||
"iD and vD into some\nrelationship.",
|
||||
"This constraint that I've\nplotted here as equation 2 is",
|
||||
"simply the constraint imposed\nby this device.",
|
||||
"OK, next, let me\ngo to 1 prime.",
|
||||
"And in 1 prime, let\nme go ahead and",
|
||||
"plot the 1 prime equation.",
|
||||
"And that equation, as we\nrewrite that here, is V",
|
||||
"divided by R minus vD divided\nby R. So I'm just going to",
|
||||
"plot that equation for you\nin a second graph.",
|
||||
"So how do I plot this?",
|
||||
"So notice here that when vD is\n0, then iD is V divided by R.",
|
||||
"So that is one point on\nthe straight line.",
|
||||
"Notice that this is an equation\nfor a straight line.",
|
||||
"It's a linear relationship\nbetween iD and vD.",
|
||||
"Next, when iD is 0--\nso when iD is 0--",
|
||||
"then notice that R and R can be\ncanceled out, and V will be",
|
||||
"equal to vD.",
|
||||
"So when iD is 0, V\nand vD are equal.",
|
||||
"So therefore, vD equals V. So\nthis is the line when iD is 0.",
|
||||
"And for that, vD equals V. So\nthen I get this [? long, ?]",
|
||||
"straight line for the\nrelationship between vD and iD",
|
||||
"according to 1 prime.",
|
||||
"So what's the slope\nof this line here?",
|
||||
"Can you tell me what the\nslope of this line is.",
|
||||
"Let me give you a few seconds\nto think about it.",
|
||||
null,
|
||||
"OK, from the equation 1 prime--\nfrom this equation--",
|
||||
"the slope is simply given by the\ncoefficient of vD, since",
|
||||
"the slope is negative, which\nis why the line is inclined",
|
||||
"the following way.",
|
||||
"So the slope here is simply\nminus 1 divided by R.",
|
||||
"So that is my constraint\nthat relates vD to iD.",
|
||||
"And where did that constraint\ncome from?",
|
||||
"That constraint is the\nconstraint on iD and vD that",
|
||||
"has been imposed by the\nrest of the circuit.",
|
||||
"So if the first constraint was\nimposed by the device, then",
|
||||
"the second constraint is\nimposed by the Thevenin",
|
||||
"equivalent that is connected\nto the device.",
|
||||
"The Thevenin equivalent was\nthat V and R in series and",
|
||||
"those two impose a Thevenin\nconstraint on the terminal",
|
||||
"pair that relates vD and iD.",
|
||||
"So now my next step is,\ngiven these two graphs",
|
||||
"for iD versus vD--",
|
||||
"and clearly those are\nmy two constraints.",
|
||||
"Graph 2 says that iD and vD\nmust be somewhere on this",
|
||||
"trajectory.",
|
||||
"Graph 1 prime says, well, I'm\nnot going to let vD and iD be",
|
||||
"anywhere else but\non this curve.",
|
||||
"That's it.",
|
||||
"Both of them are fighting with\neach other and telling each",
|
||||
"other, nope, I'm not going to\nallow you to do anything.",
|
||||
"You have to be on my curve.",
|
||||
"So in this case, I have two\ncurves, and I need a point",
|
||||
"that satisfies both curves.",
|
||||
"And that is easy enough to do.",
|
||||
"And I simply have to go\nand satisfy both these",
|
||||
"constraints, and that will\ngive me the answer",
|
||||
"for vD versus iD.",
|
||||
"Before I do that, so I can go\nand solve it for you, let me",
|
||||
"go and pick some values for\nthe various parameters.",
|
||||
"So as before, I'm going to pick\nV equals 1 volt, R equals",
|
||||
"1 ohm, a, a quarter of an amp,\nand b to be one volt inverse.",
|
||||
"So I'll pick the same parameters\nas I had done when",
|
||||
"I did the analytical method.",
|
||||
"Next, what I'll do is I'll\nsubstitute these parameters",
|
||||
"into the two equations 1 prime\nand 2 and rewrite them with",
|
||||
"the parameters substituted.",
|
||||
"So for 1 prime, I get iD.",
|
||||
"Since V is 1 and R is 1, I get\nV divided by R equals 1.",
|
||||
"And then since R is\n1, I get minus vD.",
|
||||
"So this is 1 prime, once I've\nsubstituted the values.",
|
||||
"And then for equation\n2, what do I get?",
|
||||
"I get iD equals ae\nraised to bvD.",
|
||||
"a is 1/4, so I write\nthat down.",
|
||||
"b is 1, and so I\nget vD up here.",
|
||||
"So I have my two equations in\nterms of the parameters I have",
|
||||
"chosen, and now I can go ahead\nand plot the two equations and",
|
||||
"see where they intersect.",
|
||||
"I've given you the form of the\ngraph here, and so let me go",
|
||||
"ahead and plot this.",
|
||||
"Let me go ahead and plot 2\nfirst. 2 looks like this,",
|
||||
"where this point is 1/4.",
|
||||
"That was the a point.",
|
||||
"As I said before, this curve\nis simply my Equation 2.",
|
||||
"Then let me go ahead and\nplot equation 1 prime.",
|
||||
"And as you recall, that looked\nsomething like this where the",
|
||||
"vD intercept was V and the\ny-intercept was given by V",
|
||||
"divided by R.",
|
||||
"And in this case, it was\n1, and V was also 1.",
|
||||
"So those are my two curves, and\nhere's the point where the",
|
||||
"two coincide.",
|
||||
"And then I just have to go and\nfind the values of iD and vD",
|
||||
"where they two intersect.",
|
||||
"So at this point, it will be\n0.56 volts, and this point",
|
||||
"will be 0.44 amps.",
|
||||
"It's the same as what\nI calculated in",
|
||||
"the analytical method.",
|
||||
"So let me go ahead and write\nthat down. iD equals, in this",
|
||||
"case, 0.44 amps, and vD\nequals 0.56 volts.",
|
||||
"So basically, I've just\ntaken the two graphs,",
|
||||
"superimposed them.",
|
||||
"This was 1 prime, and the\nnon-linear one was related to",
|
||||
"Equation 2.",
|
||||
"So before I jump off to one\nother thing, I can define",
|
||||
"something for you.",
|
||||
"Notice this curve here.",
|
||||
"This is a straight line that\nreflects the Thevenin",
|
||||
"constraint that I apply on\nmy non-linear device.",
|
||||
"And I mentioned earlier we're\ngoing to do this again and",
|
||||
"again and again.",
|
||||
"I think you will see this at\nleast 10 more times in this",
|
||||
"course where I take a Thevenin\nequivalent of the following",
|
||||
"form, some voltage V, some R,\nand apply that in series",
|
||||
"across something interesting.",
|
||||
"So this line that I see here is\nthe constraint imposed by",
|
||||
"the Thevenin equivalent.",
|
||||
"And you can see that from\nthe equation 1 prime.",
|
||||
"Now, there's a name\nfor this line.",
|
||||
"So this line is called the "load\nline." You will see more",
|
||||
"reasons for this later.",
|
||||
"But this line is called\nthe "load line."",
|
||||
"Let me show you one other little\ntrick, just in case you",
|
||||
"didn't completely get how I\nsolved the graphical method.",
|
||||
"But one little trick here.",
|
||||
"If you like PowerPoint,\nyou will enjoy this.",
|
||||
"And if you don't like\nPowerPoint, you",
|
||||
"will hate me for it.",
|
||||
"So if you look at these\ncurves, I have my two",
|
||||
"equations in iD-- the 1 prime\nand 2-- and I've plotted them",
|
||||
"for you here.",
|
||||
"On the left-hand side,\nI plotted equation 2.",
|
||||
"Right-hand side, I plotted\nequation 1.",
|
||||
"And fundamentally, all that the\ngraphical method is doing",
|
||||
"is simply superimposing\nthe two graphs.",
|
||||
"And by superimposing the two\ngraphs, it is finding the",
|
||||
"point where the two\ncurves intersect.",
|
||||
"And this is what you get.",
|
||||
"So let me do that again.",
|
||||
"So I take one of the curves and\nsuperimpose it on top of",
|
||||
"the other curve given the\nsame axes and the same",
|
||||
"scales for the axes.",
|
||||
"And then I go ahead and find\nthe solution for the point",
|
||||
"where the two intersect.",
|
||||
null
|
||||
]
|
||||
}
|
||||
|
||||
</textarea>
|
||||
|
||||
@@ -5,9 +5,6 @@
|
||||
<li>
|
||||
<a href="#" class="new-module">New Section</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#" class="new-module">New Module</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#" class="new-module">New Unit</a>
|
||||
</li>
|
||||
|
||||
4
cms/templates/widgets/html-edit.html
Normal file
4
cms/templates/widgets/html-edit.html
Normal file
@@ -0,0 +1,4 @@
|
||||
<section class="html-edit">
|
||||
<textarea name="" class="edit-box" rows="8" cols="40">${module.definition['data']['text']}</textarea>
|
||||
<div class="preview">${module.definition['data']['text']}</div>
|
||||
</section>
|
||||
@@ -38,7 +38,7 @@
|
||||
% for week in weeks:
|
||||
<li>
|
||||
<header>
|
||||
<h1><a href="#">${week.name}</a></h1>
|
||||
<h1><a href="#" class="week-edit" id="${week.url}">${week.name}</a></h1>
|
||||
<ul>
|
||||
% if week.goals:
|
||||
% for goal in week.goals:
|
||||
@@ -53,7 +53,7 @@
|
||||
<ul>
|
||||
% for module in week.get_children():
|
||||
<li class="${module.type}">
|
||||
<a href="#" class="${module.type}-edit">${module.name}</a>
|
||||
<a href="#" class="module-edit" id="${module.url}">${module.name}</a>
|
||||
<a href="#" class="draggable">handle</a>
|
||||
</li>
|
||||
% endfor
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
<li>
|
||||
<img src="http://placehold.it/300x180" alt="" /><h5>Video-file-name</h5>
|
||||
</li>
|
||||
@@ -1,4 +0,0 @@
|
||||
<section class="caption-save">
|
||||
<a href="#" class="close-box">Cancel</a>
|
||||
<button class="close-box">Save changes</button>
|
||||
</section>
|
||||
@@ -1,16 +1,8 @@
|
||||
<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>
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
<div class="tooltip">
|
||||
<ul>
|
||||
<li><a href="#view" rel="leanModal">View</a></li>
|
||||
<li><a href="#">Download</a></li>
|
||||
<li><a href="#" class="delete-speed">Delete</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
@@ -1,38 +0,0 @@
|
||||
<li class="video-box">
|
||||
|
||||
<div class="thumb"><img src="http://placehold.it/100x65" /></div>
|
||||
|
||||
<div class="meta">
|
||||
<strong>video-name</strong> 236mb Uploaded 6 hours ago by <em>Anant Agrawal</em>
|
||||
<p>
|
||||
<ul class="speed-list">
|
||||
Speed
|
||||
<li class="speed">
|
||||
0.75x
|
||||
<%include file="speed-tooltip.html"/>
|
||||
</li>
|
||||
<li class="speed">Normal
|
||||
<%include file="speed-tooltip.html"/>
|
||||
</li>
|
||||
<li class="speed">1.25x
|
||||
<%include file="speed-tooltip.html"/>
|
||||
</li>
|
||||
<li class="speed">1.5x
|
||||
<%include file="speed-tooltip.html"/>
|
||||
</li>
|
||||
<li style="background: #eee;" ><a href="#upload" rel="leanModal" class="new-upload">+</a></li>
|
||||
</ul>
|
||||
</p>
|
||||
<p>
|
||||
<a href="#">Download All</a> —
|
||||
<a href="#" style="color: brown;" class="remove">Delete All</a> —
|
||||
<a href="#" class="edit-captions"> Edit Captions </a> —
|
||||
<a href="#" class="use-video">Use clip ⬆</a>
|
||||
</p>
|
||||
</div>
|
||||
<div class="caption-box">
|
||||
<%include file="captions.html"/>
|
||||
<%include file="save-captions.html"/>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
<li class="video-box">
|
||||
<div class="thumb"><img src="http://placehold.it/155x90" /></div>
|
||||
|
||||
<div class="meta">
|
||||
<strong>video-name</strong> 236mb
|
||||
<p>Uploaded 6 hours ago by <em>Anant Agrawal</em></p>
|
||||
<p>
|
||||
<ul class="speed-list">
|
||||
Speed
|
||||
<li class="speed">
|
||||
0.75x
|
||||
<%include file="speed-tooltip.html"/>
|
||||
</li>
|
||||
<li class="speed">Normal
|
||||
<%include file="speed-tooltip.html"/>
|
||||
</li>
|
||||
<li class="speed">1.25x
|
||||
<%include file="speed-tooltip.html"/>
|
||||
</li>
|
||||
<li class="speed">1.5x
|
||||
<%include file="speed-tooltip.html"/>
|
||||
</li>
|
||||
<li style="background: #eee;" ><a href="#upload" rel="leanModal" class="new-upload">+</a></li>
|
||||
</ul>
|
||||
</p>
|
||||
<p>
|
||||
<a href="#">Download all</a> —
|
||||
<a href="#" stle="color: brown;" class="remove-video">Remove ⬇ </a>
|
||||
|
||||
</p>
|
||||
</div>
|
||||
<div style="margin-top: 30px;">
|
||||
<%include file="captions.html"/>
|
||||
</div>
|
||||
</li>
|
||||
@@ -6,4 +6,6 @@ from django.conf.urls.defaults import patterns, url
|
||||
|
||||
urlpatterns = patterns('',
|
||||
url(r'^$', 'contentstore.views.index', name='index'),
|
||||
url(r'^edit_item$', 'contentstore.views.edit_item', name='edit_item'),
|
||||
url(r'^save_item$', 'contentstore.views.save_item', name='save_item'),
|
||||
)
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -1,14 +1,24 @@
|
||||
import json
|
||||
import logging
|
||||
|
||||
from x_module import XModule, XModuleDescriptor
|
||||
from x_module import XModule
|
||||
from mako_module import MakoModuleDescriptor
|
||||
from lxml import etree
|
||||
from pkg_resources import resource_string
|
||||
|
||||
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': [resource_string(__name__, 'js/module/html.coffee')]}
|
||||
|
||||
|
||||
class Module(XModule):
|
||||
id_attribute = 'filename'
|
||||
|
||||
9
common/lib/xmodule/js/module/html.coffee
Normal file
9
common/lib/xmodule/js/module/html.coffee
Normal file
@@ -0,0 +1,9 @@
|
||||
class @HTML
|
||||
constructor: (@id) ->
|
||||
@edit_box = $("##{@id} .edit-box")
|
||||
@preview = $("##{@id} .preview")
|
||||
@edit_box.on('input', =>
|
||||
@preview.empty().append(@edit_box.val())
|
||||
)
|
||||
|
||||
save: -> {text: @edit_box.val()}
|
||||
18
common/lib/xmodule/mako_module.py
Normal file
18
common/lib/xmodule/mako_module.py
Normal file
@@ -0,0 +1,18 @@
|
||||
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'
|
||||
|
||||
@@ -5,6 +5,9 @@ setup(
|
||||
version="0.1",
|
||||
packages=find_packages(),
|
||||
install_requires=['distribute'],
|
||||
package_data={
|
||||
'': ['js/*']
|
||||
},
|
||||
|
||||
# See http://guide.python-distribute.org/creation.html#entry-points
|
||||
# for a description of entry_points
|
||||
@@ -19,6 +22,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,
|
||||
@@ -202,6 +221,7 @@ class XModuleDescriptor(Plugin):
|
||||
self.definition = definition if definition is not None else {}
|
||||
self.name = Location(kwargs.get('location')).name
|
||||
self.type = Location(kwargs.get('location')).category
|
||||
self.url = Location(kwargs.get('location')).url()
|
||||
|
||||
# For now, we represent goals as a list of strings, but this
|
||||
# is one of the things that we are going to be iterating on heavily
|
||||
@@ -220,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):
|
||||
|
||||
7
rakefile
7
rakefile
@@ -58,6 +58,11 @@ task :pylint => REPORT_DIR do
|
||||
end
|
||||
end
|
||||
|
||||
default_options = {
|
||||
:lms => '8000',
|
||||
:cms => '8001',
|
||||
}
|
||||
|
||||
[:lms, :cms].each do |system|
|
||||
task_name = "test_#{system}"
|
||||
report_dir = File.join(REPORT_DIR, task_name)
|
||||
@@ -76,7 +81,7 @@ end
|
||||
Other useful environments are devplus (for dev testing with a real local database)
|
||||
desc
|
||||
task system, [:env, :options] => [] do |t, args|
|
||||
args.with_defaults(:env => 'dev', :options => '')
|
||||
args.with_defaults(:env => 'dev', :options => default_options[system])
|
||||
sh(django_admin(system, args.env, 'runserver', args.options))
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user