Repository with sources and generator of https://larlet.fr/david/ https://larlet.fr/david/
Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

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