PageSourceSearch

https://rousseau5.ch/wp-content/themes/rousseau5/assets/js/articles-hub.js?ver=1788273759

js rousseau5.ch collected 2026-10-06 12:23:14 UTC 4,596 bytes, 116 lines download raw bytes

1/**
2 * Hub des articles — filtrage de ce qui est déjà dans la page.
3 * Même principe que le glossaire : le serveur rend tout, le script masque.
4 */
5(function () {
6	'use strict';
7
8	var $$ = function (s, r) { return Array.prototype.slice.call((r || document).querySelectorAll(s)); };
9	var cartes  = $$('[data-hub-liste] .know-art-card');
10	if (!cartes.length) { return; }
11
12	var pilules = $$('.know-cat-btn');
13	var compte  = document.querySelector('[data-hub-compte]');
14	var vide    = document.querySelector('[data-hub-vide]');
15	var champ   = document.querySelector('[data-hub-recherche] input');
16	var effacer = document.querySelector('[data-hub-effacer]');
17	var actif   = '';
18	var requete = [];
19
20	/* « cedule » doit trouver « cédule », et « Cédule » aussi : tout passe
21	   par la même normalisation — minuscules, accents décomposés puis
22	   retirés — des deux côtés de la comparaison. */
23	function normaliser(t) {
24		return (t || '').toLowerCase().normalize('NFD').replace(/[\u0300-\u036f]/g, '').replace(/[^a-z0-9 ]+/g, ' ').replace(/\s+/g, ' ').trim();
25	}
26
27	function appliquer() {
28		var n = 0;
29		cartes.forEach(function (c) {
30			/* Un article peut porter plusieurs thèmes : data-hub-int est
31			   une liste de slugs séparés par des espaces. */
32			var siens = (c.getAttribute('data-hub-int') || '').split(/\s+/);
33			var ok = !actif || siens.indexOf(actif) !== -1;
34			if (ok && requete.length) {
35				var index = c.getAttribute('data-hub-mot') || '';
36				/* Chaque mot tapé doit se trouver quelque part dans l'index :
37				   « ibgi remploi » réduit, il n'élargit pas. */
38				ok = requete.every(function (mot) { return index.indexOf(mot) !== -1; });
39			}
40			c.hidden = !ok;
41			if (ok) { n++; }
42		});
43		if (compte) {
44			compte.textContent = (actif || requete.length)
45				? n + (n > 1 ? ' articles' : ' article')
46				: '';
47		}
48		if (vide) { vide.hidden = n !== 0; vide.textContent = n === 0 ? 'Aucun article dans cette sélection.' : ''; }
49		if (effacer) { effacer.hidden = !requete.length; }
50	}
51
52	function chercher(texte, pousserUrl) {
53		requete = normaliser(texte).split(' ').filter(Boolean);
54		appliquer();
55		if (pousserUrl && window.history && history.replaceState) {
56			var u = new URL(location.href);
57			if (requete.length) { u.searchParams.set('q', texte.trim()); } else { u.searchParams.delete('q'); }
58			history.replaceState(history.state, '', u);
59		}
60	}
61
62	if (champ) {
63		var minuterie = null;
64		champ.addEventListener('input', function () {
65			clearTimeout(minuterie);
66			minuterie = setTimeout(function () { chercher(champ.value, true); }, 120);
67		});
68	}
69	if (effacer && champ) {
70		effacer.addEventListener('click', function () { champ.value = ''; chercher('', true); champ.focus(); });
71	}
72
73	function choisir(cible, pousser) {
74		actif = cible;
75		pilules.forEach(function (o) {
76			var on = (o.getAttribute('data-hub-int') || '') === actif;
77			o.classList.toggle('active', on);
78			if (on) { o.setAttribute('aria-current', 'page'); } else { o.removeAttribute('aria-current'); }
79		});
80		appliquer();
81		if (pousser && window.history && history.pushState) {
82			/* L'adresse suit le filtre — sans écraser une recherche en cours :
83			   thème et mots-clés se combinent, l'URL porte les deux. */
84			var u = new URL(location.href);
85			if (actif) { u.searchParams.set('theme', actif); } else { u.searchParams.delete('theme'); }
86			history.pushState({ hub: actif }, '', u);
87		}
88	}
89
90	pilules.forEach(function (b) {
91		b.addEventListener('click', function (e) {
92			/* Les pilules sont de vrais liens vers l'archive du thème, pour
93			   que Google les suive. Ici on intercepte : filtrer sur place
94			   vaut mieux qu'un rechargement. Un clic milieu, ctrl ou cmd
95			   garde le comportement natif — on n'enlève pas à l'utilisateur
96			   le droit d'ouvrir dans un onglet. */
97			if (e.metaKey || e.ctrlKey || e.shiftKey || e.button !== 0) { return; }
98			e.preventDefault();
99			var cible = b.getAttribute('data-hub-int') || '';
100			choisir(actif === cible ? '' : cible, true);
101			var grille = document.getElementById('tous-les-articles');
102			if (grille && cible) { grille.scrollIntoView({ behavior: 'smooth', block: 'start' }); }
103		});
104	});
105
106	window.addEventListener('popstate', function () {
107		choisir(new URLSearchParams(location.search).get('theme') || '', false);
108	});
109
110	// Arrivée directe sur ?theme=… ou ?q=… — partage, signet, futur assistant.
111	var params = new URLSearchParams(location.search);
112	var voulu = params.get('theme');
113	if (voulu) { choisir(voulu, false); }
114	var q = params.get('q');
115	if (q && champ) { champ.value = q; chercher(q, false); }
116})();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.