improved ui a bit
This commit is contained in:
1 parent
002ca66666
commit
cbb4d0a674
5 files changed
+97
-20
No files matched your search
@@ -6,6 +6,7 @@
|
||||
"https://unpkg.com/pure-rand/lib/esm/pure-rand.js": "https://unpkg.com/pure-rand@6.0.4/lib/esm/pure-rand.js"
|
||||
},
|
||||
"remote": {
|
||||
"https://cdn.jsdelivr.net/npm/highlight.js@11.9.0": "91a9625e96503cd01729ec392b4dfb0a33d6062395c1907041344bd7706ac099",
|
||||
"https://deno.land/std@0.200.0/_util/os.ts": "d932f56d41e4f6a6093d56044e29ce637f8dcc43c5a90af43504a889cf1775e3",
|
||||
"https://deno.land/std@0.200.0/assert/assert.ts": "9a97dad6d98c238938e7540736b826440ad8c1c1e54430ca4c4e623e585607ee",
|
||||
"https://deno.land/std@0.200.0/assert/assertion_error.ts": "4d0bde9b374dfbcbe8ac23f54f567b77024fb67dbb1906a852d67fe050d42f56",
|
||||
@@ -185,13 +186,19 @@
|
||||
"https://denopkg.com/chiefbiiko/sha1@master/deps.ts": "434b70f37ed145ca5259353c96fdee1e7d1cd8c6a32baad9dce2aedc79d0a3bc",
|
||||
"https://denopkg.com/chiefbiiko/sha1@master/mod.ts": "146a101c9776cc9c807053c93f23e4b321ade5251f65745df418f4a75d5fd27b",
|
||||
"https://denopkg.com/chiefbiiko/std-encoding@v1.1.1/mod.ts": "e61017da4cef146863d614a961b4e61f1df14b72c906092bd02161f913e76522",
|
||||
"https://esm.sh/highlight.js@11.9.0": "fedce3b9e0d80a1302f7880a5db7527b00fb565777abe6350769883790465c65",
|
||||
"https://esm.sh/highlight.js@11.9.0/es/languages/javascript.js": "28afc23607edc404bc69093b2f1eb82dbae810e3ef6bf1357c3e90b5bb5c6fea",
|
||||
"https://esm.sh/preact-render-to-string@5.1.19?deps=preact@10.5.15": "fba6961b9688151eeccc5425e05740009c3e7abee863615e626fb13e1d17e87a",
|
||||
"https://esm.sh/preact@10.19.2": "41f31ba8eecf666f08289f2205f57c45f74baba5be815a55c15c4cc61086143c",
|
||||
"https://esm.sh/preact@10.19.2/jsx-runtime": "2a4111d9aa667a3e3776ffd9082d00d63f6960c038d01620d79f80645ecc049d",
|
||||
"https://esm.sh/stable/preact@10.19.2/denonext/jsx-runtime.js": "f196c14042fc6019f3fed31eec7cfedea4669d0926858939380a5f54bd503798",
|
||||
"https://esm.sh/stable/preact@10.19.2/denonext/preact.mjs": "dc999b6432dc04d74ad7b692a8801f346294d815266dff915d0f222c120fd0b0",
|
||||
"https://esm.sh/stable/preact@10.5.15/denonext/preact.mjs": "4e6645aa945a53e44eaa4d882f9f9b4e76c992875fad9ef5791784474a71a116",
|
||||
"https://esm.sh/v135/highlight.js@11.9.0/denonext/es/languages/javascript.js": "e6dbfe6f4e73f1ea4b346b20336e48a710be4aa516c0baad2b68721ce5fd3a7c",
|
||||
"https://esm.sh/v135/highlight.js@11.9.0/denonext/highlight.mjs": "a6c1ad8d57cb7bff25c3e0084d9312631fa6e24cd7da5a9565314410897af271",
|
||||
"https://esm.sh/v135/highlight.js@11.9.0/denonext/lib/core.js": "8653667a14004953b2fcbf10be691096e9f699741b23e5a858cb1e4b09f9e3b3",
|
||||
"https://esm.sh/v135/preact-render-to-string@5.1.19/X-ZC9wcmVhY3RAMTAuNS4xNQ/denonext/preact-render-to-string.mjs": "3ce1bda513633d15cd313e97ab7eacba9bd50eb4dc95e41861056c6bae1bfac8",
|
||||
"https://unpkg.com/@highlightjs/cdn-assets@11.9.0/highlight.min.js": "837a6fa5b0c736b52bbde2b2b6190f305da3fc9ed41681db5321507057b5c846",
|
||||
"https://unpkg.com/pure-rand@6.0.4/lib/esm/distribution/UniformArrayIntDistribution.js": "121a5017f80ac3c36359877407f6f9d16cc8d28fb88e21990d1ecba6a6ad6a90",
|
||||
"https://unpkg.com/pure-rand@6.0.4/lib/esm/distribution/UniformBigIntDistribution.js": "1fafebba70f83e619d852964506bbb259e26618238b087bf7cab203b9848bf71",
|
||||
"https://unpkg.com/pure-rand@6.0.4/lib/esm/distribution/UniformIntDistribution.js": "fb21df31e3395ed0f38194ec5e99bcba6c89be02acd2d7cc07145b665d997e78",
|
||||
|
||||
+18
-5
@@ -6,6 +6,9 @@
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<title>JS Reading App</title>
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.9.4/css/bulma.min.css">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.9.0/build/styles/default.min.css">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/atom-one-light.min.css">
|
||||
|
||||
<script src="https://unpkg.com/htmx.org@1.9.9"></script>
|
||||
</head>
|
||||
<body>
|
||||
@@ -25,12 +28,22 @@
|
||||
</div>
|
||||
|
||||
<script>
|
||||
|
||||
function getIndexFromHash(){
|
||||
if(document.location.hash.length < 2){
|
||||
return null;
|
||||
}
|
||||
const ret = document.location.hash.substr(1)
|
||||
if(isNaN(ret)){
|
||||
return ret;
|
||||
}
|
||||
return parseInt(ret) - 1;
|
||||
}
|
||||
|
||||
function getDefaultIndex(){
|
||||
if(document.location.hash.length > 1){
|
||||
return document.location.hash.substr(1)
|
||||
}
|
||||
return localStorage.getItem("defaultIndex") || '0';
|
||||
return getIndexFromHash() || localStorage.getItem("defaultIndex") || '0';
|
||||
}
|
||||
|
||||
document.body.addEventListener('htmx:configRequest', function(evt) {
|
||||
evt.detail.headers.session = localStorage.getItem("seed");
|
||||
evt.detail.path = evt.detail.path.replace(":seed", localStorage.getItem("seed"));
|
||||
@@ -46,7 +59,7 @@
|
||||
if(isNaN(evt.detail.value)){
|
||||
return;
|
||||
}
|
||||
document.location.hash = evt.detail.value
|
||||
document.location.hash = parseInt(evt.detail.value) + 1;
|
||||
localStorage.setItem("defaultIndex", evt.detail.value);
|
||||
});
|
||||
|
||||
|
||||
+30
-1
@@ -6,7 +6,21 @@ function basicFrenchQuestion(argumentValue){
|
||||
}
|
||||
|
||||
function basicQuestionValidator(expected){
|
||||
return (answer) => answer.toString() === expected.toString();
|
||||
const cannonicalString = (v) => {
|
||||
if(v === null){
|
||||
return 'null';
|
||||
}
|
||||
if(v === undefined){
|
||||
return 'undefined'
|
||||
}
|
||||
return v.toString()
|
||||
|
||||
}
|
||||
|
||||
return (answer) => {
|
||||
return cannonicalString(answer) === cannonicalString(expected);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function basicQuestionMetaData(question){
|
||||
@@ -211,3 +225,18 @@ export function question015(x){
|
||||
question015.questions = [-4, 2, 7].map(basicQuestionMetaData(question015))
|
||||
|
||||
|
||||
export function question016(id){
|
||||
const people = [{id: 12, name: "bob"},
|
||||
{id: 34, name: "alice"},
|
||||
{id: 56, name: "cedric"},
|
||||
{id: 6, name: "david"}, ]
|
||||
for(const person of people){
|
||||
if (person.id === id){
|
||||
return person;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
question016.questions = [12, 56, 7].map(basicQuestionMetaData(question016))
|
||||
|
||||
|
||||
+41
-13
@@ -5,6 +5,9 @@ import { renderToString } from "https://esm.sh/preact-render-to-string@5.1.19?de
|
||||
import * as prand from 'https://unpkg.com/pure-rand/lib/esm/pure-rand.js';
|
||||
import {QuestionSource, QuestionMeta} from './shared.ts';
|
||||
|
||||
import highlightJs from "https://esm.sh/highlight.js@11.9.0"
|
||||
import highlightJsJavascript from "https://esm.sh/highlight.js@11.9.0/es/languages/javascript.js"
|
||||
highlightJs.registerLanguage('javascript', highlightJsJavascript);
|
||||
|
||||
type Question = [QuestionSource, QuestionMeta];
|
||||
|
||||
@@ -14,7 +17,7 @@ type QuestionURLS = {
|
||||
answerQuestionUrl: string
|
||||
};
|
||||
|
||||
const questions: Question = Object.values(rawQuestions).flatMap(s => s.questions.map( q => [s, q]));
|
||||
const questions: Question[] = Object.values(rawQuestions).flatMap(s => s.questions.map( (q, idx) => [s as QuestionSource, q as QuestionMeta]));
|
||||
|
||||
const apiRouter = new Router();
|
||||
const loginRouter = new Router();
|
||||
@@ -28,10 +31,10 @@ function hashString(str: string): number {
|
||||
hash |= 0; // Convert to 32bit integer
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function randomPermutation(seed: number, n: number): number[] {
|
||||
function randomPermutation(seed: number, n: number): number[] {
|
||||
const rand = prand.mersenne(seed)
|
||||
const base = [...Array(n).keys()];
|
||||
for(let i = 0; i < (n -1); i++){
|
||||
@@ -41,20 +44,30 @@ function hashString(str: string): number {
|
||||
base[j] = tmp;
|
||||
}
|
||||
return base;
|
||||
}
|
||||
}
|
||||
|
||||
function isSecretSeed(seed: string): boolean{
|
||||
return seed === 'cannonical';
|
||||
}
|
||||
|
||||
|
||||
function getRandomQuestion<T>(seed: string, index: number, questions: Question[]): Question {
|
||||
if(isSecretSeed(seed)){
|
||||
return questions[index] ;
|
||||
}
|
||||
const numberSeed = hashString(seed);
|
||||
const permutations = randomPermutation(numberSeed, questions.length)
|
||||
return questions[permutations[index]];
|
||||
|
||||
return [... questions[permutations[index]]];
|
||||
}
|
||||
|
||||
function getQuestionPage(question: Question, urls: QuestionURLS){
|
||||
function getQuestionPage(question: Question, urls: QuestionURLS, questionIndex: number){
|
||||
const source = highlightJs.highlight(question[0].toString(), {language: 'javascript'}).value;
|
||||
return (<div>
|
||||
<pre> { question[0].toString() }</pre>
|
||||
<div class="content mt-2 mb-2">
|
||||
<div style="text-align:center">
|
||||
{questionIndex + 1}/{ questions.length }
|
||||
</div>
|
||||
<pre> <code dangerouslySetInnerHTML={{__html: source}}></code></pre>
|
||||
<div class="content mt-2 mb-2" >
|
||||
{ question[1].question_fr }
|
||||
</div>
|
||||
|
||||
@@ -129,17 +142,26 @@ function processValidAnswer(ctx, answer: string): void {
|
||||
ctx.response.body = renderToString(getValidAnswerMessage());
|
||||
}
|
||||
|
||||
function getQuestionIndex(ctx){
|
||||
const index = Number.parseInt(ctx.params.idx??"0");
|
||||
return index % questions.length;
|
||||
}
|
||||
|
||||
function getNextQuestionIndex(ctx){
|
||||
return (getQuestionIndex(ctx) + 1) % questions.length
|
||||
}
|
||||
|
||||
function getQuestion(ctx): Question{
|
||||
const seed = ctx.params.seed;
|
||||
const index = Number.parseInt(ctx.params.idx??"0");
|
||||
const index = getQuestionIndex(ctx);
|
||||
return getRandomQuestion(seed, index, questions);
|
||||
}
|
||||
|
||||
function getUrls(ctx): QuestionURLS{
|
||||
const seed = ctx.params.seed;
|
||||
const index = Number.parseInt(ctx.params.idx??"0");
|
||||
const nextQuestionUrl = `/api/v1/random-questions/${seed}/${index + 1}`;
|
||||
const index = getQuestionIndex(ctx);
|
||||
const nextQuestionIndex = getNextQuestionIndex(ctx);
|
||||
const nextQuestionUrl = `/api/v1/random-questions/${seed}/${nextQuestionIndex}`;
|
||||
const validationUrl = `/api/v1/random-questions/${seed}/${index}/validate`;
|
||||
const answerQuestionUrl = `/api/v1/random-questions/${seed}/${index}/answer`
|
||||
return {nextQuestionUrl, validationUrl, answerQuestionUrl};
|
||||
@@ -201,12 +223,18 @@ apiRouter.get("/api/v1/random-questions/:seed/:idx/answer", (ctx)=> {
|
||||
apiRouter.get("/api/v1/random-questions/:seed/:idx", (ctx)=> {
|
||||
const q = getQuestion(ctx);
|
||||
const urls = getUrls(ctx);
|
||||
const questionIndex = getQuestionIndex(ctx);
|
||||
|
||||
ctx.response.body = renderToString(getQuestionPage(q, urls));
|
||||
ctx.response.body = renderToString(getQuestionPage(q, urls, questionIndex));
|
||||
ctx.response.headers.append("HX-Trigger", JSON.stringify({'set-question-id': ctx.params.idx}));
|
||||
});
|
||||
|
||||
|
||||
loginRouter.get("/toto", (ctx)=> {
|
||||
ctx.response.body = highlightJs.highlight('function(){console.log("hello world")}', {language: 'javascript'}).value;
|
||||
});
|
||||
|
||||
|
||||
loginRouter.post("/api/v1/login", async (ctx)=> {
|
||||
const username = (await ctx.request.body().value).get("username");
|
||||
ctx.response.headers.append("HX-Trigger", JSON.stringify({'set-seed': username}));
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
interface QuestionSource {
|
||||
export interface QuestionSource {
|
||||
toString(): string;
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user