diff --git a/runtime/scripts/part.js b/runtime/scripts/part.js index 2b3ae2a55..e503a1cef 100644 --- a/runtime/scripts/part.js +++ b/runtime/scripts/part.js @@ -367,6 +367,15 @@ Part.prototype = /** @lends Numbas.parts.Part.prototype */ { } }); }, + + /** All children of this part: all gaps and steps, but not alternatives. + * + * @returns {Array.} + */ + allChildren: function() { + return this.gaps.concat(this.steps); + }, + /** Initialise this part's display object. * Only called if the question this part belongs to has a display. */ diff --git a/themes/default/files/resources/exam.css b/themes/default/files/resources/exam.css index d01ef6ad4..c387c86ac 100644 --- a/themes/default/files/resources/exam.css +++ b/themes/default/files/resources/exam.css @@ -490,6 +490,7 @@ input.jme { overflow: visible auto; padding-right: 1em; padding-bottom: 2em; + position: relative; } .feedback-icon { @@ -1066,12 +1067,12 @@ select.multiplechoice { } .warnings { - position: absolute; - z-index: 1; + position: absolute; + z-index: 1; + width: 20em; margin-top: 1em; - width: 20em; - display: inline-block; opacity: 0; + display: inline-block; transition: opacity 0.2s; border-color: hsl(30, 20%, 50%); background-color: hsl(30, 20%, 95%); @@ -1083,14 +1084,16 @@ select.multiplechoice { transition: opacity 0s; } } + +.gap .warnings { + margin-top: -0.5em; +} .warnings.stick-right { right: 0.5em; } .warnings.shown { opacity: 1; } -.warnings.alert-warning { -} .part .warning { margin: 0.1em; display: block; diff --git a/themes/default/files/scripts/part-display.js b/themes/default/files/scripts/part-display.js index 2065fb0fc..dc40ed2b4 100644 --- a/themes/default/files/scripts/part-display.js +++ b/themes/default/files/scripts/part-display.js @@ -178,6 +178,51 @@ Numbas.queueScript('part-display',['display-util', 'display-base','util','jme'], return _warningsShown(v); } },this); + + function position_warnings() { + if(!pd.html || !pd.warningsShown.peek()) { + return; + } + var warnings_box = pd.html.querySelector('.warnings'); + var answer = pd.html.querySelector('.student-answer'); + var offsetTop = 0; + var offsetLeft = 0; + var el = answer; + while(el.offsetParent && !el.classList.contains('question')) { + offsetTop += el.offsetTop; + offsetLeft += el.offsetLeft; + el = el.offsetParent; + } + var answer_height = answer.getBoundingClientRect().height; + var answer_width = answer.getBoundingClientRect().width; + + var wtop = offsetTop + (p.isGap ? 0 : answer_height); + var wleft = (offsetLeft + (p.isGap ? answer_width : 0)); + + warnings_box.style.top = wtop + 'px'; + warnings_box.style.left = wleft + 'px'; + + var box = warnings_box.getBoundingClientRect(); + var docWidth = document.documentElement.clientWidth; + var margin = 10; + var dr = box.right - docWidth + document.documentElement.clientLeft + margin; + if(dr > 0) { + wleft -= dr; + if(p.isGap) { + wtop += answer_height; + } + warnings_box.style.left = wleft + 'px'; + warnings_box.style.top = wtop + 'px'; + } + warnings_box.style.width = ''; + const ideal_width = parseFloat(window.getComputedStyle(warnings_box).width.replace('px','')); + var maxWidth = docWidth - 3*margin; + if(ideal_width > maxWidth) { + warnings_box.style.width = maxWidth + 'px'; + } + } + + /** Show the warnings. * * @member {Function} showWarnings @@ -186,7 +231,11 @@ Numbas.queueScript('part-display',['display-util', 'display-base','util','jme'], */ this.showWarnings = function() { this.warningsShown(true); + position_warnings(); } + + setInterval(position_warnings,200); + /** Hide the warnings. * * @member {Function} hideWarnings @@ -481,7 +530,7 @@ Numbas.queueScript('part-display',['display-util', 'display-base','util','jme'], pd.resolve_html_promise = resolve; }); - /** Called when Kncokout has finished binding the HTML for this part to the DOM. + /** Called when Knockout has finished binding the HTML for this part to the DOM. * * @memberof Numbas.display.PartDisplay */ diff --git a/themes/default/files/scripts/question-display.js b/themes/default/files/scripts/question-display.js index 027b583a9..a2c640207 100644 --- a/themes/default/files/scripts/question-display.js +++ b/themes/default/files/scripts/question-display.js @@ -416,9 +416,17 @@ Numbas.queueScript('question-display',['display-util', 'display-base','jme-varia p.getScope(), qd.contextDescription+' '+(p.display.name() || p.name) ); + function add_html_to_part(p, html) { + if(p.display) { + p.display.html = html; + p.display.resolve_html_promise(html); + } + p.allChildren().forEach(function(cp) { + add_html_to_part(cp, html.querySelector('.part[data-part-path="'+cp.path+'"]')); + }); + } promise.then(function(html) { - p.display.html = html; - p.display.resolve_html_promise(html); + add_html_to_part(p, html); }); }); }, diff --git a/themes/default/templates/xslt/part.xslt b/themes/default/templates/xslt/part.xslt index c93dd5e59..94c6c4c9b 100644 --- a/themes/default/templates/xslt/part.xslt +++ b/themes/default/templates/xslt/part.xslt @@ -40,7 +40,7 @@ css: {answered: scoreFeedback.answered, 'has-warnings': hasWarnings}, attr: {"feedback-state": scoreFeedback.state} - + ko foreach: warnings /ko