summaryrefslogtreecommitdiff
path: root/js/codeq/prolog.js
diff options
context:
space:
mode:
authorMarko Pušnik <marko.pusnik@guru.si>2015-09-25 17:52:01 +0200
committerMarko Pušnik <marko.pusnik@guru.si>2015-09-25 17:52:01 +0200
commit2d2efca92351293ab179956efee78ef8f697afd6 (patch)
tree4664bb71aa60f942e9393e6e91d630065c2734a2 /js/codeq/prolog.js
parent23352d5f8a99d1457e64b76a958ca12dc789065d (diff)
refactor menu + some forms to use bootstrap properly
Diffstat (limited to 'js/codeq/prolog.js')
-rw-r--r--js/codeq/prolog.js712
1 files changed, 356 insertions, 356 deletions
diff --git a/js/codeq/prolog.js b/js/codeq/prolog.js
index 66ab970..f2f060f 100644
--- a/js/codeq/prolog.js
+++ b/js/codeq/prolog.js
@@ -1,356 +1,356 @@
-/**
- * Created by robert on 9/17/15.
- *
- * The prolog state of the state machine. When it is entered it'll prepare the console and code editor and load a sub-state machine which represents the 4 different parts fo the screen.
- */
-
-(function() {
- var subScreens, //this will be the actual (sub)state machine
- stateNameTag = 'stateName', //a tag for data which is added to some html elements
- jqScreen = $('#screen_prolog'), // the screen container element
- //quadrants
- jqDescription = jqScreen.find('.block1'),
- jqCode = jqScreen.find('.block2'),
- jqConsole = jqScreen.find('.block3'),
- jqInfo = jqScreen.find('.block4'),
- jqAllQuadrants = jqDescription.add(jqCode).add(jqConsole).add(jqInfo), // all the quadrants
- // buttons
- jqBtnPlan = jqScreen.find('.btn-plan'),
- jqBtnHint = jqScreen.find('.btn-hint'),
- jqBtnTest = jqScreen.find('.btn-test'),
- jqAllButtons = jqBtnPlan.add(jqBtnHint).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)
- substates = {
- 'description': {
- 'enter': function () {
- currentSubState = 'block1';
- jqScreen.addClass(currentSubState);
- },
- 'exit': function () {
- jqScreen.removeClass(currentSubState);
- currentSubState = null;
- }
- },
- 'code': {
- 'enter': function () {
- currentSubState = 'block2';
- jqScreen.addClass(currentSubState);
- },
- 'exit': function () {
- jqScreen.removeClass(currentSubState);
- currentSubState = null;
- }
- },
- 'info': {
- 'enter': function () {
- currentSubState = 'block4';
- jqScreen.addClass(currentSubState);
- },
- 'exit': function () {
- jqScreen.removeClass(currentSubState);
- currentSubState = null;
- }
- },
- 'console': {
- 'enter': function () {
- currentSubState = 'block3';
- jqScreen.addClass(currentSubState);
- },
- 'exit': function () {
- jqScreen.removeClass(currentSubState);
- currentSubState = null;
- }
- }
- };
- var prologHandler; //created when we enter the prolog state and destroyed once we leave it
- codeq.globalStateMachine.register('prolog', {
- 'enter': function (data) {
- $('#navigation-login').css('display', '');
- $('#navigation-language').css('display', '');
- $('#navigation-problem').css('display', '');
- $("#navigation-prolog").addClass("active");
- $('#navigation-prolog').css('display', '');
-
- jqScreen.css('display', '');//we have to show the screen now so the code editor shows its initial values correctly
- prologHandler = createPrologHandler(data.data);
- subScreens = codeq.makeStateMachine(substates);
- subScreens.transition(jqDescription.data(stateNameTag));
-/* Q.delay(100).then(function(){
- jqAllQuadrants.addClass('transition');//for smooth animations - need to be delayed, because otherwise we get some weird "animations" while the page is loading
- }).done();*/
- jqAllButtons.on(transitionEventName, function (event) {
- subScreens.transition('info'); // set focus on the hints quadrant
- event.stopPropagation(); // don't allow the event to go on and trigger further transition
- });
- jqAllQuadrants.on(transitionEventName, function () {
- subScreens.transition($(this).data(stateNameTag));
- });
- },
- 'exit': function () {
- jqAllButtons.off(); // unregister all event handlers
- jqAllQuadrants.off();
- jqScreen.css('display', 'none');
-// jqAllQuadrants.removeClass('transition');
- prologHandler.destroy();
- prologHandler = null;
- subScreens.destroy();
- subScreens = null;
- jqScreen.addClass('block1');
-
- $('#navigation-login').css('display', 'none');
- $('#navigation-language').css('display', 'none');
- $('#navigation-problem').css('display', 'none');
- $("#navigation-prolog").removeClass("active");
- $('#navigation-prolog').css('display', 'none');
- }
- });
-
- jqDescription.data(stateNameTag, 'description');
- jqCode.data(stateNameTag, 'code');
- jqConsole.data(stateNameTag, 'console');
- jqInfo.data(stateNameTag, 'info');
-
- // a constant
- var firstCharacterPos = {'line': 0, 'ch': 0};
-
- var makePrologTerminalHandler = function (jqConsole, editor, problem_id, activityHandler) {
- var promptMode = true, // default: query composition; alternative: query result browsing
- manualStop = false,// if the user stopped showing next answers (false) or if there are no more answers (true)
- terminal = codeq.makeConsole(jqConsole, {
- 'greeting': 'CodeQ Prolog terminal proxy',
- 'autoHistory': true
- }),
- tcs = function terminalCommandSuccess (data) {
- var t, lines, i;
- if (data.code === 0) {
- t = data.terminal;
- terminal.append(t.messages.join('\n'), 'output');
- promptMode = !t.have_more;
- }
- else {
- terminal.append(data.message, 'error');
- promptMode = true;
- }
- if (promptMode) {
- terminal.setLineBuffered();
- terminal.append(manualStop ? '?- ' : '.\n?- ', 'output');
- }
- },
- tcf = function terminalCommandFailed (error) {
- promptMode = true;
- terminal.setLineBuffered();
- terminal.append(error + '\n', 'error');
- terminal.append('?- ', 'output');
- };
-
- terminal.onKeypress = function (c) {
- if (promptMode) return c; // query composition: return the character unchanged
- switch (c) {
- case ' ':
- case ';':
- case '\n':
- return ';'; // show next answer on space, semicolon or enter
- default:
- return '.'; // everything else: stop searching for answers
- }
- };
-
- terminal.onInput = function (command) {
- if (promptMode) {
- promptMode = false;
- manualStop = false;
- terminal.setNotBuffered();
- return codeq.comms.sendQuery({
- 'problem_id': problem_id,
- 'step': 'run',
- 'program': editor.getDoc().getValue(),
- 'query': command,
- 'trace': activityHandler.addAndPurge({'typ': 'slv', 'qry': command})
- }, problem_id).then(tcs, tcf);
- }
- else {
- terminal.append('\n', 'input');
- if (command == ';') {
- // show next answer
- return codeq.comms.sendQuery({
- 'problem_id': problem_id,
- 'step': 'next',
- 'trace': activityHandler.addAndPurge({'typ': 'nxt'})
- }, problem_id).then(tcs, tcf);
- }
- else {
- // stop searching for answers
- manualStop = true;
- return codeq.comms.sendQuery({
- 'problem_id': problem_id,
- 'step': 'end',
- 'trace': activityHandler.addAndPurge({'typ': 'stp'})
- }, problem_id).then(tcs, tcf);
- }
-
- }
- };
-
- terminal.leftmostCol = 3;
- terminal.append('?- ', 'output');
-
- return terminal;
- };
-
- var makeActivityHandler = function (editor, problem_id) {
- var lastActivityMillis = Date.now(),
- deltaActivityMillis = function deltaActivityMillisFunc () {
- var now = Date.now(),
- dt = now - lastActivityMillis;
- lastActivityMillis = now;
- return dt;
- },
- queue = [],
- ts = null,
- timer = function () {
- var promise;
- ts = null;
- if (queue.length === 0) return Q(true);
- promise = codeq.comms.sendActivity(queue, editor.getDoc().getValue(), problem_id);
- queue.length = 0;
- return promise;
- },
- flush = function () {
- clearTimeout(ts);
- return timer();
- };
-
- return {
- 'queueTrace': function (trace) {
- trace['dt'] = deltaActivityMillis();
- queue.push(trace);
- if (ts === null) ts = setTimeout(timer, 10000); // flush every 10 seconds
- return this;
- },
- 'flush': flush,
- 'addAndPurge': function (trace) {
- var accumulatedTrace = queue;
- queue = [];
- trace['dt'] = deltaActivityMillis();
- accumulatedTrace.push(trace);
- if (ts !== null) {
- clearTimeout(ts);
- ts = null;
- }
- return accumulatedTrace;
- }
- };
- };
-
- /**
- * Creates a new handler for the given Prolog assignment definition.
- *
- * @param {PrologTaskDef} info
- * @returns {{destroy: Function, processServerHints: Function}}
- */
- createPrologHandler = function (info) {
- var problem = info.problem,
- jqDescriptionContent = jqDescription.find('.description'),
- jqEditor = jqCode.find('.code_editor'),
- jqTerminal = jqConsole.find('.console'),
- jqHints = jqInfo.find('.hints'),
- editor = CodeMirror(jqEditor[0], { cursorHeight: 0.85, lineNumbers: true, matchBrackets: true }),
- activityHandler = makeActivityHandler(editor, problem.id),
- terminal = makePrologTerminalHandler(jqTerminal, editor, problem.id, activityHandler),
- hinter = codeq.makeHinter(jqHints, jqEditor, editor, problem.hint, problem.plan),
- commError = function (error) {
- alert(error);
- };
-
- editor.setValue(info.solution);
- $('#title').text(problem.slug);
- jqDescriptionContent.html(problem.description);
- jqBtnPlan.prop('disabled', (problem.plan || '').length == 0);
-
- editor.on('change', function (instance, changeObj) {
- var doc = editor.getDoc(),
- pos = codeq.codePointCount(doc.getRange(firstCharacterPos, changeObj.from));
-
- if (changeObj.removed) {
- activityHandler.queueTrace({'typ': 'r', 'off': pos, 'len': codeq.codePointCount(changeObj.removed.join(''))});
- }
-
- if (changeObj.text) {
- activityHandler.queueTrace({'typ': 'ins', 'off': pos, 'txt': changeObj.text});
- }
- });
-
- jqBtnPlan.on('click', function () {
- if (!hinter.planNext()) {
- jqBtnPlan.prop('disabled', true).blur();
- }
- });
- jqBtnHint.on('click', function () {
- terminal.append('hint.\n', 'input');
- terminal.inputDisable();
- var doc = editor.getDoc();
- codeq.comms.sendHint({
- 'language': 'prolog',
- 'program': editor.getDoc().getValue(),
- 'problem_id': problem.id
- })
- .then(function (data) {
- if (data.code === 0) {
- hinter.handle(data.hints);
- }
- else {
- terminal.append(data.message + '\n', 'error');
- }
- })
- .fail(commError)
- .fin(function () {
- terminal.inputEnable();
- terminal.append('?- ', 'output');
- })
- .done();
- });
- jqBtnTest.on('click', function () {
- terminal.append('test.\n', 'input');
- terminal.inputDisable();
- var doc = editor.getDoc();
- codeq.comms.sendTest({
- 'language': 'prolog',
- 'program': editor.getDoc().getValue(),
- 'problem_id': problem.id
- })
- .then(function (data) {
- if (data.code === 0) {
- hinter.handle(data.hints);
- }
- else {
- terminal.append(data.message + '\n', 'error');
- }
- })
- .fail(commError)
- .fin(function () {
- terminal.inputEnable();
- terminal.append('?- ', 'output');
- })
- .done();
- });
-
- return {
- destroy: function () {
- $('#title').text('');//empty the title text
- jqAllButtons.off();
- editor.off('change');
- hinter.destroy();
- terminal.destroy();
- jqDescriptionContent.empty();
- jqEditor.empty(); // TODO: perhaps you do not want to "free" the editor, just empty it
- jqTerminal.empty(); // TODO: the same with the console
- jqDescriptionContent = null;
- jqEditor = null;
- jqTerminal = null;
- jqHints = null;
- }
- };
- };
-})();
+/**
+ * Created by robert on 9/17/15.
+ *
+ * The prolog state of the state machine. When it is entered it'll prepare the console and code editor and load a sub-state machine which represents the 4 different parts fo the screen.
+ */
+
+(function() {
+ var subScreens, //this will be the actual (sub)state machine
+ stateNameTag = 'stateName', //a tag for data which is added to some html elements
+ jqScreen = $('#screen_prolog'), // the screen container element
+ //quadrants
+ jqDescription = jqScreen.find('.block1'),
+ jqCode = jqScreen.find('.block2'),
+ jqConsole = jqScreen.find('.block3'),
+ jqInfo = jqScreen.find('.block4'),
+ jqAllQuadrants = jqDescription.add(jqCode).add(jqConsole).add(jqInfo), // all the quadrants
+ // buttons
+ jqBtnPlan = jqScreen.find('.btn-plan'),
+ jqBtnHint = jqScreen.find('.btn-hint'),
+ jqBtnTest = jqScreen.find('.btn-test'),
+ jqAllButtons = jqBtnPlan.add(jqBtnHint).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)
+ substates = {
+ 'description': {
+ 'enter': function () {
+ currentSubState = 'block1';
+ jqScreen.addClass(currentSubState);
+ },
+ 'exit': function () {
+ jqScreen.removeClass(currentSubState);
+ currentSubState = null;
+ }
+ },
+ 'code': {
+ 'enter': function () {
+ currentSubState = 'block2';
+ jqScreen.addClass(currentSubState);
+ },
+ 'exit': function () {
+ jqScreen.removeClass(currentSubState);
+ currentSubState = null;
+ }
+ },
+ 'info': {
+ 'enter': function () {
+ currentSubState = 'block4';
+ jqScreen.addClass(currentSubState);
+ },
+ 'exit': function () {
+ jqScreen.removeClass(currentSubState);
+ currentSubState = null;
+ }
+ },
+ 'console': {
+ 'enter': function () {
+ currentSubState = 'block3';
+ jqScreen.addClass(currentSubState);
+ },
+ 'exit': function () {
+ jqScreen.removeClass(currentSubState);
+ currentSubState = null;
+ }
+ }
+ };
+ var prologHandler; //created when we enter the prolog state and destroyed once we leave it
+ codeq.globalStateMachine.register('prolog', {
+ 'enter': function (data) {
+ $('#navigation-login').css('display', '');
+ $('#navigation-language').css('display', '');
+ $('#navigation-problem').css('display', '');
+ $("#navigation-prolog").addClass("active");
+ $('#navigation-prolog').css('display', '');
+
+ jqScreen.css('display', '');//we have to show the screen now so the code editor shows its initial values correctly
+ prologHandler = createPrologHandler(data.data);
+ subScreens = codeq.makeStateMachine(substates);
+ subScreens.transition(jqDescription.data(stateNameTag));
+/* Q.delay(100).then(function(){
+ jqAllQuadrants.addClass('transition');//for smooth animations - need to be delayed, because otherwise we get some weird "animations" while the page is loading
+ }).done();*/
+ jqAllButtons.on(transitionEventName, function (event) {
+ subScreens.transition('info'); // set focus on the hints quadrant
+ event.stopPropagation(); // don't allow the event to go on and trigger further transition
+ });
+ jqAllQuadrants.on(transitionEventName, function () {
+ subScreens.transition($(this).data(stateNameTag));
+ });
+ },
+ 'exit': function () {
+ jqAllButtons.off(); // unregister all event handlers
+ jqAllQuadrants.off();
+ jqScreen.css('display', 'none');
+// jqAllQuadrants.removeClass('transition');
+ prologHandler.destroy();
+ prologHandler = null;
+ subScreens.destroy();
+ subScreens = null;
+ jqScreen.addClass('block1');
+
+ $('#navigation-login').css('display', 'none');
+ $('#navigation-language').css('display', 'none');
+ $('#navigation-problem').css('display', 'none');
+ $("#navigation-prolog").removeClass("active");
+ $('#navigation-prolog').css('display', 'none');
+ }
+ });
+
+ jqDescription.data(stateNameTag, 'description');
+ jqCode.data(stateNameTag, 'code');
+ jqConsole.data(stateNameTag, 'console');
+ jqInfo.data(stateNameTag, 'info');
+
+ // a constant
+ var firstCharacterPos = {'line': 0, 'ch': 0};
+
+ var makePrologTerminalHandler = function (jqConsole, editor, problem_id, activityHandler) {
+ var promptMode = true, // default: query composition; alternative: query result browsing
+ manualStop = false,// if the user stopped showing next answers (false) or if there are no more answers (true)
+ terminal = codeq.makeConsole(jqConsole, {
+ 'greeting': 'CodeQ Prolog terminal proxy',
+ 'autoHistory': true
+ }),
+ tcs = function terminalCommandSuccess (data) {
+ var t, lines, i;
+ if (data.code === 0) {
+ t = data.terminal;
+ terminal.append(t.messages.join('\n'), 'output');
+ promptMode = !t.have_more;
+ }
+ else {
+ terminal.append(data.message, 'error');
+ promptMode = true;
+ }
+ if (promptMode) {
+ terminal.setLineBuffered();
+ terminal.append(manualStop ? '?- ' : '.\n?- ', 'output');
+ }
+ },
+ tcf = function terminalCommandFailed (error) {
+ promptMode = true;
+ terminal.setLineBuffered();
+ terminal.append(error + '\n', 'error');
+ terminal.append('?- ', 'output');
+ };
+
+ terminal.onKeypress = function (c) {
+ if (promptMode) return c; // query composition: return the character unchanged
+ switch (c) {
+ case ' ':
+ case ';':
+ case '\n':
+ return ';'; // show next answer on space, semicolon or enter
+ default:
+ return '.'; // everything else: stop searching for answers
+ }
+ };
+
+ terminal.onInput = function (command) {
+ if (promptMode) {
+ promptMode = false;
+ manualStop = false;
+ terminal.setNotBuffered();
+ return codeq.comms.sendQuery({
+ 'problem_id': problem_id,
+ 'step': 'run',
+ 'program': editor.getDoc().getValue(),
+ 'query': command,
+ 'trace': activityHandler.addAndPurge({'typ': 'slv', 'qry': command})
+ }, problem_id).then(tcs, tcf);
+ }
+ else {
+ terminal.append('\n', 'input');
+ if (command == ';') {
+ // show next answer
+ return codeq.comms.sendQuery({
+ 'problem_id': problem_id,
+ 'step': 'next',
+ 'trace': activityHandler.addAndPurge({'typ': 'nxt'})
+ }, problem_id).then(tcs, tcf);
+ }
+ else {
+ // stop searching for answers
+ manualStop = true;
+ return codeq.comms.sendQuery({
+ 'problem_id': problem_id,
+ 'step': 'end',
+ 'trace': activityHandler.addAndPurge({'typ': 'stp'})
+ }, problem_id).then(tcs, tcf);
+ }
+
+ }
+ };
+
+ terminal.leftmostCol = 3;
+ terminal.append('?- ', 'output');
+
+ return terminal;
+ };
+
+ var makeActivityHandler = function (editor, problem_id) {
+ var lastActivityMillis = Date.now(),
+ deltaActivityMillis = function deltaActivityMillisFunc () {
+ var now = Date.now(),
+ dt = now - lastActivityMillis;
+ lastActivityMillis = now;
+ return dt;
+ },
+ queue = [],
+ ts = null,
+ timer = function () {
+ var promise;
+ ts = null;
+ if (queue.length === 0) return Q(true);
+ promise = codeq.comms.sendActivity(queue, editor.getDoc().getValue(), problem_id);
+ queue.length = 0;
+ return promise;
+ },
+ flush = function () {
+ clearTimeout(ts);
+ return timer();
+ };
+
+ return {
+ 'queueTrace': function (trace) {
+ trace['dt'] = deltaActivityMillis();
+ queue.push(trace);
+ if (ts === null) ts = setTimeout(timer, 10000); // flush every 10 seconds
+ return this;
+ },
+ 'flush': flush,
+ 'addAndPurge': function (trace) {
+ var accumulatedTrace = queue;
+ queue = [];
+ trace['dt'] = deltaActivityMillis();
+ accumulatedTrace.push(trace);
+ if (ts !== null) {
+ clearTimeout(ts);
+ ts = null;
+ }
+ return accumulatedTrace;
+ }
+ };
+ };
+
+ /**
+ * Creates a new handler for the given Prolog assignment definition.
+ *
+ * @param {PrologTaskDef} info
+ * @returns {{destroy: Function, processServerHints: Function}}
+ */
+ createPrologHandler = function (info) {
+ var problem = info.problem,
+ jqDescriptionContent = jqDescription.find('.description'),
+ jqEditor = jqCode.find('.code_editor'),
+ jqTerminal = jqConsole.find('.console'),
+ jqHints = jqInfo.find('.hints'),
+ editor = CodeMirror(jqEditor[0], { cursorHeight: 0.85, lineNumbers: true, matchBrackets: true }),
+ activityHandler = makeActivityHandler(editor, problem.id),
+ terminal = makePrologTerminalHandler(jqTerminal, editor, problem.id, activityHandler),
+ hinter = codeq.makeHinter(jqHints, jqEditor, editor, problem.hint, problem.plan),
+ commError = function (error) {
+ alert(error);
+ };
+
+ editor.setValue(info.solution);
+ $('#screen_prolog .title').text(problem.slug);
+ jqDescriptionContent.html(problem.description);
+ jqBtnPlan.prop('disabled', (problem.plan || '').length == 0);
+
+ editor.on('change', function (instance, changeObj) {
+ var doc = editor.getDoc(),
+ pos = codeq.codePointCount(doc.getRange(firstCharacterPos, changeObj.from));
+
+ if (changeObj.removed) {
+ activityHandler.queueTrace({'typ': 'r', 'off': pos, 'len': codeq.codePointCount(changeObj.removed.join(''))});
+ }
+
+ if (changeObj.text) {
+ activityHandler.queueTrace({'typ': 'ins', 'off': pos, 'txt': changeObj.text});
+ }
+ });
+
+ jqBtnPlan.on('click', function () {
+ if (!hinter.planNext()) {
+ jqBtnPlan.prop('disabled', true).blur();
+ }
+ });
+ jqBtnHint.on('click', function () {
+ terminal.append('hint.\n', 'input');
+ terminal.inputDisable();
+ var doc = editor.getDoc();
+ codeq.comms.sendHint({
+ 'language': 'prolog',
+ 'program': editor.getDoc().getValue(),
+ 'problem_id': problem.id
+ })
+ .then(function (data) {
+ if (data.code === 0) {
+ hinter.handle(data.hints);
+ }
+ else {
+ terminal.append(data.message + '\n', 'error');
+ }
+ })
+ .fail(commError)
+ .fin(function () {
+ terminal.inputEnable();
+ terminal.append('?- ', 'output');
+ })
+ .done();
+ });
+ jqBtnTest.on('click', function () {
+ terminal.append('test.\n', 'input');
+ terminal.inputDisable();
+ var doc = editor.getDoc();
+ codeq.comms.sendTest({
+ 'language': 'prolog',
+ 'program': editor.getDoc().getValue(),
+ 'problem_id': problem.id
+ })
+ .then(function (data) {
+ if (data.code === 0) {
+ hinter.handle(data.hints);
+ }
+ else {
+ terminal.append(data.message + '\n', 'error');
+ }
+ })
+ .fail(commError)
+ .fin(function () {
+ terminal.inputEnable();
+ terminal.append('?- ', 'output');
+ })
+ .done();
+ });
+
+ return {
+ destroy: function () {
+ $('#screen_prolog .title').text('');//empty the title text
+ jqAllButtons.off();
+ editor.off('change');
+ hinter.destroy();
+ terminal.destroy();
+ jqDescriptionContent.empty();
+ jqEditor.empty(); // TODO: perhaps you do not want to "free" the editor, just empty it
+ jqTerminal.empty(); // TODO: the same with the console
+ jqDescriptionContent = null;
+ jqEditor = null;
+ jqTerminal = null;
+ jqHints = null;
+ }
+ };
+ };
+})();