summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleš Smodiš <aless@guru.si>2015-09-21 17:45:31 +0200
committerAleš Smodiš <aless@guru.si>2015-09-21 17:45:31 +0200
commitcee672f22d516ecc73f84a3dbe01328883a2a47d (patch)
tree2f977f01c4619d2e422cbc8b498218cbe9972dc4
parent86b478fc57f6eb8bc1addd07d4feb95c83f6792c (diff)
Refactoring: simplified python.js and prolog.js, removed all DOM IDs except for the top-level block #screen_prolog, made a copy of the latter into #screen_python so the two screens can now diverge.
-rw-r--r--css/codeq.css94
-rw-r--r--index.html54
-rw-r--r--js/codeq/prolog.js328
-rw-r--r--js/codeq/python.js270
-rw-r--r--js/codeq/stateMachine.js12
5 files changed, 271 insertions, 487 deletions
diff --git a/css/codeq.css b/css/codeq.css
index cfb9286..3de5b0b 100644
--- a/css/codeq.css
+++ b/css/codeq.css
@@ -39,7 +39,7 @@ body {
}
/**** animations *****/
-.transition{
+.transition, .quadrants > * > .block {
-moz-transition: all 1s ease;
-webkit-transition: all 1s ease;
-o-transition: all 1s ease;
@@ -55,34 +55,24 @@ body {
height: 100%;
}
- .block {
+ /* default for all quadrants (no focus anywhere) */
+ .quadrants > * > .block {
overflow: auto;
min-height: 100%; height: 100%;
}
- .block-focus {
- overflow: auto;
- min-height: 100%; height: 100%;
- min-width: 34%; width: 34%;
- }
-
- .block-less-height{/*these names were made for the 'md' variant but need to be the same here for the javascript code to resize them when the focus changes*/
- overflow: auto;
- min-height: 100%; height: 100%;
- min-width: 22%; width: 22%;
- }
-
- .block-less-width{/*these names were made for the 'md' variant but need to be the same here for the javascript code to resize them when the focus changes*/
- overflow: auto;
- min-height: 100%; height: 100%;
- min-width: 22%; width: 22%;
- }
-
- .block-less-everything{/*these names were made for the 'md' variant but need to be the same here for the javascript code to resize them when the focus changes*/
- overflow: auto;
- min-height: 100%; height: 100%;
- min-width: 22%; width: 22%;
- }
+ /* focus on 1st block */
+ .quadrants.block1 > * > .block { min-width: 22%; width: 22%; }
+ .quadrants.block1 > * > .block.block1 { min-width: 34%; width: 34%; }
+ /* focus on 2nd block */
+ .quadrants.block2 > * > .block { min-width: 22%; width: 22%; }
+ .quadrants.block2 > * > .block.block2 { min-width: 34%; width: 34%; }
+ /* focus on 3rd block */
+ .quadrants.block3 > * > .block { min-width: 22%; width: 22%; }
+ .quadrants.block3 > * > .block.block3 { min-width: 34%; width: 34%; }
+ /* focus on 4th block */
+ .quadrants.block4 > * > .block { min-width: 22%; width: 22%; }
+ .quadrants.block4 > * > .block.block4 { min-width: 34%; width: 34%; }
}
/* md */
@@ -91,34 +81,32 @@ body {
height: 100%;
}
- .block {
+ /* default for all quadrants (no focus anywhere) */
+ .quadrants > * > .block {
overflow: auto;
min-height: 50%; height: 50%;
}
- .block-focus {
- overflow: auto;
- min-height: 60%; height: 60%;
- min-width: 60%; width: 60%;
- }
-
- .block-less-height{
- overflow: auto;
- min-height: 40%; height: 40%;
- min-width: 60%; width: 60%;
- }
-
- .block-less-width{
- overflow: auto;
- min-height: 60%; height: 60%;
- min-width: 40%; width: 40%;
- }
-
- .block-less-everything{
- overflow: auto;
- min-height: 40%; height: 40%;
- min-width: 40%; width: 40%;
- }
+ /* focus on 1st block */
+ .quadrants.block1 > * > .block1 { min-height: 60%; height: 60%; min-width: 60%; width: 60%; }
+ .quadrants.block1 > * > .block2 { min-height: 60%; height: 60%; min-width: 40%; width: 40%; }
+ .quadrants.block1 > * > .block3 { min-height: 40%; height: 40%; min-width: 60%; width: 60%; }
+ .quadrants.block1 > * > .block4 { min-height: 40%; height: 40%; min-width: 40%; width: 40%; }
+ /* focus on 2nd block */
+ .quadrants.block2 > * > .block1 { min-height: 60%; height: 60%; min-width: 40%; width: 40%; }
+ .quadrants.block2 > * > .block2 { min-height: 60%; height: 60%; min-width: 60%; width: 60%; }
+ .quadrants.block2 > * > .block3 { min-height: 40%; height: 40%; min-width: 40%; width: 40%; }
+ .quadrants.block2 > * > .block4 { min-height: 40%; height: 40%; min-width: 60%; width: 60%; }
+ /* focus on 3rd block */
+ .quadrants.block3 > * > .block1 { min-height: 40%; height: 40%; min-width: 60%; width: 60%; }
+ .quadrants.block3 > * > .block2 { min-height: 40%; height: 40%; min-width: 40%; width: 40%; }
+ .quadrants.block3 > * > .block3 { min-height: 60%; height: 60%; min-width: 60%; width: 60%; }
+ .quadrants.block3 > * > .block4 { min-height: 60%; height: 60%; min-width: 40%; width: 40%; }
+ /* focus on 4th block */
+ .quadrants.block4 > * > .block1 { min-height: 40%; height: 40%; min-width: 40%; width: 40%; }
+ .quadrants.block4 > * > .block2 { min-height: 40%; height: 40%; min-width: 60%; width: 60%; }
+ .quadrants.block4 > * > .block3 { min-height: 60%; height: 60%; min-width: 40%; width: 40%; }
+ .quadrants.block4 > * > .block4 { min-height: 60%; height: 60%; min-width: 60%; width: 60%; }
}
/* sm */
@@ -132,17 +120,17 @@ body {
/***** blocks *****/
/* description */
-#description {
+.block > .description {
padding: 0.5em;
}
/* info */
-#info {
+.block > .hints {
padding: 0.5em;
}
/* code_editor */
-#code_editor {
+.block > .code_editor {
min-height: 100%;
height: 100%;
padding-top: 50px;
@@ -152,7 +140,7 @@ body {
}
/* console */
-#console {
+.block > .console {
background: black;
font-size: 14px;
height: 100%;
diff --git a/index.html b/index.html
index a767ff4..99f6330 100644
--- a/index.html
+++ b/index.html
@@ -118,29 +118,57 @@
</table>
</div>
- <div class="container-fluid" id="screen_prolog" style="display: none;">
+ <div class="container-fluid quadrants block1" id="screen_prolog" style="display: none;">
<div class="row">
- <div class="col-lg-3 col-md-6 col-sm-12 block" id="description_outer_div">
- <div id="description"></div>
+ <div class="col-lg-3 col-md-6 col-sm-12 block block1">
+ <div class="description"></div>
<div class="block-label">Instructions</div>
</div>
- <div class="col-lg-3 col-md-6 col-sm-12 block" id="code_editor_outer_div">
- <nav class="navbar navbar-default" id="block-toolbar">
+ <div class="col-lg-3 col-md-6 col-sm-12 block block2">
+ <nav class="navbar navbar-default">
<div class="container-fluid">
- <button type="button" class="btn btn-default navbar-btn" id="btn_code_plan">Plan</button>
- <button type="button" class="btn btn-default navbar-btn" id="btn_code_hint">Hint</button>
- <button type="button" class="btn btn-default navbar-btn" id="btn_code_test">Test</button>
+ <button type="button" class="btn btn-default navbar-btn btn-plan">Plan</button>
+ <button type="button" class="btn btn-default navbar-btn btn-hint">Hint</button>
+ <button type="button" class="btn btn-default navbar-btn btn-test">Test</button>
</div>
</nav>
- <div id="code_editor"></div>
+ <div class="code_editor"></div>
<div class="block-label">Code</div>
</div>
- <div class="col-lg-3 col-md-6 col-sm-12 block" id="console_outer_div">
- <div id="console"></div>
+ <div class="col-lg-3 col-md-6 col-sm-12 block block3">
+ <div class="console"></div>
<div class="block-label">Console</div>
</div>
- <div class="col-lg-3 col-md-6 col-sm-12 block" id="info_outer_div">
- <div id="info"></div>
+ <div class="col-lg-3 col-md-6 col-sm-12 block block4">
+ <div class="hints"></div>
+ <div class="block-label">Hints</div>
+ </div>
+ </div><!--/row-->
+ </div><!--container-->
+
+ <div class="container-fluid quadrants block1" id="screen_python" style="display: none;">
+ <div class="row">
+ <div class="col-lg-3 col-md-6 col-sm-12 block block1">
+ <div class="description"></div>
+ <div class="block-label">Instructions</div>
+ </div>
+ <div class="col-lg-3 col-md-6 col-sm-12 block block2">
+ <nav class="navbar navbar-default">
+ <div class="container-fluid">
+ <button type="button" class="btn btn-default navbar-btn btn-plan">Plan</button>
+ <button type="button" class="btn btn-default navbar-btn btn-hint">Hint</button>
+ <button type="button" class="btn btn-default navbar-btn btn-test">Test</button>
+ </div>
+ </nav>
+ <div class="code_editor"></div>
+ <div class="block-label">Code</div>
+ </div>
+ <div class="col-lg-3 col-md-6 col-sm-12 block block3">
+ <div class="console"></div>
+ <div class="block-label">Console</div>
+ </div>
+ <div class="col-lg-3 col-md-6 col-sm-12 block block4">
+ <div class="hints"></div>
<div class="block-label">Hints</div>
</div>
</div><!--/row-->
diff --git a/js/codeq/prolog.js b/js/codeq/prolog.js
index e411bc4..e339fea 100644
--- a/js/codeq/prolog.js
+++ b/js/codeq/prolog.js
@@ -5,221 +5,101 @@
*/
(function() {
- var subScreens,//this will the actual (sub)state machine
- stateNameTag = 'stateName';//a tag for data which is added to some html elements
-
- //get the divs which are the main elements being change on transitions between states in the sub-state machine
- var divs = {};
- divs['description'] = $('#description_outer_div');
- divs['code'] = $('#code_editor_outer_div');
- divs['console'] = $('#console_outer_div');
- divs['info'] = $('#info_outer_div');
-
- //these tags connect the div to their respective state in the sub-state machine
- divs['description'].data(stateNameTag, 'description');
- divs['code'].data(stateNameTag, 'code');
- divs['console'].data(stateNameTag, 'console');
- divs['info'].data(stateNameTag, 'info');
-
- var 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)
- /**
- * the general function which should be called on the mousedown event to trigger the transition between states
- */
- mouseDownEventFunction = function () {
- subScreens.transition($(this).data(stateNameTag));
- },
- /**
- * removes the above function from the divs
- */
- removeListenersFromDivs = function () {
- $.each(divs, function (i, value) {
- value.off(transitionEventName, mouseDownEventFunction);
- });
- },
- /**
- * removes the 'block' class from all divs we need to change when we change the current state
- */
- removeBlockClassesFromDivs = function () {
- $.each(divs, function (i, value) {
- value.removeClass('block');
- });
- },
- /**
- * removes all those special classes from the divs, which are set when a new state is entered and it also adds the 'block' class back
- */
- removeChangedClassesFromDivs = function () {
- $.each(divs, function (i, value) {
- value.removeClass('block-focus block-less-width block-less-height block-less-everything').addClass('block');//these class names were chosen for the view where the screen is partitioned in 4 quarters (2 by 2)
- });
- },
- /**
- *
- * @param current the key of the state ('description','code','hint','console'), which is currently active, because it must not have a transition set
- */
- setTransitionsBetweenDivs = function (current) {
- $.each(divs, function (key, value) {
- if (current !== key) value.on(transitionEventName, mouseDownEventFunction);
- });
- },
- /**
- *
- * @param divsWithClasses a object where we have the keys of the divs object paired with the class name we want to assign to them e.g. :
- * {
- 'description': 'block-focus',
- 'code': 'block-less-width',
- 'console': 'block-less-height',
- 'info': 'block-less-everything'
- }
- */
- addClassesToDivs = function (divsWithClasses) {
- $.each(divsWithClasses, function (divName, className) {
- divs[divName].addClass(className);
- });
- },
- /**
- * the buttons (hint and test) will have to 'eat' the mousedown event to prevent some weird transitions.
- * Because a click on them won't trigger the transition to the code part, but will transition to the hints part.
- *
- * @param event
- */
- mouseDownEventIgnoreFun = function(event){
- event.stopPropagation();
- },
- /**
- * The transition from the buttons to the hints screen will be triggered with this function
- */
- clickListenerTransitionFun = function(){
- subScreens.transition(divs['info'].data(stateNameTag));
- },
- /**
- * add the above function to the buttons
- */
- addClickListenerTranstions = function(){
- $('#btn_code_plan').on('click',clickListenerTransitionFun);
- $('#btn_code_hint').on('click',clickListenerTransitionFun);
- $('#btn_code_test').on('click',clickListenerTransitionFun);
-
- $('#btn_code_plan').on(transitionEventName,mouseDownEventIgnoreFun);
- $('#btn_code_hint').on(transitionEventName,mouseDownEventIgnoreFun);
- $('#btn_code_test').on(transitionEventName,mouseDownEventIgnoreFun);
- },
- /**
- * and a function to remove it
- */
- removeClickListenerTransition = function(){
- $('#btn_code_plan').off('click',clickListenerTransitionFun);
- $('#btn_code_hint').off('click',clickListenerTransitionFun);
- $('#btn_code_test').off('click',clickListenerTransitionFun);
-
- $('#btn_code_plan').off(transitionEventName,mouseDownEventIgnoreFun);
- $('#btn_code_hint').off(transitionEventName,mouseDownEventIgnoreFun);
- $('#btn_code_test').off(transitionEventName,mouseDownEventIgnoreFun);
- },
+ 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 () {
- removeBlockClassesFromDivs();
- addClassesToDivs({
- 'description': 'block-focus',
- 'code': 'block-less-width',
- 'console': 'block-less-height',
- 'info': 'block-less-everything'
- });
- setTransitionsBetweenDivs('description');
-
- //and set up the buttons
- addClickListenerTranstions();
+ currentSubState = 'block1';
+ jqScreen.addClass(currentSubState);
},
'exit': function () {
- removeChangedClassesFromDivs();
- removeListenersFromDivs();
- removeClickListenerTransition();
+ jqScreen.removeClass(currentSubState);
+ currentSubState = null;
}
},
'code': {
'enter': function () {
- removeBlockClassesFromDivs();
- addClassesToDivs({
- 'description': 'block-less-width',
- 'code': 'block-focus',
- 'console': 'block-less-everything',
- 'info': 'block-less-height'
- });
- setTransitionsBetweenDivs('code');
-
- //and set up the buttons
- addClickListenerTranstions();
+ currentSubState = 'block2';
+ jqScreen.addClass(currentSubState);
},
'exit': function () {
- removeChangedClassesFromDivs();
- removeListenersFromDivs();
- removeClickListenerTransition();
+ jqScreen.removeClass(currentSubState);
+ currentSubState = null;
}
},
'info': {
'enter': function () {
- removeBlockClassesFromDivs();
- addClassesToDivs({
- 'description': 'block-less-everything',
- 'code': 'block-less-height',
- 'console': 'block-less-width',
- 'info': 'block-focus'
- });
- setTransitionsBetweenDivs('info');
-
- //and set up the buttons
- addClickListenerTranstions();
+ currentSubState = 'block4';
+ jqScreen.addClass(currentSubState);
},
'exit': function () {
- removeChangedClassesFromDivs();
- removeListenersFromDivs();
- removeClickListenerTransition();
+ jqScreen.removeClass(currentSubState);
+ currentSubState = null;
}
},
'console': {
'enter': function () {
- removeBlockClassesFromDivs();
- addClassesToDivs({
- 'description': 'block-less-height',
- 'code': 'block-less-everything',
- 'console': 'block-focus',
- 'info': 'block-less-width'
- });
- setTransitionsBetweenDivs('console');
-
- //and set up the buttons
- addClickListenerTranstions();
+ currentSubState = 'block3';
+ jqScreen.addClass(currentSubState);
},
'exit': function () {
- removeChangedClassesFromDivs();
- removeListenersFromDivs();
- removeClickListenerTransition();
+ jqScreen.removeClass(currentSubState);
+ currentSubState = null;
}
}
};
- var prologHandler;//created when we enter the prolog state and destroyed once we leave it
+ var prologHandler; //created when we enter the prolog state and destroyed once we leave it
codeq.globalStateMachine.register('prolog', {
'enter': function (data) {
- $('#disabled').css('cursor', 'wait');
- $('#disabled').css('display', '');
- $('#screen_prolog').css('display', '');//we have to show the screen now so the code editor shopws its initial values correctly
- prologHandler = createPrologHandler(data.data)//codeq.createProgrammingLanguageHandler('prolog',data.data,codeq.makePrologTerminalHandler);
+ 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(divs['description'].data(stateNameTag));
- Q.delay(100).then(function(){
- $('div.col-lg-3.col-md-6.col-sm-12').addClass('transition');//for smooth animations - need to be delayed, because otherwise we get some weird "animations" while the page is loading
- }).done();
-
- $('#disabled').css('display', 'none');
+ 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 () {
- $('#screen_prolog').css('display', 'none');
- $('div.col-lg-3.col-md-6.col-sm-12').removeClass('transition');
+ 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');
}
});
+ jqDescription.data(stateNameTag, 'description');
+ jqCode.data(stateNameTag, 'code');
+ jqConsole.data(stateNameTag, 'console');
+ jqInfo.data(stateNameTag, 'info');
+
// a constant
var firstCharacterPos = {'line': 0, 'ch': 0};
@@ -360,19 +240,19 @@
*/
createPrologHandler = function (info) {
var problem = info.problem,
- jqDescription = $('#description'),
- jqEditor = $('#code_editor'),
- jqConsole = $('#console'),
- jqHints = $('#info'),
+ 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(jqConsole, editor, problem.id, activityHandler),
+ terminal = makePrologTerminalHandler(jqTerminal, editor, problem.id, activityHandler),
hinter = codeq.makeHinter(jqHints, jqEditor, editor, problem.hint, problem.plan);
editor.setValue(info.solution);
$('#title').text(problem.slug);
- jqDescription.html(problem.description);
- $('#btn_code_plan').prop('disabled', (problem.plan || '').length == 0);
+ jqDescriptionContent.html(problem.description);
+ jqBtnPlan.prop('disabled', (problem.plan || '').length == 0);
editor.on('change', function (instance, changeObj) {
var doc = editor.getDoc(),
@@ -387,58 +267,57 @@
}
});
- $('#btn_code_plan').on('click', function () {
+ jqBtnPlan.on('click', function () {
if (!hinter.planNext()) {
- $('#btn_code_plan').prop('disabled', true);
- $('#btn_code_plan').blur();
+ jqBtnPlan.prop('disabled', true).blur();
}
});
- $('#btn_code_hint').on('click', function () {
+ 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
- })
+ 'language': 'prolog',
+ 'program': editor.getDoc().getValue(),
+ 'problem_id': problem.id
+ })
.then(
- function hintSuccess(data) {
- if (data.code === 0)
- hinter.handle(data.hints);
- else
- terminal.append(data.message + '\n', 'error');
- },
- function hintFailed (error) {
- terminal.append(error + '\n', 'error');
- }
- )
+ function hintSuccess(data) {
+ if (data.code === 0)
+ hinter.handle(data.hints);
+ else
+ terminal.append(data.message + '\n', 'error');
+ },
+ function hintFailed (error) {
+ terminal.append(error + '\n', 'error');
+ }
+ )
.fin(function () {
terminal.inputEnable();
terminal.append('?- ', 'output');
})
.done();
});
- $('#btn_code_test').on('click', function () {
+ 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
- })
+ 'language': 'prolog',
+ 'program': editor.getDoc().getValue(),
+ 'problem_id': problem.id
+ })
.then(
- function testSuccess(data) {
- if (data.code === 0)
- hinter.handle(data.hints);
- else
- terminal.append(data.message + '\n', 'error');
- },
- function testFailed (error) {
- terminal.append(error + '\n', 'error');
- }
- )
+ function testSuccess(data) {
+ if (data.code === 0)
+ hinter.handle(data.hints);
+ else
+ terminal.append(data.message + '\n', 'error');
+ },
+ function testFailed (error) {
+ terminal.append(error + '\n', 'error');
+ }
+ )
.fin(function () {
terminal.inputEnable();
terminal.append('?- ', 'output');
@@ -448,17 +327,16 @@
return {
destroy: function () {
- $('#btn_code_hint').off('click');
- $('#btn_code_test').off('click');
+ jqAllButtons.off();
editor.off('change');
hinter.destroy();
terminal.destroy();
- jqDescription.empty();
+ jqDescriptionContent.empty();
jqEditor.empty(); // TODO: perhaps you do not want to "free" the editor, just empty it
- jqConsole.empty(); // TODO: the same with the console
- jqDescription = null;
+ jqTerminal.empty(); // TODO: the same with the console
+ jqDescriptionContent = null;
jqEditor = null;
- jqConsole = null;
+ jqTerminal = null;
jqHints = null;
}
};
diff --git a/js/codeq/python.js b/js/codeq/python.js
index c5f7df6..39077d8 100644
--- a/js/codeq/python.js
+++ b/js/codeq/python.js
@@ -7,219 +7,101 @@
*/
(function() {
- var subScreens,//this will the actual (sub)state machine
- stateNameTag = 'stateName';//a tag for data which is added to some html elements
-
- //get the divs which are the main elements being change on transitions between states in the sub-state machine
- var divs = {};
- divs['description'] = $('#description_outer_div');
- divs['code'] = $('#code_editor_outer_div');
- divs['console'] = $('#console_outer_div');
- divs['info'] = $('#info_outer_div');
-
- //these tags connect the div to their respective state in the sub-state machine
- divs['description'].data(stateNameTag, 'description');
- divs['code'].data(stateNameTag, 'code');
- divs['console'].data(stateNameTag, 'console');
- divs['info'].data(stateNameTag, 'info');
-
- var 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)
- /**
- * the general function which should be called on the mousedown event to trigger the transition between states
- */
- mouseDownEventFunction = function () {
- subScreens.transition($(this).data(stateNameTag));
- },
- /**
- * removes the above function from the divs
- */
- removeListenersFromDivs = function () {
- $.each(divs, function (i, value) {
- value.off(transitionEventName, mouseDownEventFunction);
- });
- },
- /**
- * removes the 'block' class from all divs we need to change when we change the current state
- */
- removeBlockClassesFromDivs = function () {
- $.each(divs, function (i, value) {
- value.removeClass('block');
- });
- },
- /**
- * removes all those special classes from the divs, which are set when a new state is entered and it also adds the 'block' class back
- */
- removeChangedClassesFromDivs = function () {
- $.each(divs, function (i, value) {
- value.removeClass('block-focus block-less-width block-less-height block-less-everything').addClass('block');//these class names were chosen for the view where the screen is partitioned in 4 quarters (2 by 2)
- });
- },
- /**
- *
- * @param current the key of the state ('description','code','hint','console'), which is currently active, because it must not have a transition set
- */
- setTransitionsBetweenDivs = function (current) {
- $.each(divs, function (key, value) {
- if (current !== key) value.on(transitionEventName, mouseDownEventFunction);
- });
- },
- /**
- *
- * @param divsWithClasses a object where we have the keys of the divs object paired with the class name we want to assign to them e.g. :
- * {
- 'description': 'block-focus',
- 'code': 'block-less-width',
- 'console': 'block-less-height',
- 'info': 'block-less-everything'
- }
- */
- addClassesToDivs = function (divsWithClasses) {
- $.each(divsWithClasses, function (divName, className) {
- divs[divName].addClass(className);
- });
- },
- /**
- * the buttons (hint and test) will have to 'eat' the mousedown event to prevent some weird transitions.
- * Because a click on them won't trigger the transition to the code part, but will transition to the hints part.
- *
- * @param event
- */
- mouseDownEventIgnoreFun = function(event){
- event.stopPropagation();
- },
- /**
- * The transition from the buttons to the hints screen will be triggered with this function
- */
- clickListenerTransitionFun = function(){
- subScreens.transition(divs['info'].data(stateNameTag));
- },
- /**
- * add the above function to the buttons
- */
- addClickListenerTranstions = function(){
- $('#btn_code_plan').on('click',clickListenerTransitionFun);
- $('#btn_code_hint').on('click',clickListenerTransitionFun);
- $('#btn_code_test').on('click',clickListenerTransitionFun);
-
- $('#btn_code_plan').on(transitionEventName,mouseDownEventIgnoreFun);
- $('#btn_code_hint').on(transitionEventName,mouseDownEventIgnoreFun);
- $('#btn_code_test').on(transitionEventName,mouseDownEventIgnoreFun);
- },
- /**
- * and a function to remove it
- */
- removeClickListenerTransition = function(){
- $('#btn_code_plan').off('click',clickListenerTransitionFun);
- $('#btn_code_hint').off('click',clickListenerTransitionFun);
- $('#btn_code_test').off('click',clickListenerTransitionFun);
-
- $('#btn_code_plan').off(transitionEventName,mouseDownEventIgnoreFun);
- $('#btn_code_hint').off(transitionEventName,mouseDownEventIgnoreFun);
- $('#btn_code_test').off(transitionEventName,mouseDownEventIgnoreFun);
- },
+ 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_python'), // 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 () {
- removeBlockClassesFromDivs();
- addClassesToDivs({
- 'description': 'block-focus',
- 'code': 'block-less-width',
- 'console': 'block-less-height',
- 'info': 'block-less-everything'
- });
- setTransitionsBetweenDivs('description');
-
- //and set up the buttons
- addClickListenerTranstions();
+ currentSubState = 'block1';
+ jqScreen.addClass(currentSubState);
},
'exit': function () {
- removeChangedClassesFromDivs();
- removeListenersFromDivs();
- removeClickListenerTransition();
+ jqScreen.removeClass(currentSubState);
+ currentSubState = null;
}
},
'code': {
'enter': function () {
- removeBlockClassesFromDivs();
- addClassesToDivs({
- 'description': 'block-less-width',
- 'code': 'block-focus',
- 'console': 'block-less-everything',
- 'info': 'block-less-height'
- });
- setTransitionsBetweenDivs('code');
-
- //and set up the buttons
- addClickListenerTranstions();
+ currentSubState = 'block2';
+ jqScreen.addClass(currentSubState);
},
'exit': function () {
- removeChangedClassesFromDivs();
- removeListenersFromDivs();
- removeClickListenerTransition();
+ jqScreen.removeClass(currentSubState);
+ currentSubState = null;
}
},
'info': {
'enter': function () {
- removeBlockClassesFromDivs();
- addClassesToDivs({
- 'description': 'block-less-everything',
- 'code': 'block-less-height',
- 'console': 'block-less-width',
- 'info': 'block-focus'
- });
- setTransitionsBetweenDivs('info');
-
- //and set up the buttons
- addClickListenerTranstions();
+ currentSubState = 'block4';
+ jqScreen.addClass(currentSubState);
},
'exit': function () {
- removeChangedClassesFromDivs();
- removeListenersFromDivs();
- removeClickListenerTransition();
+ jqScreen.removeClass(currentSubState);
+ currentSubState = null;
}
},
'console': {
'enter': function () {
- removeBlockClassesFromDivs();
- addClassesToDivs({
- 'description': 'block-less-height',
- 'code': 'block-less-everything',
- 'console': 'block-focus',
- 'info': 'block-less-width'
- });
- setTransitionsBetweenDivs('console');
-
- //and set up the buttons
- addClickListenerTranstions();
+ currentSubState = 'block3';
+ jqScreen.addClass(currentSubState);
},
'exit': function () {
- removeChangedClassesFromDivs();
- removeListenersFromDivs();
- removeClickListenerTransition();
+ jqScreen.removeClass(currentSubState);
+ currentSubState = null;
}
}
};
- var pythonHandler;
+ var pythonHandler; //created when we enter the python state and destroyed once we leave it
codeq.globalStateMachine.register('python', {
'enter': function (data) {
- $('#disabled').css('display', '');
- $('#screen_prolog').css('display', '');//we have to show the screen now so the code editor shopws its initial values correctly
- pythonHandler = createPythonHandler(data.data);//codeq.createProgrammingLanguageHandler('prolog',data.data,codeq.makePythonTerminalHandler);
+ jqScreen.css('display', '');//we have to show the screen now so the code editor shows its initial values correctly
+ pythonHandler = createPythonHandler(data.data);
subScreens = codeq.makeStateMachine(substates);
- subScreens.transition(divs['description'].data(stateNameTag));
- Q.delay(100).then(function(){
- $('div.col-lg-3.col-md-6.col-sm-12').addClass('transition');
- }).done();
- $('#disabled').css('display', 'none');
+ 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 () {
- $('#screen_prolog').css('display', 'none');
- $('div.col-lg-3.col-md-6.col-sm-12').removeClass('transition');
+ jqAllButtons.off(); // unregister all event handlers
+ jqAllQuadrants.off();
+ jqScreen.css('display', 'none');
+// jqAllQuadrants.removeClass('transition');
pythonHandler.destroy();
+ pythonHandler = null;
subScreens.destroy();
+ subScreens = null;
+ jqScreen.addClass('.block1');
}
});
+ jqDescription.data(stateNameTag, 'description');
+ jqCode.data(stateNameTag, 'code');
+ jqConsole.data(stateNameTag, 'console');
+ jqInfo.data(stateNameTag, 'info');
+
// a constant
var firstCharacterPos = {'line': 0, 'ch': 0};
@@ -310,19 +192,19 @@
*/
var createPythonHandler = function (info) {
var problem = info.problem,
- jqDescription = $('#description'),
- jqEditor = $('#code_editor'),
- jqConsole = $('#console'),
- jqHints = $('#info'),
+ 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, mode: 'python' }),
activityHandler = makeActivityHandler(editor, problem.id),
- terminal = makePythonTerminalHandler(jqConsole, editor, problem.id, activityHandler),
+ terminal = makePythonTerminalHandler(jqTerminal, editor, problem.id, activityHandler),
hinter = codeq.makeHinter(jqHints, jqEditor, editor, problem.hint, problem.plan);
editor.setValue(info.solution);
$('#title').text(problem.slug);
- jqDescription.html(problem.description);
- $('#btn_code_plan').prop('disabled', (problem.plan || '').length == 0);
+ jqDescriptionContent.html(problem.description);
+ jqBtnPlan.prop('disabled', (problem.plan || '').length == 0);
editor.on('change', function (instance, changeObj) {
var doc = editor.getDoc(),
@@ -337,13 +219,12 @@
}
});
- $('#btn_code_plan').on('click', function () {
+ jqBtnPlan.on('click', function () {
if (!hinter.planNext()) {
- $('#btn_code_plan').prop('disabled', true);
- $('#btn_code_plan').blur();
+ jqBtnPlan.prop('disabled', true).blur();
}
});
- $('#btn_code_hint').on('click', function () {
+ jqBtnHint.on('click', function () {
var doc = editor.getDoc();
codeq.comms.sendHint({
'language': 'python',
@@ -361,7 +242,7 @@
}
).done();
});
- $('#btn_code_test').on('click', function () {
+ jqBtnTest.on('click', function () {
var doc = editor.getDoc();
codeq.comms.sendTest({
'language': 'python',
@@ -387,17 +268,16 @@
return {
destroy: function () {
- $('#btn_code_hint').off('click');
- $('#btn_code_test').off('click');
+ jqAllButtons.off();
editor.off('change');
hinter.destroy();
terminal.destroy();
- jqDescription.empty();
+ jqDescriptionContent.empty();
jqEditor.empty(); // TODO: perhaps you do not want to "free" the editor, just empty it
- jqConsole.empty(); // TODO: the same with the console
- jqDescription = null;
+ jqTerminal.empty(); // TODO: the same with the console
+ jqDescriptionContent = null;
jqEditor = null;
- jqConsole = null;
+ jqTerminal = null;
jqHints = null;
}
};
diff --git a/js/codeq/stateMachine.js b/js/codeq/stateMachine.js
index cfb27e7..dff89d5 100644
--- a/js/codeq/stateMachine.js
+++ b/js/codeq/stateMachine.js
@@ -6,8 +6,17 @@ codeq.makeStateMachine = function(def){
var currState = null;
return {
'transition': function(name){
+ var newState = def[name];
+ if (!newState) {
+ codeq.log.error('Cannot transition to state ' + name + ': it is not defined');
+ return;
+ }
+ if (newState === currState) {
+ codeq.log.info('Will not transition between identical states: ' + name);
+ return;
+ }
if(currState !== null) currState.exit();
- currState = def[name];
+ currState = newState;
currState.enter.apply(currState,Array.prototype.slice.apply(arguments,[1]));
},
'destroy': function(){
@@ -15,6 +24,7 @@ codeq.makeStateMachine = function(def){
currState = null;
},
'register': function(name,state){
+ if (name in def) codeq.log.error('The state ' + name + ' is already registered, overriding');
def[name] = state;
}
}