#236 [pl][terms] add a key
This commit is contained in:
parent
1e25f58b19
commit
ff698a26a4
|
@ -56,9 +56,9 @@
|
|||
|
||||
<ul class="list-inline">
|
||||
<li v-for="category in s.el.categories" class="list-inline-item">
|
||||
<button class="badge bg-primary text-white" @click="filter = ':' + category">
|
||||
<a :href="`#:${category}`" class="badge bg-primary text-white" @click.prevent="filter = ':' + category">
|
||||
{{category}}
|
||||
</button>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
<template>
|
||||
<div>
|
||||
<p>
|
||||
<strong><LinkedTextMultiple :texts="term.term" noicons/></strong>
|
||||
<span v-if="term.original.length">(<LinkedTextMultiple :texts="term.original" glue="; " noicons/>)</span>
|
||||
– <LinkedText :text="term.definition" noicons/>
|
||||
</p>
|
||||
|
||||
<ul class="list-inline">
|
||||
<li v-for="category in term.categories" class="list-inline-item">
|
||||
<a v-if="categoryLink" :href="`#:${category}`" class="badge bg-primary text-white" @click.prevent="filter = ':' + category">
|
||||
{{category}}
|
||||
</a>
|
||||
<span v-else="" class="badge bg-primary text-white">
|
||||
{{category}}
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p v-if="flags && (term.flags.length || term.images.length)" class="text-center">
|
||||
<img v-for="flag in term.flags" :src="`/flags/${flag}.png`" class="flag m-1"/>
|
||||
<img v-for="image in term.images" :src="buildImageUrl(image, 'big')" class="flag m-1"/>
|
||||
</p>
|
||||
|
||||
<div v-if="versions && term.versions.length" class="my-3 mx-2">
|
||||
<p>
|
||||
<button :class="['btn', versionsShown ? 'btn-primary' : 'btn-outline-primary', 'btn-sm']" @click="versionsShown = !versionsShown">
|
||||
<Icon v="language"/>
|
||||
<T>sources.otherVersions</T>
|
||||
<Icon :v="versionsShown ? 'caret-up' : 'caret-down'"/>
|
||||
</button>
|
||||
</p>
|
||||
<ul v-if="versionsShown">
|
||||
<li v-for="version in term.versions" v-if="locales[version.locale] !== undefined">
|
||||
<h4 class="h6 mb-2">
|
||||
<strong>
|
||||
<a :href="`${locales[version.locale].url}`" target="_blank" rel="noopener">{{locales[version.locale].name}}</a>:
|
||||
</strong>
|
||||
</h4>
|
||||
<Term :term="version"/>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
term: { required: true },
|
||||
categoryLink: { type: Boolean },
|
||||
flags: { type: Boolean },
|
||||
versions: { type: Boolean },
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
versionsShown: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -39,53 +39,12 @@
|
|||
|
||||
<template v-slot:row="s"><template v-if="s">
|
||||
<td class="cell-wide">
|
||||
<p>
|
||||
<strong><LinkedTextMultiple :texts="s.el.term" noicons/></strong>
|
||||
<span v-if="s.el.original.length">(<LinkedTextMultiple :texts="s.el.original" glue="; " noicons/>)</span>
|
||||
– <LinkedText :text="s.el.definition" noicons/>
|
||||
<template v-if="s.el.category">
|
||||
<br/>
|
||||
<span class="badge bg-primary text-white">
|
||||
{{s.el.category}}
|
||||
</span>
|
||||
</template>
|
||||
</p>
|
||||
|
||||
<ul class="list-inline">
|
||||
<li v-for="category in s.el.categories" class="list-inline-item">
|
||||
<button class="badge bg-primary text-white" @click="filter = ':' + category">
|
||||
{{category}}
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p v-if="s.el.flags.length || s.el.images.length" class="text-center">
|
||||
<img v-for="flag in s.el.flags" :src="`/flags/${flag}.png`" class="flag m-1"/>
|
||||
<img v-for="image in s.el.images" :src="buildImageUrl(image, 'big')" class="flag m-1"/>
|
||||
</p>
|
||||
<Term :term="s.el" categoryLink flags versions/>
|
||||
|
||||
<div class="small" v-if="s.el.base && entries[s.el.base]">
|
||||
<p><strong><T>nouns.edited</T>:</strong></p>
|
||||
|
||||
<p>
|
||||
<strong><LinkedTextMultiple :texts="entries[s.el.base].term" noicons/></strong>
|
||||
<span v-if="entries[s.el.base].original.length">(<LinkedTextMultiple :texts="entries[s.el.base].original" glue="; " noicons/>)</span>
|
||||
– <LinkedText :text="entries[s.el.base].definition" noicons/>
|
||||
<template v-if="entries[s.el.base].category">
|
||||
<br/>
|
||||
<span class="badge bg-primary text-white">
|
||||
{{entries[s.el.base].category}}
|
||||
</span>
|
||||
</template>
|
||||
</p>
|
||||
|
||||
<ul class="list-inline">
|
||||
<li v-for="category in entries[s.el.base].categories" class="list-inline-item">
|
||||
<span class="badge bg-primary text-white">
|
||||
{{category}}
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
<Term :term="entries[s.el.base]" flags/>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
|
|
|
@ -49,7 +49,12 @@
|
|||
</div>
|
||||
|
||||
<div class="row" v-if="$isGranted('terms')">
|
||||
<div class="col-12 col-lg-6">
|
||||
<div class="col-12 col-lg-4">
|
||||
<label for="key"><strong><T>sources.submit.key</T></strong></label>
|
||||
<input type="text" id="key" class="form-control" v-model="form.key" maxlength="255"/>
|
||||
<p class="small text-muted"><T>sources.submit.keyInfo</T></p>
|
||||
</div>
|
||||
<div class="col-12 col-lg-4">
|
||||
<div class="form-group">
|
||||
<label class="text-nowrap"><strong>
|
||||
<T>profile.flags</T>
|
||||
|
@ -57,7 +62,7 @@
|
|||
<ListInput v-model="form.flags" v-slot="s"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 col-lg-6">
|
||||
<div class="col-12 col-lg-4">
|
||||
<div class="form-group">
|
||||
<label class="text-nowrap"><strong>
|
||||
<T>nouns.terms.images</T>
|
||||
|
@ -101,6 +106,7 @@
|
|||
form: {
|
||||
term: [''],
|
||||
original: [],
|
||||
key: '',
|
||||
definition: '',
|
||||
categories: [],
|
||||
flags: [],
|
||||
|
@ -121,6 +127,7 @@
|
|||
this.form = {
|
||||
term: [''],
|
||||
original: [],
|
||||
key: '',
|
||||
definition: '',
|
||||
categories: [],
|
||||
flags: [],
|
||||
|
@ -135,6 +142,7 @@
|
|||
this.form = {
|
||||
term: word.term,
|
||||
original: word.original,
|
||||
key: word.key,
|
||||
definition: word.definition,
|
||||
categories: word.categories,
|
||||
flags: word.flags,
|
||||
|
|
|
@ -21,30 +21,64 @@ const approve = async (db, id) => {
|
|||
await caches.terms.invalidate();
|
||||
}
|
||||
|
||||
const linkOtherVersions = async (req, terms) => {
|
||||
const keys = new Set(terms.filter(s => !!s && s.key).map(s => `'` + s.key + `'`));
|
||||
|
||||
const otherVersions = await req.db.all(SQL`
|
||||
SELECT t.*, u.username AS author FROM terms t
|
||||
LEFT JOIN users u ON t.author_id = u.id
|
||||
WHERE t.locale != ${global.config.locale}
|
||||
AND t.deleted = 0
|
||||
AND t.approved >= ${req.isGranted('terms') ? 0 : 1}
|
||||
AND t.key IN (`.append([...keys].join(',')).append(SQL`)
|
||||
`));
|
||||
|
||||
const otherVersionsMap = {};
|
||||
otherVersions.forEach(version => {
|
||||
if (otherVersionsMap[version.key] === undefined) {
|
||||
otherVersionsMap[version.key] = [];
|
||||
}
|
||||
otherVersionsMap[version.key].push(version);
|
||||
});
|
||||
|
||||
return terms.map(t => {
|
||||
t.versions = t.key ? otherVersionsMap[t.key] || [] : [];
|
||||
return t;
|
||||
});
|
||||
};
|
||||
|
||||
const router = Router();
|
||||
|
||||
router.get('/terms', handleErrorAsync(async (req, res) => {
|
||||
return res.json(await caches.terms.fetch(async () => {
|
||||
return sortClearedLinkedText(await req.db.all(SQL`
|
||||
SELECT i.*, u.username AS author FROM terms i
|
||||
LEFT JOIN users u ON i.author_id = u.id
|
||||
WHERE i.locale = ${global.config.locale}
|
||||
AND i.approved >= ${req.isGranted('terms') ? 0 : 1}
|
||||
AND i.deleted = 0
|
||||
`), 'term');
|
||||
return await linkOtherVersions(
|
||||
req,
|
||||
sortClearedLinkedText(await req.db.all(SQL`
|
||||
SELECT i.*, u.username AS author FROM terms i
|
||||
LEFT JOIN users u ON i.author_id = u.id
|
||||
WHERE i.locale = ${global.config.locale}
|
||||
AND i.approved >= ${req.isGranted('terms') ? 0 : 1}
|
||||
AND i.deleted = 0
|
||||
`), 'term'),
|
||||
);
|
||||
}, !req.isGranted('terms')));
|
||||
}));
|
||||
|
||||
router.get('/terms/search/:term', handleErrorAsync(async (req, res) => {
|
||||
const term = '%' + req.params.term + '%';
|
||||
return res.json(sortClearedLinkedText(await req.db.all(SQL`
|
||||
SELECT i.*, u.username AS author FROM terms i
|
||||
LEFT JOIN users u ON i.author_id = u.id
|
||||
WHERE i.locale = ${global.config.locale}
|
||||
AND i.approved >= ${req.isGranted('terms') ? 0 : 1}
|
||||
AND i.deleted = 0
|
||||
AND (i.term like ${term} OR i.original like ${term})
|
||||
`)), 'term');
|
||||
return res.json(
|
||||
await linkOtherVersions(
|
||||
req,
|
||||
sortClearedLinkedText(await req.db.all(SQL`
|
||||
SELECT i.*, u.username AS author FROM terms i
|
||||
LEFT JOIN users u ON i.author_id = u.id
|
||||
WHERE i.locale = ${global.config.locale}
|
||||
AND i.approved >= ${req.isGranted('terms') ? 0 : 1}
|
||||
AND i.deleted = 0
|
||||
AND (i.term like ${term} OR i.original like ${term})
|
||||
`), 'term'),
|
||||
)
|
||||
);
|
||||
}));
|
||||
|
||||
router.post('/terms/submit', handleErrorAsync(async (req, res) => {
|
||||
|
@ -58,10 +92,10 @@ router.post('/terms/submit', handleErrorAsync(async (req, res) => {
|
|||
|
||||
const id = ulid();
|
||||
await req.db.get(SQL`
|
||||
INSERT INTO terms (id, term, original, definition, approved, base_id, locale, author_id, category, flags, images)
|
||||
INSERT INTO terms (id, term, original, key, definition, approved, base_id, locale, author_id, category, flags, images)
|
||||
VALUES (
|
||||
${id},
|
||||
${req.body.term.join('|')}, ${req.body.original.join('|')}, ${req.body.definition},
|
||||
${req.body.term.join('|')}, ${req.body.original.join('|')}, ${req.body.key || null}, ${req.body.definition},
|
||||
0, ${req.body.base}, ${global.config.locale}, ${req.user ? req.user.id : null},
|
||||
${req.body.categories.join(',')}, ${JSON.stringify(req.body.flags)}, ${req.body.images}
|
||||
)
|
||||
|
|
|
@ -719,10 +719,11 @@ export class InclusiveEntry {
|
|||
}
|
||||
|
||||
export class TermsEntry {
|
||||
constructor({id, term, original, definition, author, category = null, flags = '[]', images = '', approved = true, base_id = null}) {
|
||||
constructor({id, term, original, key = null, definition, author, category = null, flags = '[]', images = '', approved = true, base_id = null, locale, versions = []}) {
|
||||
this.id = id;
|
||||
this.term = term.split('|');
|
||||
this.original = original ? original.split('|') : [];
|
||||
this.key = key || null;
|
||||
this.definition = definition;
|
||||
this.author = author;
|
||||
this.categories = category ? category.split(',') : [];
|
||||
|
@ -730,6 +731,8 @@ export class TermsEntry {
|
|||
this.images = images ? images.split(',') : [];
|
||||
this.approved = !!approved;
|
||||
this.base = base_id;
|
||||
this.locale = locale;
|
||||
this.versions = versions.map(v => new TermsEntry(v));
|
||||
}
|
||||
|
||||
matches(filter) {
|
||||
|
|
Reference in New Issue