summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTimotej Lazar <timotej.lazar@fri.uni-lj.si>2016-02-23 17:31:56 +0100
committerTimotej Lazar <timotej.lazar@fri.uni-lj.si>2016-02-23 17:31:56 +0100
commit1dd4d473bb136c607eeea3a2d655b3f56e5aeee8 (patch)
tree3c9c8999bc7e2e5af2e53f6485ac1f213f253cd4
parent2fa2481829bda1f475c7f9681551631cb0ba6b4f (diff)
Remove explicit "Hint" button
Hints are now generated for each tested program, and the user can press a button to reveal the hints.
-rw-r--r--css/codeq/hint.css23
-rw-r--r--index.html2
-rw-r--r--js/codeq/hint.js126
-rw-r--r--js/codeq/prolog.js37
-rw-r--r--js/codeq/python.js34
-rw-r--r--js/codeq/robot.js4
6 files changed, 102 insertions, 124 deletions
diff --git a/css/codeq/hint.css b/css/codeq/hint.css
index 05bd970..803479f 100644
--- a/css/codeq/hint.css
+++ b/css/codeq/hint.css
@@ -18,7 +18,8 @@ a.hint-static-link {
cursor: pointer;
}
-.hint-static img {
+div.hint-static img {
+ max-height: 12em;
max-width: 80%;
/* center img trick */
display: block;
@@ -26,22 +27,18 @@ a.hint-static-link {
margin-right: auto;
}
-.hints > div {
- border: 1px solid gray;
- border-radius: 4px;
- margin-bottom: 0.5em;
+div.hints > div.feedback {
+ border-top: 1px solid gray;
+ margin-bottom: 1.5em;
margin-top: 0.5em;
- opacity: 0.8;
- padding: 0.5em;
}
-
-.hints > div:first-child {
- border: 2px solid black;
- opacity: 1;
+div.hints > div.feedback:first-child {
+ border-top: none;
}
-.hints > div:hover {
- opacity: 1;
+div.hints > div.feedback > div {
+ margin-bottom: 0.5em;
+ margin-top: 0.5em;
}
.popup-hint > :last-child {
diff --git a/index.html b/index.html
index ecd3b1b..040dd6b 100644
--- a/index.html
+++ b/index.html
@@ -345,7 +345,6 @@
<div class="col-lg-6 col-md-12 col-sm-12 block block2">
<div class="block-toolbar">
<button type="button" class="btn btn-default btn-plan" data-tkey="btn_plan">Plan</button>
- <button type="button" class="btn btn-default ladda-button btn-hint" data-style="slide-up" data-spinner-color="blue"><span class="ladda-label" data-tkey="btn_hint">Hint</span></button>
<button type="button" class="btn btn-default ladda-button btn-test" data-style="slide-up" data-spinner-color="blue"><span class="ladda-label" data-tkey="btn_test">Test</span></button>
</div>
<div class="code_editor"></div>
@@ -384,7 +383,6 @@
<div class="col-lg-6 col-md-12 col-sm-12 block block2">
<div class="block-toolbar">
<button type="button" class="btn btn-default btn-plan" data-tkey="btn_plan">Plan</button>
- <button type="button" class="btn btn-default ladda-button btn-hint" data-style="slide-up" data-spinner-color="blue"><span class="ladda-label" data-tkey="btn_hint">Hint</span></button>
<button type="button" class="btn btn-default ladda-button btn-test" data-style="slide-up" data-spinner-color="blue"><span class="ladda-label" data-tkey="btn_test">Test</span></button>
<button type="button" class="btn btn-default btn-run" data-tkey="btn_run">Run</button>
<button type="button" class="btn btn-default btn-stop" data-tkey="btn_stop">Stop</button>
diff --git a/js/codeq/hint.js b/js/codeq/hint.js
index bc42694..0550a41 100644
--- a/js/codeq/hint.js
+++ b/js/codeq/hint.js
@@ -24,7 +24,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */
var firstCharacterPos = {'line': 0, 'ch': 0},
sel_no_scroll = {'scroll': false};
- codeq.makeHinter = function (jqHints, jqEditor, editor, trNamespace, problemDef, commonDef) {
+ codeq.makeHinter = function (jqHints, jqEditor, editor, trNamespace, problemDef, commonDef, activityHandler) {
var hintCounter = 0, // for generating unique class-names
hintCleaners = [],
popoverHintCleaners = [], // we require separate cleaners for popups, because they are rebuilt when the editor's DOM changes
@@ -51,6 +51,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */
popoverHintCleaners[i]();
}
popoverHintCleaners.length = 0;
+ $('div.hints > div.feedback > button.display-hints').off().remove();
},
addMark = function (start, end, style) {
@@ -180,7 +181,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */
},
typeHandlers = {
- 'static': function (template, hint) {
+ 'static': function (template, hint, box) {
var content = prepareStaticHintContent(template, hint.indices, hint.id),
args = hint ? hint.args : null,
hintIndex = 0,
@@ -222,15 +223,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */
}
}
else {
- jqContainer.prepend(jq);
+ jqContainer.append(jq);
}
codeq.tr.translateDom(jq);
- //// scroll into view if overflowing
- //deltaHeight = jqHints.height() - jqHintsContainer.height();
- //if (deltaHeight > 0) {
- // jqHintsContainer.scrollTop(deltaHeight);
- //}
- jqHintsContainer.scrollTop(0);
},
jqContainer, jqButton;
@@ -238,7 +233,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */
// hint sequence
jqContainer = $('<div class="hint-static-group"></div>');
jqButton = $('<a class="hint-static-link" ' + ta(trButton) + '></a>');
- jqHints.prepend(jqContainer);
+ box.append(jqContainer);
jqContainer.append(jqButton);
jqButton.on('click', function () {
nextJqHint();
@@ -246,7 +241,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */
}
else {
// a single hint
- jqContainer = jqHints;
+ jqContainer = box;
jqButton = null;
}
nextJqHint();
@@ -254,7 +249,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */
// no hint cleaner here, a static hint remains on the screen
},
- 'popup': function (template, hint) {
+ 'popup': function (template, hint, box) {
codeq.log.debug('Processing popup hint');
var args = hint.args,
style = hint.style || '',
@@ -297,7 +292,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */
return instFunc;
},
- 'dropdown': function (template, hint) {
+ 'dropdown': function (template, hint, box) {
codeq.log.debug('Processing dropdown hint');
var completion = null, // the completion object, created in showHint()
close = function () {
@@ -330,6 +325,46 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */
}
},
+ // process and append [hints] to the element [box]
+ appendHints = function (hints, box) {
+ var finalizers = [],
+ i, hint, hintDef, hintContent, hintType, t, fn, ret;
+
+ activityHandler.queueTrace({'typ': 'hint', 'feedback': hints});
+ for (i = 0; i < hints.length; i++) {
+ hint = hints[i];
+ hintDef = hintProblemDefs[hint.id] || hintCommonDefs[hint.id];
+ if (!hintDef) {
+ codeq.log.error('Undefined hint: ' + hint.id);
+ continue;
+ }
+ hintContent = hintProblemTr[hint.id] || hintCommonTr[hint.id];
+ if (!hintContent) {
+ codeq.log.error('Hint without content: ' + hint.id);
+ continue;
+ }
+
+ t = typeof hintDef;
+ if (t === 'string') hintType = hintDef; // currently a hint type is a string
+ else if ((t === 'object') && (hintDef !== null)) hintType = hintDef.type; // but in future we may use an object, if a definition becomes more complex
+ else {
+ codeq.log.error('Cannot determine the type of hint ' + hint.id + ' from: ' + hintDef);
+ continue;
+ }
+
+ fn = typeHandlers[hintType];
+ if (!fn) codeq.log.error('Unsupported hint type: ' + hintType);
+ else {
+ ret = fn(hintContent, hint, box);
+ if (typeof ret === 'function') finalizers.push(ret);
+ }
+ }
+ // invoke any finalizers
+ for (i = 0; i < finalizers.length; i++) {
+ finalizers[i]();
+ }
+ },
+
/**
* When the editor updates its DOM, we have to re-register any popup hints.
*/
@@ -349,7 +384,12 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */
*/
'planNext': function () {
if (planIdx < planDef.length) {
- typeHandlers['static'](planDef[planIdx], {'id': 'plan'});
+ var jqHintBox = $('<div class="feedback"></div>');
+ activityHandler.queueTrace({'typ': 'plan', 'index': planIdx});
+ clearHints();
+ typeHandlers['static'](planDef[planIdx], {'id': 'plan'}, jqHintBox);
+ jqHints.prepend(jqHintBox);
+ jqHintsContainer.scrollTop(0);
planIdx++;
}
return planIdx < planDef.length;
@@ -366,42 +406,48 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */
* @param {ServerHint[]} hints an array of hints from the server
*/
'handle': function (hints) {
- var finalizers = [],
- i, hint, hintDef, hintContent, hintType, t, fn, ret;
+ var i, hint, hintDef, hintContent,
+ n_correct = 0, n_all = 0,
+ jqHintBox = $('<div class="feedback"></div>'),
+ jqHintBtn;
+ // clear any existing hints
clearHints();
+
+ // display the test_results hint first if found
for (i = 0; i < hints.length; i++) {
hint = hints[i];
- hintDef = hintProblemDefs[hint.id] || hintCommonDefs[hint.id];
- if (!hintDef) {
- codeq.log.error('Undefined hint: ' + hint.id);
- continue;
- }
- hintContent = hintProblemTr[hint.id] || hintCommonTr[hint.id];
- if (!hintContent) {
- codeq.log.error('Hint without content: ' + hint.id);
- continue;
+ if (hint.id === 'test_results') {
+ activityHandler.queueTrace({'typ': 'test', 'feedback': hint});
+ n_correct = hint.args.passed
+ n_all = hint.args.total
+ hintContent = hintProblemTr[hint.id] || hintCommonTr[hint.id];
+ typeHandlers['static'](hintContent, hint, jqHintBox);
+ hints.splice(i, 1);
+ break;
}
+ }
- t = typeof hintDef;
- if (t === 'string') hintType = hintDef; // currently a hint type is a string
- else if ((t === 'object') && (hintDef !== null)) hintType = hintDef.type; // but in future we may use an object, if a definition becomes more complex
- else {
- codeq.log.error('Cannot determine the type of hint ' + hint.id + ' from: ' + hintDef);
- continue;
+ // display remaining hints
+ if (hints.length > 0) {
+ if (n_all == 0 || n_correct == n_all) {
+ // no test_results or program correct: show all hints immediately
+ appendHints(hints, jqHintBox);
}
-
- fn = typeHandlers[hintType];
- if (!fn) codeq.log.error('Unsupported hint type: ' + hintType);
else {
- ret = fn(hintContent, hint);
- if (typeof ret === 'function') finalizers.push(ret);
+ // otherwise, hide hints behind a button
+ jqHintBtn = $('<button class="display-hints" data-tkey="btn_hint">Hint</button>');
+ codeq.tr.translateDom(jqHintBtn);
+ jqHintBtn.on('click', function (e) {
+ jqHintBtn.off().remove();
+ appendHints(hints, jqHintBox);
+
+ });
+ jqHintBox.append(jqHintBtn);
}
}
- // invoke any finalizers
- for (i = 0; i < finalizers.length; i++) {
- finalizers[i]();
- }
+ jqHints.prepend(jqHintBox);
+ jqHintsContainer.scrollTop(0);
},
'destroy': function () {
diff --git a/js/codeq/prolog.js b/js/codeq/prolog.js
index b2ea3e1..3d34423 100644
--- a/js/codeq/prolog.js
+++ b/js/codeq/prolog.js
@@ -33,9 +33,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */
jqAllQuadrants = jqDescription.add(jqCode).add(jqConsole).add(jqInfo), // all the quadrants
// buttons
jqBtnPlan = jqScreen.find('.btn-plan'),
- jqBtnHint = jqScreen.find('.btn-hint').ladda(),
jqBtnTest = jqScreen.find('.btn-test').ladda(),
- jqAllButtons = jqBtnPlan.add(jqBtnHint).add(jqBtnTest), // all the buttons
+ jqAllButtons = jqBtnPlan.add(jqBtnTest), // all the buttons
// misc
currentSubState = null,
transitionEventName = 'mousedown',//event name of the event which will trigger the transition between these substates - the most common transition at least (there are some corner cases on the hint and test buttons -> see the code below)
@@ -251,7 +250,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */
}),
activityHandler = codeq.makeActivityHandler(editor, problemDef.id),
terminal = makePrologTerminalHandler(jqTerminal, editor, problemDef.id, activityHandler),
- hinter = codeq.makeHinter(jqHints, jqEditor, editor, 'prolog_hints', problemDef, commonDef),
+ hinter = codeq.makeHinter(jqHints, jqEditor, editor, 'prolog_hints', problemDef, commonDef, activityHandler),
commError = function (error) {
alert(error);
};
@@ -279,42 +278,14 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */
});
jqBtnPlan.on('click', function () {
- activityHandler.queueTrace({'typ': 'plan'});
if (!hinter.planNext()) {
jqBtnPlan.prop('disabled', true).blur();
}
});
- jqBtnHint.on('click', function () {
- editor.setOption('readOnly', true);
- terminal.inputDisable();
- jqBtnTest.prop('disabled', true);
- jqBtnHint.ladda('start');
- codeq.comms.sendHint({
- 'program': editor.getDoc().getValue(),
- 'problem_id': problemDef.id
- })
- .then(function (data) {
- if (data.code === 0) {
- activityHandler.queueTrace({'typ': 'hint', 'feedback': data.hints});
- hinter.handle(data.hints);
- }
- else {
- terminal.append(data.message + '\n', 'error');
- }
- })
- .fail(commError)
- .fin(function () {
- editor.setOption('readOnly', false);
- terminal.inputEnable();
- jqBtnHint.ladda('stop');
- jqBtnTest.prop('disabled', false);
- })
- .done();
- });
+
jqBtnTest.on('click', function () {
editor.setOption('readOnly', true);
terminal.inputDisable();
- jqBtnHint.prop('disabled', true);
jqBtnTest.ladda('start');
codeq.comms.sendTest({
'program': editor.getDoc().getValue(),
@@ -322,7 +293,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */
})
.then(function (data) {
if (data.code === 0) {
- activityHandler.queueTrace({'typ': 'test', 'feedback': data.hints});
hinter.handle(data.hints);
}
else {
@@ -334,7 +304,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */
editor.setOption('readOnly', false);
terminal.inputEnable();
jqBtnTest.ladda('stop');
- jqBtnHint.prop('disabled', false);
})
.done();
});
diff --git a/js/codeq/python.js b/js/codeq/python.js
index 10032e8..f2b0184 100644
--- a/js/codeq/python.js
+++ b/js/codeq/python.js
@@ -35,11 +35,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */
jqAllQuadrants = jqDescription.add(jqCode).add(jqConsole).add(jqInfo), // all the quadrants
// buttons
jqBtnPlan = jqScreen.find('.btn-plan'),
- jqBtnHint = jqScreen.find('.btn-hint').ladda(),
jqBtnTest = jqScreen.find('.btn-test').ladda(),
jqBtnRun = jqScreen.find('.btn-run'),
jqBtnStop = jqScreen.find('.btn-stop'),
- jqInfoButtons = jqBtnPlan.add(jqBtnHint).add(jqBtnTest), // all info-focusing buttons
+ jqInfoButtons = jqBtnPlan.add(jqBtnTest), // all info-focusing buttons
jqAllButtons = jqInfoButtons.add(jqBtnRun).add(jqBtnStop), // all buttons
// misc
currentSubState = null,
@@ -208,7 +207,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */
}),
activityHandler = codeq.makeActivityHandler(editor, problemDef.id),
terminal = makePythonTerminalHandler(jqTerminal, editor, problemDef.id, activityHandler),
- hinter = codeq.makeHinter(jqHints, jqEditor, editor, 'python_hints', problemDef, commonDef),
+ hinter = codeq.makeHinter(jqHints, jqEditor, editor, 'python_hints', problemDef, commonDef, activityHandler),
commError = function (error) {
alert(error);
};
@@ -236,39 +235,12 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */
});
jqBtnPlan.on('click', function () {
- activityHandler.queueTrace({'typ': 'plan'});
if (!hinter.planNext()) {
jqBtnPlan.prop('disabled', true).blur();
}
});
- jqBtnHint.on('click', function () {
- editor.setOption('readOnly', true);
- jqBtnTest.prop('disabled', true);
- jqBtnHint.ladda('start');
- codeq.comms.sendHint({
- 'program': editor.getDoc().getValue(),
- 'problem_id': problemDef.id
- })
- .then(function (data) {
- if (data.code === 0) {
- activityHandler.queueTrace({'typ': 'hint', 'feedback': data.hints});
- hinter.handle(data.hints);
- }
- else {
- terminal.append('error: ' + data.message);
- }
- })
- .fail(commError)
- .fin(function () {
- editor.setOption('readOnly', false);
- jqBtnHint.ladda('stop');
- jqBtnTest.prop('disabled', false);
- })
- .done();
- });
jqBtnTest.on('click', function () {
editor.setOption('readOnly', true);
- jqBtnHint.prop('disabled', true);
jqBtnTest.ladda('start');
codeq.comms.sendTest({
'program': editor.getDoc().getValue(),
@@ -276,7 +248,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */
})
.then(function (data) {
if (data.code === 0) {
- activityHandler.queueTrace({'typ': 'test', 'feedback': data.hints});
hinter.handle(data.hints);
}
else {
@@ -287,7 +258,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */
.fin(function () {
editor.setOption('readOnly', false);
jqBtnTest.ladda('stop');
- jqBtnHint.prop('disabled', false);
})
.done();
});
diff --git a/js/codeq/robot.js b/js/codeq/robot.js
index f5c04a1..42f336c 100644
--- a/js/codeq/robot.js
+++ b/js/codeq/robot.js
@@ -178,7 +178,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */
}),
activityHandler = codeq.makeActivityHandler(editor, problemDef.id),
terminal = makeRobotTerminalHandler(jqTerminal, editor, problemDef.id, activityHandler),
- hinter = codeq.makeHinter(jqHints, jqEditor, editor, 'robot_hints', problemDef, commonDef),
+ hinter = codeq.makeHinter(jqHints, jqEditor, editor, 'robot_hints', problemDef, commonDef, activityHandler),
commError = function (error) {
alert(error);
},
@@ -236,7 +236,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */
});
jqBtnPlan.on('click', function () {
- activityHandler.queueTrace({'typ': 'plan'});
if (!hinter.planNext()) {
jqBtnPlan.prop('disabled', true).blur();
}
@@ -250,7 +249,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */
})
.then(function (data) {
if (data.code === 0) {
- activityHandler.queueTrace({'typ': 'hint', 'feedback': data.hints});
hinter.handle(data.hints);
}
else {