From cee672f22d516ecc73f84a3dbe01328883a2a47d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ale=C5=A1=20Smodi=C5=A1?= Date: Mon, 21 Sep 2015 17:45:31 +0200 Subject: 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. --- js/codeq/python.js | 270 +++++++++++++++-------------------------------------- 1 file changed, 75 insertions(+), 195 deletions(-) (limited to 'js/codeq/python.js') 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; } }; -- cgit v1.2.1