253 lines
8.5 KiB
Svelte
253 lines
8.5 KiB
Svelte
<script>
|
||
import {
|
||
Badge,
|
||
Button,
|
||
Icon,
|
||
Spinner,
|
||
} from '@sveltestrap/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] === null || !String(v[i]).length) {
|
||
v.splice(i, 1);
|
||
}
|
||
}
|
||
}
|
||
|
||
// Sort cells (case doesn't count in sort)
|
||
if (flag.ignore_order) {
|
||
v = v.sort((a,b) => {
|
||
const aUC = String(a).toUpperCase();
|
||
const bUC = String(b).toUpperCase();
|
||
if (aUC < bUC) {
|
||
return -1;
|
||
}
|
||
if (aUC > bUC) {
|
||
return 1;
|
||
}
|
||
|
||
return 0;
|
||
});
|
||
}
|
||
|
||
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} pts
|
||
</div>
|
||
{/if}
|
||
{#if !no_label}
|
||
<label for="sol_{flag.type}{flag.id}_0">{flag.label} :</label>
|
||
{/if}
|
||
{#if !flag.found && !$settings.hideCaseSensitivity && !flag.ignore_case}
|
||
<Badge
|
||
class="float-end"
|
||
color="danger"
|
||
title="Ce flag est sensible à la casse !"
|
||
>
|
||
aA
|
||
</Badge>
|
||
{/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 if value}
|
||
<input
|
||
class="form-control is-valid"
|
||
disabled
|
||
id="sol_{flag.type}{flag.id}_0"
|
||
type="text"
|
||
title="Flag trouvé à {flag.found}"
|
||
value={value}
|
||
>
|
||
{:else}
|
||
<Icon
|
||
name="check"
|
||
class="form-control-feedback text-success"
|
||
aria-hidden="true"
|
||
title="Flag trouvé à {flag.found}"
|
||
/>
|
||
{/if}
|
||
</div>
|