add import filter capability to html & problem editing; provides latex2edx interface
This commit is contained in:
8
cms/envs/dev_ike.py
Normal file
8
cms/envs/dev_ike.py
Normal file
@@ -0,0 +1,8 @@
|
||||
# dev environment for ichuang/mit
|
||||
|
||||
from .common import *
|
||||
from logsettings import get_logger_config
|
||||
from .dev import *
|
||||
import socket
|
||||
|
||||
#MITX_FEATURES['USE_DJANGO_PIPELINE']=False # don't recompile scss
|
||||
@@ -1,10 +1,26 @@
|
||||
% if metadata:
|
||||
<%
|
||||
import hashlib
|
||||
hlskey = hashlib.md5(module.location.url()).hexdigest()
|
||||
%>
|
||||
<section class="metadata_edit">
|
||||
<h3>Metadata</h3>
|
||||
<ul>
|
||||
% for keyname in editable_metadata_fields:
|
||||
<li><label>${keyname}:</label> <input type='text' data-metadata-name='${keyname}' value='${metadata[keyname]}' size='60' /></li>
|
||||
<li>
|
||||
% if keyname=='source_code':
|
||||
<a href="#hls-modal-${hlskey}" style="color:yellow;" id="hls-trig-${hlskey}" >Edit High Level Source</a>
|
||||
% else:
|
||||
<label>${keyname}:</label>
|
||||
<input type='text' data-metadata-name='${keyname}' value='${metadata[keyname]}' size='60' />
|
||||
% endif
|
||||
</li>
|
||||
% endfor
|
||||
</ul>
|
||||
|
||||
% if 'source_code' in editable_metadata_fields:
|
||||
<%include file="source-edit.html" />
|
||||
% endif
|
||||
|
||||
</section>
|
||||
% endif
|
||||
|
||||
109
cms/templates/widgets/source-edit.html
Normal file
109
cms/templates/widgets/source-edit.html
Normal file
@@ -0,0 +1,109 @@
|
||||
<%
|
||||
import hashlib
|
||||
hlskey = hashlib.md5(module.location.url()).hexdigest()
|
||||
%>
|
||||
|
||||
<section id="hls-modal-${hlskey}" class="upload-modal modal" style="width:80%!important; left:30%!important; height:90%; overflow:auto; background:#ECF7D3;" >
|
||||
<a href="#" class="close-button"><span class="close-icon"></span></a>
|
||||
<div id="hls-div">
|
||||
<header>
|
||||
<h2>High Level Source Editing</h2>
|
||||
</header>
|
||||
|
||||
<form id="hls-form">
|
||||
<section class="source-edit">
|
||||
<textarea name="" data-metadata-name="source_code" class="source-edit-box hls-data" rows="8" cols="40">${metadata['source_code']|h}</textarea>
|
||||
</section>
|
||||
<div class="submit">
|
||||
<button type="reset" class="hls-compile">Save & Compile to edX XML</button>
|
||||
<button type="reset" class="hls-save">Save</button>
|
||||
<button type="reset" class="hls-refresh">Refresh</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<script type="text/javascript" src="/static/js/vendor/CodeMirror/stex.js"></script>
|
||||
<script type="text/javascript">
|
||||
$('#hls-trig-${hlskey}').leanModal({ top:40, overlay:0.8, closeButton: ".close-button"});
|
||||
|
||||
$('#hls-modal-${hlskey}').data('editor',CodeMirror.fromTextArea($('#hls-modal-${hlskey}').find('.hls-data')[0], {lineNumbers: true, mode: 'stex'}));
|
||||
|
||||
$('#hls-trig-${hlskey}').click(function(){slow_refresh_hls($('#hls-modal-${hlskey}'))})
|
||||
|
||||
// refresh button
|
||||
|
||||
$('#hls-modal-${hlskey}').find('.hls-refresh').click(function(){refresh_hls($('#hls-modal-${hlskey}'))});
|
||||
|
||||
function refresh_hls(el){
|
||||
el.data('editor').refresh();
|
||||
}
|
||||
|
||||
function slow_refresh_hls(el){
|
||||
el.delay(200).queue(function(){
|
||||
refresh_hls(el);
|
||||
$(this).dequeue();
|
||||
});
|
||||
}
|
||||
|
||||
// compile & save button
|
||||
|
||||
$('#hls-modal-${hlskey}').find('.hls-compile').click(compile_hls_${hlskey});
|
||||
|
||||
function compile_hls_${hlskey}(){
|
||||
|
||||
editor = $('#hls-modal-${hlskey}').data('editor')
|
||||
var myquery = { latexin: editor.getValue() };
|
||||
|
||||
$.ajax({
|
||||
url: '${metadata.get('source_processor_url','https://qisx.mit.edu:5443/latex2edx')}',
|
||||
type: 'GET',
|
||||
contentType: 'application/json',
|
||||
data: escape(JSON.stringify(myquery)),
|
||||
crossDomain: true,
|
||||
dataType: 'jsonp',
|
||||
jsonpCallback: 'process_return_${hlskey}',
|
||||
beforeSend: function (xhr) { xhr.setRequestHeader ("Authorization", "Basic eHFhOmFnYXJ3YWw="); },
|
||||
timeout : 7000,
|
||||
success: function(result) {
|
||||
console.log(result);
|
||||
},
|
||||
error: function() {
|
||||
alert('Error: cannot connect to latex2edx server');
|
||||
console.log('error!');
|
||||
}
|
||||
});
|
||||
// $('#hls-modal-${hlskey}').hide();
|
||||
}
|
||||
|
||||
function process_return_${hlskey}(datadict){
|
||||
// datadict is json of array with "xml" and "message"
|
||||
// if "xml" value is '' then the conversion failed
|
||||
xml = datadict.xml;
|
||||
console.log('xml:');
|
||||
console.log(xml);
|
||||
if (xml.length==0){
|
||||
alert('Conversion failed! error:'+ datadict.message);
|
||||
}else{
|
||||
set_raw_edit_box(xml,'${hlskey}');
|
||||
save_hls($('#hls-modal-${hlskey}'));
|
||||
}
|
||||
}
|
||||
|
||||
function set_raw_edit_box(data,key){
|
||||
// get the codemirror editor for the raw-edit-box
|
||||
// it's a CodeMirror-wrap class element
|
||||
$('#hls-modal-'+key).closest('.component').find('.CodeMirror-wrap')[0].CodeMirror.setValue(data);
|
||||
}
|
||||
|
||||
// save button
|
||||
|
||||
$('#hls-modal-${hlskey}').find('.hls-save').click(function(){save_hls($('#hls-modal-${hlskey}'))});
|
||||
|
||||
function save_hls(el){
|
||||
el.find('.hls-data').val(el.data('editor').getValue());
|
||||
el.closest('.component').find('.save-button').click();
|
||||
}
|
||||
|
||||
</script>
|
||||
23
common/lib/xmodule/xmodule/templates/html/latex_html.yaml
Normal file
23
common/lib/xmodule/xmodule/templates/html/latex_html.yaml
Normal file
@@ -0,0 +1,23 @@
|
||||
---
|
||||
metadata:
|
||||
display_name: E-text Written in LaTeX
|
||||
source_processor_url: https://qisx.mit.edu:5443/latex2edx
|
||||
source_code: |
|
||||
\subsection{Example of E-text in LaTeX}
|
||||
|
||||
It is very convenient to write complex equations in LaTeX.
|
||||
|
||||
\begin{equation}
|
||||
x = \frac{-b\pm\sqrt{b^2-4*a*c}}{2a}
|
||||
\end{equation}
|
||||
|
||||
Seize the moment.
|
||||
|
||||
data: |
|
||||
<html>
|
||||
<h2>Example: E-text page</h2>
|
||||
<p>
|
||||
It is very convenient to write complex equations in LaTeX.
|
||||
</p>
|
||||
</html>
|
||||
children: []
|
||||
@@ -0,0 +1,27 @@
|
||||
---
|
||||
metadata:
|
||||
display_name: Problem Written in LaTeX
|
||||
source_processor_url: https://qisx.mit.edu:5443/latex2edx
|
||||
source_code: |
|
||||
\subsection{Example: Option Response Problem in Latex}
|
||||
|
||||
Where is the earth?
|
||||
|
||||
\edXabox{options='up','down' expect='down'}
|
||||
|
||||
data: |
|
||||
<problem>
|
||||
<text>
|
||||
<h2>Example: Option Response Problem</h2>
|
||||
<p>
|
||||
An option response problem presents option boxes for students to select from. Correctness of input is evaluated based
|
||||
on which option is defined as correct in the optioninput statement.
|
||||
</p>
|
||||
<p>Select the correct options:</p>
|
||||
<optionresponse direction="vertical" randomize="yes">
|
||||
<p><text class="inline">The location of the sky is: </text><optioninput inline="1" options="('Up','Down')" correct="Up"></optioninput></p>
|
||||
<p><text>The location of the earth is: </text><optioninput options="('Up','Down')" correct="Down"></optioninput></p>
|
||||
</optionresponse>
|
||||
</text>
|
||||
</problem>
|
||||
children: []
|
||||
182
common/static/js/vendor/CodeMirror/stex.js
vendored
Normal file
182
common/static/js/vendor/CodeMirror/stex.js
vendored
Normal file
@@ -0,0 +1,182 @@
|
||||
/*
|
||||
* Author: Constantin Jucovschi (c.jucovschi@jacobs-university.de)
|
||||
* Licence: MIT
|
||||
*/
|
||||
|
||||
CodeMirror.defineMode("stex", function(cmCfg, modeCfg)
|
||||
{
|
||||
function pushCommand(state, command) {
|
||||
state.cmdState.push(command);
|
||||
}
|
||||
|
||||
function peekCommand(state) {
|
||||
if (state.cmdState.length>0)
|
||||
return state.cmdState[state.cmdState.length-1];
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
function popCommand(state) {
|
||||
if (state.cmdState.length>0) {
|
||||
var plug = state.cmdState.pop();
|
||||
plug.closeBracket();
|
||||
}
|
||||
}
|
||||
|
||||
function applyMostPowerful(state) {
|
||||
var context = state.cmdState;
|
||||
for (var i = context.length - 1; i >= 0; i--) {
|
||||
var plug = context[i];
|
||||
if (plug.name=="DEFAULT")
|
||||
continue;
|
||||
return plug.styleIdentifier();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function addPluginPattern(pluginName, cmdStyle, brackets, styles) {
|
||||
return function () {
|
||||
this.name=pluginName;
|
||||
this.bracketNo = 0;
|
||||
this.style=cmdStyle;
|
||||
this.styles = styles;
|
||||
this.brackets = brackets;
|
||||
|
||||
this.styleIdentifier = function(content) {
|
||||
if (this.bracketNo<=this.styles.length)
|
||||
return this.styles[this.bracketNo-1];
|
||||
else
|
||||
return null;
|
||||
};
|
||||
this.openBracket = function(content) {
|
||||
this.bracketNo++;
|
||||
return "bracket";
|
||||
};
|
||||
this.closeBracket = function(content) {
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
var plugins = new Array();
|
||||
|
||||
plugins["importmodule"] = addPluginPattern("importmodule", "tag", "{[", ["string", "builtin"]);
|
||||
plugins["documentclass"] = addPluginPattern("documentclass", "tag", "{[", ["", "atom"]);
|
||||
plugins["usepackage"] = addPluginPattern("documentclass", "tag", "[", ["atom"]);
|
||||
plugins["begin"] = addPluginPattern("documentclass", "tag", "[", ["atom"]);
|
||||
plugins["end"] = addPluginPattern("documentclass", "tag", "[", ["atom"]);
|
||||
|
||||
plugins["DEFAULT"] = function () {
|
||||
this.name="DEFAULT";
|
||||
this.style="tag";
|
||||
|
||||
this.styleIdentifier = function(content) {
|
||||
};
|
||||
this.openBracket = function(content) {
|
||||
};
|
||||
this.closeBracket = function(content) {
|
||||
};
|
||||
};
|
||||
|
||||
function setState(state, f) {
|
||||
state.f = f;
|
||||
}
|
||||
|
||||
function normal(source, state) {
|
||||
if (source.match(/^\\[a-zA-Z@]+/)) {
|
||||
var cmdName = source.current();
|
||||
cmdName = cmdName.substr(1, cmdName.length-1);
|
||||
var plug;
|
||||
if (plugins.hasOwnProperty(cmdName)) {
|
||||
plug = plugins[cmdName];
|
||||
} else {
|
||||
plug = plugins["DEFAULT"];
|
||||
}
|
||||
plug = new plug();
|
||||
pushCommand(state, plug);
|
||||
setState(state, beginParams);
|
||||
return plug.style;
|
||||
}
|
||||
|
||||
// escape characters
|
||||
if (source.match(/^\\[$&%#{}_]/)) {
|
||||
return "tag";
|
||||
}
|
||||
|
||||
// white space control characters
|
||||
if (source.match(/^\\[,;!\/]/)) {
|
||||
return "tag";
|
||||
}
|
||||
|
||||
var ch = source.next();
|
||||
if (ch == "%") {
|
||||
// special case: % at end of its own line; stay in same state
|
||||
if (!source.eol()) {
|
||||
setState(state, inCComment);
|
||||
}
|
||||
return "comment";
|
||||
}
|
||||
else if (ch=='}' || ch==']') {
|
||||
plug = peekCommand(state);
|
||||
if (plug) {
|
||||
plug.closeBracket(ch);
|
||||
setState(state, beginParams);
|
||||
} else
|
||||
return "error";
|
||||
return "bracket";
|
||||
} else if (ch=='{' || ch=='[') {
|
||||
plug = plugins["DEFAULT"];
|
||||
plug = new plug();
|
||||
pushCommand(state, plug);
|
||||
return "bracket";
|
||||
}
|
||||
else if (/\d/.test(ch)) {
|
||||
source.eatWhile(/[\w.%]/);
|
||||
return "atom";
|
||||
}
|
||||
else {
|
||||
source.eatWhile(/[\w-_]/);
|
||||
return applyMostPowerful(state);
|
||||
}
|
||||
}
|
||||
|
||||
function inCComment(source, state) {
|
||||
source.skipToEnd();
|
||||
setState(state, normal);
|
||||
return "comment";
|
||||
}
|
||||
|
||||
function beginParams(source, state) {
|
||||
var ch = source.peek();
|
||||
if (ch == '{' || ch == '[') {
|
||||
var lastPlug = peekCommand(state);
|
||||
var style = lastPlug.openBracket(ch);
|
||||
source.eat(ch);
|
||||
setState(state, normal);
|
||||
return "bracket";
|
||||
}
|
||||
if (/[ \t\r]/.test(ch)) {
|
||||
source.eat(ch);
|
||||
return null;
|
||||
}
|
||||
setState(state, normal);
|
||||
lastPlug = peekCommand(state);
|
||||
if (lastPlug) {
|
||||
popCommand(state);
|
||||
}
|
||||
return normal(source, state);
|
||||
}
|
||||
|
||||
return {
|
||||
startState: function() { return { f:normal, cmdState:[] }; },
|
||||
copyState: function(s) { return { f: s.f, cmdState: s.cmdState.slice(0, s.cmdState.length) }; },
|
||||
|
||||
token: function(stream, state) {
|
||||
var t = state.f(stream, state);
|
||||
var w = stream.current();
|
||||
return t;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
CodeMirror.defineMIME("text/x-stex", "stex");
|
||||
CodeMirror.defineMIME("text/x-latex", "stex");
|
||||
Reference in New Issue
Block a user