diff --git a/formulaires/inc-saisies-cvt-boutons.html b/formulaires/inc-saisies-cvt-boutons.html index b7528f52225a699b263ceb1a7d9c0eed0b97cb45..3e747d048aa382ecb54bc87e427986b3547c5524 100644 --- a/formulaires/inc-saisies-cvt-boutons.html +++ b/formulaires/inc-saisies-cvt-boutons.html @@ -1,11 +1,10 @@ <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> diff --git a/formulaires/inc-saisies-cvt-etapes-courante.html b/formulaires/inc-saisies-cvt-etapes-courante.html index 7875d73f7c0b0ff0638777d640f80162922dfa52..b0389d2cbcaf05e4f8a50a03558b918b470b1a80 100644 --- a/formulaires/inc-saisies-cvt-etapes-courante.html +++ b/formulaires/inc-saisies-cvt-etapes-courante.html @@ -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{"}|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{'"', #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> diff --git a/formulaires/inc-saisies-cvt-etapes-defaut.html b/formulaires/inc-saisies-cvt-etapes-defaut.html index c784fe3d9d94c6bd058be1a474b994403c528bb9..4d10af7d136142ef29a690795bd85ea3a675a912 100644 --- a/formulaires/inc-saisies-cvt-etapes-defaut.html +++ b/formulaires/inc-saisies-cvt-etapes-defaut.html @@ -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}, diff --git a/formulaires/inc-saisies-cvt.html b/formulaires/inc-saisies-cvt.html index 8f16e9d113b2fb3502d65430ec20d850f8377793..39faf0579fc271ea80f0d761133e9bfa45153e3c 100644 --- a/formulaires/inc-saisies-cvt.html +++ b/formulaires/inc-saisies-cvt.html @@ -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}} diff --git a/inc/saisies_afficher_si_js.php b/inc/saisies_afficher_si_js.php index 9c6f5c000e6df345e938251219f693b1a029ce13..522de1d0e87a5cf3ee05c9f21e89035a37ec9f7d 100644 --- a/inc/saisies_afficher_si_js.php +++ b/inc/saisies_afficher_si_js.php @@ -114,3 +114,4 @@ function saisies_afficher_si_js_est_statique($test) { return true; } } + diff --git a/inc/saisies_formulaire.php b/inc/saisies_formulaire.php index 8c2ee2704b8b470f5dd3e3e0b18437b71d9d06f5..e1b1eed32635d63ce79c2e82706e6b5ca1df9325 100644 --- a/inc/saisies_formulaire.php +++ b/inc/saisies_formulaire.php @@ -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; +} diff --git a/javascript/saisies_afficher_si.js b/javascript/saisies_afficher_si.js index a79238340b42587a41904805499aba62fac30343..7b977c998ea626c5b2c44e35bc418ca31e3426b2 100644 --- a/javascript/saisies_afficher_si.js +++ b/javascript/saisies_afficher_si.js @@ -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; +} diff --git a/saisies_pipelines.php b/saisies_pipelines.php index 0661c7e2df8df413fe80420b11321d7b02969d6b..59b2d8fa87da163a19ea3dd3ba603b800a4acfb0 100644 --- a/saisies_pipelines.php +++ b/saisies_pipelines.php @@ -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('"', '"', $i['afficher_si']);// Pour éviter que les " 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; diff --git a/tests/FormulaireTest.php b/tests/FormulaireTest.php index cc155a87e130915ab7facc8b5fabe3f1081a173d..4c492fd1485d7ca5c76073c33759b017def4ef4b 100644 --- a/tests/FormulaireTest.php +++ b/tests/FormulaireTest.php @@ -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); + } } diff --git a/tests/bootstrap.php b/tests/bootstrap.php index a79ecba8415498f31d5d41a33761ad2398b14311..18dfb75b818c932b984956e8f5eeab4f537048cc 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -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é