Permission is granted to copy, distribute and/or modify this document
   under the terms of the GNU Free Documentation License, Version 1.3
   or any later version published by the Free Software Foundation;
   with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
   A copy of the license is included in the section entitled "GNU
   Free Documentation License".

# Javascript functions

Some function may be useful to manipulate elements on the page.

###### Show-hide elements according to a form state

The module ``ShowHide`` will allow you to show/hide part of your page using a specific test.

This must be use inside a javascript module.

## Usage

In this module, the module will listen to all input given in the ``container_from`` div, and will show or hide the content of the ``container_target`` according to the result of the ``test`` function.

		<div id="container_from">
			{{ form_row(form.accompagnementRQTHDate) }}
		</div>
		
		<div id="container_target">
			{{ form_row(form.accompagnementComment) }}
		</div>

    import { ShowHide } from 'ShowHide/show_hide.js';

    var 
        from = document.getElementById("container_from"),
        target = document.getElementById("container_target")
        ;

    new ShowHide({
        froms: [from], // the value of from should be an iterable
        container: [target], // the value of container should be an iterable
        test: function(froms, event) {
            // iterate over each element of froms
            for (let f of froms.values()) {
                // get all input inside froms
                for (let input of f.querySelectorAll('input').values()) {
                    if (input.value === 'autre') {
                        return input.checked;
                    }
                }
            }

            return false;
        }
    });

Once instantiated, the class ``ShowHide`` will:

1. get all input from each element inside the ``froms`` values
2. attach an event listener (by default, ``change``) to each input inside each entry in ``froms``
3. each time the event is fired, launch the function ``test``
4. show the element in the container given in ``container``, if the result of ``test`` is true, or hide them otherwise.

The test is also launched when the page is loaded.

## Show/hide while the user enter data: using the ``input`` event

One can force to use another event on the input elements, instead of the default ``'change'`` event. 

For achieving this, use the `event_name` option.

    new ShowHide({
        froms: froms,
        test: test_function,
        container: containers ,
        // using this option, we use the event `input` instead of `change`
        event_name: 'input'
    });

### Examples

   :language: javascript

## Using Show/Hide in collections forms

Using show / hide in collection forms implies: 

* to launch show/hide manually for each entry when the page is loaded ; 
* to catch when an entry is added to the form ;

As the show/hide is started manually and not on page load, we add the option ``load_event: null`` to the options: 

   new ShowHide({
     load_event: null,
     froms: [ from ],
     container: [ container ],
     test: my_test_function
   });

   When using ``load_event: null`` inside the options, the value of event will be ``null`` as second argument for the test function.

   ```javascript
      my_test_function(froms, event) {
          // event will be null on first launch
      }
```

Example usage: here, we would like to catch for element inside a CV form, where the user may add multiple formation entries.

   import { ShowHide } from 'ShowHide/show_hide.js';

   // we factorize the creation of show hide element in this function.
   var make_show_hide = function(entry) {
       let
           obtained = entry.querySelector('[data-diploma-obtained]'),
           reconnue = entry.querySelector('[data-diploma-reconnue]')
       ;
       new ShowHide({
           load_event: null,
           froms: [ obtained ],
           container: [ reconnue ],
           test: my_test_function
       });
   };

   // this code is fired when an entry is added on the page
   window.addEventListener('collection-add-entry', function(e) {
       // if the form contains multiple collection, we filter them here:
       if (e.detail.collection.dataset.collectionName === 'formations') {
           make_show_hide(e.detail.entry);
       }
   });

   // on page load, we create a show/hide 
   window.addEventListener('load', function(_e) {
       let
           formations = document.querySelectorAll('[data-formation-entry]')
           ;

       for (let f of formations.values()) {
           make_show_hide(f);
       }
   });

## Handling encapsulated show/hide elements

This module allow to handle encapsulated show/hide elements. For instance :

* in a first checkbox list, a second checkbox list is shown if some element is checked ;
* in this second checkbox list, a third input is shown if some element is checked inside the second checkbox list.

As a consequence, if the given element in the first checkbox list is unchecked, the third input must also be hidden.

Example: when a situation professionnelle is ``en activite``, the second element ``type contrat`` must be shown if ``en_activite`` is checked. Inside ``type_contrat``, ``type_contrat_aide`` should be shown when ``contrat_aide`` is checked.

        <div id="situation_prof">
            <input type="radio" name="situationProfessionnelle" value="" checked="checked" />
            <input type="radio" name="situationProfessionnelle" value="sans_emploi" />
            <input type="radio" name="situationProfessionnelle" value="en_activite" />
        </div>
        
        
        <div id="type_contrat">
            <input type="checkbox" name="typeContrat[]" value="cdd" /> 
            <input type="checkbox" name="typeContrat[]" value="cdi" />
            <input type="checkbox" name="typeContrat[]" value="contrat_aide" />
        </div>
        
        <div id="type_contrat_aide">
            <input type="text" name="typeContratAide" />
        </div>

The JS code will be:

   import { ShowHide } from 'ShowHide/show_hide.js';
   // we search for the element within the DOM
   // NOTE: all the elements should be searched before instanciating the showHides. 
   // if not, the elements **may** have disappeared from the DOM

   var
       situation_prof = document.getElementById('situation_prof'),
       type_contrat = document.getElementById('type_contrat'),
       type_contrat_aide = document.getElementById('type_contrat_aide'),
       ;

   // the first show/hide will apply on situation_prof
   new ShowHide({
       // the id will help us to keep a track of the element
       id: 'situation_prof_type_contrat',
       froms: [situation_prof],
       container: [type_contrat],
       test: function(froms) {
           for (let f of froms.values()) {
               for (let input of f.querySelectorAll('input').values()) {
                   if (input.value === 'en_activite') {
                       return input.checked;
                   }
               }
           }
           
           return false;
       }
   });

   // the show/hide will apply on "contrat aide"
   var show_hide_contrat_aide = new ShowHide({
       froms: [type_contrat],
       container: [type_contrat_aide],
       test: function(froms) {
           for (let f of froms.values()) {
               for (let input of f.querySelectorAll('input').values()) {
                   if (input.value === 'contrat_aide') {
                       return input.checked;
                   }
               }
           }
           
           return false;
       }
   });

   // we handle here the case when the first show-hide is changed: the third input must also disappears
   window.addEventListener('show-hide-hide', function (e) {
       if (e.detail.id = 'situation_prof_type_contrat') {
           // we force the 3rd element to disappears
           show_hide_contrat_aide.forceHide();
       }
   });

   // when the first show-hide is changed, it makes appears the second one.
   // we check here that the second show-hide is processed.
   window.addEventListener('show-hide-show', function (e) {
       if (e.detail.id = 'situation_prof_type_contrat') {
           show_hide_contrat_aide.forceCompute();
       }
   });