Select2

Select2 est une librairie Javascript / jQuery qui améliore l’usage des sélecteurs (balises <select>) natifs des navigateurs en facilitant entre autres la recherche d’un terme dans la liste. Ce plugin intègre Select2 dans SPIP.

Fonctionnement

Une fois le plugin activé, Select2 est actif dans l’espace privé pour toutes les balises <select> ou <input> ayant la classe CSS .select2.

La configuration (Menu : Squelettes > Select2) permet de compléter les sélecteurs sur lesquels le plugin doit s’appliquer automatiquement.

Il est possible d’activer Select2 sur l’espace public automatiquement aussi, depuis cette configuration.

Important: L’identifiant (l’attribut id) de la balise select ou input doit être unique sur la page ; Select2 ne peut s’activer qu’une fois par identifiant (le dernier appelé).

Tester

Une page de test (en lien depuis la configuration) permet de visualiser quelques exemples de sélecteurs uniques et multiples avec diverses configurations. Son code source est le fichier dans prive/squelettes/contenu/tester_select2.html du plugin.

Capture de la page de test de Select2 en SPIP 4.2

Exemple de HTML / SPIP

#SET{id,u4}
<div class="editer pleine_largeur">
	<label for="demo_#GET{id}">Ajax Search</label>
		<select class="select2" name="demo_#GET{id}" id="demo_#GET{id}"
			data-placeholder="Sélectionnez une ville..."
			data-ajax-url="[(#URL_API{select2_autocomplete,demo/city}|attribut_html)]"
			data-minimum-input-length="1"
		>
			<option value="">Sélectionnez une ville...</option>
		</select>
</div>

Exemple avec Saisies

Cet exemple utilise les plugins Saisies et Pays. Il suffit d’ajouter l’option class=select2 à la balise #SAISIE :

[(#SAISIE{pays, pays, 
	label=<:utilisateurs:label_recherche_pays:>,
	option_intro=<:utilisateurs:option_tous:>,
	multiple=oui,
	class=select2,
})]

Compléter la configuration par défaut

Select2 dispose de 2 manières d’adapter sa configuration, par Javascript, ou par attributs HTML

En appelant directement une méthode javascript

  • soit la fonction jQuery .select2() de la librairie d’origine, et en lui transmettant des options
  • soit la fonction jQuery .spip_select2() qui enrichit la précédente
  • soit SpipSelect2.on_select(select, options), dont la fonction jQuery .spip_select2 est un alias
  • soit SpipSelect2.on_input(input, options)

Par exemple

jQuery("select").select2({"placeholder": "La forme ?"});
jQuery("select").spip_select2({"placeholder": "La forme ?"});
SpipSelect2.on_select(document.querySelector("select"), {"placeholder": "Que dire ?"});
SpipSelect2.on_input(document.querySelector("input.text"));

Via des attributs HTML data-xx

  • soit par les attributs data-xx sur la balise <select> ou <input>, qui prennent alors le pas sur les options transmises à l’initialisation.

Par exemple :

<select class="select2" id="select1" name="demo" data-placeholder="Ça va ?">
    <option></option>
    <option value="oui">Yep!</option>
    <option value="non">Bof.</option>
</select>
jQuery("#select2").select2({"placeholder": "La forme ?"});

La documentation de Select2 sera donc à étudier :)

Addition du plugin SPIP

Des options supplémentaires non présentes dans le Javascript par défaut sont ajoutées au plugin SPIP. Ces options sont disponibles :

  • si vous utilisez les classes CSS prévues sur les <select> (.select2 ou tout autre configurée en plus par vos soins)
  • si vous appelez directement une des fonctions
    • SpipSelect2.on_select()
    • SpipSelect2.on_input()
    • jQuery .spip_select2()

Mais pas si vous appelez directement la méthode jQuery .select2() native.

sortAlpha

-  {sortAlpha: true}
-  ou data-sort-alpha="true".

Si cet attribut est présent, les options de sélection seront triées par ordre alphabétique.

Cela est effectué en interne, en utilisant une fonction sorter ;
En simplifiant cela pourrait ressembler à :

    jQuery('#select3a').spip_select2({sortAlpha: true});
    // est à peu près équivalent à :
    jQuery('#select3b').select2({
        /*'sorter': data => data.sort((a, b) => a.text.localeCompare(b.text))*/
        sorter: function(data) {
            return data.sort(function(a, b) {
                return a.text.localeCompare(b.text);
            })
        }
    });

highlightSearchTerm

-  {highlightSearchTerm: true}
-  ou data-highlight-search-term="true".

Cette option met en évidence le terme de recherche dans la liste des résultats, en appliquant
un span .select2-rendered__match sur le terme recherché, qui est par défaut décoré avec un souligné.

Additions à la librairie javascript Select2

Les options suivantes nécessitent d’avoir chargé le javascript javascript/select2.fork.full.js (ce que fait le plugin d’ailleurs) à la place de lib/select2/js/select2.full.js, si vous chargez vous-même les scripts dans l’espace public sans passer par la configuration du plugin.

Il n’est malheureusement pas possible actuellement d’obtenir ces comportements sans adapter le code source de la librairie.

onEnterSubmit

-  {onEnterSubmit: true}
-  ou data-on-enter-submit="true".

Appuyer la touche Entrée en ayant le focus sur le sélecteur fermé soumet le formulaire (comportement généralement présent sur les navigateurs). Par défaut, Select2 quand à lui ouvre le sélecteur.

Autocomplete Ajax

On peut indiquer une URL de recherche à Select2 afin qu’il obtienne la liste des choix en fonction de la recherche tapée par l’utilisateur. Un exemple est proposé dans le plugin, visible sur la page de test.

Par exemple :

<select class="select2" id="chiens" name="chiens[]" 
    data-placeholder="Quelle race de chien ?"
    data-ajax-url="[(#URL_API{select2_autocomplete,demo/dogs}|attribut_html)]"
    data-minimum-input-length="1"
>
</select>

L’API doit retourner un format spécifique (cf action/select2_autocomplete.php) pour fonctionner par défaut, mais du javascript supplémentaire peut servir pour adapter des apis déjà existantes. Cf. documentation Ajax de Select2.

onAjaxLoad ...

Attention avec l’autocomplètion. Si vous appelez directement .select2() (ce n’est pas le cas pour .spip_select2() utilisé par le plugin cependant), chaque requête ajax pour obtenir la liste des éléments recherchés va déclencher la fonction SPIP onAjaxLoad. Votre code ne doit pas redémarrer l’initialisation des <select> déjà gérés par Select2 dans ce cas (sinon vous verrez le sélecteur se refermer aussitôt !).

Remplacer le plugin Chosen

Ce plugin peut remplacer le plugin Chosen.

Pour cela il faut

  • soit déclarer la classe CSS .chosen dans la configuration du plugin Select2 pour qu’il s’applique dessus,
  • soit modifier son code HTML (remplacer la classe chosen par select2)
  • soit appeler directement Select2 dans son propre code javascript, tel que :
jQuery('select.chosen').select2();
// ou
jQuery('select.chosen').spip_select2();

Il faudra également adapter les styles CSS spécifiques si vous en utilisiez, par exemple en fournissant css/select2_public.css (corollaire de css/chosen_public.css)

Intégration publique uniquement sur certaines pages

Si vous souhaitez charger Select2 uniquement sur certaines pages publiques (donc sans cocher la configuration qui ajoute Select2 partout dans l’espace public), voici un petit moyen :

Créer un squelette pour insérer les éléments nécessaires, tel que inclure/select2_loader.html :

[<link href="(#CHEMIN{lib/select2/css/select2.css}|timestamp)" rel="stylesheet" />]
[<link href="(#CSS{css/select2_public.css}|timestamp)" rel="stylesheet" />]
[<script type="text/javascript" src="(#CHEMIN{javascript/select2.fork.full.js}|timestamp)"></script>]
[<script type="text/javascript" src="(#CHEMIN{lib/select2/js/i18n/#LANG.js}|timestamp)"></script>]
[<script type="text/javascript" src="(#CHEMIN{javascript/SpipSelect2.js}|timestamp)"></script>]
[<script type="text/javascript" src="(#CHEMIN{javascript/SpipSelect2Loader.js}|timestamp)"></script>]
#FILTRE{compacte_head}

Et l’appeler, simplement où vous le souhaitez :

<INCLURE{fond=inclure/select2_loader} />

Surcharge de la librairie native

Notons que nous avons remplacé la librairie native, qui s’appellerait ainsi :

[<script type="text/javascript" src="(#CHEMIN{lib/select2/js/select2.full.js}|timestamp)"></script>]

Par une surcharge :

[<script type="text/javascript" src="(#CHEMIN{javascript/select2.fork.full.js}|timestamp)"></script>]

La surcharge permet simplement de faire fonctionner l’option onEnterSubmit.

La balise URL_API

La balise #URL_API, définie par ce plugin, permet de générer facilement les urls. Elle accepte 4 arguments :
-  le nom de l’action
-  le chemin
-  les arguments à transmettre a l’URL sous la forme arg1=yy&arg2=zz

Exemples :
-  #URL_API{select2_autocomplete.api}
-  #URL_API{select2_autocomplete,demo/city}
-  #URL_API{select2_autocomplete,demo/city,term=a&_type=query&q=a}

Historique

Version 2

  • Compatible SPIP 4.2 minimum
  • Permet l’utilisation de Select2 sur des champs de type input[type=text]
  • Changement de signature de #URL_API
    • Avant (déprécié) : #URL_API{nom/chemin, params} tel que #URL_API{toto/truc/muche, id_toto=3}
    • Après : #URL_API{nom, chemin, params} tel que #URL_API{toto, truc/muche, id_toto=3}

Discussion

6 discussions

  • 1

    Ça marche très bien mais je viens de découvrir 2 étrangetés :
    -  le plugin était encore en version 1.x, et je pense qu’il n’y avait pas de mise à jour proposées sinon il y a longtemps que j’aurai fait des mises à jour
    -  à l’exécution, une erreur apparaît dans la console du navigateur : « Uncaught SyntaxError: redeclaration of let SpipSelect2 <anonymous>exemple.com/local/cache-js/a920a5fe7e3a2c2d8ebdb6291338b001.js?1744220261:1 ». Pourtant la déclaration de la class SpipSelect2 n’est faite qu’une fois, dans le js concaténé, et pourquoi ce ’let’ ? je sais pas...

    • Ah pour la non présentation de la version c’est probablement que le nouveau tag ne commence pas par ’v’ : https://git.spip.net/spip-contrib-extensions/select2/-/tags C’est possible un tag sans ’v’ maintenant ? Au cas où c’est un changement récent, ce site était en SPIP 4.2 jusqu’à il y a peu et ça expliquerait la non présentation de la MAJ. Reste l’erreur de redéclaration let js.

    Reply to this message

  • 5

    Bonjour
    j’essai désespérément d’intégrer select2 dans un champ de la fabrique

    dans la doc il est dit "Pour autoriser des saisies multiples (et annuler maximum-selection-length = 1), il faut spécifier un séparateur : ce que j’ai fait

    j’ai donc pour un champ input dans la fabrique

    class=select2,
    data-placeholder = Sélectionnez une option...,
    data-highlightSearchTerm = true,
    data-separator = |,
    data-data=[(#ARRAY{clim,clim,chauf,chauf})],
    multiple=oui
    

    le code généré

    [(#SAISIE{input, test_select2,
    				label=<:annonce:champ_test_select2_label:/>,
    				class=select2,
    data-placeholder = "Sélectionnez une option...",
    data-highlightSearchTerm = "true",
    data-separator = "|",
    data-data=[(#ARRAY{cle1,valeur1,cle2,valeur2})],
    multiple=oui})]

    mais au final le data-maximum-selection-length reste à 1 et data-placeholder ne s’affiche pas

    
    

    je ne vois pas ou je me suis trompée
    ce n’est peut être pas la bonne méthode
    merci pour votre aide

    • Bonjour,

      les options data-xxx ne sont pas passés tel quel à une saisie (pour différentes raisons trop compliqué à détaillé).

      Il vous faut

      1. Soit déclarer vos saisies en mode PHP et utiliser attributs_data (cf Référence des saisies
      2. Soit si vous voulez rester sur #SAISIE, utiliser l’argument attributs pour passer des attributs supplémentaires.

    • Bonjour Maïeul et merci

      dans la fabrique j’ai changé le mode des saisies de HTML à PHP
      j’ai donc maintenant

      		[
      			'saisie' => 'input',
      			'options' => [
      			'nom' => 'test_select2',
      			'label' => _T('annonce:champ_test_select2_label'),
      			'class' => 'select2',
      			'placeholder' => ' Sélectionnez une option...',	
      			'multiple' =>'oui',
      			'data' => array('Climatisation' =>'Climatisation','Chauffage' =>'Chauffage'),			
      		       'separator' => '|',			
      			],
      		],

      mais ’separator’ n’est pas pris en compte et j’ai toujours data-maximum-selection-length = 1

    • est-ce que le markup html genéré est bon, deja ?

    • à priori oui
      les 2 choix sont bien proposés
      si j’en choisi un il se met bien en place
      mais data-maximum-selection-length=“1”

      <div class="editer editer_test_select2 saisie_input">
      	<label class="editer-label" for="champ_test_select2">Test select2</label>
      			<datalist id="champ_test_select2_data">
      	<option value="Climatisation">Climatisation</option>
      	<option value="Chauffage">Chauffage</option>
      </datalist>
      
      <input type="hidden" name="test_select2" class="text select2" id="champ_test_select2" list="champ_test_select2_data" placeholder=" Sélectionnez une option..." data-select2-on="on"><select type="text" class="text select2-hidden-accessible" id="champ_test_select2:select2" list="champ_test_select2_data" multiple="" data-placeholder=" Sélectionnez une option..." data-maximum-selection-length="1" data-tags="true" data-on-enter-submit="true" data-select2-on="on" data-select2-id="champ_test_select2:select2" tabindex="-1" aria-hidden="true">
      
      	<option value="Climatisation">Climatisation</option>
      	<option value="Chauffage">Chauffage</option>
      
      </select><span class="select2 select2-container select2-container--default" dir="ltr" data-select2-id="1" style="width: 560.797px;"><span class="selection"><span class="select2-selection select2-selection--multiple" role="combobox" aria-haspopup="true" aria-expanded="false" tabindex="-1" aria-disabled="false"><ul class="select2-selection__rendered"><li class="select2-search select2-search--inline"><input class="select2-search__field" type="search" tabindex="0" autocomplete="off" autocorrect="off" autocapitalize="none" spellcheck="false" role="searchbox" aria-autocomplete="list" placeholder=" Sélectionnez une option..." style="width: 548.797px;"></li></ul></span></span><span class="dropdown-wrapper" aria-hidden="true"></span></span>
      </div>
    • Bon
      après avoir bidouiller SpipSelect2.js j’arrive à mettre plusieurs tags à la suite :-)

      select.dataset.separator = select.getAttribute('separator');        if (!select.dataset.separator) { select.dataset.maximumSelectionLength = 1;

      mais l’enregistrement ne met pas le | entre les mots mais null

      je bidouille encore et force la valeur select.dataset.separator = “|”; dans les fonctions suivantes
      if (input.value) et const update_input = function ()

      bref ça fini par fonctionner en bidouillant

      dommage je ferai sans

    Reply to this message

  • 1

    Bonjour,

    J’utilise Select2 dans un formulaire sur l’espace public avec #FORMULAIRE_EDITER_ARTICLE.

    Sur cette même page j’ai un autre formulaire en Ajax avec #FORMULAIRE_EDITER_LIENS, mais quand celui-ci est modifié, les champs de l’autre formulaire avec Select2 (editer_article) ne fonctionne plus.

    Faut-il recharger le script ? Comment je fais ?

    Merci d’avance.

    Reply to this message

  • Bonjour,

    Pour info la version du tags v1.1.0 ne prend pas en compte la correction javascript de :
    https://git.spip.net/spip-contrib-extensions/select2/commit/09951a019fb53c138decdd847a6a2f07bcf2be55

    Sinon : merci pour le plugin !

    Reply to this message

  • 2

    Hop,

    Quand plusieurs <select> ont le même name (ce qui n’est pas recommandé mais parfaitement valable), le script ne s’active que sur le dernier.

    Exemple :

    [(#SAISIE{selection, glop, class=select2, label="Glop mais sans select2 :c"})]
    [(#SAISIE{selection, glop, class=select2, label="Glop avec un beau select2"})]

    Je ne sais pas si le bug est dans l’implémentation du plugin ou directement dans la lib, pas encore vu de trace de ce bug dans leur tracker.

    Dans chosen, pas ce problème.

    • C’est clairement indiqué dans la documentation, en tout cas dans le readme :

      Important: L’identifiant (l’attribut id) de la balise select doit être unique sur la page ; Select2 ne peut s’activer qu’une fois par identifiant (le dernier appelé).

      C’est pas le name le problème, mais l’ID.

    • Aaaah ok, my bad.
      Donc en donnant un id unique en param de la saisie, tout rentre dans l’ordre.
      Merci :)

    Reply to this message

  • Bonjour,

    Je dirais : enfin !

    J’utilise select2 quand chosen ne convient ou ne suffit pas depuis pas mal de temps et ça fait plaisir de le voir porter en plugin pour Spip.

    Donc merci Marcimat !

    Reply to this message

Add a comment

Avant de faire part d’un problème sur un plugin X, merci de lire ce qui suit :

  • Désactiver tous les plugins que vous ne voulez pas tester afin de vous assurer que le bug vient bien du plugin X. Cela vous évitera d’écrire sur le forum d’une contribution qui n’est finalement pas en cause.
  • Cherchez et notez les numéros de version de tout ce qui est en place au moment du test :
    • version de SPIP, en bas de la partie privée
    • version du plugin testé et des éventuels plugins nécessités
    • version de PHP (exec=info en partie privée)
    • version de MySQL / SQLite
  • Si votre problème concerne la partie publique de votre site, donnez une URL où le bug est visible, pour que les gens puissent voir par eux-mêmes.
  • En cas de page blanche, merci d’activer l’affichage des erreurs, et d’indiquer ensuite l’erreur qui apparaît.

Merci d’avance pour les personnes qui vous aideront !

Par ailleurs, n’oubliez pas que les contributeurs et contributrices ont une vie en dehors de SPIP.

Who are you?
[Log in]

To show your avatar with your message, register it first on gravatar.com (free et painless) and don’t forget to indicate your Email addresse here.

Enter your comment here

This form accepts SPIP shortcuts {{bold}} {italic} -*list [text->url] <quote> <code> and HTML code <q> <del> <ins>. To create paragraphs, just leave empty lines.

Add a document

Follow the comments: RSS 2.0 | Atom