Merge pull request #2932 from edx/dcs/fix-matlab-input
This fixes LMS-2387 by removing a resize call that prevented scrolling.
This commit is contained in:
@@ -832,6 +832,8 @@ class MatlabInput(CodeInput):
|
||||
'queue_len': str(self.queue_len),
|
||||
'queue_msg': self.queue_msg,
|
||||
'button_enabled': self.button_enabled(),
|
||||
'matlab_editor_js': '{static_url}js/vendor/CodeMirror/addons/octave.js'.format(
|
||||
static_url=self.capa_system.STATIC_URL),
|
||||
}
|
||||
return extra_context
|
||||
|
||||
|
||||
@@ -1,16 +1,21 @@
|
||||
<%! from django.utils.translation import ugettext as _ %>
|
||||
<section id="textbox_${id}" class="textbox">
|
||||
<section id="textbox_${id}" class="capa_inputtype textbox cminput">
|
||||
<textarea rows="${rows}" cols="${cols}" name="input_${id}"
|
||||
aria-label="${_("{programming_language} editor").format(programming_language=mode)}"
|
||||
aria-describedby="answer_${id}"
|
||||
id="input_${id}"
|
||||
tabindex="0"
|
||||
% if hidden:
|
||||
data-mode="${mode}"
|
||||
data-tabsize="${tabsize}"
|
||||
% if linenumbers:
|
||||
data-linenums="true"
|
||||
% endif
|
||||
% if hidden:
|
||||
style="display:none;"
|
||||
% endif
|
||||
% endif
|
||||
>${value|h}</textarea>
|
||||
|
||||
<div class="grader-status" tabindex="1">
|
||||
<div class="grader-status" tabindex="-1">
|
||||
% if status == 'unsubmitted':
|
||||
<span class="unanswered" style="display:inline-block;" id="status_${id}" aria-describedby="input_${id}"><span class="sr">Status: </span>Unanswered</span>
|
||||
% elif status == 'correct':
|
||||
@@ -34,31 +39,4 @@
|
||||
<div class="external-grader-message">
|
||||
${msg|n}
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// Note: We need to make the area follow the CodeMirror for this to work.
|
||||
$(function(){
|
||||
var cm = CodeMirror.fromTextArea(document.getElementById("input_${id}"), {
|
||||
% if linenumbers == 'true':
|
||||
lineNumbers: true,
|
||||
% endif
|
||||
mode: "${mode}",
|
||||
matchBrackets: true,
|
||||
lineWrapping: true,
|
||||
indentUnit: "${tabsize}",
|
||||
tabSize: "${tabsize}",
|
||||
indentWithTabs: false,
|
||||
extraKeys: {
|
||||
"Esc": function(cm) {
|
||||
$('.grader-status').focus();
|
||||
return false;
|
||||
},
|
||||
"Tab": function(cm) {
|
||||
cm.replaceSelection("${' '*tabsize}", "end");
|
||||
}
|
||||
},
|
||||
smartIndent: false
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</section>
|
||||
|
||||
@@ -1,11 +1,22 @@
|
||||
<section id="textbox_${id}" class="textbox">
|
||||
<textarea rows="${rows}" cols="${cols}" name="input_${id}" aria-describedby="answer_${id}" id="input_${id}"
|
||||
% if hidden:
|
||||
style="display:none;"
|
||||
% endif
|
||||
<section id="textbox_${id}" class="capa_inputtype cminput">
|
||||
<div class="script_placeholder" data-src="${matlab_editor_js}"/>
|
||||
<textarea
|
||||
rows="${rows}"
|
||||
cols="${cols}"
|
||||
name="input_${id}"
|
||||
aria-describedby="answer_${id}"
|
||||
id="input_${id}"
|
||||
data-tabsize="${tabsize}"
|
||||
data-mode="octave"
|
||||
% if linenumbers:
|
||||
data-linenums="true"
|
||||
% endif
|
||||
% if hidden:
|
||||
style="display:none;"
|
||||
% endif
|
||||
>${value|h}</textarea>
|
||||
|
||||
<div class="grader-status">
|
||||
<div class="grader-status" tabindex="-1">
|
||||
% if status == 'unsubmitted':
|
||||
<span class="unanswered" style="display:inline-block;" id="status_${id}"><span class="sr">Status: </span>Unanswered</span>
|
||||
% elif status == 'correct':
|
||||
@@ -40,28 +51,7 @@
|
||||
%endif
|
||||
|
||||
<script>
|
||||
// Note: We need to make the area follow the CodeMirror for this to work.
|
||||
$(function(){
|
||||
var cm = CodeMirror.fromTextArea(document.getElementById("input_${id}"), {
|
||||
% if linenumbers == 'true':
|
||||
lineNumbers: true,
|
||||
% endif
|
||||
mode: "matlab",
|
||||
matchBrackets: true,
|
||||
lineWrapping: true,
|
||||
indentUnit: "${tabsize}",
|
||||
tabSize: "${tabsize}",
|
||||
indentWithTabs: false,
|
||||
extraKeys: {
|
||||
"Tab": function(cm) {
|
||||
cm.replaceSelection("${' '*tabsize}", "end");
|
||||
}
|
||||
},
|
||||
smartIndent: false
|
||||
});
|
||||
|
||||
$("#textbox_${id}").find('.CodeMirror-scroll').height(${int(13.5*eval(rows))});
|
||||
|
||||
var gentle_alert = function (parent_elt, msg) {
|
||||
if($(parent_elt).find('.capa_alert').length) {
|
||||
$(parent_elt).find('.capa_alert').remove();
|
||||
@@ -80,8 +70,13 @@
|
||||
input_id = "${id}";
|
||||
|
||||
// save the codemirror text to the textarea
|
||||
cm.save();
|
||||
// since there could be multiple codemirror instances on the page,
|
||||
// save all of them.
|
||||
$('.CodeMirror').each(function(i, el){
|
||||
el.CodeMirror.save();
|
||||
});
|
||||
var input = $("#input_${id}");
|
||||
|
||||
// pull out the coded text
|
||||
submission = input.val();
|
||||
|
||||
|
||||
@@ -435,6 +435,7 @@ class MatlabTest(unittest.TestCase):
|
||||
'tabsize': int(self.tabsize),
|
||||
'button_enabled': True,
|
||||
'queue_len': '3',
|
||||
'matlab_editor_js': '/dummy-static/js/vendor/CodeMirror/addons/octave.js',
|
||||
}
|
||||
|
||||
self.assertEqual(context, expected)
|
||||
@@ -465,6 +466,7 @@ class MatlabTest(unittest.TestCase):
|
||||
'tabsize': int(self.tabsize),
|
||||
'button_enabled': True,
|
||||
'queue_len': '3',
|
||||
'matlab_editor_js': '/dummy-static/js/vendor/CodeMirror/addons/octave.js',
|
||||
}
|
||||
|
||||
self.assertEqual(context, expected)
|
||||
@@ -495,6 +497,7 @@ class MatlabTest(unittest.TestCase):
|
||||
'tabsize': int(self.tabsize),
|
||||
'button_enabled': False,
|
||||
'queue_len': '0',
|
||||
'matlab_editor_js': '/dummy-static/js/vendor/CodeMirror/addons/octave.js',
|
||||
}
|
||||
|
||||
self.assertEqual(context, expected)
|
||||
@@ -524,6 +527,7 @@ class MatlabTest(unittest.TestCase):
|
||||
'tabsize': int(self.tabsize),
|
||||
'button_enabled': True,
|
||||
'queue_len': '1',
|
||||
'matlab_editor_js': '/dummy-static/js/vendor/CodeMirror/addons/octave.js',
|
||||
}
|
||||
|
||||
self.assertEqual(context, expected)
|
||||
@@ -589,11 +593,7 @@ class MatlabTest(unittest.TestCase):
|
||||
output = self.the_input.get_html()
|
||||
self.assertEqual(
|
||||
etree.tostring(output),
|
||||
"""<div>{\'status\': \'queued\', \'button_enabled\': True, \'rows\': \'10\', \'queue_len\': \'3\'\
|
||||
, \'mode\': \'\', \'cols\': \'80\', \'STATIC_URL\': \'/dummy-static/\', \'linenumbers\': \'true\'\
|
||||
, \'queue_msg\': \'\', \'value\': \'print "good evening"\', \'msg\': u\'Submitted\
|
||||
. As soon as a response is returned, this message will be replaced by that feedback.\', \'hidden\': \'\'\
|
||||
, \'id\': \'prob_1_2\', \'tabsize\': 4}</div>"""
|
||||
"""<div>{\'status\': \'queued\', \'button_enabled\': True, \'rows\': \'10\', \'queue_len\': \'3\', \'mode\': \'\', \'cols\': \'80\', \'STATIC_URL\': \'/dummy-static/\', \'linenumbers\': \'true\', \'queue_msg\': \'\', \'value\': \'print "good evening"\', \'msg\': u\'Submitted. As soon as a response is returned, this message will be replaced by that feedback.\', \'matlab_editor_js\': \'/dummy-static/js/vendor/CodeMirror/addons/octave.js\', \'hidden\': \'\', \'id\': \'prob_1_2\', \'tabsize\': 4}</div>"""
|
||||
)
|
||||
|
||||
# test html, that is correct HTML5 html, but is not parsable by XML parser.
|
||||
|
||||
@@ -514,7 +514,7 @@ div.problem {
|
||||
border: 1px solid black;
|
||||
font-size: 14px;
|
||||
line-height: 18px;
|
||||
resize: both;
|
||||
resize: none;
|
||||
|
||||
.cm-tab {
|
||||
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAMCAYAAAAkuj5RAAAAAXNSR0IArs4c6QAAAGFJREFUSMft1LsRQFAQheHPowAKoACx3IgEKtaEHujDjORSgWTH/ZOdnZOcM/sgk/kFFWY0qV8foQwS4MKBCS3qR6ixBJvElOobYAtivseIE120FaowJPN75GMu8j/LfMwNjh4HUpwg4LUAAAAASUVORK5CYII=);
|
||||
|
||||
@@ -484,6 +484,31 @@ class @Problem
|
||||
|
||||
return display
|
||||
|
||||
cminput: (container) =>
|
||||
element = $(container).find("textarea")
|
||||
tabsize = element.data("tabsize")
|
||||
mode = element.data("mode")
|
||||
linenumbers = element.data("linenums")
|
||||
spaces = Array(parseInt(tabsize) + 1).join(" ")
|
||||
CodeMirror.fromTextArea element[0], {
|
||||
lineNumbers: linenumbers
|
||||
indentUnit: tabsize
|
||||
tabSize: tabsize
|
||||
mode: mode
|
||||
matchBrackets: true
|
||||
lineWrapping: true
|
||||
indentWithTabs: false
|
||||
smartIndent: false
|
||||
extraKeys: {
|
||||
"Esc": (cm) ->
|
||||
$(".grader-status").focus()
|
||||
return false
|
||||
"Tab": (cm) ->
|
||||
cm.replaceSelection(spaces, "end")
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
inputtypeShowAnswerMethods:
|
||||
choicegroup: (element, display, answers) =>
|
||||
element = $(element)
|
||||
|
||||
118
common/static/js/vendor/CodeMirror/addons/octave.js
vendored
Normal file
118
common/static/js/vendor/CodeMirror/addons/octave.js
vendored
Normal file
@@ -0,0 +1,118 @@
|
||||
CodeMirror.defineMode("octave", function() {
|
||||
function wordRegexp(words) {
|
||||
return new RegExp("^((" + words.join(")|(") + "))\\b");
|
||||
}
|
||||
|
||||
var singleOperators = new RegExp("^[\\+\\-\\*/&|\\^~<>!@'\\\\]");
|
||||
var singleDelimiters = new RegExp('^[\\(\\[\\{\\},:=;]');
|
||||
var doubleOperators = new RegExp("^((==)|(~=)|(<=)|(>=)|(<<)|(>>)|(\\.[\\+\\-\\*/\\^\\\\]))");
|
||||
var doubleDelimiters = new RegExp("^((!=)|(\\+=)|(\\-=)|(\\*=)|(/=)|(&=)|(\\|=)|(\\^=))");
|
||||
var tripleDelimiters = new RegExp("^((>>=)|(<<=))");
|
||||
var expressionEnd = new RegExp("^[\\]\\)]");
|
||||
var identifiers = new RegExp("^[_A-Za-z][_A-Za-z0-9]*");
|
||||
|
||||
var builtins = wordRegexp([
|
||||
'error', 'eval', 'function', 'abs', 'acos', 'atan', 'asin', 'cos',
|
||||
'cosh', 'exp', 'log', 'prod', 'log10', 'max', 'min', 'sign', 'sin', 'sinh',
|
||||
'sqrt', 'tan', 'reshape', 'break', 'zeros', 'default', 'margin', 'round', 'ones',
|
||||
'rand', 'syn', 'ceil', 'floor', 'size', 'clear', 'zeros', 'eye', 'mean', 'std', 'cov',
|
||||
'det', 'eig', 'inv', 'norm', 'rank', 'trace', 'expm', 'logm', 'sqrtm', 'linspace', 'plot',
|
||||
'title', 'xlabel', 'ylabel', 'legend', 'text', 'meshgrid', 'mesh', 'num2str'
|
||||
]);
|
||||
|
||||
var keywords = wordRegexp([
|
||||
'return', 'case', 'switch', 'else', 'elseif', 'end', 'endif', 'endfunction',
|
||||
'if', 'otherwise', 'do', 'for', 'while', 'try', 'catch', 'classdef', 'properties', 'events',
|
||||
'methods', 'global', 'persistent', 'endfor', 'endwhile', 'printf', 'disp', 'until', 'continue'
|
||||
]);
|
||||
|
||||
|
||||
// tokenizers
|
||||
function tokenTranspose(stream, state) {
|
||||
if (!stream.sol() && stream.peek() === '\'') {
|
||||
stream.next();
|
||||
state.tokenize = tokenBase;
|
||||
return 'operator';
|
||||
}
|
||||
state.tokenize = tokenBase;
|
||||
return tokenBase(stream, state);
|
||||
}
|
||||
|
||||
|
||||
function tokenComment(stream, state) {
|
||||
if (stream.match(/^.*%}/)) {
|
||||
state.tokenize = tokenBase;
|
||||
return 'comment';
|
||||
};
|
||||
stream.skipToEnd();
|
||||
return 'comment';
|
||||
}
|
||||
|
||||
function tokenBase(stream, state) {
|
||||
// whitespaces
|
||||
if (stream.eatSpace()) return null;
|
||||
|
||||
// Handle one line Comments
|
||||
if (stream.match('%{')){
|
||||
state.tokenize = tokenComment;
|
||||
stream.skipToEnd();
|
||||
return 'comment';
|
||||
}
|
||||
|
||||
if (stream.match(/^(%)|(\.\.\.)/)){
|
||||
stream.skipToEnd();
|
||||
return 'comment';
|
||||
}
|
||||
|
||||
// Handle Number Literals
|
||||
if (stream.match(/^[0-9\.+-]/, false)) {
|
||||
if (stream.match(/^[+-]?0x[0-9a-fA-F]+[ij]?/)) {
|
||||
stream.tokenize = tokenBase;
|
||||
return 'number'; };
|
||||
if (stream.match(/^[+-]?\d*\.\d+([EeDd][+-]?\d+)?[ij]?/)) { return 'number'; };
|
||||
if (stream.match(/^[+-]?\d+([EeDd][+-]?\d+)?[ij]?/)) { return 'number'; };
|
||||
}
|
||||
if (stream.match(wordRegexp(['nan','NaN','inf','Inf']))) { return 'number'; };
|
||||
|
||||
// Handle Strings
|
||||
if (stream.match(/^"([^"]|(""))*"/)) { return 'string'; } ;
|
||||
if (stream.match(/^'([^']|(''))*'/)) { return 'string'; } ;
|
||||
|
||||
// Handle words
|
||||
if (stream.match(keywords)) { return 'keyword'; } ;
|
||||
if (stream.match(builtins)) { return 'builtin'; } ;
|
||||
if (stream.match(identifiers)) { return 'variable'; } ;
|
||||
|
||||
if (stream.match(singleOperators) || stream.match(doubleOperators)) { return 'operator'; };
|
||||
if (stream.match(singleDelimiters) || stream.match(doubleDelimiters) || stream.match(tripleDelimiters)) { return null; };
|
||||
|
||||
if (stream.match(expressionEnd)) {
|
||||
state.tokenize = tokenTranspose;
|
||||
return null;
|
||||
};
|
||||
|
||||
|
||||
// Handle non-detected items
|
||||
stream.next();
|
||||
return 'error';
|
||||
};
|
||||
|
||||
|
||||
return {
|
||||
startState: function() {
|
||||
return {
|
||||
tokenize: tokenBase
|
||||
};
|
||||
},
|
||||
|
||||
token: function(stream, state) {
|
||||
var style = state.tokenize(stream, state);
|
||||
if (style === 'number' || style === 'variable'){
|
||||
state.tokenize = tokenTranspose;
|
||||
}
|
||||
return style;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
CodeMirror.defineMIME("text/x-octave", "octave");
|
||||
Reference in New Issue
Block a user