Commit 2a20b3f6 by Dave St.Germain

This fixes LMS-2387 by removing a resize call that prevented scrolling.

It also enables syntax highlighting for matlab input fields, which
wasn't previously enabled.
parent e13d1670
......@@ -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
......
<%! 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>
<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)
......
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");
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