diff options
-rw-r--r-- | css/codeq.css | 26 | ||||
-rw-r--r-- | index.html | 95 | ||||
-rw-r--r-- | js/codeq/hint.js | 68 | ||||
-rw-r--r-- | js/codeq/login.js | 4 | ||||
-rw-r--r-- | js/codeq/problem.js | 70 | ||||
-rw-r--r-- | js/codeq/prolog.js | 8 | ||||
-rw-r--r-- | js/codeq/python.js | 8 |
7 files changed, 184 insertions, 95 deletions
diff --git a/css/codeq.css b/css/codeq.css index 0e4c689..3a9195f 100644 --- a/css/codeq.css +++ b/css/codeq.css @@ -44,6 +44,32 @@ body { border-top-right-radius: 0; } +/* modalLogIn */ + +#modalLogIn{ + min-width: 250px; + padding: 14px 14px 0; + overflow:hidden; + background-color:rgba(255,255,255,.8); +} +#modalLogIn .help-block{ + font-size:12px +} +#modalLogIn .bottom{ + background-color:rgba(255,255,255,.8); + border-top:1px solid #ddd; + clear:both; + padding:14px; +} +#modalLogIn .ssa-buttons{ + margin-bottom: 1em; +} + +#modalLogIn .form-group { + margin-bottom: 10px; +} + + /* screen language */ #screen_language { @@ -42,7 +42,7 @@ <li style="display: none;" id="navigation-prolog"><a href="">Prolog</a></li> </ul> <ul class="nav navbar-nav navbar-right"> - <p class="navbar-text" id="signed-in-title">Signed in as Franc Jožef</p> + <p class="navbar-text" id="signed-in-title"></p> <li class="dropdown lang-selection"> <a href="#" class="dropdown-toggle" data-toggle="dropdown" aria-expanded="true"> <span class="lang-choice"></span> @@ -112,7 +112,7 @@ </div> <!-- login screen --> - <div class="container" id="screen_login"> + <!--div class="container" id="screen_login"> <form class="form-signin"> <h2 class="form-signin-heading">Please login</h2> <div class="form-group"> @@ -123,10 +123,10 @@ <button class="btn btn-lg btn-default btn-block" type="button" id="submit">Login</button> </div> <div class="form-group"> - <a href="" data-dismiss="modal" data-toggle="modal" role="button" data-target="#modalSignIn">New User? Sign-in..</a> + <a href="" data-dismiss="modal" data-toggle="modal" role="button" data-target="#modalSignUp">New User? Sign-up..</a> </div> </form> - </div> + </div--> <!-- main screen: programming language selection, settings, etc. --> @@ -297,63 +297,106 @@ </div><!--container--> <!-- Modals --> - <div id="modalSignIn" class="modal fade in" tabindex="-1" role="dialog" aria-hidden="false" style="display: none;"> - <div class="modal-dialog"> + + <div id="modalLogIn" class="modal fade in" tabindex="-1" role="dialog" aria-hidden="false" data-keyboard="false" data-backdrop="static" style="display: none;"> + <div class="modal-dialog modal-sm"> + <div class="modal-content"> + <div class="modal-header"> + <h3 class="text-center">Please sign in</h3> + </div> + <div class="modal-body"> + <div class="row"> + <div class="col-md-12"> + Login via + <div class="ssa-buttons"> + <img src="res/gumb_aaiprijava.png" style="width: 49%"> + </div> + or + <form class="form" role="form" method="post" action="login" accept-charset="UTF-8" id="login-nav"> + <div class="form-group"> + <label class="sr-only" for="username">Username</label> + <input type="text" class="form-control" id="username" placeholder="Username" required> + </div> + <div class="form-group"> + <label class="sr-only" for="password">Password</label> + <input type="password" class="form-control" id="password" placeholder="Password" required> + <div class="help-block text-right"><a href="#">Forgot the password?</a></div> + </div> + <div class="form-group"> + <button class="btn btn-primary btn-block" data-dismiss="modal" type="button" id="submit">Sign in</button> + </div> + <div class="checkbox"> + <label> + <input type="checkbox"> keep me logged-in + </label> + </div> + </form> + </div> + </div> + </div><!--/modal-body--> + <div class="modal-footer"> + <div class="text-center"> + New here ? <a href="#" data-dismiss="modal" data-toggle="modal" role="button" data-target="#modalSignUp"><b>Sign Up</b></a> + </div> + </div><!--/modal-footer--> + </div> + </div> + </div> + + + <div id="modalSignUp" class="modal fade in" tabindex="-1" role="dialog" aria-hidden="false" style="display: none;"> + <div class="modal-dialog modal-sm"> <div class="modal-content"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> - <h2 class="text-center">Sign-in</h2> + <h3 class="text-center">Sign up</h3> </div> <div class="modal-body"> <form class="form" method="post"> - <div class="form-group"> - <label class="control-label">Email</label> - <input class="form-control" name="email" id="inputEmail" type="email" data-ng-model="newuser.email" placeholder="email@you.com (kept private)" required=""> - </div> <div class="form-group" bs-has-error=""> - <label class="control-label">Username</label> - <input class="form-control" name="username" id="inputUsername" type="text" data-ng-model="newuser.username" placeholder="desired username" pattern="^[a-z,A-Z,0-9,_]{5,15}$" data-valid-min="5" title="Choose a alpha-numeric username of 5-15 characters" required=""> + <label class="control-label small">Username</label> + <input class="form-control" name="username" id="modalSignUpUsername" type="text" placeholder="desired username" pattern="^[a-z,A-Z,0-9,_]{5,15}$" data-valid-min="5" title="Choose a alpha-numeric username of 5-15 characters" required=""> </div> <div class="form-group"> - <label class="control-label">Password</label> - <input class="form-control" name="password" id="inputpassword" type="password" data-ng-model="newuser.password" placeholder="password" pattern="^[a-z,A-Z,0-9,_]{6,15}$" data-valid-min="6" title="Choose a alpha-numeric password of a least 6 characters" required=""> + <label class="control-label small">Password</label> + <input class="form-control" name="password" id="modalSignUpPassword" type="password" placeholder="password" pattern="^[a-z,A-Z,0-9,_]{6,15}$" data-valid-min="6" title="Choose a alpha-numeric password of a least 6 characters" required=""> </div> <div class="form-group"> - <label class="control-label">Verify (repeat password)</label> - <input class="form-control" name="verify" id="inputVerify" type="password" data-ng-model="newuser.verify" placeholder="password (again)" pattern="^[a-z,A-Z,0-9,_]{6,15}$" data-valid-min="6" title="Choose a alpha-numeric password of a least 6 characters" required=""> + <label class="control-label small">Verify (repeat password)</label> + <input class="form-control" name="verify" id="modalSignUpVerify" type="password" placeholder="password (again)" pattern="^[a-z,A-Z,0-9,_]{6,15}$" data-valid-min="6" title="Choose a alpha-numeric password of a least 6 characters" required=""> </div> </form><!--/row--> </div><!--/modal-body--> <div class="modal-footer"> - <button class="btn btn-default" data-dismiss="modal" aria-hidden="true">Cancel</button> - <button class="btn btn-lg btn-primary" id="btnRegister" type="submit">Sign</button> + <button class="btn btn-default" data-dismiss="modal" aria-hidden="true" data-toggle="modal" data-target="#modalLogIn">Cancel</button> + <button class="btn btn-primary" data-dismiss="modal" data-toggle="modal" data-target="#modalLogIn" id="btnSignUp" type="submit">Sign up</button> </div><!--/modal-footer--> </div> </div> </div> <div id="modalChangePassword" class="modal fade in" tabindex="-1" role="dialog" aria-hidden="false" style="display: none;"> - <div class="modal-dialog"> + <div class="modal-dialog modal-sm"> <div class="modal-content"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> - <h2 class="text-center">Password Change</h2> + <h3 class="text-center">Change password </h3> </div> <div class="modal-body"> <form class="form" method="post"> <div class="form-group"> - <label>New Password</label> - <input class="form-control input-lg" placeholder="Enter a new password" name="new" type="password"> + <label class="control-label small">New Password</label> + <input class="form-control" placeholder="Enter a new password" name="new" type="password"> </div> <div class="form-group"> - <label>Verify Password</label> - <input class="form-control input-lg" placeholder="Repeat the password again" name="verify" type="password"> + <label class="control-label small">Verify Password</label> + <input class="form-control" placeholder="Repeat the password again" name="verify" type="password"> </div> </form><!--/row--> </div><!--/modal-body--> <div class="modal-footer"> <button class="btn btn-default" data-dismiss="modal" aria-hidden="true">Cancel</button> - <button class="btn btn-lg btn-primary" id="btnPasswdChange" type="submit">Change</button> + <button class="btn btn-primary" id="btnPasswdChange" type="submit">Change</button> </div><!--/modal-footer--> </div> </div> diff --git a/js/codeq/hint.js b/js/codeq/hint.js index 1b97afc..d30f934 100644 --- a/js/codeq/hint.js +++ b/js/codeq/hint.js @@ -7,7 +7,7 @@ var firstCharacterPos = {'line': 0, 'ch': 0}, sel_no_scroll = {'scroll': false}; - codeq.makeHinter = function (jqHints, jqEditor, editor, trNamespace, hintDefsA, commonHintDefsA, planDef) { + codeq.makeHinter = function (jqHints, jqEditor, editor, trNamespace, problemDef, commonDef) { var hintCounter = 0, // for generating unique class-names hintCleaners = [], planIdx = 0, @@ -133,25 +133,15 @@ 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]; - } + var hintProblemDefs = problemDef.hint_type, + hintCommonDefs = commonDef.hint_type, + hintProblemTr = problemDef.hint, + hintCommonTr = commonDef.hint, + planDef = problemDef.plan.sl; return { - /** Display the next "planning" hint and return whether there are + /** + * Display the next "planning" hint and return whether there are * any more available. */ 'planNext': function () { @@ -170,46 +160,50 @@ */ 'handle': function (serverHints) { var n = serverHints.length, - /** number */ i, - /** ServerHint */ serverHint, - /** HintDefinition */ hintDef, - hintType, hintTemplate, t, fn, indices; + i, serverHint, hintId, hintDef, hintContent, hintType, hintTemplate, t, fn, indices; clearHints(); mainLoop: for (i = 0; i < n; i++) { serverHint = serverHints[i]; - hintDef = hintDefs[serverHint.id]; + hintId = serverHint.id; + hintDef = hintProblemDefs[hintId]; + if (hintDef) { + hintContent = hintProblemTr[hintId]; + } + else { + hintDef = hintCommonDefs[hintId]; + hintContent = hintCommonTr[hintId]; + } if (!hintDef) { - codeq.log.error('Undefined hint ' + serverHint.id); + codeq.log.error('Undefined hint: ' + hintId); + continue; + } + if (!hintContent) { + codeq.log.error('Hint without content: ' + hintId); continue; } if (serverHint.indices) { indices = serverHint.indices; for (i = 0; i < indices.length; i++) { - hintDef = hintDef[indices[i]]; - if (!hintDef) { - codeq.log.error('Undefined hint ' + serverHint.id + ' with indices ' + serverHint.indices); + hintContent = hintContent[indices[i]]; + if (!hintContent) { + codeq.log.error('Cannot reference hint ' + hintId + ' with indices ' + serverHint.indices); continue mainLoop; } } } + t = typeof hintDef; - if ((t === 'string') || (hintDef instanceof Array)) { - hintType = 'static'; - hintTemplate = hintDef; - } - else if (t === 'object') { - hintType = hintDef.type; - hintTemplate = hintDef.message; - } + if (t === 'string') hintType = hintDef; + else if ((t === 'object') && (hintDef !== null)) hintType = hintDef.type; else { - codeq.log.error('Unsupported hint definition: ' + t); + codeq.log.error('Cannot determine type of hint ' + hintId + ' from: ' + hintDef); continue; } fn = typeHandlers[hintType]; if (!fn) codeq.log.error('Unsupported hint type: ' + hintType); - else fn(hintType, hintTemplate, serverHint); + else fn(hintType, hintContent.sl, serverHint); } }, diff --git a/js/codeq/login.js b/js/codeq/login.js index e3204d3..e5a446b 100644 --- a/js/codeq/login.js +++ b/js/codeq/login.js @@ -36,8 +36,9 @@ }; codeq.globalStateMachine.register('login',{ 'enter': function(){ + $('#signed-in-title').html(''); $("#submit").on('click', loginFun); - //$('#modalLogin').modal(); + $('#modalLogIn').modal(); $("#screen_login").css('display', ''); $('#disabled').css('display', 'none'); @@ -45,6 +46,7 @@ 'exit' : function(){ $("#submit").off('click', loginFun); $("#screen_login").css('display', 'none'); + $('#signed-in-title').html('Signed in as '+$('#username').val()); $("#password").val(''); } }); diff --git a/js/codeq/problem.js b/js/codeq/problem.js index 7ae54d8..d07e5fa 100644 --- a/js/codeq/problem.js +++ b/js/codeq/problem.js @@ -10,13 +10,23 @@ // processed form, hint key -> translation language -> value // ================================================================================ + defaultHintCondition = function (translation) { + // must contain at least one translation + var key; + if (!translation || typeof translation !== 'object') return false; + for (key in translation) { + if (!translation.hasOwnProperty(key)) continue; + return true; + } + return false; + }, 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') || {}; + tr = chooseDefaultTranslation(rawTranslations, 'hint', defaultHintCondition) || {}; for (key in tr) { // copy the hints if (!tr.hasOwnProperty(key)) continue; defaultHint[key] = tr[key]; @@ -26,7 +36,7 @@ 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 + if (!tr || !defaultHintCondition(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; @@ -37,22 +47,26 @@ } } // create all translations for hints + for (i = allHintKeys.length - 1; i >= 0; i--) { + allHints[allHintKeys[i]] = {}; // create keys with no translations, we'll fill them in the next loop + } for (i = langs.length - 1; i >= 0; i--) { lang = langs[i]; tr = rawTranslations[lang]; // set up hints - if (!tr || !tr.hint) { + if (!tr || !defaultHintCondition(tr.hint)) { // there's no hint in the current language, copy the default in its entirety - allHints[lang] = defaultHint; + for (j = allHintKeys.length - 1; j >= 0; j--) { + key = allHintKeys[j]; + allHints[key][lang] = defaultHint[key]; + } } 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--) { + for (j = allHintKeys.length - 1; j >= 0; j--) { key = allHintKeys[j]; - hint[key] = h[key] || defaultHint[key]; + allHints[key][lang] = h[key] || defaultHint[key]; } } } @@ -64,9 +78,14 @@ // processed form, hint key -> translation language -> value // ================================================================================ + defaultPlanCondition = function (translation) { + // default plan must be non-empty + if (!translation || !(translation instanceof Array)) return false; + return translation.length > 0; + }, processPlans = function (rawTranslations) { // find the default plan translation - var defaultPlan = chooseDefaultTranslation(rawTranslations, 'plan') || [], + var defaultPlan = chooseDefaultTranslation(rawTranslations, 'plan', defaultPlanCondition) || [], allPlans = {}, // the result i, lang, tr; // create all translations for plan @@ -74,12 +93,12 @@ 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; + if (tr && defaultPlanCondition(tr.plan)) { + allPlans[lang] = tr.plan; } else { - allPlans[lang] = tr.plan; + // there's no plan in the current language, copy the default plan + allPlans[lang] = defaultPlan; } } return allPlans; @@ -111,7 +130,7 @@ /** * convert the input translations (arg0) for given keys (arg1..argN) - * so each keys holds all its translations for ever language + * so each keys holds all its translations for every language */ convertTranslations = function () { var translations = arguments[0] || {}, @@ -187,7 +206,10 @@ '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 <a> elements - 'hints': processHints(rawTranslations) // hint translations: keyword -> lang -> value + 'commonDef': { + 'hint': processHints(rawTranslations), // hint translations: keyword -> lang -> value + 'hint_type': data.hint_type || {} + } }; }, @@ -218,7 +240,7 @@ .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); + codeq.globalStateMachine.transition(language, generalProblemData, data.commonDef, userProblemData.solution); }) ) .fail(function (reason) { @@ -233,14 +255,15 @@ // Problem definition processing // ================================================================================ - chooseDefaultTranslation = function (rawTranslations, translationKey) { + chooseDefaultTranslation = function (rawTranslations, translationKey, condition) { 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; + lang, value; + if (typeof condition !== 'function') condition = function (x) { return !!x; }; + if (tr && condition(tr[translationKey])) return tr[translationKey]; + for (lang in rawTranslations) { // find a translation with content + if (!rawTranslations.hasOwnProperty(lang)) continue; tr = rawTranslations[lang]; - if (tr[translationKey]) return tr[translationKey]; + if (tr && condition(tr[translationKey])) return tr[translationKey]; } return null; // default must be chosen by the caller }, @@ -254,7 +277,8 @@ '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 + 'plan': processPlans(rawTranslations), // plan translations: keyword -> lang -> value + 'hint_type': rawData.hint_type || {} }; }, diff --git a/js/codeq/prolog.js b/js/codeq/prolog.js index 87ac353..bcced1c 100644 --- a/js/codeq/prolog.js +++ b/js/codeq/prolog.js @@ -66,14 +66,14 @@ }; var prologHandler; //created when we enter the prolog state and destroyed once we leave it codeq.globalStateMachine.register('prolog', { - 'enter': function (problemDef, commonHints, currentSolution) { + 'enter': function (problemDef, commonDef, currentSolution) { $('#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); + prologHandler = createPrologHandler(problemDef, commonDef, currentSolution); subScreens = codeq.makeStateMachine(substates); subScreens.transition(jqDescription.data(stateNameTag)); /* Q.delay(100).then(function(){ @@ -253,7 +253,7 @@ * @param {PrologTaskDef} info * @returns {{destroy: Function, processServerHints: Function}} */ - createPrologHandler = function (problemDef, commonHints, currentSolution) { + createPrologHandler = function (problemDef, commonDef, currentSolution) { var //problem = info.problem, jqDescriptionContent = jqDescription.find('.description'), jqEditor = jqCode.find('.code_editor'), @@ -264,7 +264,7 @@ }), 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), + hinter = codeq.makeHinter(jqHints, jqEditor, editor, 'prolog_hints', problemDef, commonDef), commError = function (error) { alert(error); }; diff --git a/js/codeq/python.js b/js/codeq/python.js index e20fe06..8a9e92f 100644 --- a/js/codeq/python.js +++ b/js/codeq/python.js @@ -71,14 +71,14 @@ }; var pythonHandler; //created when we enter the python state and destroyed once we leave it codeq.globalStateMachine.register('python', { - 'enter': function (problemDef, commonHints, currentSolution) { + 'enter': function (problemDef, commonDef, currentSolution) { $('#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); + pythonHandler = createPythonHandler(problemDef, commonDef, currentSolution); subScreens = codeq.makeStateMachine(substates); subScreens.transition(jqDescription.data(stateNameTag)); /* Q.delay(100).then(function(){ @@ -211,7 +211,7 @@ * @param {PrologTaskDef} info * @returns {{destroy: Function, processServerHints: Function}} */ - var createPythonHandler = function (problemDef, commonHints, currentSolution) { + var createPythonHandler = function (problemDef, commonDef, currentSolution) { var //problem = info.problem, jqDescriptionContent = jqDescription.find('.description'), jqEditor = jqCode.find('.code_editor'), @@ -223,7 +223,7 @@ }), 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), + hinter = codeq.makeHinter(jqHints, jqEditor, editor, 'python_hints', problemDef, commonDef), commError = function (error) { alert(error); }; |