feat(ktb): add markdown parsing, sanitation, and add-lect feature
This commit is contained in:
parent
bf8538bbb9
commit
6873a8d920
4 changed files with 116 additions and 53 deletions
|
|
@ -81,15 +81,25 @@ document.addEventListener("alpine:init", () => {
|
||||||
this.update_css_variables();
|
this.update_css_variables();
|
||||||
},
|
},
|
||||||
|
|
||||||
async fetch_all_lects() {
|
async fetch_all_lects() {
|
||||||
try {
|
try {
|
||||||
const res = await axios.get("http://localhost:1225/lects");
|
const res = await axios.get("http://localhost:1225/lects");
|
||||||
console.log(JSON.stringify(res.data));
|
return res.data;
|
||||||
return res.data;
|
} catch (e) {
|
||||||
} catch (e) {
|
console.error(e);
|
||||||
console.error(e);
|
}
|
||||||
}
|
},
|
||||||
},
|
|
||||||
|
async post_lect(lect_name) {
|
||||||
|
try {
|
||||||
|
const res = await axios.post("http://localhost:1225/lect", {
|
||||||
|
lect_name,
|
||||||
|
});
|
||||||
|
return res.data.lect;
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
async fetch_all_terms(search_term) {
|
async fetch_all_terms(search_term) {
|
||||||
try {
|
try {
|
||||||
|
|
@ -180,13 +190,17 @@ document.addEventListener("alpine:init", () => {
|
||||||
|
|
||||||
filter_results(search_term) {
|
filter_results(search_term) {
|
||||||
if (!search_term) return this.search_results.results;
|
if (!search_term) return this.search_results.results;
|
||||||
return this.search_results.results.filter(
|
return this.search_results.results.filter((item) =>
|
||||||
(item) =>
|
item.word_forms
|
||||||
item.word_forms
|
.map((wf) => wf.word_form.toLowerCase())
|
||||||
.map((wf) => wf.word_form.toLowerCase())
|
.join()
|
||||||
.join()
|
.includes(search_term.toLowerCase()),
|
||||||
.includes(search_term.toLowerCase()),
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
md(text){
|
||||||
|
console.log(marked.parse(text));
|
||||||
|
return DOMPurify.sanitize(marked.parse(text), {ALLOWED_TAGS: ['br', 'em', 'strong', 'code', '#text']});
|
||||||
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,8 @@
|
||||||
<title>Dictionary Cards</title>
|
<title>Dictionary Cards</title>
|
||||||
<link rel="stylesheet" href="styles.css" />
|
<link rel="stylesheet" href="styles.css" />
|
||||||
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
|
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/marked@18.0.6/lib/marked.umd.min.js"></script>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/dompurify@3.4.12/dist/purify.min.js"></script>
|
||||||
<script src="https://unpkg.com/alpinejs" defer></script>
|
<script src="https://unpkg.com/alpinejs" defer></script>
|
||||||
<script src="script.js"></script>
|
<script src="script.js"></script>
|
||||||
</head>
|
</head>
|
||||||
|
|
@ -16,7 +18,10 @@
|
||||||
x-data="{
|
x-data="{
|
||||||
search_term: '',
|
search_term: '',
|
||||||
showPrefs: false,
|
showPrefs: false,
|
||||||
lects: []
|
lects: [],
|
||||||
|
md(text){
|
||||||
|
return $store.dictionary.md(text);
|
||||||
|
},
|
||||||
}"
|
}"
|
||||||
x-init="$store.dictionary.fetch_all_lects().then((lects_response)=>{
|
x-init="$store.dictionary.fetch_all_lects().then((lects_response)=>{
|
||||||
if(!!lects_response.lects) {
|
if(!!lects_response.lects) {
|
||||||
|
|
@ -169,6 +174,9 @@
|
||||||
<!-- wfs -->
|
<!-- wfs -->
|
||||||
<h4>Trofal</h4>
|
<h4>Trofal</h4>
|
||||||
<table class="is-fullwidth">
|
<table class="is-fullwidth">
|
||||||
|
<tbody>
|
||||||
|
|
||||||
|
|
||||||
<template
|
<template
|
||||||
x-for="wf2 in (lemma_detail?.word_forms ?? [])">
|
x-for="wf2 in (lemma_detail?.word_forms ?? [])">
|
||||||
<tr x-data="{
|
<tr x-data="{
|
||||||
|
|
@ -201,36 +209,44 @@
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</template>
|
</template>
|
||||||
|
</tbody>
|
||||||
|
|
||||||
<!-- Add new wf -->
|
<!-- Add new wf -->
|
||||||
<tr x-data="{
|
<tfoot>
|
||||||
adding_word_form:false,
|
<tr x-data="{
|
||||||
new_word_form_text:'',
|
adding_word_form:false,
|
||||||
selected_lect:''
|
new_word_form_text:'',
|
||||||
}">
|
selected_lect:'',
|
||||||
|
adding_lect:false,
|
||||||
|
new_lect_name:''
|
||||||
|
}">
|
||||||
|
|
||||||
<td colspan="3" x-show="!adding_word_form">
|
<td colspan="3" x-show="!adding_word_form" style="width: 16em;">
|
||||||
<button class="is-fullwidth hollow primary"
|
<button class="is-fullwidth hollow primary"
|
||||||
@click="adding_word_form = !adding_word_form">+</button>
|
@click="adding_word_form = !adding_word_form">+</button>
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
<td x-show="adding_word_form">
|
<td x-show="adding_word_form">
|
||||||
<select name="vilgovor" x-model="selected_lect">
|
<select name="vilgovor" x-model="selected_lect" x-show="!adding_lect">
|
||||||
<template x-for="lect in lects">
|
<template x-for="lect in lects">
|
||||||
<option :value="lect.name" x-text="lect.name"></option>
|
<option :value="lect.name" x-text="lect.name"></option>
|
||||||
</template>
|
</template>
|
||||||
</select>
|
</select>
|
||||||
</td>
|
<input type="text" x-show="adding_lect" x-model="new_lect_name">
|
||||||
<td x-show="adding_word_form">
|
<button class="float-right tiny primary" x-show="!adding_lect" @click="adding_lect = true" title="neo govor">+</button>
|
||||||
<input type="text" x-model="new_word_form_text">
|
<button class="float-right tiny edit" x-show="adding_lect" title="jame" @click="adding_lect = false">/</button>
|
||||||
</td>
|
</td>
|
||||||
<td x-show="adding_word_form">
|
<td x-show="adding_word_form">
|
||||||
<button class="tiny edit" x-show="adding_word_form" title="jame" @click="adding_word_form = false">/</button>
|
<input type="text" x-model="new_word_form_text">
|
||||||
<button class="tiny" x-show="adding_word_form" title="antaa"
|
</td>
|
||||||
@click="await post_new_word_form(item.lemma_name, selected_lect, new_word_form_text); adding_word_form = false">></button>
|
<td x-show="adding_word_form">
|
||||||
</td>
|
<button class="tiny edit" x-show="adding_word_form" title="jame" @click="adding_word_form = false">/</button>
|
||||||
|
<button class="tiny" x-show="adding_word_form" title="antaa"
|
||||||
|
@click="await post_new_word_form(item.lemma_name, adding_lect ? new_lect_name : selected_lect, new_word_form_text); adding_word_form = false">></button>
|
||||||
|
</td>
|
||||||
|
|
||||||
</tr>
|
</tr>
|
||||||
|
</tfoot>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
<h4>Imi</h4>
|
<h4>Imi</h4>
|
||||||
|
|
@ -241,7 +257,7 @@
|
||||||
editing: false,
|
editing: false,
|
||||||
edited_text: def.definition_text.toString()
|
edited_text: def.definition_text.toString()
|
||||||
}" @click.outside="editing = false">
|
}" @click.outside="editing = false">
|
||||||
<span x-show="!editing" x-text="def.definition_text" @click="editing = true"></span>
|
<span x-show="!editing" x-html="md(def.definition_text)" @click="editing = true"></span>
|
||||||
<input type="text" x-show="editing" x-model="edited_text">
|
<input type="text" x-show="editing" x-model="edited_text">
|
||||||
<button class="float-right tiny hollow primary" title="kawari" x-show="!editing"
|
<button class="float-right tiny hollow primary" title="kawari" x-show="!editing"
|
||||||
@click="editing = true">~</button>
|
@click="editing = true">~</button>
|
||||||
|
|
@ -292,7 +308,7 @@
|
||||||
edited_text: ex.example_text.toString()
|
edited_text: ex.example_text.toString()
|
||||||
}"
|
}"
|
||||||
@click.outside="editing = false">
|
@click.outside="editing = false">
|
||||||
<span x-show="!editing" x-text="ex.example_text" @click="editing = true"></span>
|
<span x-show="!editing" x-html="md(ex.example_text)" @click="editing = true"></span>
|
||||||
<input type="text" x-show="editing" x-model="edited_text">
|
<input type="text" x-show="editing" x-model="edited_text">
|
||||||
<button class="float-right tiny hollow primary" x-show="!editing" @click="editing = true" title="kawari">~</button>
|
<button class="float-right tiny hollow primary" x-show="!editing" @click="editing = true" title="kawari">~</button>
|
||||||
<button class="float-right tiny edit" x-show="editing" @click="editing = false" title="jame">/</button>
|
<button class="float-right tiny edit" x-show="editing" @click="editing = false" title="jame">/</button>
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
|
font-family: 'Verdana', -apple-system, BlinkMacSystemFont, sans-serif;
|
||||||
background-color: var(--color-main-bg);
|
background-color: var(--color-main-bg);
|
||||||
color: var(--color-text);
|
color: var(--color-text);
|
||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
|
|
@ -72,15 +72,19 @@ ul {
|
||||||
}
|
}
|
||||||
|
|
||||||
li {
|
li {
|
||||||
margin-top: calc(var(--space-xs)/2);
|
margin-top: calc(var(--space-xs));
|
||||||
margin-bottom: calc(var(--space-xs)/2);
|
margin-bottom: calc(var(--space-xs)/2);
|
||||||
margin-left: var(--space-md);
|
margin-left: var(--space-md);
|
||||||
}
|
}
|
||||||
|
|
||||||
table {
|
tbody {
|
||||||
table-layout: fixed;
|
table-layout: fixed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tfoot {
|
||||||
|
table-layout: auto;
|
||||||
|
}
|
||||||
|
|
||||||
.float-right {
|
.float-right {
|
||||||
float: right;
|
float: right;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -79,6 +79,21 @@ function initExpress() {
|
||||||
res.status(200).send({ lect });
|
res.status(200).send({ lect });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
app.post("/lect", (req, res) => {
|
||||||
|
const lect_name = req.query.lect_name?.toString();
|
||||||
|
|
||||||
|
if (!lect_name) {
|
||||||
|
return void res.sendStatus(400);
|
||||||
|
}
|
||||||
|
|
||||||
|
const lect = new Lect();
|
||||||
|
lect.name = lect_name;
|
||||||
|
lect.save().then((lect)=>{
|
||||||
|
res.status(200).send({ lect })
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
app.get("/lects", async (_req, res) => {
|
app.get("/lects", async (_req, res) => {
|
||||||
const lects = await Lect.find();
|
const lects = await Lect.find();
|
||||||
res.status(200).send({ lects });
|
res.status(200).send({ lects });
|
||||||
|
|
@ -261,13 +276,27 @@ function initExpress() {
|
||||||
|
|
||||||
let word_form = new WordForm();
|
let word_form = new WordForm();
|
||||||
let lemma = await Lemma.findOne({where:{lemma_name}});
|
let lemma = await Lemma.findOne({where:{lemma_name}});
|
||||||
let lect = await Lect.findOne({where:{name:lect_name}});
|
let lect;
|
||||||
|
try{
|
||||||
|
lect = await Lect.findOne({where:{name:lect_name}});
|
||||||
|
} catch {
|
||||||
|
console.info(`Lect ${lect_name} not found.`);
|
||||||
|
}
|
||||||
|
|
||||||
if(!lect || !lemma){
|
if(!lemma){
|
||||||
console.error(`Error: ${JSON.stringify({lect:lect, lemma:lemma})}`);
|
console.error(`Error: ${JSON.stringify({lect:lect, lemma:lemma})}`);
|
||||||
return void res.status(400).send();
|
return void res.status(400).send();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(!lect) {
|
||||||
|
lect = new Lect();
|
||||||
|
lect.name = lect_name;
|
||||||
|
await lect
|
||||||
|
.save()
|
||||||
|
.then((l)=>{console.info(`Created lect: ${JSON.stringify(l)}`)});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
word_form.word_form = word_form_text;
|
word_form.word_form = word_form_text;
|
||||||
word_form.lemma = lemma;
|
word_form.lemma = lemma;
|
||||||
word_form.lect = lect;
|
word_form.lect = lect;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue