server/frontend/fic/src/lib/components/FlagKey.svelte

226 lines
7.8 KiB
Svelte

<script>
import {
Button,
Icon,
Spinner,
} from 'sveltestrap';
import { tick } from 'svelte';
import { my } from '$lib/stores/my.js';
import { settings } from '$lib/stores/settings.js';
export { className as class };
let className = '';
export let exercice_id = 0;
export let flag = { };
export let no_label = false;
export let value = "";
let values = [""];
function waitChoices(i) {
my.refresh((my) => {
let haveChoices = false;
if (my && my.exercices[exercice_id].flags) {
my.exercices[exercice_id].flags.forEach((f) => {
if (f.id == flag.id && f.choices) {
haveChoices = true;
}
})
}
if (haveChoices) {
wcsubmitted = false;
} else if (i > 0) {
setTimeout(waitChoices, 450, i-1);
}
})
}
let wcsubmitted = false;
async function wantchoices() {
if (!confirm("Êtes-vous sûr de vouloir utiliser " + (flag.choices_cost * $settings.wchoiceCurrentCoefficient) + " points pour avoir une liste de propositions à la place de ce champ de texte à compléter ?")) {
return;
}
wcsubmitted = true;
const response = await fetch(
"wantchoices/" + exercice_id,
{
method: "POST",
headers: {'Accept': 'application/json'},
body: JSON.stringify({ id: Number(flag.id) }),
}
)
if (response.status < 300) {
waitChoices(15);
} else {
wcsubmitted = false;
}
}
function addItem() {
values.push("");
values = values;
}
$: {
let v = values.slice();
// Remove empty cells
if (!flag.nb_lines) {
for (let i = v.length - 1; i > 0; i--) {
if (!v[i].length) {
v.splice(i, 1);
}
}
}
// Sort cells
if (flag.ignore_order) {
v = v.sort();
}
value = v.join(flag.separator ? flag.separator : ',');
if (flag.separator) {
value += flag.separator;
}
}
$: {
if (flag.nb_lines) {
while (values.length != flag.nb_lines) {
if (values.length > flag.nb_lines) {
values.pop();
} else {
values.push("");
}
}
}
}
</script>
<div class={className + " form-group"}>
{#if flag.bonus_gain}
<div class={'float-end badge bg-' + (flag.found?'success':'danger')} title={'Ce flag est optionnel, si vous le complétez il vous rapportera ' + flag.bonus_gain + ' points supplémentaires'}>
optionnel | {#if flag.bonus_gain > 0}+{/if}{flag.bonus_gain}&nbsp;pts
</div>
{/if}
{#if !no_label}
<label for="sol_{flag.type}{flag.id}_0">{flag.label}&nbsp;:</label>
{/if}
{#if flag.found && flag.value}
<span>{flag.value}</span>
{/if}
{#if !flag.found}
{#each values as v, index}
{#if !flag.choices}
<div class="input-group" class:mt-1={index != 0}>
{#if flag.type == 'number'}
<input
type="number"
class="form-control flag"
id="sol_{flag.type}{flag.id}_{index}"
autocomplete="off"
bind:value={values[index]}
placeholder={flag.placeholder}
title={flag.placeholder}
min={flag.min}
max={flag.max}
step={flag.step}
>
{:else if !flag.multiline}
<input
type="text"
class="form-control flag"
id="sol_{flag.type}{flag.id}_{index}"
autocomplete="off"
bind:value={values[index]}
placeholder={flag.placeholder}
title={flag.placeholder}
on:keydown={(e) => {if (flag.separator && e.keyCode === 13) { e.preventDefault(); addItem(); tick().then(() => { document.getElementById('sol_' + flag.type + '' + flag.id + '_' + (values.length - 1)).focus(); }); return false;}}}
>
{:else}
<textarea
class="form-control flag"
id="sol_{flag.type}{flag.id}_{index}"
autocomplete="off"
bind:value={values[index]}
placeholder="{flag.placeholder}"
title="{flag.placeholder}"
></textarea>
{/if}
{#if flag.unit}
<span class="input-group-text">{flag.unit}</span>
{/if}
{#if flag.choices_cost > 0}
<Button
color="success"
type="button"
on:click={wantchoices}
disabled={wcsubmitted || $settings.disablesubmitbutton}
title="Cliquez pour échanger ce champ de texte par une liste de choix. L'opération vous coûtera {flag.choices_cost * $settings.wchoiceCurrentCoefficient} points."
>
{#if wcsubmitted}
<Spinner size="sm" class="me-2" />
{/if}
<Icon name="list-task" />
Liste de propositions ({flag.choices_cost * $settings.wchoiceCurrentCoefficient} {flag.choices_cost * $settings.wchoiceCurrentCoefficient===1?"point":"points"})
</Button>
{:else if flag.separator && !flag.nb_lines && index == values.length - 1}
<Button
color="success"
type="button"
title="Ajouter un élément."
on:click={addItem}
>
<Icon name="plus" />
</Button>
{/if}
</div>
{:else if flag.type == 'radio'}
{#each Object.keys(flag.choices) as l, i}
<div class="form-check">
<input
id="sol_{flag.type}{flag.id}_{index}_{i}"
type="radio"
value={l}
bind:group={values[index]}
class="form-check-input"
>
<label
class="form-check-label"
for="sol_{flag.type}{flag.id}_{index}_{i}"
>
{flag.choices[l]}
</label>
</div>
{/each}
{:else}
<select
class="form-select"
id="sol_{flag.type}{flag.id}_{index}"
bind:value={values[index]}
>
{#each Object.keys(flag.choices) as l}
<option value={l}>{flag.choices[l]}</option>
{/each}
</select>
{/if}
{/each}
{#if flag.help}
<small class="form-text text-muted">{@html flag.help}</small>
{/if}
{:else}
<Icon
name="check"
class="form-control-feedback text-success"
aria-hidden="true"
title="Flag trouvé à {flag.found}"
/>
{/if}
</div>