Skip to content
Extraits de code Groupes Projets
Valider 0c3ad2e6 rédigé par Maïeul's avatar Maïeul
Parcourir les fichiers

fix(#331): ajuster le libellé de l'étape suivante en fonction des `afficher_si`

Pour cela on met un attribut html `data-resume_etapes_futures` sur le `<form>`.

Ce résumé est envoyé au squelette sous forme de tableau PHP, puis converti en JSON.

Il est calculé dynamiquement en fonction des options globales du
squelette.

Cet attribut sert également pour le calcul des `afficher_si` des étapes
suivantes dans le fil d'ariane des étapes, ainsi que pour le calcul du
nombre total d'étape. On supprime par conséquent les attributs
`data-afficher_si` sur les `<li>` d'étape et
`data-afficher_si-etapes-futures` sur le `div.formulaire_spip__etapes--courante`.

On simplifie (et debug) le code squelette de masquage des étapes passées
qui ne répondaient pas aux `afficher_si`.

On ajuste le JS en conséquent.

fix #331
parent 4fcc2a56
Aucune branche associée trouvée
Aucune étiquette associée trouvée
Aucune requête de fusion associée trouvée
<p class="boutons" [ data-afficher_si="(#ENV*{_saisies/options/afficher_si_submit}|saisies_afficher_si_js{#ENV{_saisies}})"]>
<span class="image_loading"></span>
[(#SET{label_valider, #ENV*{_saisies/options/texte_submit, #ENV*{saisies_texte_submit, <:bouton_enregistrer:>}}})]
#SET{label_enregistrer,#GET{label_valider}}
[(#ENV{_etape}|et{#ENV{_etape}|!={#ENV{_etapes}}}|oui)
[(#SET{label_valider, #ENV*{_saisies/options/etapes_suivant, <:bouton_suivant:>}})]
[(#ENV*{_saisies/options/etapes_precedent_suivant_titrer}|oui)
#SET{etape,#ENV*{_saisies_par_etapes/etape_#VAL{#ENV{_etape}|plus{1}}}
[(#SET{etape_suivante_titre,#INCLURE{
......@@ -13,12 +12,11 @@
label=#GET{etape/options/label},
icone=#GET{etape/options/icone},
taille_icone=#GET{etape/options/taille_icone}
}|sinon{<:saisies:etapes_recapitulatif_label:>}})]
}|sinon{<:saisies:etapes_recapitulatif_label:>}})]
#SET{label_valider,#GET{label_valider}|trim|label_ponctuer|concat{' ',#GET{etape_suivante_titre}|wrap{'<span class="titre-etape">'}}}
]
]
[(#ENV{_etape}|>{1}|oui)
[(#SET{label_precedent,#ENV*{_saisies/options/etapes_precedent, <:precedent|ucfirst:>}})]
[(#ENV*{_saisies/options/etapes_precedent_suivant_titrer}|oui)
......@@ -33,5 +31,5 @@
]
<button type="submit" class="submit submit_precedent" name="aller_a_etape" value="[(#ENV{_saisies}|saisies_determiner_recul_rapide{#ENV{_etape}})]"><span class="btn__label">[(#GET{label_precedent}|_T_ou_typo)]</span></button>
]
<button type="submit" class="submit[ (#ENV{_etapes}|?{submit_suivant,submit_main})]" value="1"><span class="btn__label">[(#GET{label_valider}|_T_ou_typo)]</span></button>
<button type="submit" class="submit[ (#ENV{_etapes}|?{submit_suivant,submit_main})]" value="1" data-label_enregistrer="#GET{label_enregistrer}"><span class="btn__label">[(#GET{label_valider}|_T_ou_typo)]</span></button>
</p>
......@@ -25,19 +25,17 @@
]
[(#REM) Mettre toutes les étapes futures]
[(#GET{etape_courante}|>{#ENV{_etape}}|oui)
[(#VALEUR{options/afficher_si}|oui)
#SET{afficher_si,#GET{afficher_si}|array_merge{#ARRAY{#CLE,#VAL{&quot;}|str_replace{'"',#VALEUR{options/afficher_si}|saisies_afficher_si_js{#ENV{etapes}}}}}}
]
#SET{etapes_max,#GET{etapes_max}|plus{1}}
]
</BOUCLE_etapes>
#SET{params, #ARRAY{
'etape',<span class="formulaire_spip_etape__courante">#GET{etape_a_afficher}</span>,
'etapes', <span class="formulaire_spip_etape__total">#GET{etapes_max}</span>,
'label_etape',#GET{etape_a_afficher_label}
}
}
<div class="formulaire_spip__etapes etapes formulaire_spip__etapes--courante" [data-afficher_si-etapes-futures="(#VAL{'"'}|str_replace{'&quot;', #GET{afficher_si}|json_encode})"] data-etapes_max="#GET{etapes_max}">
<div class="formulaire_spip__etapes etapes formulaire_spip__etapes--courante" data-etapes_max="#GET{etapes_max}">
[(#VAL{saisies:cvt_etapes_courante}|_T{#GET{params}})]
</div>
</B_etapes>
......@@ -5,15 +5,12 @@
<BOUCLE_etapes(DATA){source table, #ENV{etapes}}>
#SET{etape,#CLE|replace{etape_,''}}
#SET{afficher_si,#VALEUR{options/afficher_si}|saisies_afficher_si_js{#ENV{etapes}}}
#SET{afficher,non}
[(#VALEUR|in_any{#GET{afficher_si_masquees}}|non|ou{#ENV{_etape}|<{#GET{etape}}})
#SET{afficher,oui}
[(#GET{afficher_si}|saisies_afficher_si_js_est_statique|oui)
#SET{afficher,#GET{afficher_si}|saisies_evaluer_afficher_si}
]
#SET{afficher,oui}
[(#VALEUR|in_any{#GET{afficher_si_masquees}}|oui)
#SET{afficher,''}
]
[(#GET{afficher}|oui)
<li [data-afficher_si="(#GET{afficher_si})"] class="etapes__item"[(#ENV{_etape}|=={#GET{etape}}|oui) aria-current="step"]>
<li class="etapes__item #CLE" [(#ENV{_etape}|=={#GET{etape}}|oui) aria-current="step"]>
#SET{label_etape,#INCLURE{
fond=inclure/fieldset_legend,
label=#VALEUR{options/label},
......
......@@ -3,7 +3,7 @@
[<p class="reponse_formulaire reponse_formulaire_ok"[(#HTML5|oui) role="status"]>(#ENV**{message_ok})</p>]
[<p class="reponse_formulaire reponse_formulaire_erreur"[(#HTML5|oui) role="alert"]>(#ENV**{message_erreur})</p>]
[(#ENV{editable}|oui)
<form method="post" action="#ENV{action}" enctype="multipart/form-data"><div>
<form method="post" action="#ENV{action}" enctype="multipart/form-data"[ data-resume_etapes_futures="(#ENV{_resume_etapes_futures}|json_encode|attribut_html)"]><div>
[(#REM) declarer les hidden qui declencheront le service du formulaire
parametre : url d'action ]
#ACTION_FORMULAIRE{#ENV{action}}
......
......@@ -114,3 +114,4 @@ function saisies_afficher_si_js_est_statique($test) {
return true;
}
}
......@@ -124,3 +124,47 @@ function saisies_determiner_deplacement_rapide(array $saisies, int $etape, int $
}
return $i;
}
/**
* Retourne un résumé des étapes futures (qu'elles s'afficheront finalement ou pas).
* @param array $etapes liste des étapes (sous forme de tableau de saisies)
* @param int $etape etape courante
* @param array $options_demandees tableau décrivant les options qu'on demande
* @return array [
* 'etape_n' => ['info_x' => 'valeur_x', 'info_y' => 'valeur_y' …]
* …
* ]
**/
function saisies_resumer_etapes_futures(array $etapes, int $etape, array $options_demandees): array {
$return = [];
foreach ($etapes as $e => $description) {
$numero_etape = intval(str_replace('etape_', '', $e));
if ($numero_etape > $etape) {
$output_etape = [];
foreach ($options_demandees as $option) {
if (isset($description['options'][$option])) {
$output_etape[$option] = $description['options'][$option];
}
}
$return[$e] = $output_etape;
}
}
return $return;
}
/**
* Détermine quels options d'étapes sont utiles au résumé des étapes futures
* En fonction des options globales du formulaire
* @param array $options_globales optiosn globales du formulaire
* @return array liste des options à garder
**/
function saisies_determiner_options_demandees_resumer_etapes_futures(array $options_globales): array {
$options = ['afficher_si'];// on veut dans tous les cas les afficher_si
if (in_array($options_globales['etapes_precedent_suivant_titrer'] ?? '', ['on', true], true)) {
$options[] = 'label';
}
return $options;
}
......@@ -6,11 +6,13 @@ afficher_si_current_data = '';
function afficher_si_init() {
$('form:not([data-afficher_si-init])').each(function(){
// Seulement si au moins un afficher_si dedans !
if ($(this).find('[data-afficher_si]').length !== 0 || $(this).find('[data-afficher_si-etapes-futures]') !== 0) {
if ($(this).find('[data-afficher_si]').length !== 0 || $(this).find('[data-resume_etapes_futures]') !== 0) {
form = $(this);
form.find('.formulaire_spip__etapes').each(function() {
$(this).css('min-height', $(this).height());
});
afficher_si_init_chemin_etapes(form);
afficher_si_set_current_data(form);
form.find('[data-afficher_si]').each(function(){
condition = verifier_afficher_si($(this), true);
......@@ -18,6 +20,7 @@ function afficher_si_init() {
}
);
afficher_si_set_etapes_presentation_courante(form);
afficher_si_set_etape_suivante(form);
// Un écouteur sur la modif de tous les champs de ce form
$(this).find('textarea, input, select').change(function(){
......@@ -34,6 +37,7 @@ function afficher_si_init() {
animer_afficher_si($(this), condition);
})
afficher_si_set_etapes_presentation_courante(form, name);
afficher_si_set_etape_suivante(form, name);
}
});
$(this).attr('data-afficher_si-init', true);
......@@ -167,11 +171,14 @@ function afficher_si(args) {
//@param form, le formulaire
//@param name le nom de la saisie dont la valeur vient juste de changer
function afficher_si_set_etapes_presentation_courante(form, name='') {
form.find('.formulaire_spip__etapes--courante[data-afficher_si-etapes-futures]').each(function() {
afficher_si_etapes = JSON.parse($(this).attr('data-afficher_si-etapes-futures'));
etape_total = $(this).attr('data-etapes_max');
for (etape in afficher_si_etapes) {
condition = afficher_si_etapes[etape];
var etapes = afficher_si_parse_data_etapes_futures(form);
if (!etapes) {
return;
}
form.find('[data-etapes_max]').each(function() {
var etape_total = $(this).attr('data-etapes_max');
for (etape in etapes) {
var condition = etapes[etape]['afficher_si'] ?? 'true';
if (!name || condition.includes(name)) {
$(this).attr('data-' + etape, eval(condition));
}
......@@ -182,3 +189,60 @@ function afficher_si_set_etapes_presentation_courante(form, name='') {
$(this).find('.formulaire_spip_etape__total').text(etape_total);
});
}
// Pour le libellé de l'étape suivante
//@param form, le formulaire
//@param name le nom de la saisie dont la valeur vient juste de changer
function afficher_si_set_etape_suivante(form, name) {
var etapes = afficher_si_parse_data_etapes_futures(form);
if (!etapes) {
return;
}
var label_enregistrer = form.find('button.submit_suivant').attr('data-label_enregistrer');
var titre_retenu = label_enregistrer;
// Chercher la première future étape
for (etape in etapes) {
var afficher_si_etape = etapes[etape]['afficher_si'] ?? 'true';
if (eval(afficher_si_etape)) {
titre_retenu = etapes[etape]['label'];
break;
}
}
form.find('button.submit_suivant').each(function() {
var $span = $(this).find('.btn__label');
// Stocker le modèle pour suivant, si pas deja fait
if (!$(this).attr('data-modele')) {
$(this).attr('data-modele', $span.html());
}
// Puis ajuster le titre, le modèle variant selon que nous passons directement à la validation ou pas
if (titre_retenu == label_enregistrer) {
$span.html(titre_retenu);
} else {
$span.html($(this).attr('data-modele'));
$span.find('.titre-etape').html(titre_retenu);
}
});
}
// Recopier les info d'afficher_si présente dans [data-resume_etapes_futures] au sein de chaque etapes futures
// Le but est de simplifier ainsi le code principal, en se contentant du code de animer_afficher_si()
// @param jquery obcet form
function afficher_si_init_chemin_etapes(form) {
var etapes = afficher_si_parse_data_etapes_futures(form);
if (!etapes) {
return;
}
for (etape in etapes) {
var afficher_si_etape = etapes[etape]['afficher_si'] ?? '';
if (afficher_si_etape) {
form.find('.etapes__item.' + etape).attr('data-afficher_si', afficher_si_etape);
}
}
}
function afficher_si_parse_data_etapes_futures(form) {
var data = form.attr('data-resume_etapes_futures');
if (!data) {
return;
}
var etapes = JSON.parse(data);
return etapes;
}
......@@ -169,8 +169,21 @@ function saisies_formulaire_charger($flux) {
if ($etapes = saisies_lister_par_etapes($saisies)) {
$flux['data']['_etapes'] = count($etapes);
$flux['data']['_saisies_par_etapes'] = $etapes;
}
// Construction du tableau resumé des étapes futures
$options_resume = saisies_determiner_options_demandees_resumer_etapes_futures($saisies['options']);
$resume_etapes_futures = saisies_resumer_etapes_futures($etapes, _request('_etape') ?? 1, $options_resume);
// Convertir les afficher_si en code JS
$resume_etapes_futures = array_map(function ($i) use ($etapes) {
if (!isset($i['afficher_si'])) {
return $i;
}
$i['afficher_si'] = saisies_afficher_si_js($i['afficher_si'], $etapes);
$i['afficher_si'] = str_replace('&quot;', '"', $i['afficher_si']);// Pour éviter que les &quot; soit à nouveau encodé par json_encode, ce qui fout la merde au decodage en JS
return $i;
}, $resume_etapes_futures);
$flux['data']['_resume_etapes_futures'] = $resume_etapes_futures;
}
// On ajoute le tableau complet des saisies
$flux['data']['_saisies'] = $saisies;
......
......@@ -11,6 +11,8 @@ use PHPUnit\Framework\Attributes\RunInSeparateProcess;
* @covers saisies_determiner_deplacement_rapide()
* @covers saisies_determiner_avance_rapide()
* @covers saisies_determiner_recul_rapide()
* @covers saisies_resumer_etapes_futures()
* @covers saisies_determiner_options_demandees_resumer_etapes_futures()
* @uses saisies_lister_champs()
* @uses saisies_lister_par_nom()
* @uses saisies_lister_par_etapes()
......@@ -208,4 +210,208 @@ class FormulaireTest extends TestCase {
$this->assertTrue(True);
}
}
static public function dataResumerEtapesFutures(): array {
return [
'avec_titre' => [
// Expected
[
'etape_3' => [
'afficher_si' => '@toto@ == "hop"',
'label' => 'etape 3',
],
'etape_4' => [
'afficher_si' => 'false',
'label' => 'etape 4',
],
'etape_5' => [
'afficher_si' => 'true',
'label' => 'etape 5',
],
],
// Etapes
[
'etape_1' => [
'options' => [
'label' => 'etape 1',
'afficher_si' => 'false',
],
'saisies' => []
],
'etape_2' => [
'options' => [
'label' => 'etape 2',
'icone' => 'etape2.svg',
'taille_icone' => '16px'
],
'saisies' => [
[
'saisie' => 'input',
'options' => [
'nom' => 'toto',
]
]
]
],
'etape_3' => [
'options' => [
'label' => 'etape 3',
'icone' => 'etape3.svg',
'taille_icone' => '16px',
'afficher_si' => '@toto@ == "hop"',
],
'saisies' => []
],
'etape_4' => [
'options' => [
'label' => 'etape 4',
'afficher_si' => 'false',
'icone' => 'etape4.svg',
'taille_icone' => '16px'
],
'saisies' => []
],
'etape_5' => [
'options' => [
'label' => 'etape 5',
'afficher_si' => 'true',
'icone' => 'etape5.svg',
'taille_icone' => '16px'
],
'saisies' => []
]
],
// Etape
2,
// Options demandées
[
'afficher_si',
'label'
]
],
'sans_titre' => [
// Expected
[
'etape_3' => [
'afficher_si' => '@toto@ == "hop"',
],
'etape_4' => [
'afficher_si' => 'false',
],
'etape_5' => [
'afficher_si' => 'true',
],
],
// Etapes
[
'etape_1' => [
'options' => [
'label' => 'etape 1',
'afficher_si' => 'false',
],
'saisies' => []
],
'etape_2' => [
'options' => [
'label' => 'etape 2',
'icone' => 'etape2.svg',
'taille_icone' => '16px'
],
'saisies' => [
[
'saisie' => 'input',
'options' => [
'nom' => 'toto',
]
]
]
],
'etape_3' => [
'options' => [
'label' => 'etape 3',
'icone' => 'etape3.svg',
'taille_icone' => '16px',
'afficher_si' => '@toto@ == "hop"',
],
'saisies' => []
],
'etape_4' => [
'options' => [
'label' => 'etape 4',
'afficher_si' => 'false',
'icone' => 'etape4.svg',
'taille_icone' => '16px'
],
'saisies' => []
],
'etape_5' => [
'options' => [
'label' => 'etape 5',
'afficher_si' => 'true',
'icone' => 'etape5.svg',
'taille_icone' => '16px'
],
'saisies' => []
]
],
// Etape
2,
// Options demandeées
[
'afficher_si'
]
]
];
}
/**
* @dataProvider dataResumerEtapesFutures
* @uses saisies_afficher_si_evaluer_plugin()
* @uses saisies_afficher_si_secure()
* @uses saisies_afficher_si_verifier_syntaxe()
* @uses saisies_lister_par_nom()
* @uses saisie_nom2name()
* @uses saisies_afficher_si_js_defaut()
* @uses saisies_evaluer_afficher_si()
**/
public function testResumerEtapesFutures(array $expected, array $etapes, int $etape, array $options_demandees): void {
$actual = saisies_resumer_etapes_futures($etapes, $etape, $options_demandees);
$this->assertSame($expected, $actual);
}
static function dataDeterminerOptionsDemandeesResumerEtapesFutures() {
return [
'standard' => [
// Expected
['afficher_si'],
// Provided
[]
],
'etapes_precedent_suivant_titrer_on' => [
// Expected
['afficher_si', 'label'],
// Provided
['etapes_precedent_suivant_titrer' => 'on']
],
'etapes_precedent_suivant_titrer_true' => [
// Expected
['afficher_si', 'label'],
// Provided
['etapes_precedent_suivant_titrer' => true]
],
'etapes_precedent_suivant_titrer_off' => [
// Expected
['afficher_si'],
// Provided
['etapes_precedent_suivant_titrer' => '']
],
];
}
/**
@dataProvider dataDeterminerOptionsDemandeesResumerEtapesFutures
*/
public function testDeterminerOptionsDemandeesResumerEtapesFutures($expected, $provided) {
$actual = saisies_determiner_options_demandees_resumer_etapes_futures($provided);
$this->assertEquals($expected, $actual);
}
}
......@@ -314,6 +314,14 @@ if (!function_exists('find_all_in_path')) {
}
}
if (!function_exists('recuperer_fond')) {
// Pour récuperer fond, on envoi un tableau qui donne le nom et les args du fond
function recuperer_fond(string $nom, array $contexte): array{
return ['nom' => $nom, 'contexte' => $contexte];
}
}
/**
* Mock pour la fonction de translitteration
* Cette fonction n'est utilisé que pour des tri alphab accentué
......
0% Chargement en cours ou .
You are about to add 0 people to the discussion. Proceed with caution.
Terminez d'abord l'édition de ce message.
Veuillez vous inscrire ou vous pour commenter