Repository with sources and generator of https://larlet.fr/david/ https://larlet.fr/david/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375
  1. {% extends "base_2024.html" %}
  2. {% block lang %}fr{% endblock %}
  3. {% block title %}Recherche{% endblock %}
  4. {% block description %}Voici l’espace personnel de David Larlet sur le Web.{% endblock %}
  5. {% block content %}
  6. <header>
  7. <hgroup>
  8. <h1>Recherche</h1>
  9. <p>Seuls les contenus de ces 8 dernières années sont indexés.</p>
  10. </hgroup>
  11. </header>
  12. <nav>
  13. <p>
  14. <a href="/david/" title="Aller à l’accueil">
  15. Accueil</a>
  16. <a rel="tags"
  17. href="/david/2024/#tags"
  18. title="Liste de toutes les étiquettes">
  19. Étiquettes</a>
  20. <a href="/david/log/" title="Accès au flux RSS">Suivre</a>
  21. </p>
  22. </nav>
  23. <form action="https://duckduckgo.com/" method="get" id="form-search">
  24. <fieldset>
  25. <legend>Recherche</legend>
  26. <label for="input-search">Termes de votre recherche :</label>
  27. <input id="input-search" type="search" name="q" aria-describedby="indexation-infos" required>
  28. <input type="submit" value="Chercher">
  29. <p id="indexation-infos" role="status"><small></small></p>
  30. </fieldset>
  31. </form>
  32. <div id="search-results"></div>
  33. <hr>
  34. <p>
  35. Vous pouvez aussi consulter les archives chronologiques de
  36. <a href="/david/2024/">2024</a>,
  37. <a href="/david/2023/">2023</a>,
  38. <a href="/david/2022/">2022</a>,
  39. <a href="/david/2021/">2021</a>,
  40. <a href="/david/2020/">2020</a>,
  41. <a href="/david/blog/">etc</a>.
  42. </p>
  43. {% endblock content %}
  44. {% block search %}{% endblock search %}
  45. {% block extra_body %}
  46. <template id="search-result">
  47. <h2>
  48. <a href="${url}">${title}</a> <time datetime="${date}">${date}</time>
  49. </h2>
  50. <p>${content}</p>
  51. </template>
  52. {# djlint:off #}
  53. <script id="search-index" type="application/json">{{ search_index }}</script>
  54. {# djlint:on #}
  55. <!-- French stopwords from https://github.com/stopwords-iso/stopwords-fr -->
  56. <script id="search-stop-words" type="application/json">
  57. [
  58. "a", "abord", "absolument", "afin", "ah", "ai", "aie", "aient", "aies",
  59. "ailleurs", "ainsi", "ait", "allaient", "allo", "allons", "allô",
  60. "alors", "anterieur", "anterieure", "anterieures", "apres", "après",
  61. "as", "assez", "attendu", "au", "aucun", "aucune", "aucuns", "aujourd",
  62. "aujourd'hui", "aupres", "auquel", "aura", "aurai", "auraient", "aurais",
  63. "aurait", "auras", "aurez", "auriez", "aurions", "aurons", "auront",
  64. "aussi", "autant", "autre", "autrefois", "autrement", "autres", "autrui",
  65. "aux", "auxquelles", "auxquels", "avaient", "avais", "avait", "avant",
  66. "avec", "avez", "aviez", "avions", "avoir", "avons", "ayant", "ayez",
  67. "ayons", "b", "bah", "bas", "basee", "bat", "beau", "beaucoup", "bien",
  68. "bigre", "bon", "boum", "bravo", "brrr", "c", "car", "ce", "ceci",
  69. "cela", "celle", "celle-ci", "celle-là", "celles", "celles-ci",
  70. "celles-là", "celui", "celui-ci", "celui-là", "celà", "cent",
  71. "cependant", "certain", "certaine", "certaines", "certains", "certes",
  72. "ces", "cet", "cette", "ceux", "ceux-ci", "ceux-là", "chacun", "chacune",
  73. "chaque", "cher", "chers", "chez", "chiche", "chut", "chère", "chères",
  74. "ci", "cinq", "cinquantaine", "cinquante", "cinquantième", "cinquième",
  75. "clac", "clic", "combien", "comme", "comment", "comparable",
  76. "comparables", "compris", "concernant", "contre", "couic", "crac", "d",
  77. "da", "dans", "de", "debout", "dedans", "dehors", "deja", "delà",
  78. "depuis", "dernier", "derniere", "derriere", "derrière", "des",
  79. "desormais", "desquelles", "desquels", "dessous", "dessus", "deux",
  80. "deuxième", "deuxièmement", "devant", "devers", "devra", "devrait",
  81. "different", "differentes", "differents", "différent", "différente",
  82. "différentes", "différents", "dire", "directe", "directement", "dit",
  83. "dite", "dits", "divers", "diverse", "diverses", "dix", "dix-huit",
  84. "dix-neuf", "dix-sept", "dixième", "doit", "doivent", "donc", "dont",
  85. "dos", "douze", "douzième", "dring", "droite", "du", "duquel", "durant",
  86. "dès", "début", "désormais", "e", "effet", "egale", "egalement",
  87. "egales", "eh", "elle", "elle-même", "elles", "elles-mêmes", "en",
  88. "encore", "enfin", "entre", "envers", "environ", "es", "essai", "est",
  89. "et", "etant", "etc", "etre", "eu", "eue", "eues", "euh", "eurent",
  90. "eus", "eusse", "eussent", "eusses", "eussiez", "eussions", "eut", "eux",
  91. "eux-mêmes", "exactement", "excepté", "extenso", "exterieur", "eûmes",
  92. "eût", "eûtes", "f", "fais", "faisaient", "faisant", "fait", "faites",
  93. "façon", "feront", "fi", "flac", "floc", "fois", "font", "force",
  94. "furent", "fus", "fusse", "fussent", "fusses", "fussiez", "fussions",
  95. "fut", "fûmes", "fût", "fûtes", "g", "gens", "h", "ha", "haut", "hein",
  96. "hem", "hep", "hi", "ho", "holà", "hop", "hormis", "hors", "hou", "houp",
  97. "hue", "hui", "huit", "huitième", "hum", "hurrah", "hé", "hélas", "i",
  98. "ici", "il", "ils", "importe", "j", "je", "jusqu", "jusque", "juste",
  99. "k", "l", "la", "laisser", "laquelle", "las", "le", "lequel", "les",
  100. "lesquelles", "lesquels", "leur", "leurs", "longtemps", "lors",
  101. "lorsque", "lui", "lui-meme", "lui-même", "là", "lès", "m", "ma",
  102. "maint", "maintenant", "mais", "malgre", "malgré", "maximale", "me",
  103. "meme", "memes", "merci", "mes", "mien", "mienne", "miennes", "miens",
  104. "mille", "mince", "mine", "minimale", "moi", "moi-meme", "moi-même",
  105. "moindres", "moins", "mon", "mot", "moyennant", "multiple", "multiples",
  106. "même", "mêmes", "n", "na", "naturel", "naturelle", "naturelles", "ne",
  107. "neanmoins", "necessaire", "necessairement", "neuf", "neuvième", "ni",
  108. "nombreuses", "nombreux", "nommés", "non", "nos", "notamment", "notre",
  109. "nous", "nous-mêmes", "nouveau", "nouveaux", "nul", "néanmoins", "nôtre",
  110. "nôtres", "o", "oh", "ohé", "ollé", "olé", "on", "ont", "onze",
  111. "onzième", "ore", "ou", "ouf", "ouias", "oust", "ouste", "outre",
  112. "ouvert", "ouverte", "ouverts", "o|", "où", "p", "paf", "pan", "par",
  113. "parce", "parfois", "parle", "parlent", "parler", "parmi", "parole",
  114. "parseme", "partant", "particulier", "particulière", "particulièrement",
  115. "pas", "passé", "pendant", "pense", "permet", "personne", "personnes",
  116. "peu", "peut", "peuvent", "peux", "pff", "pfft", "pfut", "pif", "pire",
  117. "pièce", "plein", "plouf", "plupart", "plus", "plusieurs", "plutôt",
  118. "possessif", "possessifs", "possible", "possibles", "pouah", "pour",
  119. "pourquoi", "pourrais", "pourrait", "pouvait", "prealable",
  120. "precisement", "premier", "première", "premièrement", "pres", "probable",
  121. "probante", "procedant", "proche", "près", "psitt", "pu", "puis",
  122. "puisque", "pur", "pure", "q", "qu", "quand", "quant", "quant-à-soi",
  123. "quanta", "quarante", "quatorze", "quatre", "quatre-vingt", "quatrième",
  124. "quatrièmement", "que", "quel", "quelconque", "quelle", "quelles",
  125. "quelqu'un", "quelque", "quelques", "quels", "qui", "quiconque",
  126. "quinze", "quoi", "quoique", "r", "rare", "rarement", "rares",
  127. "relative", "relativement", "remarquable", "rend", "rendre", "restant",
  128. "reste", "restent", "restrictif", "retour", "revoici", "revoilà", "rien",
  129. "s", "sa", "sacrebleu", "sait", "sans", "sapristi", "sauf", "se", "sein",
  130. "seize", "selon", "semblable", "semblaient", "semble", "semblent",
  131. "sent", "sept", "septième", "sera", "serai", "seraient", "serais",
  132. "serait", "seras", "serez", "seriez", "serions", "serons", "seront",
  133. "ses", "seul", "seule", "seulement", "si", "sien", "sienne", "siennes",
  134. "siens", "sinon", "six", "sixième", "soi", "soi-même", "soient", "sois",
  135. "soit", "soixante", "sommes", "son", "sont", "sous", "souvent", "soyez",
  136. "soyons", "specifique", "specifiques", "speculatif", "stop",
  137. "strictement", "subtiles", "suffisant", "suffisante", "suffit", "suis",
  138. "suit", "suivant", "suivante", "suivantes", "suivants", "suivre",
  139. "sujet", "superpose", "sur", "surtout", "t", "ta", "tac", "tandis",
  140. "tant", "tardive", "te", "tel", "telle", "tellement", "telles", "tels",
  141. "tenant", "tend", "tenir", "tente", "tes", "tic", "tien", "tienne",
  142. "tiennes", "tiens", "toc", "toi", "toi-même", "ton", "touchant",
  143. "toujours", "tous", "tout", "toute", "toutefois", "toutes", "treize",
  144. "trente", "tres", "trois", "troisième", "troisièmement", "trop", "très",
  145. "tsoin", "tsouin", "tu", "té", "u", "un", "une", "unes", "uniformement",
  146. "unique", "uniques", "uns", "v", "va", "vais", "valeur", "vas", "vers",
  147. "via", "vif", "vifs", "vingt", "vivat", "vive", "vives", "vlan", "voici",
  148. "voie", "voient", "voilà", "voire", "vont", "vos", "votre", "vous",
  149. "vous-mêmes", "vu", "vé", "vôtre", "vôtres", "w", "x", "y", "z", "zut",
  150. "à", "â", "ça", "ès", "étaient", "étais", "était", "étant", "état",
  151. "étiez", "étions", "été", "étée", "étées", "étés", "êtes", "être", "ô"
  152. ]
  153. </script>
  154. <script type="text/javascript">
  155. /* See:
  156. * https://gomakethings.com/how-to-create-a-search-page-for-a-static-website-with-vanilla-js/
  157. * https://gomakethings.com/how-to-update-the-url-of-a-page-without-causing-a-reload-using-vanilla-javascript/
  158. */
  159. ;
  160. (function() {
  161. // Retrieving the search index and stopwords from JSON.
  162. // See https://v8.dev/blog/cost-of-javascript-2019#json
  163. let searchIndex = JSON.parse(
  164. document.getElementById('search-index').textContent
  165. )
  166. let stopWords = JSON.parse(
  167. document.getElementById('search-stop-words').textContent
  168. )
  169. // Get the DOM elements
  170. let form = document.querySelector('#form-search')
  171. let input = document.querySelector('#input-search')
  172. let resultList = document.querySelector('#search-results')
  173. let searchStatus = document.querySelector('[role="status"] small')
  174. let searchResultTemplate = document.querySelector('#search-result')
  175. // Make sure required content exists
  176. if (
  177. !form ||
  178. !input ||
  179. !resultList ||
  180. !searchStatus ||
  181. !searchIndex ||
  182. !stopWords ||
  183. !searchResultTemplate
  184. )
  185. return
  186. // Create a submit handler
  187. form.addEventListener('submit', function(event) {
  188. event.preventDefault()
  189. search(input.value)
  190. })
  191. // Create a typeahead handler
  192. form.addEventListener('keyup', function(event) {
  193. search(input.value)
  194. })
  195. // Create a reset handler
  196. form.addEventListener('reset', function() {
  197. search('')
  198. searchStatus.innerHTML = ''
  199. })
  200. // Check for query strings onload
  201. onload()
  202. /**
  203. * If there's a query string search term, search it on page load
  204. */
  205. function onload() {
  206. let query = new URLSearchParams(window.location.search).get('s')
  207. if (!query) return
  208. input.value = query
  209. search(query)
  210. }
  211. /**
  212. * Search for matches
  213. * @param {String} query The term to search for
  214. */
  215. function search(query) {
  216. // Create a regex for each query
  217. let regMap = query
  218. .toLowerCase()
  219. .split(' ')
  220. .filter(function(word) {
  221. return word.length && !stopWords.includes(word)
  222. })
  223. .map(function(word) {
  224. return new RegExp(word, 'i')
  225. })
  226. // Get and sort the results
  227. let results = searchIndex
  228. .reduce(function(results, article, index) {
  229. // Setup priority count
  230. let priority = 0
  231. // Assign priority
  232. for (let reg of regMap) {
  233. if (reg.test(article.title)) {
  234. priority += 100
  235. }
  236. let occurences = article.content.match(reg)
  237. if (occurences) {
  238. priority += occurences.length
  239. }
  240. }
  241. // If any matches, push to results
  242. if (priority > 0) {
  243. results.push({
  244. priority: priority,
  245. article: article,
  246. })
  247. }
  248. return results
  249. }, [])
  250. .sort(function(article1, article2) {
  251. return article2.priority - article1.priority
  252. })
  253. results = [
  254. ...new Map(results.map(item => [item['article']['title'], item])).values()
  255. ]
  256. // Display the results
  257. showResults(results, regMap)
  258. // Update the URL
  259. updateURL(query)
  260. }
  261. /**
  262. * Show the search results in the UI
  263. * @param {Array} results The results to display
  264. * @param {List} regMap Regular expressions for the highlights
  265. */
  266. function showResults(results, regMap) {
  267. let status = 'Aucune publication n’a été trouvée 😢'
  268. let searchResults = ''
  269. if (results.length) {
  270. const plural = results.length > 1 ? 's' : ''
  271. status = `${results.length} publication${plural} trouvée${plural} 🙌`
  272. searchResults = results
  273. .map(function(result) {
  274. return interpolate(searchResultTemplate.innerHTML, {
  275. url: result.article.url,
  276. title: highlightText(result.article.title, regMap),
  277. date: result.article.date,
  278. content: highlightText(result.article.content, regMap),
  279. })
  280. })
  281. .join('')
  282. }
  283. searchStatus.innerHTML = status
  284. resultList.innerHTML = searchResults
  285. }
  286. /**
  287. * Get a template from a string
  288. * https://stackoverflow.com/a/41015840
  289. * https://gomakethings.com/html-templates-with-vanilla-javascript/
  290. * @param {String} str The string to interpolate
  291. * @param {Object} params The parameters
  292. * @return {String} The interpolated string
  293. */
  294. function interpolate(str, params) {
  295. let names = Object.keys(params)
  296. let vals = Object.values(params)
  297. return new Function(...names, `return \`${str}\``)(...vals)
  298. }
  299. /**
  300. * Highlight the text in the UI
  301. * @param {String} text The content to highlight
  302. * @param {List} regMap Regular expressions for the highlights
  303. */
  304. function highlightText(text, regMap) {
  305. // TODO: deal with close matches when multiple words are looked for,
  306. // it does not look trivial because you have to memorize positions
  307. // then create extracts.
  308. // For instance: `microsoft github`
  309. const extractBoundariesSize = 100
  310. const textLength = text.length
  311. let extracts = []
  312. for (let reg of regMap) {
  313. const index = text.search(reg)
  314. if (index === -1) {
  315. continue
  316. }
  317. let extract = text.substring(
  318. index - extractBoundariesSize,
  319. index + reg.source.length + extractBoundariesSize
  320. )
  321. // TODISCUSS: we replace with the source but in case there is
  322. // an uppercase letter it will disappear from the extract
  323. // (is that confusing or closer to what is expected?)
  324. extract = extract.replace(reg, `<mark>${reg.source}</mark>`)
  325. const prefixEllipsis = index - extractBoundariesSize >= 0 ? '…' : ''
  326. const suffixEllipsis =
  327. index + extractBoundariesSize <= textLength ? '…' : ''
  328. extracts.push(`${prefixEllipsis}${extract}${suffixEllipsis}`)
  329. }
  330. if (!extracts.length && textLength < 200) {
  331. // If there is no match but it's a short title, return it.
  332. return text
  333. }
  334. return extracts.join('')
  335. }
  336. /**
  337. * Update the URL with a query string for the search string
  338. * @param {String} query The search query
  339. */
  340. function updateURL(query) {
  341. // Create the properties
  342. let state = history.state
  343. let title = document.title
  344. let url = window.location.origin + window.location.pathname
  345. if (query) {
  346. url += '?s=' + encodeURI(query)
  347. }
  348. // Update the URL
  349. history.pushState(state, title, url)
  350. }
  351. })()
  352. </script>
  353. {% endblock %}