From 7dab4d3640b7b37c407eea111eda1fc0b71adbda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ale=C5=A1=20Smodi=C5=A1?= Date: Mon, 28 Sep 2015 18:44:48 +0200 Subject: Implement in-structure GUI translation for python and problem editing screens. Hints are not yet covered. --- js/codeq/comms.js | 8 ++- js/codeq/hint.js | 23 ++++++- js/codeq/navigation.js | 2 +- js/codeq/problem.js | 173 ++++++++++++++++++++++++++++++++++++++++++++---- js/codeq/prolog.js | 33 +++++---- js/codeq/python.js | 33 +++++---- js/codeq/translation.js | 7 ++ 7 files changed, 236 insertions(+), 43 deletions(-) (limited to 'js/codeq') diff --git a/js/codeq/comms.js b/js/codeq/comms.js index 2d934bd..5ac3d66 100644 --- a/js/codeq/comms.js +++ b/js/codeq/comms.js @@ -164,8 +164,8 @@ // AJAX communication support functions (loading of static web resources) // ================================================================================ - var languageCache = {},// language defs, keyed by language identifier - problemCache = {},// problem cache, 3-level, keyed by: language, problem group, and problem identifier + var languageCache = {}, // language defs, keyed by language identifier + problemCache = {}, // problem cache, 3-level, keyed by: language, problem group, and problem identifier ajaxGet = function (url) { return Q.Promise(function (resolve, reject, notify) { $.ajax({ @@ -407,6 +407,10 @@ ); languageCache[identifier] = x; return x; + }, + + 'getProblemDef': function (language, group, problem) { + return ajaxGet(ajaxPrefix + language + '/' + group + '/' + problem + '/problem.json'); } }; })(); diff --git a/js/codeq/hint.js b/js/codeq/hint.js index e1c7a6b..1b97afc 100644 --- a/js/codeq/hint.js +++ b/js/codeq/hint.js @@ -7,10 +7,11 @@ var firstCharacterPos = {'line': 0, 'ch': 0}, sel_no_scroll = {'scroll': false}; - codeq.makeHinter = function (jqHints, jqEditor, editor, hintDefs, planDef) { + codeq.makeHinter = function (jqHints, jqEditor, editor, trNamespace, hintDefsA, commonHintDefsA, planDef) { var hintCounter = 0, // for generating unique class-names hintCleaners = [], planIdx = 0, + dictionary = [], clearHints = function () { var i; @@ -130,6 +131,25 @@ } }; + codeq.tr.registerDictionary(trNamespace, dictionary); + + // TODO: below is a temporary code to bridge the old implementation with the new data format + if (planDef.sl) planDef = planDef.sl; + else planDef = planDef.en || []; + var hintDefs = {}, t1, t2, k; + if (hintDefsA.sl) t1 = hintDefsA.sl; + else t1 = hintDefsA.en || {}; + if (commonHintDefsA.sl) t2 = commonHintDefsA.sl; + else t2 = commonHintDefsA.en || {}; + for (k in t2) { + if (!t2.hasOwnProperty(k)) continue; + hintDefs[k] = t2[k]; + } + for (k in t1) { + if (!t1.hasOwnProperty(k)) continue; + hintDefs[k] = t1[k]; + } + return { /** Display the next "planning" hint and return whether there are * any more available. @@ -195,6 +215,7 @@ 'destroy': function () { clearHints(); + codeq.tr.unregisterDictionary(trNamespace); jqHints.empty(); jqHints = null; jqEditor = null; diff --git a/js/codeq/navigation.js b/js/codeq/navigation.js index 4445a3d..30503e0 100644 --- a/js/codeq/navigation.js +++ b/js/codeq/navigation.js @@ -57,7 +57,7 @@ History.pushState({'state': name, 'params': Array.prototype.slice.apply(arguments, [1])}, null, '?s=' + name); } catch (e) { - codeq.log.error('init: History.pushState() failed for new state ' + name+'. Error:'+e); + codeq.log.error('init: History.pushState() failed for new state ' + name+'. Error:'+e, e); } }, 'destroy': function () { diff --git a/js/codeq/problem.js b/js/codeq/problem.js index 3e218d8..35b45af 100644 --- a/js/codeq/problem.js +++ b/js/codeq/problem.js @@ -2,8 +2,93 @@ var jqScreen = $('#screen_problem'), languageCache = {}, // keyed by language identifier: processed data about languages translationCache = [], // keys are autogenerated in ta(), a value is a dictionary of translations of a translation key for every language + problemCache = {}, // problem data cache, 3-level, keyed by: language, problem group, and problem identifier langs, Nlangs, // constants, set on init + // ================================================================================ + // Hint processing: extract hints from the translations and return them in the + // processed form, hint key -> translation language -> value + // ================================================================================ + + processHints = function (rawTranslations) { + var defaultHint = {}, // here we put all the hints with their default translations + allHints = {}, // the result + allHintKeys = [], + tr, key, i, lang, hint, h, j; + // find the default hint translations, they will form the basis of default hints + tr = chooseDefaultTranslation(rawTranslations, 'hint') || {}; + for (key in tr) { // copy the hints + if (!tr.hasOwnProperty(key)) continue; + defaultHint[key] = tr[key]; + allHintKeys.push(key); + } + // copy any hints not in the default hints to the default hints + for (i = langs.length - 1; i >= 0; i--) { + lang = langs[i]; + tr = rawTranslations[lang]; + if (!tr || !tr.hint) continue; // skip unavailable translations or translations with no hints + hint = tr.hint; + for (key in hint) { + if (!hint.hasOwnProperty(key) || !hint[key]) continue; + if (!key in defaultHint) { + defaultHint[key] = hint[key]; + allHintKeys.push(key); + } + } + } + // create all translations for hints + for (i = langs.length - 1; i >= 0; i--) { + lang = langs[i]; + tr = rawTranslations[lang]; + // set up hints + if (!tr || !tr.hint) { + // there's no hint in the current language, copy the default in its entirety + allHints[lang] = defaultHint; + } + else { + // make a copy of all hints, using the default hint value where a hint value is missing + hint = {}; + allHints[lang] = hint; + h = tr.hint; + for (j = allHintKeys.length; j >= 0; j--) { + key = allHintKeys[j]; + hint[key] = h[key] || defaultHint[key]; + } + } + } + return allHints; + }, + + // ================================================================================ + // Plan processing: extract plans from the translations and return them in the + // processed form, hint key -> translation language -> value + // ================================================================================ + + processPlans = function (rawTranslations) { + // find the default plan translation + var defaultPlan = chooseDefaultTranslation(rawTranslations, 'plan') || [], + allPlans = {}, // the result + i, lang, tr; + // create all translations for plan + for (i = langs.length - 1; i >= 0; i--) { + lang = langs[i]; + tr = rawTranslations[lang]; + // set up plan + if (!tr || !tr.plan) { + // there's no plan in the current language, copy the default plan + allPlans[lang] = defaultPlan; + } + else { + allPlans[lang] = tr.plan; + } + } + return allPlans; + }, + + // ================================================================================ + // Group + problems directory processing + // ================================================================================ + chooseTranslation = function (keyword, lang, currentDict, enDict, translations) { var tr = currentDict[keyword], otherLang; @@ -65,11 +150,12 @@ */ createLanguageData = function (data, languageIdentifier) { // data is the content of language.json var li = languageIdentifier, // a shorthand + rawTranslations = data.translations || {}, groups = data.groups || {}, html = [], problemReferences = [], groupIdentifier, group, problems, problemIdentifier, problem; - var langDict = convertTranslations(data.translations, 'name', 'description'), // this will be the resulting dictionary: multi-level keys that lead up to the lang-dict + var langDict = convertTranslations(rawTranslations, 'name', 'description'), // this will be the resulting dictionary: multi-level keys that lead up to the lang-dict groupDict, problemDict; // title: HTML structure for "name" and "desc" html.push('


'); @@ -91,24 +177,29 @@ problem = problems[problemIdentifier] || {}; problemDict = convertTranslations(problem.translations, 'name'); html.push('
  • '); - problemReferences.push({'g': groupIdentifier, 'p': problemIdentifier}); + problemReferences.push({'g': groupIdentifier, 'p': problemIdentifier, 'id': problem.id}); } html.push(''); } html.push(''); return { - 'language': languageIdentifier, - 'html': html.join(''), - 'refs': problemReferences, - 'hints': {} // TODO: prepare common hints for the language + 'language': languageIdentifier, // 'prolog', 'python', ... + 'html': html.join(''), // the DOM structure (without textual content), as HTML text + 'refs': problemReferences, // array of problem info {g: group, p: problem, id: problem_id}, referenced from DOM elements + 'hints': processHints(rawTranslations) // hint translations: keyword -> lang -> value }; }, + // ================================================================================ + // DOM instantiation. + // The transition to problem solving takes place here, after the user clicks on a + // problem and all the required data is loaded. + // ================================================================================ /** * Instantiates the screen from the given processed data. */ - createDom = function (data) { + createDom = function (data) { // data is the (cached) result of createLanguageData() var language = data.language; jqScreen.html(data.html); codeq.tr.translateDom(jqScreen); @@ -119,12 +210,15 @@ codeq.log.error('Clicked on a problem link having erroneous index: ' + index); return; } - // transition codeq.wait( - codeq.comms.getProblem(language, ref.g, ref.p) - .then(function (data) { - if (data.code !== 0) throw new Error('Failed to obtain problem data, code: ' + data.code + ', message: ' + data.message); - codeq.globalStateMachine.transition(language, data); + Q.all([ + codeq.comms.getProblem(language, ref.g, ref.p), // TODO: use ref.id instead // the current solution + getProblemData(language, ref.g, ref.p) // the (cached) result of processProblemData() + ]) + .spread(function (userProblemData, generalProblemData) { + if (userProblemData.code !== 0) throw new Error('Failed to obtain user problem data, code: ' + userProblemData.code + ', message: ' + userProblemData.message); + if (!generalProblemData) throw new Error('General problem data is not defined'); + codeq.globalStateMachine.transition(language, generalProblemData, data.hints, userProblemData.solution); }) ) .fail(function (reason) { @@ -134,6 +228,61 @@ .done(); }); }, + + // ================================================================================ + // Problem definition processing + // ================================================================================ + + chooseDefaultTranslation = function (rawTranslations, translationKey) { + var tr = rawTranslations.en, // try English as the default + lang; + if (tr && tr[translationKey]) return tr[translationKey]; + for (lang in rawTranslations) { // find a translation with hints + if (!rawTranslations.hasOwnProperty(lang) || rawTranslations[lang]) continue; + tr = rawTranslations[lang]; + if (tr[translationKey]) return tr[translationKey]; + } + return null; // default must be chosen by the caller + }, + + processProblemData = function (rawData, language, group, problem) { + var rawTranslations = rawData.translations || {}; + return { + 'language': language, + 'group': group, + 'problem': problem, + 'id': rawData.id, + 'translations': convertTranslations(rawTranslations, 'title', 'name', 'slug', 'description'), // GUI translations: keyword -> lang -> value + 'hint': processHints(rawTranslations), // hint translations: keyword -> lang -> value + 'plan': processPlans(rawTranslations) // plan translations: keyword -> lang -> value + }; + }, + + getProblemData = function (language, group, problem) { + var langCache = problemCache[language], + groupCache, cachedProblem, promise; + if (langCache) { + groupCache = langCache[group]; + if (!groupCache) { + groupCache = {}; + langCache[group] = groupCache; + } + } + else { + langCache = {}; + problemCache[language] = langCache; + groupCache = {}; + langCache[group] = groupCache; + } + cachedProblem = groupCache[problem]; + if (cachedProblem) return Q(cachedProblem); + return codeq.comms.getProblemDef(language, group, problem).then(function (rawData) { + var data = processProblemData(rawData); + groupCache[problem] = data; + return data; + }); + }, + currentLanguage; // the currently active language // ================================================================================ diff --git a/js/codeq/prolog.js b/js/codeq/prolog.js index be6b0c8..cd3fcb4 100644 --- a/js/codeq/prolog.js +++ b/js/codeq/prolog.js @@ -66,7 +66,7 @@ }; var prologHandler; //created when we enter the prolog state and destroyed once we leave it codeq.globalStateMachine.register('prolog', { - 'enter': function (data) { + 'enter': function (problemDef, commonHints, currentSolution) { $('#navigation-login').css('display', ''); $('#navigation-language').css('display', ''); $('#navigation-problem').css('display', ''); @@ -74,7 +74,7 @@ $('#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); + prologHandler = createPrologHandler(problemDef, commonHints, currentSolution); subScreens = codeq.makeStateMachine(substates); subScreens.transition(jqDescription.data(stateNameTag)); /* Q.delay(100).then(function(){ @@ -245,30 +245,36 @@ }; }; + codeq.on('init', function (args) { + codeq.tr.registerDictionary('prolog', codeq.tr.emptyDictionary); // to make the translator happy, when this screen is not active + }); + /** * 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, + createPrologHandler = function (problemDef, commonHints, currentSolution) { + 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), + activityHandler = makeActivityHandler(editor, problemDef.id), + terminal = makePrologTerminalHandler(jqTerminal, editor, problemDef.id, activityHandler), + hinter = codeq.makeHinter(jqHints, jqEditor, editor, 'prolog_hints', problemDef.hint, commonHints, problemDef.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); + codeq.tr.registerDictionary('prolog', problemDef.translations); + codeq.tr.translateDom(jqScreen); + if (currentSolution) editor.setValue(currentSolution); +// $('#screen_prolog .title').text(problem.slug); +// jqDescriptionContent.html(problem.description); + jqBtnPlan.prop('disabled', ((problemDef.plan && problemDef.plan.en) || []).length == 0); editor.on('change', function (instance, changeObj) { var doc = editor.getDoc(), @@ -295,7 +301,7 @@ codeq.comms.sendHint({ 'language': 'prolog', 'program': editor.getDoc().getValue(), - 'problem_id': problem.id + 'problem_id': problemDef.id }) .then(function (data) { if (data.code === 0) { @@ -319,7 +325,7 @@ codeq.comms.sendTest({ 'language': 'prolog', 'program': editor.getDoc().getValue(), - 'problem_id': problem.id + 'problem_id': problemDef.id }) .then(function (data) { if (data.code === 0) { @@ -351,6 +357,7 @@ jqEditor = null; jqTerminal = null; jqHints = null; + codeq.tr.registerDictionary('prolog', codeq.tr.emptyDictionary); } }; }; diff --git a/js/codeq/python.js b/js/codeq/python.js index e80bbb7..8b66881 100644 --- a/js/codeq/python.js +++ b/js/codeq/python.js @@ -71,7 +71,7 @@ }; var pythonHandler; //created when we enter the python state and destroyed once we leave it codeq.globalStateMachine.register('python', { - 'enter': function (data) { + 'enter': function (problemDef, commonHints, currentSolution) { $('#navigation-login').css('display', ''); $('#navigation-language').css('display', ''); $('#navigation-problem').css('display', ''); @@ -79,7 +79,7 @@ $('#navigation-python').css('display', ''); jqScreen.css('display', '');//we have to show the screen now so the code editor shows its initial values correctly - pythonHandler = createPythonHandler(data.data); + pythonHandler = createPythonHandler(problemDef, commonHints, currentSolution); subScreens = codeq.makeStateMachine(substates); subScreens.transition(jqDescription.data(stateNameTag)); /* Q.delay(100).then(function(){ @@ -203,7 +203,9 @@ }; }; - + codeq.on('init', function (args) { + codeq.tr.registerDictionary('python', codeq.tr.emptyDictionary); // to make the translator happy, when this screen is not active + }); /** * Creates a new handler for the given Prolog assignment definition. @@ -211,24 +213,26 @@ * @param {PrologTaskDef} info * @returns {{destroy: Function, processServerHints: Function}} */ - var createPythonHandler = function (info) { - var problem = info.problem, + var createPythonHandler = function (problemDef, commonHints, currentSolution) { + 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, mode: 'python' }), - activityHandler = makeActivityHandler(editor, problem.id), - terminal = makePythonTerminalHandler(jqTerminal, editor, problem.id, activityHandler), - hinter = codeq.makeHinter(jqHints, jqEditor, editor, problem.hint, problem.plan), + activityHandler = makeActivityHandler(editor, problemDef.id), + terminal = makePythonTerminalHandler(jqTerminal, editor, problemDef.id, activityHandler), + hinter = codeq.makeHinter(jqHints, jqEditor, editor, 'python_hints', problemDef.hint, commonHints, problemDef.plan), commError = function (error) { alert(error); }; - editor.setValue(info.solution); - $('#screen_python .title').text(problem.slug); - jqDescriptionContent.html(problem.description); - jqBtnPlan.prop('disabled', (problem.plan || '').length == 0); + codeq.tr.registerDictionary('python', problemDef.translations); + codeq.tr.translateDom(jqScreen); + if (currentSolution) editor.setValue(currentSolution); +// $('#screen_python .title').text(problem.slug); +// jqDescriptionContent.html(problem.description); + jqBtnPlan.prop('disabled', ((problemDef.plan && problemDef.plan.en) || []).length == 0); editor.on('change', function (instance, changeObj) { var doc = editor.getDoc(), @@ -253,7 +257,7 @@ codeq.comms.sendHint({ 'language': 'python', 'program': editor.getDoc().getValue(), - 'problem_id': problem.id + 'problem_id': problemDef.id }) .then(function (data) { if (data.code === 0) { @@ -271,7 +275,7 @@ codeq.comms.sendTest({ 'language': 'python', 'program': editor.getDoc().getValue(), - 'problem_id': problem.id + 'problem_id': problemDef.id }) .then(function (data) { if (data.code === 0) { @@ -323,6 +327,7 @@ jqEditor = null; jqTerminal = null; jqHints = null; + codeq.tr.registerDictionary('python', codeq.tr.emptyDictionary); } }; }; diff --git a/js/codeq/translation.js b/js/codeq/translation.js index af39cdc..d4278ac 100644 --- a/js/codeq/translation.js +++ b/js/codeq/translation.js @@ -6,6 +6,7 @@ translationKey = jqElt.data('tkey'), dict = dicts[dictionaryKey], translations, html, key; + if (dict === codeq.tr.emptyDictionary) return; // silent ignore if (!dict) { codeq.log.error('Cannot find translation dictionary ' + dictionaryKey); return; @@ -61,6 +62,12 @@ dicts[name] = dict; }, + 'unregisterDictionary': function (name) { + delete dicts[name]; + }, + + 'emptyDictionary': {}, // use this with registerDictionary when you don't want any translations + 'translateDom': function (jqTopElt) { var lang = codeq.getLang(); jqTopElt.find('.translatable').each(function () { -- cgit v1.2.1 From 116ee90e005a01dd7c9b08519ad658dcbdce8992 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ale=C5=A1=20Smodi=C5=A1?= Date: Mon, 28 Sep 2015 18:46:29 +0200 Subject: CRLF -> LF conversion for python.js and prolog.js. --- js/codeq/prolog.js | 728 ++++++++++++++++++++++++++--------------------------- js/codeq/python.js | 668 ++++++++++++++++++++++++------------------------ 2 files changed, 698 insertions(+), 698 deletions(-) (limited to 'js/codeq') diff --git a/js/codeq/prolog.js b/js/codeq/prolog.js index cd3fcb4..980a60c 100644 --- a/js/codeq/prolog.js +++ b/js/codeq/prolog.js @@ -1,364 +1,364 @@ -/** - * 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 (problemDef, commonHints, currentSolution) { - $('#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(problemDef, commonHints, currentSolution); - 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': - case 'r': - return ';'; // show next answer on space, semicolon, 'n' or 'r' - 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; - } - }; - }; - - codeq.on('init', function (args) { - codeq.tr.registerDictionary('prolog', codeq.tr.emptyDictionary); // to make the translator happy, when this screen is not active - }); - - /** - * Creates a new handler for the given Prolog assignment definition. - * - * @param {PrologTaskDef} info - * @returns {{destroy: Function, processServerHints: Function}} - */ - createPrologHandler = function (problemDef, commonHints, currentSolution) { - 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, problemDef.id), - terminal = makePrologTerminalHandler(jqTerminal, editor, problemDef.id, activityHandler), - hinter = codeq.makeHinter(jqHints, jqEditor, editor, 'prolog_hints', problemDef.hint, commonHints, problemDef.plan), - commError = function (error) { - alert(error); - }; - - codeq.tr.registerDictionary('prolog', problemDef.translations); - codeq.tr.translateDom(jqScreen); - if (currentSolution) editor.setValue(currentSolution); -// $('#screen_prolog .title').text(problem.slug); -// jqDescriptionContent.html(problem.description); - jqBtnPlan.prop('disabled', ((problemDef.plan && problemDef.plan.en) || []).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': problemDef.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': problemDef.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; - codeq.tr.registerDictionary('prolog', codeq.tr.emptyDictionary); - } - }; - }; -})(); +/** + * 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 (problemDef, commonHints, currentSolution) { + $('#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(problemDef, commonHints, currentSolution); + 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': + case 'r': + return ';'; // show next answer on space, semicolon, 'n' or 'r' + 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; + } + }; + }; + + codeq.on('init', function (args) { + codeq.tr.registerDictionary('prolog', codeq.tr.emptyDictionary); // to make the translator happy, when this screen is not active + }); + + /** + * Creates a new handler for the given Prolog assignment definition. + * + * @param {PrologTaskDef} info + * @returns {{destroy: Function, processServerHints: Function}} + */ + createPrologHandler = function (problemDef, commonHints, currentSolution) { + 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, problemDef.id), + terminal = makePrologTerminalHandler(jqTerminal, editor, problemDef.id, activityHandler), + hinter = codeq.makeHinter(jqHints, jqEditor, editor, 'prolog_hints', problemDef.hint, commonHints, problemDef.plan), + commError = function (error) { + alert(error); + }; + + codeq.tr.registerDictionary('prolog', problemDef.translations); + codeq.tr.translateDom(jqScreen); + if (currentSolution) editor.setValue(currentSolution); +// $('#screen_prolog .title').text(problem.slug); +// jqDescriptionContent.html(problem.description); + jqBtnPlan.prop('disabled', ((problemDef.plan && problemDef.plan.en) || []).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': problemDef.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': problemDef.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; + codeq.tr.registerDictionary('prolog', codeq.tr.emptyDictionary); + } + }; + }; +})(); diff --git a/js/codeq/python.js b/js/codeq/python.js index 8b66881..009c4a5 100644 --- a/js/codeq/python.js +++ b/js/codeq/python.js @@ -1,334 +1,334 @@ -/** - * Created by robert on 9/17/15. - * - * The python 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. - * - * Currentyl it is mostly a copy of the prolog state (the exception is of course the makePythonTerminalHandler instead of makePrologTerminalHandler) - */ - -(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_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'), - jqBtnRun = jqScreen.find('.btn-run'), - jqBtnStop = jqScreen.find('.btn-stop'), - jqInfoButtons = jqBtnPlan.add(jqBtnHint).add(jqBtnTest), // all info-focusing buttons - jqAllButtons = jqInfoButtons.add(jqBtnRun).add(jqBtnStop), // all 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 pythonHandler; //created when we enter the python state and destroyed once we leave it - codeq.globalStateMachine.register('python', { - 'enter': function (problemDef, commonHints, currentSolution) { - $('#navigation-login').css('display', ''); - $('#navigation-language').css('display', ''); - $('#navigation-problem').css('display', ''); - $("#navigation-python").addClass("active"); - $('#navigation-python').css('display', ''); - - jqScreen.css('display', '');//we have to show the screen now so the code editor shows its initial values correctly - pythonHandler = createPythonHandler(problemDef, commonHints, currentSolution); - 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();*/ - jqInfoButtons.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 - }); - jqBtnRun.on(transitionEventName, function (event) { - subScreens.transition('console'); // 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'); - pythonHandler.destroy(); - pythonHandler = null; - subScreens.destroy(); - subScreens = null; - jqScreen.addClass('block1'); - - $('#navigation-login').css('display', 'none'); - $('#navigation-language').css('display', 'none'); - $('#navigation-problem').css('display', 'none'); - $("#navigation-python").removeClass("active"); - $('#navigation-python').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 makePythonTerminalHandler = function (jqConsole, editor, problem_id, activityHandler) { - var terminal = codeq.makeConsole(jqConsole, { - 'greeting': 'CodeQ Python terminal proxy', - 'autoHistory': true - }), - tcs = function terminalCommandSuccess (data) { - if (data.code !== 0) { - terminal.append(data.message, 'error'); - } - }, - tcf = function terminalCommandFailed (error) { - terminal.append(error + '\n', 'error'); - }; - - terminal.onInput = function (text) { - terminal.leftmostCol = 0; - return codeq.comms.sendPythonPush({ - 'text': text + '\n' - }).then(tcs, tcf); - }; - - codeq.comms.on('terminal_output', function (data) { - var text = data.text, - lines = text.split('\n'); - terminal.append(text, 'output'); - terminal.leftmostCol = lines[lines.length-1].length; - }); - - terminal.leftmostCol = 1; - - 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; - } - }; - }; - - codeq.on('init', function (args) { - codeq.tr.registerDictionary('python', codeq.tr.emptyDictionary); // to make the translator happy, when this screen is not active - }); - - /** - * Creates a new handler for the given Prolog assignment definition. - * - * @param {PrologTaskDef} info - * @returns {{destroy: Function, processServerHints: Function}} - */ - var createPythonHandler = function (problemDef, commonHints, currentSolution) { - 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, mode: 'python' }), - activityHandler = makeActivityHandler(editor, problemDef.id), - terminal = makePythonTerminalHandler(jqTerminal, editor, problemDef.id, activityHandler), - hinter = codeq.makeHinter(jqHints, jqEditor, editor, 'python_hints', problemDef.hint, commonHints, problemDef.plan), - commError = function (error) { - alert(error); - }; - - codeq.tr.registerDictionary('python', problemDef.translations); - codeq.tr.translateDom(jqScreen); - if (currentSolution) editor.setValue(currentSolution); -// $('#screen_python .title').text(problem.slug); -// jqDescriptionContent.html(problem.description); - jqBtnPlan.prop('disabled', ((problemDef.plan && problemDef.plan.en) || []).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': 'rm', '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 () { - var doc = editor.getDoc(); - codeq.comms.sendHint({ - 'language': 'python', - 'program': editor.getDoc().getValue(), - 'problem_id': problemDef.id - }) - .then(function (data) { - if (data.code === 0) { - hinter.handle(data.hints); - } - else { - terminal.append('error: ' + data.message); - } - }) - .fail(commError) - .done(); - }); - jqBtnTest.on('click', function () { - var doc = editor.getDoc(); - codeq.comms.sendTest({ - 'language': 'python', - 'program': editor.getDoc().getValue(), - 'problem_id': problemDef.id - }) - .then(function (data) { - if (data.code === 0) { - hinter.handle(data.hints); - } - else { - terminal.append('error: ' + data.message); - } - }) - .fail(commError) - .done(); - }); - jqBtnRun.on('click', function () { - var program = editor.getDoc().getValue(); - codeq.comms.sendPythonStop({}) - .then(function () { - codeq.comms.sendPythonExec({ - 'program': program - }); - }) - .fail(commError) - .done(); - // focus the terminal - jqTerminal.click(); - }); - jqBtnStop.on('click', function () { - codeq.comms.sendPythonStop({}) - .fail(commError) - .done(); - }); - - // TODO first line of interpreter output is buffered without this, why? - codeq.comms.sendPythonPush({ - 'text': '' - }); - - return { - destroy: function () { - $('#screen_python .title').text('');//empty the title text - jqAllButtons.off(); - editor.off('change'); - codeq.comms.off('terminal_output'); // stop listening for the terminal events from server - 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; - codeq.tr.registerDictionary('python', codeq.tr.emptyDictionary); - } - }; - }; -})(); +/** + * Created by robert on 9/17/15. + * + * The python 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. + * + * Currentyl it is mostly a copy of the prolog state (the exception is of course the makePythonTerminalHandler instead of makePrologTerminalHandler) + */ + +(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_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'), + jqBtnRun = jqScreen.find('.btn-run'), + jqBtnStop = jqScreen.find('.btn-stop'), + jqInfoButtons = jqBtnPlan.add(jqBtnHint).add(jqBtnTest), // all info-focusing buttons + jqAllButtons = jqInfoButtons.add(jqBtnRun).add(jqBtnStop), // all 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 pythonHandler; //created when we enter the python state and destroyed once we leave it + codeq.globalStateMachine.register('python', { + 'enter': function (problemDef, commonHints, currentSolution) { + $('#navigation-login').css('display', ''); + $('#navigation-language').css('display', ''); + $('#navigation-problem').css('display', ''); + $("#navigation-python").addClass("active"); + $('#navigation-python').css('display', ''); + + jqScreen.css('display', '');//we have to show the screen now so the code editor shows its initial values correctly + pythonHandler = createPythonHandler(problemDef, commonHints, currentSolution); + 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();*/ + jqInfoButtons.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 + }); + jqBtnRun.on(transitionEventName, function (event) { + subScreens.transition('console'); // 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'); + pythonHandler.destroy(); + pythonHandler = null; + subScreens.destroy(); + subScreens = null; + jqScreen.addClass('block1'); + + $('#navigation-login').css('display', 'none'); + $('#navigation-language').css('display', 'none'); + $('#navigation-problem').css('display', 'none'); + $("#navigation-python").removeClass("active"); + $('#navigation-python').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 makePythonTerminalHandler = function (jqConsole, editor, problem_id, activityHandler) { + var terminal = codeq.makeConsole(jqConsole, { + 'greeting': 'CodeQ Python terminal proxy', + 'autoHistory': true + }), + tcs = function terminalCommandSuccess (data) { + if (data.code !== 0) { + terminal.append(data.message, 'error'); + } + }, + tcf = function terminalCommandFailed (error) { + terminal.append(error + '\n', 'error'); + }; + + terminal.onInput = function (text) { + terminal.leftmostCol = 0; + return codeq.comms.sendPythonPush({ + 'text': text + '\n' + }).then(tcs, tcf); + }; + + codeq.comms.on('terminal_output', function (data) { + var text = data.text, + lines = text.split('\n'); + terminal.append(text, 'output'); + terminal.leftmostCol = lines[lines.length-1].length; + }); + + terminal.leftmostCol = 1; + + 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; + } + }; + }; + + codeq.on('init', function (args) { + codeq.tr.registerDictionary('python', codeq.tr.emptyDictionary); // to make the translator happy, when this screen is not active + }); + + /** + * Creates a new handler for the given Prolog assignment definition. + * + * @param {PrologTaskDef} info + * @returns {{destroy: Function, processServerHints: Function}} + */ + var createPythonHandler = function (problemDef, commonHints, currentSolution) { + 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, mode: 'python' }), + activityHandler = makeActivityHandler(editor, problemDef.id), + terminal = makePythonTerminalHandler(jqTerminal, editor, problemDef.id, activityHandler), + hinter = codeq.makeHinter(jqHints, jqEditor, editor, 'python_hints', problemDef.hint, commonHints, problemDef.plan), + commError = function (error) { + alert(error); + }; + + codeq.tr.registerDictionary('python', problemDef.translations); + codeq.tr.translateDom(jqScreen); + if (currentSolution) editor.setValue(currentSolution); +// $('#screen_python .title').text(problem.slug); +// jqDescriptionContent.html(problem.description); + jqBtnPlan.prop('disabled', ((problemDef.plan && problemDef.plan.en) || []).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': 'rm', '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 () { + var doc = editor.getDoc(); + codeq.comms.sendHint({ + 'language': 'python', + 'program': editor.getDoc().getValue(), + 'problem_id': problemDef.id + }) + .then(function (data) { + if (data.code === 0) { + hinter.handle(data.hints); + } + else { + terminal.append('error: ' + data.message); + } + }) + .fail(commError) + .done(); + }); + jqBtnTest.on('click', function () { + var doc = editor.getDoc(); + codeq.comms.sendTest({ + 'language': 'python', + 'program': editor.getDoc().getValue(), + 'problem_id': problemDef.id + }) + .then(function (data) { + if (data.code === 0) { + hinter.handle(data.hints); + } + else { + terminal.append('error: ' + data.message); + } + }) + .fail(commError) + .done(); + }); + jqBtnRun.on('click', function () { + var program = editor.getDoc().getValue(); + codeq.comms.sendPythonStop({}) + .then(function () { + codeq.comms.sendPythonExec({ + 'program': program + }); + }) + .fail(commError) + .done(); + // focus the terminal + jqTerminal.click(); + }); + jqBtnStop.on('click', function () { + codeq.comms.sendPythonStop({}) + .fail(commError) + .done(); + }); + + // TODO first line of interpreter output is buffered without this, why? + codeq.comms.sendPythonPush({ + 'text': '' + }); + + return { + destroy: function () { + $('#screen_python .title').text('');//empty the title text + jqAllButtons.off(); + editor.off('change'); + codeq.comms.off('terminal_output'); // stop listening for the terminal events from server + 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; + codeq.tr.registerDictionary('python', codeq.tr.emptyDictionary); + } + }; + }; +})(); -- cgit v1.2.1 From 10de7241f22a10d65f53c891a8b07fe8650b4878 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20Pu=C5=A1nik?= Date: Tue, 29 Sep 2015 08:32:59 +0200 Subject: login removed from navbar --- js/codeq/language.js | 56 ++++++++++++++++---------------- js/codeq/login.js | 88 +++++++++++++++++++++++--------------------------- js/codeq/navigation.js | 4 --- js/codeq/problem.js | 2 -- js/codeq/prolog.js | 2 -- js/codeq/python.js | 2 -- 6 files changed, 68 insertions(+), 86 deletions(-) (limited to 'js/codeq') diff --git a/js/codeq/language.js b/js/codeq/language.js index be2a319..aac4e78 100644 --- a/js/codeq/language.js +++ b/js/codeq/language.js @@ -1,30 +1,28 @@ -/** - * Created by robert on 9/18/15. - */ - -(function(){ - var jqScreen = $('#screen_language'), - jqProlog = $('#choose-prolog'), - jqPython = $('#choose-python'), - chooseProlog = function () {codeq.globalStateMachine.transition('problem', 'prolog');}, - choosePython = function () {codeq.globalStateMachine.transition('problem', 'python');}; - - codeq.globalStateMachine.register('language',{ - 'enter': function(){ - $('#navigation-login').css('display', ''); - $("#navigation-language").addClass("active").css('display', ''); - - jqScreen.css('display', ''); - jqProlog.on('click', chooseProlog); - jqPython.on('click', choosePython); - }, - 'exit' : function(){ - jqProlog.off(); - jqPython.off(); - jqScreen.css('display', 'none'); - - $('#navigation-login').css('display', 'none'); - $('#navigation-language').css('display', 'none').removeClass("active"); - } - }); +/** + * Created by robert on 9/18/15. + */ + +(function(){ + var jqScreen = $('#screen_language'), + jqProlog = $('#choose-prolog'), + jqPython = $('#choose-python'), + chooseProlog = function () {codeq.globalStateMachine.transition('problem', 'prolog');}, + choosePython = function () {codeq.globalStateMachine.transition('problem', 'python');}; + + codeq.globalStateMachine.register('language',{ + 'enter': function(){ + $("#navigation-language").addClass("active").css('display', ''); + + jqScreen.css('display', ''); + jqProlog.on('click', chooseProlog); + jqPython.on('click', choosePython); + }, + 'exit' : function(){ + jqProlog.off(); + jqPython.off(); + jqScreen.css('display', 'none'); + + $('#navigation-language').css('display', 'none').removeClass("active"); + } + }); })(); \ No newline at end of file diff --git a/js/codeq/login.js b/js/codeq/login.js index bb92325..c400f06 100644 --- a/js/codeq/login.js +++ b/js/codeq/login.js @@ -1,48 +1,42 @@ -/** - * Created by robert on 9/17/15. - */ - -(function(){ - var loginFun = function(){ - $('#disabled').css('display', ''); - $('#disabled').css('cursor', 'wait'); - codeq.comms.connect() - .then(function () { - return codeq.comms.login($('#username').val(), $('#password').val()); - }) - .then(function (data) { - $('#disabled').css('display', 'none'); - $('#disabled').css('cursor', ''); - if (data.code !== 0) throw new Error('Login failed, code: ' + data.code + ', message: ' + data.message); - codeq.globalStateMachine.transition('language'); - //codeq.activateState('language'); - }) - .fail(function (reason) { - $('#disabled').css('display', 'none'); - $('#disabled').css('cursor', ''); - codeq.log.error('Login failed: ' + reason, reason); - alert('Login request failed: ' + reason); - $('#disabled').css('display', 'none'); - }) - .done(); - }; - codeq.globalStateMachine.register('login',{ - 'enter': function(){ - $("#submit").on('click', loginFun); - - $("#navigation-login").addClass("active"); - $('#navigation-login').css('display', ''); - - $("#screen_login").css('display', ''); - $('#disabled').css('display', 'none'); - }, - 'exit' : function(){ - $("#submit").off('click', loginFun); - $("#screen_login").css('display', 'none'); - $("#password").val(''); - - $('#navigation-login').css('display', 'none'); - $("#navigation-login").removeClass("active"); - } - }); +/** + * Created by robert on 9/17/15. + */ + +(function(){ + var loginFun = function(){ + $('#disabled').css('display', ''); + $('#disabled').css('cursor', 'wait'); + codeq.comms.connect() + .then(function () { + return codeq.comms.login($('#username').val(), $('#password').val()); + }) + .then(function (data) { + $('#disabled').css('display', 'none'); + $('#disabled').css('cursor', ''); + if (data.code !== 0) throw new Error('Login failed, code: ' + data.code + ', message: ' + data.message); + codeq.globalStateMachine.transition('language'); + //codeq.activateState('language'); + }) + .fail(function (reason) { + $('#disabled').css('display', 'none'); + $('#disabled').css('cursor', ''); + codeq.log.error('Login failed: ' + reason, reason); + alert('Login request failed: ' + reason); + $('#disabled').css('display', 'none'); + }) + .done(); + }; + codeq.globalStateMachine.register('login',{ + 'enter': function(){ + $("#submit").on('click', loginFun); + + $("#screen_login").css('display', ''); + $('#disabled').css('display', 'none'); + }, + 'exit' : function(){ + $("#submit").off('click', loginFun); + $("#screen_login").css('display', 'none'); + $("#password").val(''); + } + }); })(); \ No newline at end of file diff --git a/js/codeq/navigation.js b/js/codeq/navigation.js index 30503e0..1a7799f 100644 --- a/js/codeq/navigation.js +++ b/js/codeq/navigation.js @@ -81,10 +81,6 @@ //setup all the buttons in the banner - $('#navigation-login').on('click', function(e){ - codeq.globalStateMachine.transition('login'); - e.preventDefault();//prevent this since we'll trigger a page reload otherwise - }); $('#navigation-language').on('click', function(e){ codeq.globalStateMachine.transition('language'); e.preventDefault(); diff --git a/js/codeq/problem.js b/js/codeq/problem.js index 35b45af..464dc12 100644 --- a/js/codeq/problem.js +++ b/js/codeq/problem.js @@ -303,7 +303,6 @@ 'enter': function(language){ var data = null; // language data - $('#navigation-login').css('display', ''); $('#navigation-language').css('display', ''); $("#navigation-problem").addClass("active").css('display', ''); @@ -329,7 +328,6 @@ }, 'exit' : function(){ jqScreen.css('display', 'none'); - $('#navigation-login').css('display', 'none'); $('#navigation-language').css('display', 'none'); $('#navigation-problem').css('display', 'none').removeClass("active"); } diff --git a/js/codeq/prolog.js b/js/codeq/prolog.js index 980a60c..d827139 100644 --- a/js/codeq/prolog.js +++ b/js/codeq/prolog.js @@ -67,7 +67,6 @@ var prologHandler; //created when we enter the prolog state and destroyed once we leave it codeq.globalStateMachine.register('prolog', { 'enter': function (problemDef, commonHints, currentSolution) { - $('#navigation-login').css('display', ''); $('#navigation-language').css('display', ''); $('#navigation-problem').css('display', ''); $("#navigation-prolog").addClass("active"); @@ -99,7 +98,6 @@ subScreens = null; jqScreen.addClass('block1'); - $('#navigation-login').css('display', 'none'); $('#navigation-language').css('display', 'none'); $('#navigation-problem').css('display', 'none'); $("#navigation-prolog").removeClass("active"); diff --git a/js/codeq/python.js b/js/codeq/python.js index 009c4a5..cf2199a 100644 --- a/js/codeq/python.js +++ b/js/codeq/python.js @@ -72,7 +72,6 @@ var pythonHandler; //created when we enter the python state and destroyed once we leave it codeq.globalStateMachine.register('python', { 'enter': function (problemDef, commonHints, currentSolution) { - $('#navigation-login').css('display', ''); $('#navigation-language').css('display', ''); $('#navigation-problem').css('display', ''); $("#navigation-python").addClass("active"); @@ -109,7 +108,6 @@ subScreens = null; jqScreen.addClass('block1'); - $('#navigation-login').css('display', 'none'); $('#navigation-language').css('display', 'none'); $('#navigation-problem').css('display', 'none'); $("#navigation-python").removeClass("active"); -- cgit v1.2.1 From 268f24905e4cc488c80f1d057451b6e528e3ff05 Mon Sep 17 00:00:00 2001 From: Timotej Lazar Date: Tue, 29 Sep 2015 11:10:05 +0200 Subject: Convert tab to 4 spaces in Python codemirror --- js/codeq/python.js | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) (limited to 'js/codeq') diff --git a/js/codeq/python.js b/js/codeq/python.js index cf2199a..c58d7e6 100644 --- a/js/codeq/python.js +++ b/js/codeq/python.js @@ -217,7 +217,20 @@ 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' }), + editor = CodeMirror(jqEditor[0], { + cursorHeight: 0.85, + lineNumbers: true, + matchBrackets: true, + mode: 'python', + indentUnit: 4, + extraKeys: { + // replace tabs with spaces + Tab: function (cm) { + var spaces = Array(cm.getOption("indentUnit") + 1).join(" "); + cm.replaceSelection(spaces); + } + } + }), activityHandler = makeActivityHandler(editor, problemDef.id), terminal = makePythonTerminalHandler(jqTerminal, editor, problemDef.id, activityHandler), hinter = codeq.makeHinter(jqHints, jqEditor, editor, 'python_hints', problemDef.hint, commonHints, problemDef.plan), -- cgit v1.2.1 From a2c468392673e55425fda9a5a331b86935b07781 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ale=C5=A1=20Smodi=C5=A1?= Date: Tue, 29 Sep 2015 11:53:46 +0200 Subject: Temporary "plan" button fix: look at the presence of Slovene translation to decide whether to activate or not the button. --- js/codeq/prolog.js | 2 +- js/codeq/python.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'js/codeq') diff --git a/js/codeq/prolog.js b/js/codeq/prolog.js index d827139..640aa99 100644 --- a/js/codeq/prolog.js +++ b/js/codeq/prolog.js @@ -272,7 +272,7 @@ if (currentSolution) editor.setValue(currentSolution); // $('#screen_prolog .title').text(problem.slug); // jqDescriptionContent.html(problem.description); - jqBtnPlan.prop('disabled', ((problemDef.plan && problemDef.plan.en) || []).length == 0); + jqBtnPlan.prop('disabled', ((problemDef.plan && problemDef.plan.sl) || []).length == 0); editor.on('change', function (instance, changeObj) { var doc = editor.getDoc(), diff --git a/js/codeq/python.js b/js/codeq/python.js index c58d7e6..4724982 100644 --- a/js/codeq/python.js +++ b/js/codeq/python.js @@ -243,7 +243,7 @@ if (currentSolution) editor.setValue(currentSolution); // $('#screen_python .title').text(problem.slug); // jqDescriptionContent.html(problem.description); - jqBtnPlan.prop('disabled', ((problemDef.plan && problemDef.plan.en) || []).length == 0); + jqBtnPlan.prop('disabled', ((problemDef.plan && problemDef.plan.sl) || []).length == 0); editor.on('change', function (instance, changeObj) { var doc = editor.getDoc(), -- cgit v1.2.1 From 68847b98e7b7804656e2abe09190a1b3553dbfc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20Pu=C5=A1nik?= Date: Tue, 29 Sep 2015 13:12:02 +0200 Subject: logout, sign in + change password modals, setting drop-down, profile screen --- js/codeq/core.js | 4 +++- js/codeq/login.js | 1 + js/codeq/navigation.js | 9 +++++++++ js/codeq/statusbar.js | 2 +- 4 files changed, 14 insertions(+), 2 deletions(-) (limited to 'js/codeq') diff --git a/js/codeq/core.js b/js/codeq/core.js index 1685dd7..3dfa7c2 100644 --- a/js/codeq/core.js +++ b/js/codeq/core.js @@ -389,5 +389,7 @@ codeq.setLang(lang || 'en'); // initial language setting // go to login codeq.globalStateMachine.transition('login'); - }); + + //For performance reasons, the Tooltip and Popover data-apis are opt-in, meaning you must initialize them yourself. + $('[data-toggle="popover"]').popover()}); })(); diff --git a/js/codeq/login.js b/js/codeq/login.js index c400f06..f590acb 100644 --- a/js/codeq/login.js +++ b/js/codeq/login.js @@ -29,6 +29,7 @@ codeq.globalStateMachine.register('login',{ 'enter': function(){ $("#submit").on('click', loginFun); + //$('#modalLogin').modal(); $("#screen_login").css('display', ''); $('#disabled').css('display', 'none'); diff --git a/js/codeq/navigation.js b/js/codeq/navigation.js index 1a7799f..80fd321 100644 --- a/js/codeq/navigation.js +++ b/js/codeq/navigation.js @@ -97,4 +97,13 @@ codeq.globalStateMachine.transition('prolog'); e.preventDefault(); }); + $('#navigation-logout').on('click', function(e){ + codeq.globalStateMachine.transition('login'); + e.preventDefault();//prevent this since we'll trigger a page reload otherwise + }); + $('#navigation-profile').on('click', function(e){ + codeq.globalStateMachine.transition('profile'); + e.preventDefault();//prevent this since we'll trigger a page reload otherwise + }); + })(); \ No newline at end of file diff --git a/js/codeq/statusbar.js b/js/codeq/statusbar.js index 2134b93..56070bd 100644 --- a/js/codeq/statusbar.js +++ b/js/codeq/statusbar.js @@ -6,7 +6,7 @@ (function () { var langs = codeq.supportedLangs, - jqMenu = jqBar.find('.dropdown-menu'), + jqMenu = jqLang.find('.dropdown-menu'), lang, cssClass; for (lang in langs) { if (!langs.hasOwnProperty(lang)) continue; -- cgit v1.2.1 From 22cb497f9ed19548e30a4c86dd99aaa91fd4b344 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ale=C5=A1=20Smodi=C5=A1?= Date: Tue, 29 Sep 2015 14:13:38 +0200 Subject: Changes to process language.js files with ordered problems (arrays instead of dictionaries). --- js/codeq/problem.js | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'js/codeq') diff --git a/js/codeq/problem.js b/js/codeq/problem.js index 464dc12..7ae54d8 100644 --- a/js/codeq/problem.js +++ b/js/codeq/problem.js @@ -151,10 +151,11 @@ createLanguageData = function (data, languageIdentifier) { // data is the content of language.json var li = languageIdentifier, // a shorthand rawTranslations = data.translations || {}, - groups = data.groups || {}, + groups = data.groups || [], + Ngroups = groups.length, html = [], problemReferences = [], - groupIdentifier, group, problems, problemIdentifier, problem; + group, problems, Nproblems, problem, i, j; var langDict = convertTranslations(rawTranslations, 'name', 'description'), // this will be the resulting dictionary: multi-level keys that lead up to the lang-dict groupDict, problemDict; // title: HTML structure for "name" and "desc" @@ -162,22 +163,21 @@ html.push('
    '); // content: problem directory html.push('