Commit 850d89f8 authored by Bertrand Gauthier's avatar Bertrand Gauthier
Browse files

[FIX] FormElementCollection : corrections complémentaires pour que SearchAndSelect fonctionne.

parent 56a3ae1e
Loading
Loading
Loading
Loading
+36 −54
Original line number Diff line number Diff line
<?php
namespace UnicaenApp\Form\View\Helper;

use UnicaenApp\Form\Element\Collection;
use Laminas\Form\View\Helper\FormCollection;
use Laminas\Form\ElementInterface;
use Laminas\Form\Element\Collection as CollectionElement;
use Laminas\Form\ElementInterface;
use Laminas\Form\FieldsetInterface;
use Laminas\Form\LabelAwareInterface;
use Laminas\Form\Element\Button;
use Laminas\Form\View\Helper\FormCollection;
use UnicaenApp\Form\Element\Collection;

/**
 * Aide de vue dessinant une collection d'éléments.
@@ -37,18 +36,13 @@ class FormElementCollection extends FormCollection
    protected $defaultElementHelper = 'formControlGroup';

    /**
     * Nombre d'éléments à afficher
     *
     * @var int
     * Nombre d'éléments à afficher.
     */
    protected $countElements;
    protected int $countElements;


    /**
     * Render a collection by iterating through all fieldsets and elements
     *
     * @param  ElementInterface $element
     * @return string
     * Render a collection by iterating through all fieldsets and elements.
     */
    public function render(ElementInterface $element): string
    {
@@ -65,7 +59,9 @@ class FormElementCollection extends FormCollection
        $css = null;
        $templateMarkup = '';
        $elementHelper = $this->getElementHelper();
        assert(is_callable($elementHelper));
        $fieldsetHelper = $this->getFieldsetHelper();
        assert(is_callable($fieldsetHelper));

        if ($element instanceof CollectionElement && $element->shouldCreateTemplate()) {
            $this->countElements = $element->getCount();
@@ -82,17 +78,19 @@ class FormElementCollection extends FormCollection
        foreach ($element->getIterator() as $elementOrFieldset) {
            if ($elementOrFieldset instanceof FieldsetInterface) {
                $elementOrFieldset->setAttribute('data-index', $index);
                $markup .= $fieldsetHelper($elementOrFieldset, $this->shouldWrap());
                $fieldsetHtml = $fieldsetHelper($elementOrFieldset, $this->shouldWrap());
                $fieldsetHtml = str_replace('__index__', $index, $fieldsetHtml);
                $index++;
                $markup .= $fieldsetHtml;
            } elseif ($elementOrFieldset instanceof ElementInterface) {
                if ($element instanceof FieldsetInterface) {
                    $domId = $elementOrFieldset->getAttribute('id') ?: uniqid('element-');
                    $elementOrFieldset->setAttribute('id', $domId . '-__index__');
                    // NB : la valeur d'un id doit être unique dans un DOM. Or, en cas de collection autorisant l'ajout d'élément
                    // (par clonage), on garantit l'unicité en concaténant le pattern '__index__', pattern qui est remplacé/incrémenté
                    // par le moteur js de cette aide de vue (cf. plus bas).
                    /** Par ex, {@see \UnicaenApp\Form\Element\SearchAndSelect} ne fonctionne plus dans une collection en cas de doublon d'id. */
                }
                /**
                 * NB : la valeur d'un id doit être unique dans un DOM. Or, en cas de collection autorisant l'ajout d'élément
                 * (par clonage), on garantit l'unicité en concaténant le pattern '__index__', pattern qui est remplacé/incrémenté
                 * par le moteur js de cette aide de vue (cf. plus bas).
                 * Par ex, {@see \UnicaenApp\Form\Element\SearchAndSelect} ne fonctionne plus dans une collection en cas de doublon d'id.
                 */
                $id = $elementOrFieldset->getAttribute('id') ?: uniqid('element-');
                $elementOrFieldset->setAttribute('id', $id . '-__index__');
                $markup .= $elementHelper($elementOrFieldset);
            }
        }
@@ -142,7 +140,7 @@ class FormElementCollection extends FormCollection
        return $markup;
    }

    protected function getDelLink()
    protected function getDelLink(): string
    {
        return '<div class="collection-delete-link">' .
                    '<a class="btn btn-link" title="Supprimer cet élément de la collection">' .
@@ -151,12 +149,7 @@ class FormElementCollection extends FormCollection
                '</div>';
    }

    /**
     * Get add link
     *
     * @return string
     */
    protected function getAddLink()
    protected function getAddLink(): string
    {
        return '<div class="collection-add-link">' .
                    '<a class="btn btn-link" title="Ajouter un élément à la collection">' .
@@ -165,11 +158,7 @@ class FormElementCollection extends FormCollection
                '</div>';
    }

    /**
     * @param Collection $container
     * @return string
     */
    protected function getCss($container)
    protected function getCss(Collection $container): string
    {
        $fieldsetId = $container->getAttribute('id');

@@ -202,11 +191,7 @@ EOT;
        return $css;
    }

    /**
     * @param Collection $container
     * @return string
     */
    protected function getJavascript($container)
    protected function getJavascript(Collection $container): string
    {
        $maxEnabled = ($container->getMaxElements()) ? 'true' : 'false';
        $minEnabled = ($container->getMinElements()) ? 'true' : 'false';
@@ -291,24 +276,21 @@ $().ready(function updateButtons()
        });
    }
});


EOT;

        foreach($container->getAutocomplete() as $name => $options) {
            $javascript .= <<<EOT
$('#{$container->getAttribute('id')}').on('keyup', '.{$container->getAttribute('id')}-autocomplete', function() {
    $(this).autocompleteOctopus({
        source: '{$options['source']}',
        minLength: {$options['min-length']},
        delay: {$options['delay']}
    });
});


EOT;

        }
//        foreach($container->getAutocomplete() as $name => $options) {
//            $javascript .= <<<EOT
//$('#{$container->getAttribute('id')}').on('keyup', '.{$container->getAttribute('id')}-autocomplete', function() {
//    $(this).autocompleteOctopus({
//        source: '{$options['source']}',
//        minLength: {$options['min-length']},
//        delay: {$options['delay']}
//    });
//});
//
//
//EOT;
//        }

        return '<script type="text/javascript">' . $javascript . '</script>';
    }
+28 −94
Original line number Diff line number Diff line
<?php
namespace UnicaenApp\Form\View\Helper;

use UnicaenApp\Exception\LogicException;
use UnicaenApp\Form\Element\SearchAndSelect;
use Laminas\Form\Element\Text;
use Laminas\Form\ElementInterface;
use Laminas\Form\Exception\InvalidElementException;
use Laminas\Form\View\Helper\FormText;
use UnicaenApp\Form\Element\SearchAndSelect;

/**
 * Aide de vue générant le code HTML de l'élément de formulaire du même nom.
 *
 * @author <bertrand.gauthier@unicaen.fr>
 * @see \UnicaenApp\Form\Element\SearchAndSelect
 * Aide de vue générant le code HTML de l'élément de formulaire {@see \UnicaenApp\Form\Element\SearchAndSelect}.
 */
class FormSearchAndSelect extends FormText
{
    /**
     * @var SearchAndSelect
     */
    protected $element;
    
    /**
     * @var string
     */
    protected $autocompleteSource;
    
    /**
     * @var int
     */
    protected $autocompleteMinLength = 2;
    
    /**
     * @var string
     */
    protected $spinnerSource = "//gest.unicaen.fr/images/ajax-loader-r.gif";
    protected SearchAndSelect $element;
    protected Text $autocompleteElement;
    protected ?string $autocompleteSource = null;
    protected int $autocompleteMinLength = 2;
    protected string $spinnerSource = "//gest.unicaen.fr/images/ajax-loader-r.gif";
    
    /**
     * {@inheritdoc}
     */
    public function __invoke(ElementInterface $element = null)
    {
        if ($element && !$element instanceof SearchAndSelect) {
            throw new InvalidElementException("L'élément spécifié n'est pas du type attendu.");
        if (! $element) {
            return $this;
        }

        $this->element = $element;
        return parent::__invoke($element);
        return $this->render($element);
    }

    /**
     * {@inheritdoc}
     */
    public function render(ElementInterface $element): string
    {
        if (!$element instanceof SearchAndSelect) {
@@ -74,20 +49,22 @@ class FormSearchAndSelect extends FormText
        //   'label' => libellé affiché (ex: nom complet de la personne)
        $this->element->setName($name . "[$id]");

        // render parent
        $markup = parent::render($this->element);
        
        $elementDomId      = $this->element->getAttribute('id');
        $autocompleteDomId = $elementDomId . '-autocomplete';

        $autocomplete = new Text();
        $autocomplete->setAttributes($this->element->getAttributes())
        $this->autocompleteElement = new Text();
        $this->autocompleteElement
            ->setAttributes($this->element->getAttributes())
            ->setName($name . "[$label]")
            ->setAttribute('id', $autocompleteDomId)
            ->setAttribute('class', 'form-control form-control-sm')
            ->setValue($this->element->getValueLabel() ?: $this->element->getValue());

        $markup .= $this->getView()->formText($autocomplete);
        $this->element->setAttribute('style', $this->element->getAttribute('style') . ' display:none;');

        $markup = parent::render($this->element);

        $markup .= $this->view->formText($this->autocompleteElement);
        
        $markup .= <<<EOS
<style>
@@ -100,34 +77,21 @@ class FormSearchAndSelect extends FormText
</style>
EOS;

//        $this->getView()->plugin('inlineScript')->appendScript($this->getJavascript());
        $markup .= PHP_EOL . '<script>' . $this->getJavascript() . '</script>' . PHP_EOL;
        
        return $markup;
    }

    /**
     * 
     * @return string
     * @throws LogicException
     */
    public function getJavascript()
    protected function getJavascript(): string
    {
        if (!$this->element) {
            throw new LogicException("Aucun élément spécifié, appelez render() auparavant.");
        }
        
        $elementDomId      = $this->element->getAttribute('id');
        $autocompleteDomId = $elementDomId . '-autocomplete';
        
        $js = <<<EOT
// cache l'élément contenant l'id de la sélection
$("#{$elementDomId}").css('display', 'none');
        $autocompleteDomId = $this->autocompleteElement->getAttribute('id');
        
        return <<<EOT
$(function() {
    // jQuery UI autocomplete
    var autocomp = $("#{$autocompleteDomId}");
    autocomp.autocompleteUnicaen({ // autocompleteUnicaen() définie dans "public/js/util.js"
    autocomp.autocompleteUnicaen({ // autocompleteUnicaen() définie dans "public/unicaen/app/js/unicaen.js"
        elementDomId: '$elementDomId',
        source: '{$this->getAutocompleteSource()}',
        minLength: {$this->getAutocompleteMinLength()},
@@ -135,27 +99,15 @@ $(function() {
    });
});
EOT;
        return $js;
    }
    
    /**
     * 
     * 
     * @param string|array $autocompleteSource
     * @return SearchAndSelect
     */
    public function setAutocompleteSource($autocompleteSource)
    public function setAutocompleteSource(string $autocompleteSource): self
    {
        $this->autocompleteSource = $autocompleteSource;
        return $this;
    }

    /**
     * 
     * 
     * @return string|array $autocompleteSource
     */
    public function getAutocompleteSource()
    public function getAutocompleteSource(): string
    {
        if (null !== $this->autocompleteSource) {
            return $this->autocompleteSource;
@@ -163,41 +115,23 @@ EOT;
        return $this->element->getAutocompleteSource();
    }

    /**
     * 
     * @return int
     */
    public function getAutocompleteMinLength()
    public function getAutocompleteMinLength(): int
    {
        return $this->autocompleteMinLength;
    }

    /**
     * 
     * @param int $autocompleteMinLength
     * @return SearchAndSelect
     */
    public function setAutocompleteMinLength($autocompleteMinLength)
    public function setAutocompleteMinLength(int $autocompleteMinLength): self
    {
        $this->autocompleteMinLength = $autocompleteMinLength;
        return $this;
    }

    /**
     * 
     * @return string
     */
    public function getSpinnerSource()
    public function getSpinnerSource(): string
    {
        return $this->spinnerSource;
    }

    /**
     * 
     * @param string $spinnerSource
     * @return SearchAndSelect
     */
    public function setSpinnerSource($spinnerSource)
    public function setSpinnerSource(string $spinnerSource): self
    {
        $this->spinnerSource = $spinnerSource;
        return $this;