{"id":31883,"date":"2026-09-24T10:02:00","date_gmt":"2026-09-24T08:02:00","guid":{"rendered":"https:\/\/thibaultbazin.fr\/?page_id=31883"},"modified":"2026-09-24T11:22:28","modified_gmt":"2026-09-24T09:22:28","slug":"mes-actions-locales","status":"publish","type":"page","link":"https:\/\/thibaultbazin.fr\/index.php\/mes-actions-locales\/","title":{"rendered":"Mes actions locales"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-page\" data-elementor-id=\"31883\" class=\"elementor elementor-31883\">\n\t\t\t\t\t\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-10e6700 elementor-section-boxed elementor-section-height-default elementor-section-height-default\" data-id=\"10e6700\" data-element_type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-b4e719b\" data-id=\"b4e719b\" data-element_type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t\t\t<div class=\"elementor-element elementor-element-bf0e912 elementor-widget elementor-widget-html\" data-id=\"bf0e912\" data-element_type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t<!-- ==========================================================\n     MES ACTIONS LOCALES \u2014 THIBAULT BAZIN\n     2017 \u2192 2026\n     UNIQUEMENT ACTIONS DE TERRAIN \/ CIRCONSCRIPTION\n     Les publications parlementaires sont exclues.\n     ========================================================== -->\n\n<section id=\"tb-local\">\n\n<style>\n\n\/* ============================================================\n   BASE\n   ============================================================ *\/\n\n#tb-local {\n    --navy:#173856;\n    --navy-dark:#102a42;\n    --blue:#22577a;\n    --gold:#b28b4a;\n\n    --bg:#f5f7f9;\n    --white:#ffffff;\n    --border:#e1e7eb;\n\n    --text:#20272d;\n    --muted:#68747e;\n\n    font-family:inherit;\n    color:var(--text);\n    width:100%;\n}\n\n#tb-local *,\n#tb-local *::before,\n#tb-local *::after {\n    box-sizing:border-box;\n}\n\n#tb-local .tb-wrap {\n    width:min(1200px, calc(100% - 32px));\n    margin:auto;\n}\n\n\n\/* ============================================================\n   HERO\n   ============================================================ *\/\n\n#tb-local .tb-hero {\n    position:relative;\n    overflow:hidden;\n\n    padding:72px 38px;\n    margin-bottom:0;\n\n    border-radius:16px;\n\n    background:\n        linear-gradient(\n            125deg,\n            #102a42 0%,\n            #173856 55%,\n            #22577a 100%\n        );\n\n    color:#fff;\n}\n\n#tb-local .tb-hero::before {\n    content:\"\";\n\n    position:absolute;\n    width:430px;\n    height:430px;\n\n    right:-150px;\n    top:-240px;\n\n    border:1px solid rgba(255,255,255,.12);\n    border-radius:50%;\n}\n\n#tb-local .tb-hero::after {\n    content:\"\";\n\n    position:absolute;\n    width:290px;\n    height:290px;\n\n    right:120px;\n    bottom:-230px;\n\n    border:1px solid rgba(255,255,255,.09);\n    border-radius:50%;\n}\n\n#tb-local .tb-hero-inner {\n    position:relative;\n    z-index:2;\n\n    max-width:830px;\n}\n\n#tb-local .tb-kicker {\n    display:flex;\n    align-items:center;\n    gap:10px;\n\n    margin-bottom:16px;\n\n    text-transform:uppercase;\n\n    font-size:13px;\n    font-weight:700;\n    letter-spacing:1.4px;\n\n    color:rgba(255,255,255,.8);\n}\n\n#tb-local .tb-kicker::before {\n    content:\"\";\n\n    width:30px;\n    height:2px;\n\n    background:var(--gold);\n}\n\n#tb-local .tb-hero h1 {\n    margin:0 0 18px;\n\n    color:#fff;\n\n    font-size:clamp(38px,5vw,60px);\n    line-height:1.02;\n\n    letter-spacing:-1.5px;\n}\n\n#tb-local .tb-hero p {\n    max-width:760px;\n\n    margin:0;\n\n    color:rgba(255,255,255,.92);\n\n    font-size:18px;\n    line-height:1.7;\n}\n\n\n\/* ============================================================\n   STATS\n   ============================================================ *\/\n\n#tb-local .tb-stats {\n    position:relative;\n    z-index:5;\n\n    display:grid;\n\n    grid-template-columns:\n        repeat(3,minmax(0,1fr));\n\n    gap:14px;\n\n    margin:-22px 24px 48px;\n}\n\n#tb-local .tb-stat {\n    padding:22px;\n\n    background:#fff;\n\n    border:1px solid var(--border);\n    border-radius:10px;\n\n    box-shadow:\n        0 8px 28px\n        rgba(16,42,66,.09);\n\n    text-align:center;\n}\n\n#tb-local .tb-stat-value {\n    display:block;\n\n    color:var(--navy);\n\n    font-size:28px;\n    font-weight:800;\n}\n\n#tb-local .tb-stat-label {\n    display:block;\n\n    margin-top:5px;\n\n    color:var(--muted);\n\n    font-size:13px;\n    line-height:1.4;\n}\n\n\n\/* ============================================================\n   INTRO\n   ============================================================ *\/\n\n#tb-local .tb-intro {\n    max-width:820px;\n\n    margin:\n        0 auto\n        38px;\n\n    text-align:center;\n}\n\n#tb-local .tb-intro-small {\n    display:block;\n\n    margin-bottom:8px;\n\n    color:var(--gold);\n\n    font-size:12px;\n    font-weight:800;\n\n    letter-spacing:1.2px;\n    text-transform:uppercase;\n}\n\n#tb-local .tb-intro h2 {\n    margin:\n        0 0 12px;\n\n    color:var(--navy-dark);\n\n    font-size:clamp(27px,3.5vw,37px);\n    line-height:1.15;\n}\n\n#tb-local .tb-intro p {\n    margin:0;\n\n    color:var(--muted);\n\n    font-size:16px;\n    line-height:1.75;\n}\n\n\n\/* ============================================================\n   ANN\u00c9ES\n   ============================================================ *\/\n\n#tb-local .tb-years {\n    display:flex;\n\n    gap:8px;\n\n    overflow-x:auto;\n\n    padding:\n        3px 2px\n        10px;\n\n    margin-bottom:16px;\n\n    -webkit-overflow-scrolling:touch;\n}\n\n#tb-local .tb-year {\n    flex:0 0 auto;\n\n    min-height:42px;\n\n    padding:\n        8px 15px;\n\n    border:\n        1px solid\n        var(--border);\n\n    border-radius:24px;\n\n    background:#fff;\n    color:var(--navy);\n\n    cursor:pointer;\n\n    font:inherit;\n\n    font-size:14px;\n    font-weight:750;\n\n    transition:\n        .18s ease;\n}\n\n#tb-local .tb-year:hover {\n    border-color:var(--navy);\n\n    transform:\n        translateY(-1px);\n}\n\n#tb-local .tb-year.active {\n    color:#fff;\n\n    background:var(--navy);\n    border-color:var(--navy);\n}\n\n#tb-local .tb-year-number {\n    margin-left:5px;\n\n    opacity:.62;\n\n    font-size:11px;\n}\n\n\n\/* ============================================================\n   RECHERCHE\n   ============================================================ *\/\n\n#tb-local .tb-tools {\n    display:grid;\n\n    grid-template-columns:\n        1fr auto;\n\n    gap:12px;\n\n    margin-bottom:12px;\n}\n\n#tb-local .tb-search-wrap {\n    position:relative;\n}\n\n#tb-local .tb-search-icon {\n    position:absolute;\n\n    left:17px;\n    top:50%;\n\n    width:18px;\n    height:18px;\n\n    transform:\n        translateY(-50%);\n\n    opacity:.5;\n\n    pointer-events:none;\n}\n\n#tb-local .tb-search {\n    width:100%;\n    height:52px;\n\n    padding:\n        0 18px\n        0 48px;\n\n    border:\n        1px solid\n        var(--border);\n\n    border-radius:8px;\n\n    background:#fff;\n\n    outline:none;\n\n    font:inherit;\n    font-size:15px;\n}\n\n#tb-local .tb-search:focus {\n    border-color:var(--blue);\n\n    box-shadow:\n        0 0 0 4px\n        rgba(34,87,122,.08);\n}\n\n#tb-local .tb-reset {\n    height:52px;\n\n    padding:0 19px;\n\n    border:\n        1px solid\n        var(--border);\n\n    border-radius:8px;\n\n    background:#fff;\n\n    color:var(--navy);\n\n    cursor:pointer;\n\n    font:inherit;\n    font-size:14px;\n    font-weight:750;\n}\n\n#tb-local .tb-reset:hover {\n    background:var(--bg);\n}\n\n\n\/* ============================================================\n   NOMBRE DE R\u00c9SULTATS\n   ============================================================ *\/\n\n#tb-local .tb-result-info {\n    min-height:32px;\n\n    margin-bottom:18px;\n\n    color:var(--muted);\n\n    font-size:13px;\n}\n\n#tb-local .tb-result-info strong {\n    color:var(--navy);\n}\n\n\n\/* ============================================================\n   GRILLE\n   ============================================================ *\/\n\n#tb-local .tb-grid {\n    display:grid;\n\n    grid-template-columns:\n        repeat(3,minmax(0,1fr));\n\n    gap:24px;\n}\n\n\n\/* ============================================================\n   CARTE\n   ============================================================ *\/\n\n#tb-local .tb-card {\n    display:flex;\n    flex-direction:column;\n\n    min-width:0;\n\n    overflow:hidden;\n\n    background:#fff;\n\n    border:\n        1px solid\n        var(--border);\n\n    border-radius:12px;\n\n    box-shadow:\n        0 3px 14px\n        rgba(20,42,58,.04);\n\n    transition:\n        transform .22s ease,\n        box-shadow .22s ease,\n        border-color .22s ease;\n}\n\n#tb-local .tb-card:hover {\n    transform:\n        translateY(-5px);\n\n    border-color:#d2dce2;\n\n    box-shadow:\n        0 15px 34px\n        rgba(20,42,58,.10);\n}\n\n\n\/* IMAGE *\/\n\n#tb-local .tb-image {\n    position:relative;\n\n    display:block;\n\n    aspect-ratio:16 \/ 9;\n\n    overflow:hidden;\n\n    background:\n        linear-gradient(\n            135deg,\n            var(--navy-dark),\n            var(--blue)\n        );\n}\n\n#tb-local .tb-image img {\n    width:100%;\n    height:100%;\n\n    display:block;\n\n    object-fit:cover;\n\n    transition:\n        transform .4s ease;\n}\n\n#tb-local .tb-card:hover .tb-image img {\n    transform:\n        scale(1.04);\n}\n\n#tb-local .tb-placeholder {\n    display:flex;\n\n    align-items:center;\n    justify-content:center;\n\n    height:100%;\n\n    padding:30px;\n\n    color:#fff;\n\n    text-align:center;\n\n    font-size:20px;\n    font-weight:750;\n}\n\n#tb-local .tb-year-badge {\n    position:absolute;\n\n    top:14px;\n    left:14px;\n\n    padding:\n        6px 10px;\n\n    border-radius:5px;\n\n    background:\n        rgba(16,42,66,.93);\n\n    color:#fff;\n\n    font-size:12px;\n    font-weight:800;\n}\n\n\n\/* ============================================================\n   CONTENU CARTE\n   ============================================================ *\/\n\n#tb-local .tb-card-body {\n    display:flex;\n    flex-direction:column;\n\n    flex:1;\n\n    padding:22px;\n}\n\n#tb-local .tb-meta {\n    display:flex;\n\n    align-items:center;\n\n    flex-wrap:wrap;\n\n    gap:7px;\n\n    margin-bottom:11px;\n}\n\n#tb-local .tb-date {\n    color:var(--gold);\n\n    font-size:12px;\n    font-weight:800;\n\n    letter-spacing:.3px;\n\n    text-transform:uppercase;\n}\n\n#tb-local .tb-type {\n    padding:\n        4px 8px;\n\n    border-radius:4px;\n\n    background:var(--bg);\n\n    color:var(--navy);\n\n    font-size:10px;\n    font-weight:700;\n}\n\n#tb-local .tb-card h3 {\n    margin:\n        0 0\n        11px;\n\n    color:var(--navy-dark);\n\n    font-size:19px;\n    line-height:1.32;\n}\n\n#tb-local .tb-card h3 a {\n    color:inherit;\n\n    text-decoration:none;\n}\n\n#tb-local .tb-card h3 a:hover {\n    text-decoration:underline;\n\n    text-underline-offset:3px;\n}\n\n#tb-local .tb-excerpt {\n    flex:1;\n\n    margin:\n        0 0\n        20px;\n\n    color:var(--muted);\n\n    font-size:14px;\n    line-height:1.65;\n}\n\n#tb-local .tb-read {\n    display:inline-flex;\n\n    align-items:center;\n\n    gap:7px;\n\n    align-self:flex-start;\n\n    color:var(--navy);\n\n    text-decoration:none;\n\n    font-size:13px;\n    font-weight:800;\n}\n\n#tb-local .tb-arrow {\n    transition:\n        transform .2s ease;\n}\n\n#tb-local .tb-read:hover .tb-arrow {\n    transform:\n        translateX(4px);\n}\n\n\n\/* ============================================================\n   \u00c9TATS\n   ============================================================ *\/\n\n#tb-local .tb-state {\n    grid-column:\n        1 \/ -1;\n\n    padding:\n        65px 24px;\n\n    border:\n        1px solid\n        var(--border);\n\n    border-radius:12px;\n\n    background:var(--bg);\n\n    color:var(--muted);\n\n    text-align:center;\n\n    font-size:15px;\n}\n\n#tb-local .tb-state strong {\n    color:var(--navy);\n}\n\n#tb-local .tb-spinner {\n    width:42px;\n    height:42px;\n\n    margin:\n        0 auto\n        18px;\n\n    border:\n        3px solid\n        #d8e0e5;\n\n    border-top-color:\n        var(--navy);\n\n    border-radius:50%;\n\n    animation:\n        tbSpin .75s\n        linear infinite;\n}\n\n@keyframes tbSpin {\n    to {\n        transform:\n            rotate(360deg);\n    }\n}\n\n\n\/* ============================================================\n   AFFICHER PLUS\n   ============================================================ *\/\n\n#tb-local .tb-more {\n    display:flex;\n\n    justify-content:center;\n\n    padding:\n        38px 0\n        15px;\n}\n\n#tb-local .tb-more button {\n    display:none;\n\n    min-width:220px;\n    min-height:50px;\n\n    padding:\n        12px 24px;\n\n    border:0;\n\n    border-radius:7px;\n\n    background:var(--navy);\n\n    color:#fff;\n\n    cursor:pointer;\n\n    font:inherit;\n    font-size:14px;\n    font-weight:750;\n}\n\n#tb-local .tb-more button:hover {\n    background:var(--navy-dark);\n}\n\n\n\/* ============================================================\n   NOTE\n   ============================================================ *\/\n\n#tb-local .tb-note {\n    margin-top:40px;\n\n    padding:\n        24px 10px\n        8px;\n\n    border-top:\n        1px solid\n        var(--border);\n\n    color:var(--muted);\n\n    text-align:center;\n\n    font-size:12px;\n    line-height:1.6;\n}\n\n\n\/* ============================================================\n   MOBILE\n   ============================================================ *\/\n\n@media(max-width:960px) {\n\n    #tb-local .tb-grid {\n        grid-template-columns:\n            repeat(2,minmax(0,1fr));\n    }\n\n}\n\n\n@media(max-width:700px) {\n\n    #tb-local .tb-wrap {\n        width:\n            calc(100% - 22px);\n    }\n\n    #tb-local .tb-hero {\n        padding:\n            50px 23px;\n\n        border-radius:10px;\n    }\n\n    #tb-local .tb-hero p {\n        font-size:16px;\n    }\n\n    #tb-local .tb-stats {\n        grid-template-columns:\n            1fr 1fr;\n\n        margin:\n            -12px 8px\n            38px;\n    }\n\n    #tb-local .tb-stat:first-child {\n        grid-column:\n            1 \/ -1;\n    }\n\n    #tb-local .tb-tools {\n        grid-template-columns:\n            1fr;\n    }\n\n    #tb-local .tb-reset {\n        display:none;\n    }\n\n    #tb-local .tb-grid {\n        grid-template-columns:\n            1fr;\n    }\n\n}\n\n\n@media(max-width:420px) {\n\n    #tb-local .tb-stats {\n        grid-template-columns:\n            1fr;\n    }\n\n    #tb-local .tb-stat:first-child {\n        grid-column:auto;\n    }\n\n}\n\n<\/style>\n\n\n<div class=\"tb-wrap\">\n\n\n<!-- ========================================================\n     EN-T\u00caTE\n     ======================================================== -->\n\n<header class=\"tb-hero\">\n\n    <div class=\"tb-hero-inner\">\n\n        <div class=\"tb-kicker\">\n            4e circonscription de Meurthe-et-Moselle\n        <\/div>\n\n        <h1>\n            Mes actions locales\n        <\/h1>\n\n        <p>\n            Retrouvez mes d\u00e9placements, rencontres, visites,\n            inaugurations, permanences, comm\u00e9morations et\n            \u00e9v\u00e9nements dans la circonscription depuis 2017.\n        <\/p>\n\n    <\/div>\n\n<\/header>\n\n\n<!-- ========================================================\n     CHIFFRES\n     ======================================================== -->\n\n<div class=\"tb-stats\">\n\n    <div class=\"tb-stat\">\n\n        <span\n            class=\"tb-stat-value\"\n            id=\"tb-total\"\n        >\n            \u2014\n        <\/span>\n\n        <span class=\"tb-stat-label\">\n            publications locales recens\u00e9es\n        <\/span>\n\n    <\/div>\n\n\n    <div class=\"tb-stat\">\n\n        <span class=\"tb-stat-value\">\n            2017\n        <\/span>\n\n        <span class=\"tb-stat-label\">\n            d\u00e9but de la p\u00e9riode\n        <\/span>\n\n    <\/div>\n\n\n    <div class=\"tb-stat\">\n\n        <span class=\"tb-stat-value\">\n            2026\n        <\/span>\n\n        <span class=\"tb-stat-label\">\n            ann\u00e9e la plus r\u00e9cente\n        <\/span>\n\n    <\/div>\n\n<\/div>\n\n\n<!-- ========================================================\n     INTRODUCTION\n     ======================================================== -->\n\n<div class=\"tb-intro\">\n\n    <span class=\"tb-intro-small\">\n        Sur le terrain\n    <\/span>\n\n    <h2>\n        Mon activit\u00e9 dans la circonscription\n    <\/h2>\n\n    <p>\n        Retrouvez les actions et d\u00e9placements locaux\n        publi\u00e9s sur le site depuis 2017.\n        Vous pouvez s\u00e9lectionner une ann\u00e9e ou rechercher\n        directement une commune, une structure ou un \u00e9v\u00e9nement.\n    <\/p>\n\n<\/div>\n\n\n<!-- ========================================================\n     ANN\u00c9ES\n     ======================================================== -->\n\n<div\n    class=\"tb-years\"\n    id=\"tb-years\"\n><\/div>\n\n\n<!-- ========================================================\n     RECHERCHE\n     ======================================================== -->\n\n<div class=\"tb-tools\">\n\n    <div class=\"tb-search-wrap\">\n\n        <svg\n            class=\"tb-search-icon\"\n            viewBox=\"0 0 24 24\"\n            fill=\"none\"\n            stroke=\"currentColor\"\n            stroke-width=\"2\"\n            aria-hidden=\"true\"\n        >\n\n            <circle\n                cx=\"11\"\n                cy=\"11\"\n                r=\"7\"\n            ><\/circle>\n\n            <path\n                d=\"M20 20l-3.5-3.5\"\n            ><\/path>\n\n        <\/svg>\n\n\n        <input\n            id=\"tb-search\"\n            class=\"tb-search\"\n            type=\"search\"\n            placeholder=\"Rechercher une commune, une entreprise, une \u00e9cole\u2026\"\n            autocomplete=\"off\"\n        >\n\n    <\/div>\n\n\n    <button\n        type=\"button\"\n        id=\"tb-reset\"\n        class=\"tb-reset\"\n    >\n        R\u00e9initialiser\n    <\/button>\n\n<\/div>\n\n\n<div\n    class=\"tb-result-info\"\n    id=\"tb-results\"\n>\n    Chargement des actions locales\u2026\n<\/div>\n\n\n<!-- ========================================================\n     CARTES\n     ======================================================== -->\n\n<div\n    class=\"tb-grid\"\n    id=\"tb-grid\"\n>\n\n    <div class=\"tb-state\">\n\n        <div class=\"tb-spinner\"><\/div>\n\n        Chargement des publications locales\u2026\n\n    <\/div>\n\n<\/div>\n\n\n<div class=\"tb-more\">\n\n    <button\n        id=\"tb-more\"\n        type=\"button\"\n    >\n        Afficher plus\n    <\/button>\n\n<\/div>\n\n\n<div class=\"tb-note\">\n\n    Cette page pr\u00e9sente uniquement les publications\n    relatives aux actions locales et aux d\u00e9placements\n    dans la circonscription publi\u00e9es sur thibaultbazin.fr.\n\n<\/div>\n\n\n<\/div>\n\n\n<script>\n\n(function () {\n\n\"use strict\";\n\n\n\/* ============================================================\n   CONFIGURATION\n   ============================================================ *\/\n\nconst START_DATE =\n    \"2017-06-18T00:00:00\";\n\nconst END_DATE =\n    \"2026-12-31T23:59:59\";\n\nconst FIRST_YEAR =\n    2017;\n\nconst LAST_YEAR =\n    2026;\n\nconst API_PER_PAGE =\n    100;\n\nconst POSTS_PER_VIEW =\n    18;\n\n\n\/* ============================================================\n   \u00c9L\u00c9MENTS\n   ============================================================ *\/\n\nconst grid =\n    document.getElementById(\n        \"tb-grid\"\n    );\n\nconst yearsContainer =\n    document.getElementById(\n        \"tb-years\"\n    );\n\nconst searchInput =\n    document.getElementById(\n        \"tb-search\"\n    );\n\nconst resetButton =\n    document.getElementById(\n        \"tb-reset\"\n    );\n\nconst moreButton =\n    document.getElementById(\n        \"tb-more\"\n    );\n\nconst results =\n    document.getElementById(\n        \"tb-results\"\n    );\n\nconst totalElement =\n    document.getElementById(\n        \"tb-total\"\n    );\n\n\nlet allPosts = [];\n\nlet filteredPosts = [];\n\nlet categories =\n    new Map();\n\nlet activeYear =\n    \"\";\n\nlet visibleCount =\n    POSTS_PER_VIEW;\n\nlet workingApiMode =\n    null;\n\n\n\/* ============================================================\n   TEXTE\n   ============================================================ *\/\n\nfunction stripHtml(html) {\n\n    const div =\n        document.createElement(\n            \"div\"\n        );\n\n    div.innerHTML =\n        html || \"\";\n\n    return (\n        div.textContent ||\n        div.innerText ||\n        \"\"\n    )\n    .replace(\n        \/\\s+\/g,\n        \" \"\n    )\n    .trim();\n\n}\n\n\nfunction decodeHtml(html) {\n\n    const textarea =\n        document.createElement(\n            \"textarea\"\n        );\n\n    textarea.innerHTML =\n        html || \"\";\n\n    return textarea.value;\n\n}\n\n\nfunction normalize(text) {\n\n    return (\n        text || \"\"\n    )\n    .toLowerCase()\n    .normalize(\"NFD\")\n    .replace(\n        \/[\\u0300-\\u036f]\/g,\n        \"\"\n    )\n    .replace(\n        \/[\u2019']\/g,\n        \"'\"\n    );\n\n}\n\n\nfunction containsAny(\n    text,\n    words\n) {\n\n    const normalized =\n        normalize(text);\n\n    return words.some(\n        function(word) {\n\n            return normalized.includes(\n                normalize(word)\n            );\n\n        }\n    );\n\n}\n\n\nfunction truncate(\n    text,\n    max\n) {\n\n    if (\n        text.length <= max\n    ) {\n\n        return text;\n\n    }\n\n    return (\n        text\n        .substring(\n            0,\n            max\n        )\n        .replace(\n            \/\\s+\\S*$\/,\n            \"\"\n        )\n        +\n        \"\u2026\"\n    );\n\n}\n\n\n\/* ============================================================\n   API WORDPRESS\n   ============================================================ *\/\n\nconst API_MODES = [\n\n    \"wp-json\",\n\n    \"query\",\n\n    \"index-query\",\n\n    \"index-wp-json\"\n\n];\n\n\nfunction makeApiUrl(\n    mode,\n    path,\n    params\n) {\n\n    let url;\n\n\n    if (\n        mode ===\n        \"wp-json\"\n    ) {\n\n        url =\n            new URL(\n                \"\/wp-json\/wp\/v2\" +\n                path,\n                window.location.origin\n            );\n\n    }\n\n\n    else if (\n        mode ===\n        \"query\"\n    ) {\n\n        url =\n            new URL(\n                \"\/\",\n                window.location.origin\n            );\n\n        url.searchParams.set(\n            \"rest_route\",\n            \"\/wp\/v2\" +\n            path\n        );\n\n    }\n\n\n    else if (\n        mode ===\n        \"index-query\"\n    ) {\n\n        url =\n            new URL(\n                \"\/index.php\",\n                window.location.origin\n            );\n\n        url.searchParams.set(\n            \"rest_route\",\n            \"\/wp\/v2\" +\n            path\n        );\n\n    }\n\n\n    else {\n\n        url =\n            new URL(\n                \"\/index.php\/wp-json\/wp\/v2\" +\n                path,\n                window.location.origin\n            );\n\n    }\n\n\n    Object.entries(\n        params || {}\n    )\n    .forEach(\n        function(\n            entry\n        ) {\n\n            url.searchParams.set(\n                entry[0],\n                entry[1]\n            );\n\n        }\n    );\n\n\n    return url.toString();\n\n}\n\n\nasync function wpRequest(\n    path,\n    params = {}\n) {\n\n    const modes =\n        workingApiMode\n        ? [workingApiMode]\n        : API_MODES;\n\n\n    let lastError;\n\n\n    for (\n        const mode of modes\n    ) {\n\n        try {\n\n            const response =\n                await fetch(\n                    makeApiUrl(\n                        mode,\n                        path,\n                        params\n                    ),\n                    {\n                        credentials:\n                            \"same-origin\",\n\n                        headers: {\n                            \"Accept\":\n                                \"application\/json\"\n                        }\n                    }\n                );\n\n\n            if (\n                !response.ok\n            ) {\n\n                throw new Error(\n                    \"HTTP \" +\n                    response.status\n                );\n\n            }\n\n\n            const data =\n                await response.json();\n\n\n            workingApiMode =\n                mode;\n\n\n            return {\n                data:\n                    data,\n\n                response:\n                    response\n            };\n\n        }\n\n        catch(error) {\n\n            lastError =\n                error;\n\n        }\n\n    }\n\n\n    throw lastError;\n\n}\n\n\n\/* ============================================================\n   CAT\u00c9GORIES\n   ============================================================ *\/\n\nasync function loadCategories() {\n\n    let page =\n        1;\n\n\n    while(true) {\n\n        const result =\n            await wpRequest(\n                \"\/categories\",\n                {\n                    per_page:\n                        100,\n\n                    page:\n                        page,\n\n                    hide_empty:\n                        false\n                }\n            );\n\n\n        result.data.forEach(\n            function(category) {\n\n                categories.set(\n                    category.id,\n                    category\n                );\n\n            }\n        );\n\n\n        const pages =\n            parseInt(\n                result.response.headers.get(\n                    \"X-WP-TotalPages\"\n                ) || \"1\",\n                10\n            );\n\n\n        if (\n            page >= pages\n        ) {\n\n            break;\n\n        }\n\n\n        page++;\n\n    }\n\n}\n\n\nfunction getCategories(\n    post\n) {\n\n    return (\n        post.categories ||\n        []\n    )\n    .map(\n        function(id) {\n\n            return (\n                categories.get(id) ||\n                null\n            );\n\n        }\n    )\n    .filter(Boolean);\n\n}\n\n\n\/* ============================================================\n   PUBLICATIONS\n   ============================================================ *\/\n\nasync function loadPosts() {\n\n    const commonParams = {\n\n        per_page:\n            API_PER_PAGE,\n\n        after:\n            START_DATE,\n\n        before:\n            END_DATE,\n\n        status:\n            \"publish\",\n\n        orderby:\n            \"date\",\n\n        order:\n            \"desc\",\n\n        _embed:\n            1\n\n    };\n\n\n    const first =\n        await wpRequest(\n            \"\/posts\",\n            {\n                ...commonParams,\n                page:\n                    1\n            }\n        );\n\n\n    let posts =\n        first.data;\n\n\n    const pages =\n        parseInt(\n            first.response.headers.get(\n                \"X-WP-TotalPages\"\n            ) || \"1\",\n            10\n        );\n\n\n    \/*\n     * Chargement par petits groupes\n     * pour \u00e9viter de surcharger WordPress.\n     *\/\n\n    const batchSize =\n        4;\n\n\n    for (\n        let start = 2;\n        start <= pages;\n        start += batchSize\n    ) {\n\n        const requests =\n            [];\n\n\n        for (\n            let page = start;\n            page <\n            start + batchSize &&\n            page <= pages;\n            page++\n        ) {\n\n            requests.push(\n\n                wpRequest(\n                    \"\/posts\",\n                    {\n                        ...commonParams,\n                        page:\n                            page\n                    }\n                )\n\n            );\n\n        }\n\n\n        const batch =\n            await Promise.all(\n                requests\n            );\n\n\n        batch.forEach(\n            function(result) {\n\n                posts =\n                    posts.concat(\n                        result.data\n                    );\n\n            }\n        );\n\n    }\n\n\n    return posts;\n\n}\n\n\n\/* ============================================================\n   EXCLUSION STRICTE :\n   ASSEMBL\u00c9E NATIONALE \/ TRAVAIL PARLEMENTAIRE\n   ============================================================ *\/\n\n\/*\n * C'est le point important de cette version.\n *\n * Ces expressions sont recherch\u00e9es uniquement\n * dans :\n *\n * - le titre ;\n * - les cat\u00e9gories ;\n * - le slug ;\n * - l'URL.\n *\n * On ne regarde PAS tout le corps du texte ici,\n * afin qu'une publication locale qui mentionne\n * ponctuellement l'Assembl\u00e9e nationale ne soit\n * pas supprim\u00e9e par erreur.\n *\/\n\nconst PARLIAMENT_WORDS = [\n\n    \"assemblee nationale\",\n    \"assembl\u00e9e nationale\",\n\n    \"a l'assemblee\",\n    \"\u00e0 l'assembl\u00e9e\",\n\n    \"hemicycle\",\n    \"h\u00e9micycle\",\n\n    \"commission\",\n\n    \"commission des affaires\",\n    \"commission permanente\",\n\n    \"intervention en commission\",\n    \"interventions en commission\",\n\n    \"intervention parlementaire\",\n    \"interventions parlementaires\",\n\n    \"seance publique\",\n    \"s\u00e9ance publique\",\n\n    \"seance\",\n    \"s\u00e9ance\",\n\n    \"question au gouvernement\",\n    \"questions au gouvernement\",\n\n    \"question ecrite\",\n    \"question \u00e9crite\",\n\n    \"questions ecrites\",\n    \"questions \u00e9crites\",\n\n    \"question orale\",\n    \"questions orales\",\n\n    \"amendement\",\n    \"amendements\",\n\n    \"proposition de loi\",\n    \"propositions de loi\",\n\n    \"projet de loi\",\n    \"projets de loi\",\n\n    \"texte de loi\",\n\n    \"examen du texte\",\n\n    \"examen en commission\",\n\n    \"audition parlementaire\",\n\n    \"rapporteur\",\n\n    \"rapport parlementaire\",\n\n    \"scrutin\",\n\n    \"vote solennel\",\n\n    \"debat parlementaire\",\n    \"d\u00e9bat parlementaire\",\n\n    \"budget de l'etat\",\n    \"budget de l'\u00e9tat\",\n\n    \"projet de loi de finances\",\n\n    \"loi de finances\",\n\n    \"plfss\",\n\n    \"plf \"\n\n];\n\n\nfunction isParliamentPost(\n    post\n) {\n\n    const categoryText =\n        getCategories(post)\n        .map(\n            function(category) {\n\n                return (\n                    category.name +\n                    \" \" +\n                    category.slug\n                );\n\n            }\n        )\n        .join(\" \");\n\n\n    const title =\n        stripHtml(\n            post.title &&\n            post.title.rendered\n        );\n\n\n    const slug =\n        post.slug ||\n        \"\";\n\n\n    const link =\n        post.link ||\n        \"\";\n\n\n    const strictText =\n        [\n            title,\n            categoryText,\n            slug,\n            link\n        ]\n        .join(\" \");\n\n\n    return containsAny(\n        strictText,\n        PARLIAMENT_WORDS\n    );\n\n}\n\n\n\/* ============================================================\n   AUTRES CONTENUS \u00c0 EXCLURE\n   ============================================================ *\/\n\nconst EXCLUDED_WORDS = [\n\n    \"agenda\",\n\n    \"revue de presse\",\n\n    \"dans la presse\",\n\n    \"article de presse\",\n\n    \"interview\",\n\n    \"passage media\",\n    \"passage m\u00e9dia\",\n\n    \"radio\",\n\n    \"television\",\n    \"t\u00e9l\u00e9vision\",\n\n    \"lcp\",\n\n    \"public senat\",\n    \"public s\u00e9nat\"\n\n];\n\n\nfunction isExcludedOther(\n    post\n) {\n\n    const categoryText =\n        getCategories(post)\n        .map(\n            function(category) {\n\n                return (\n                    category.name +\n                    \" \" +\n                    category.slug\n                );\n\n            }\n        )\n        .join(\" \");\n\n\n    const title =\n        stripHtml(\n            post.title &&\n            post.title.rendered\n        );\n\n\n    const strictText =\n        title +\n        \" \" +\n        categoryText +\n        \" \" +\n        (\n            post.slug ||\n            \"\"\n        );\n\n\n    return containsAny(\n        strictText,\n        EXCLUDED_WORDS\n    );\n\n}\n\n\n\/* ============================================================\n   SIGNAUX D'ACTION LOCALE\n   ============================================================ *\/\n\nconst LOCAL_CATEGORY_WORDS = [\n\n    \"circonscription\",\n\n    \"sorties et visites\",\n\n    \"sortie et visite\",\n\n    \"retrospective\",\n\n    \"r\u00e9trospective\"\n\n];\n\n\nconst ACTION_WORDS = [\n\n    \"visite\",\n\n    \"rencontre\",\n\n    \"echange\",\n    \"\u00e9change\",\n\n    \"inauguration\",\n\n    \"inaugure\",\n    \"inaugur\u00e9\",\n\n    \"commemoration\",\n    \"comm\u00e9moration\",\n\n    \"ceremonie\",\n    \"c\u00e9r\u00e9monie\",\n\n    \"permanence\",\n\n    \"deplacement\",\n    \"d\u00e9placement\",\n\n    \"assemblee generale\",\n    \"assembl\u00e9e g\u00e9n\u00e9rale\",\n\n    \"portes ouvertes\",\n\n    \"journee\",\n    \"journ\u00e9e\",\n\n    \"festival\",\n\n    \"forum\",\n\n    \"salon\",\n\n    \"foire\",\n\n    \"comice\",\n\n    \"marche\",\n    \"march\u00e9\",\n\n    \"fete\",\n    \"f\u00eate\",\n\n    \"remise de\",\n\n    \"signature\",\n\n    \"chantier\",\n\n    \"pose de la premiere pierre\",\n    \"pose de la premi\u00e8re pierre\",\n\n    \"ouverture\",\n\n    \"anniversaire\",\n\n    \"hommage\",\n\n    \"reunion locale\",\n    \"r\u00e9union locale\"\n];\n\n\nconst LOCAL_CONTEXT_WORDS = [\n\n    \"circonscription\",\n\n    \"meurthe-et-moselle\",\n\n    \"meurthe et moselle\",\n\n    \"commune\",\n\n    \"municipalite\",\n    \"municipalit\u00e9\",\n\n    \"mairie\",\n\n    \"maire\",\n\n    \"elus locaux\",\n    \"\u00e9lus locaux\",\n\n    \"communaute de communes\",\n    \"communaut\u00e9 de communes\",\n\n    \"habitants\",\n\n    \"association\",\n\n    \"entreprise\",\n\n    \"artisan\",\n\n    \"commerce\",\n\n    \"agriculteur\",\n\n    \"agriculture\",\n\n    \"exploitation agricole\",\n\n    \"ecole\",\n    \"\u00e9cole\",\n\n    \"college\",\n    \"coll\u00e8ge\",\n\n    \"lycee\",\n    \"lyc\u00e9e\",\n\n    \"ehpad\",\n\n    \"hopital\",\n    \"h\u00f4pital\",\n\n    \"centre hospitalier\",\n\n    \"maison de sante\",\n    \"maison de sant\u00e9\",\n\n    \"gendarmerie\",\n\n    \"sapeurs-pompiers\",\n\n    \"caserne\",\n\n    \"mission locale\",\n\n    \"france services\",\n\n    \"office de tourisme\",\n\n    \"syndicat\",\n\n    \"territoire\"\n];\n\n\n\/*\n * Communes \/ territoires les plus fr\u00e9quemment\n * rencontr\u00e9s dans les publications.\n *\n * Cette liste sert de signal suppl\u00e9mentaire.\n *\/\n\nconst LOCAL_PLACES = [\n\n    \"luneville\",\n    \"lun\u00e9ville\",\n\n    \"baccarat\",\n\n    \"tomblaine\",\n\n    \"saint-nicolas-de-port\",\n\n    \"saint nicolas de port\",\n\n    \"dombasle\",\n\n    \"dombasle-sur-meurthe\",\n\n    \"varangeville\",\n    \"varang\u00e9ville\",\n\n    \"rosieres-aux-salines\",\n    \"rosi\u00e8res-aux-salines\",\n\n    \"blainville-sur-l'eau\",\n\n    \"blainville sur l'eau\",\n\n    \"damelevieres\",\n    \"damelevi\u00e8res\",\n\n    \"bayon\",\n\n    \"gerbeviller\",\n    \"gerb\u00e9viller\",\n\n    \"blamont\",\n    \"bl\u00e2mont\",\n\n    \"badonviller\",\n\n    \"cirey-sur-vezouze\",\n\n    \"cirey sur vezouze\",\n\n    \"azerailles\",\n\n    \"deneuvre\",\n\n    \"pierre-percee\",\n    \"pierre-perc\u00e9e\",\n\n    \"haroue\",\n    \"harou\u00e9\",\n\n    \"fleville\",\n    \"fl\u00e9ville\",\n\n    \"laneuveville-devant-nancy\",\n\n    \"laneuveville devant nancy\",\n\n    \"vathimenil\",\n    \"vathim\u00e9nil\",\n\n    \"einville-au-jard\",\n\n    \"einville au jard\",\n\n    \"art-sur-meurthe\",\n\n    \"art sur meurthe\",\n\n    \"moyen\",\n\n    \"arracourt\",\n\n    \"crevic\",\n    \"cr\u00e9vic\",\n\n    \"drouville\",\n\n    \"flin\",\n\n    \"pexonne\",\n\n    \"neufmaisons\",\n\n    \"sommerviller\",\n\n    \"saint-clement\",\n    \"saint-cl\u00e9ment\"\n\n];\n\n\n\/* ============================================================\n   FILTRE PRINCIPAL\n   ============================================================ *\/\n\nfunction isLocalAction(\n    post\n) {\n\n    \/*\n     * \u00c9TAPE 1 :\n     * suppression ferme du travail parlementaire.\n     *\/\n\n    if (\n        isParliamentPost(\n            post\n        )\n    ) {\n\n        return false;\n\n    }\n\n\n    \/*\n     * \u00c9TAPE 2 :\n     * suppression agendas \/ m\u00e9dias.\n     *\/\n\n    if (\n        isExcludedOther(\n            post\n        )\n    ) {\n\n        return false;\n\n    }\n\n\n    const categoryText =\n        getCategories(post)\n        .map(\n            function(category) {\n\n                return (\n                    category.name +\n                    \" \" +\n                    category.slug\n                );\n\n            }\n        )\n        .join(\" \");\n\n\n    const title =\n        stripHtml(\n            post.title.rendered\n        );\n\n\n    const excerpt =\n        stripHtml(\n            post.excerpt &&\n            post.excerpt.rendered\n        );\n\n\n    const content =\n        stripHtml(\n            post.content &&\n            post.content.rendered\n        );\n\n\n    const fullText =\n        title +\n        \" \" +\n        excerpt +\n        \" \" +\n        content;\n\n\n    \/*\n     * Cat\u00e9gorie historiquement locale.\n     *\/\n\n    if (\n        containsAny(\n            categoryText,\n            LOCAL_CATEGORY_WORDS\n        )\n    ) {\n\n        return true;\n\n    }\n\n\n    const hasAction =\n        containsAny(\n            fullText,\n            ACTION_WORDS\n        );\n\n\n    const hasContext =\n        containsAny(\n            fullText,\n            LOCAL_CONTEXT_WORDS\n        );\n\n\n    const hasPlace =\n        containsAny(\n            fullText,\n            LOCAL_PLACES\n        );\n\n\n    \/*\n     * Code postal 54xxx.\n     *\/\n\n    const hasPostalCode =\n        \/\\b54\\d{3}\\b\/\n        .test(\n            fullText\n        );\n\n\n    \/*\n     * Action clairement li\u00e9e au territoire.\n     *\/\n\n    if (\n        hasAction &&\n        (\n            hasPlace ||\n            hasContext ||\n            hasPostalCode\n        )\n    ) {\n\n        return true;\n\n    }\n\n\n    \/*\n     * Les publications \"Non class\u00e9\"\n     * repr\u00e9sentent parfois des actions de terrain.\n     *\/\n\n    if (\n        normalize(\n            categoryText\n        )\n        .includes(\n            \"non classe\"\n        )\n        &&\n        hasAction\n        &&\n        (\n            hasPlace ||\n            hasContext\n        )\n    ) {\n\n        return true;\n\n    }\n\n\n    \/*\n     * Publication clairement territoriale,\n     * m\u00eame si aucun verbe exact n'a \u00e9t\u00e9 trouv\u00e9.\n     *\/\n\n    if (\n        hasPlace &&\n        hasContext\n    ) {\n\n        return true;\n\n    }\n\n\n    return false;\n\n}\n\n\n\/* ============================================================\n   TYPE D'ACTION AFFICH\u00c9 SUR LA CARTE\n   ============================================================ *\/\n\nfunction getActionType(\n    post\n) {\n\n    const text =\n        normalize(\n\n            stripHtml(\n                post.title.rendered\n            )\n            +\n            \" \"\n            +\n            stripHtml(\n                post.excerpt &&\n                post.excerpt.rendered\n            )\n\n        );\n\n\n    if (\n        text.includes(\n            \"inaugur\"\n        )\n    ) {\n\n        return \"Inauguration\";\n\n    }\n\n\n    if (\n        text.includes(\n            \"visite\"\n        )\n    ) {\n\n        return \"Visite\";\n\n    }\n\n\n    if (\n        text.includes(\n            \"rencontre\"\n        )\n        ||\n        text.includes(\n            \"echange\"\n        )\n    ) {\n\n        return \"Rencontre\";\n\n    }\n\n\n    if (\n        text.includes(\n            \"commemoration\"\n        )\n        ||\n        text.includes(\n            \"hommage\"\n        )\n        ||\n        text.includes(\n            \"ceremonie\"\n        )\n    ) {\n\n        return \"Comm\u00e9moration\";\n\n    }\n\n\n    if (\n        text.includes(\n            \"permanence\"\n        )\n    ) {\n\n        return \"Permanence\";\n\n    }\n\n\n    if (\n        text.includes(\n            \"festival\"\n        )\n        ||\n        text.includes(\n            \"forum\"\n        )\n        ||\n        text.includes(\n            \"foire\"\n        )\n        ||\n        text.includes(\n            \"fete\"\n        )\n        ||\n        text.includes(\n            \"salon\"\n        )\n    ) {\n\n        return \"\u00c9v\u00e9nement local\";\n\n    }\n\n\n    if (\n        text.includes(\n            \"entreprise\"\n        )\n    ) {\n\n        return \"Entreprise\";\n\n    }\n\n\n    if (\n        text.includes(\n            \"agric\"\n        )\n    ) {\n\n        return \"Agriculture\";\n\n    }\n\n\n    if (\n        text.includes(\n            \"ecole\"\n        )\n        ||\n        text.includes(\n            \"college\"\n        )\n        ||\n        text.includes(\n            \"lycee\"\n        )\n    ) {\n\n        return \"\u00c9ducation\";\n\n    }\n\n\n    return \"Sur le terrain\";\n\n}\n\n\n\/* ============================================================\n   IMAGE\n   ============================================================ *\/\n\nfunction getImage(\n    post\n) {\n\n    try {\n\n        const media =\n            post._embedded[\n                \"wp:featuredmedia\"\n            ][0];\n\n\n        const sizes =\n            media.media_details &&\n            media.media_details.sizes;\n\n\n        if (\n            sizes &&\n            sizes.large\n        ) {\n\n            return (\n                sizes.large.source_url\n            );\n\n        }\n\n\n        if (\n            sizes &&\n            sizes.medium_large\n        ) {\n\n            return (\n                sizes.medium_large.source_url\n            );\n\n        }\n\n\n        return (\n            media.source_url ||\n            \"\"\n        );\n\n    }\n\n    catch(error) {\n\n        \/*\n         * Premi\u00e8re image dans l'article.\n         *\/\n\n        try {\n\n            const parser =\n                new DOMParser();\n\n\n            const documentContent =\n                parser.parseFromString(\n                    post.content.rendered,\n                    \"text\/html\"\n                );\n\n\n            const image =\n                documentContent.querySelector(\n                    \"img\"\n                );\n\n\n            return image\n                ? (\n                    image.getAttribute(\n                        \"src\"\n                    ) || \"\"\n                )\n                : \"\";\n\n        }\n\n        catch(error2) {\n\n            return \"\";\n\n        }\n\n    }\n\n}\n\n\n\/* ============================================================\n   DATE\n   ============================================================ *\/\n\nfunction formatDate(\n    date\n) {\n\n    return (\n        new Intl.DateTimeFormat(\n            \"fr-FR\",\n            {\n                day:\n                    \"numeric\",\n\n                month:\n                    \"long\",\n\n                year:\n                    \"numeric\"\n            }\n        )\n        .format(\n            new Date(\n                date\n            )\n        )\n    );\n\n}\n\n\n\/* ============================================================\n   CARTE\n   ============================================================ *\/\n\nfunction createCard(\n    post\n) {\n\n    const title =\n        decodeHtml(\n            post.title.rendered\n        );\n\n\n    const excerpt =\n        truncate(\n            stripHtml(\n                post.excerpt &&\n                post.excerpt.rendered\n            ),\n            190\n        );\n\n\n    const image =\n        getImage(\n            post\n        );\n\n\n    const year =\n        new Date(\n            post.date\n        )\n        .getFullYear();\n\n\n    const actionType =\n        getActionType(\n            post\n        );\n\n\n    const article =\n        document.createElement(\n            \"article\"\n        );\n\n\n    article.className =\n        \"tb-card\";\n\n\n    \/* IMAGE *\/\n\n    const imageLink =\n        document.createElement(\n            \"a\"\n        );\n\n\n    imageLink.className =\n        \"tb-image\";\n\n\n    imageLink.href =\n        post.link;\n\n\n    if(image) {\n\n        const img =\n            document.createElement(\n                \"img\"\n            );\n\n\n        img.src =\n            image;\n\n\n        img.alt =\n            \"\";\n\n\n        img.loading =\n            \"lazy\";\n\n\n        img.decoding =\n            \"async\";\n\n\n        imageLink.appendChild(\n            img\n        );\n\n    }\n\n    else {\n\n        const placeholder =\n            document.createElement(\n                \"div\"\n            );\n\n\n        placeholder.className =\n            \"tb-placeholder\";\n\n\n        placeholder.textContent =\n            actionType;\n\n\n        imageLink.appendChild(\n            placeholder\n        );\n\n    }\n\n\n    const badge =\n        document.createElement(\n            \"span\"\n        );\n\n\n    badge.className =\n        \"tb-year-badge\";\n\n\n    badge.textContent =\n        year;\n\n\n    imageLink.appendChild(\n        badge\n    );\n\n\n    \/* BODY *\/\n\n    const body =\n        document.createElement(\n            \"div\"\n        );\n\n\n    body.className =\n        \"tb-card-body\";\n\n\n    const meta =\n        document.createElement(\n            \"div\"\n        );\n\n\n    meta.className =\n        \"tb-meta\";\n\n\n    const date =\n        document.createElement(\n            \"span\"\n        );\n\n\n    date.className =\n        \"tb-date\";\n\n\n    date.textContent =\n        formatDate(\n            post.date\n        );\n\n\n    const type =\n        document.createElement(\n            \"span\"\n        );\n\n\n    type.className =\n        \"tb-type\";\n\n\n    type.textContent =\n        actionType;\n\n\n    meta.appendChild(\n        date\n    );\n\n\n    meta.appendChild(\n        type\n    );\n\n\n    const h3 =\n        document.createElement(\n            \"h3\"\n        );\n\n\n    const titleLink =\n        document.createElement(\n            \"a\"\n        );\n\n\n    titleLink.href =\n        post.link;\n\n\n    titleLink.textContent =\n        title;\n\n\n    h3.appendChild(\n        titleLink\n    );\n\n\n    const text =\n        document.createElement(\n            \"p\"\n        );\n\n\n    text.className =\n        \"tb-excerpt\";\n\n\n    text.textContent =\n        excerpt ||\n        \"Retrouvez cette action locale en d\u00e9tail.\";\n\n\n    const link =\n        document.createElement(\n            \"a\"\n        );\n\n\n    link.className =\n        \"tb-read\";\n\n\n    link.href =\n        post.link;\n\n\n    link.innerHTML =\n        'D\u00e9couvrir l\u2019action' +\n        '<span class=\"tb-arrow\">\u2192<\/span>';\n\n\n    body.appendChild(\n        meta\n    );\n\n\n    body.appendChild(\n        h3\n    );\n\n\n    body.appendChild(\n        text\n    );\n\n\n    body.appendChild(\n        link\n    );\n\n\n    article.appendChild(\n        imageLink\n    );\n\n\n    article.appendChild(\n        body\n    );\n\n\n    return article;\n\n}\n\n\n\/* ============================================================\n   ANN\u00c9ES\n   ============================================================ *\/\n\nfunction buildYears() {\n\n    yearsContainer.innerHTML =\n        \"\";\n\n\n    const all =\n        document.createElement(\n            \"button\"\n        );\n\n\n    all.type =\n        \"button\";\n\n\n    all.className =\n        \"tb-year active\";\n\n\n    all.dataset.year =\n        \"\";\n\n\n    all.innerHTML =\n        \"Toutes\" +\n        '<span class=\"tb-year-number\">' +\n        allPosts.length +\n        \"<\/span>\";\n\n\n    yearsContainer.appendChild(\n        all\n    );\n\n\n    for (\n        let year = LAST_YEAR;\n        year >= FIRST_YEAR;\n        year--\n    ) {\n\n        const count =\n            allPosts.filter(\n                function(post) {\n\n                    return (\n                        new Date(\n                            post.date\n                        )\n                        .getFullYear()\n                        ===\n                        year\n                    );\n\n                }\n            )\n            .length;\n\n\n        const button =\n            document.createElement(\n                \"button\"\n            );\n\n\n        button.type =\n            \"button\";\n\n\n        button.className =\n            \"tb-year\";\n\n\n        button.dataset.year =\n            String(year);\n\n\n        button.innerHTML =\n            year +\n            '<span class=\"tb-year-number\">' +\n            count +\n            \"<\/span>\";\n\n\n        yearsContainer.appendChild(\n            button\n        );\n\n    }\n\n\n    yearsContainer\n    .querySelectorAll(\n        \".tb-year\"\n    )\n    .forEach(\n        function(button) {\n\n            button.addEventListener(\n                \"click\",\n                function() {\n\n                    yearsContainer\n                    .querySelectorAll(\n                        \".tb-year\"\n                    )\n                    .forEach(\n                        function(item) {\n\n                            item.classList.remove(\n                                \"active\"\n                            );\n\n                        }\n                    );\n\n\n                    button.classList.add(\n                        \"active\"\n                    );\n\n\n                    activeYear =\n                        button.dataset.year;\n\n\n                    visibleCount =\n                        POSTS_PER_VIEW;\n\n\n                    applyFilters();\n\n                }\n            );\n\n        }\n    );\n\n}\n\n\n\/* ============================================================\n   FILTRE DE RECHERCHE\n   ============================================================ *\/\n\nfunction applyFilters() {\n\n    const query =\n        normalize(\n            searchInput.value.trim()\n        );\n\n\n    filteredPosts =\n        allPosts.filter(\n            function(post) {\n\n                if(activeYear) {\n\n                    const year =\n                        String(\n                            new Date(\n                                post.date\n                            )\n                            .getFullYear()\n                        );\n\n\n                    if(\n                        year !==\n                        activeYear\n                    ) {\n\n                        return false;\n\n                    }\n\n                }\n\n\n                if(query) {\n\n                    const searchable =\n                        normalize(\n\n                            stripHtml(\n                                post.title.rendered\n                            )\n                            +\n                            \" \"\n                            +\n                            stripHtml(\n                                post.excerpt &&\n                                post.excerpt.rendered\n                            )\n                            +\n                            \" \"\n                            +\n                            stripHtml(\n                                post.content &&\n                                post.content.rendered\n                            )\n\n                        );\n\n\n                    if(\n                        !searchable.includes(\n                            query\n                        )\n                    ) {\n\n                        return false;\n\n                    }\n\n                }\n\n\n                return true;\n\n            }\n        );\n\n\n    render();\n\n}\n\n\n\/* ============================================================\n   AFFICHAGE\n   ============================================================ *\/\n\nfunction render() {\n\n    grid.innerHTML =\n        \"\";\n\n\n    const total =\n        filteredPosts.length;\n\n\n    if(\n        total === 0\n    ) {\n\n        results.innerHTML =\n            \"<strong>0<\/strong> action trouv\u00e9e\";\n\n\n        grid.innerHTML =\n            '<div class=\"tb-state\">' +\n            '<strong>Aucune action locale trouv\u00e9e.<\/strong>' +\n            '<br><br>' +\n            'Essayez une autre ann\u00e9e ou un autre terme.' +\n            '<\/div>';\n\n\n        moreButton.style.display =\n            \"none\";\n\n\n        return;\n\n    }\n\n\n    results.innerHTML =\n        \"<strong>\" +\n        total +\n        \"<\/strong> \" +\n        (\n            total > 1\n            ? \"publications locales\"\n            : \"publication locale\"\n        );\n\n\n    filteredPosts\n    .slice(\n        0,\n        visibleCount\n    )\n    .forEach(\n        function(post) {\n\n            grid.appendChild(\n                createCard(\n                    post\n                )\n            );\n\n        }\n    );\n\n\n    if(\n        visibleCount <\n        total\n    ) {\n\n        const remaining =\n            total -\n            visibleCount;\n\n\n        moreButton.style.display =\n            \"inline-block\";\n\n\n        moreButton.textContent =\n            \"Afficher plus (\" +\n            remaining +\n            \")\";\n\n    }\n\n    else {\n\n        moreButton.style.display =\n            \"none\";\n\n    }\n\n}\n\n\n\/* ============================================================\n   \u00c9V\u00c9NEMENTS\n   ============================================================ *\/\n\nsearchInput.addEventListener(\n    \"input\",\n    function() {\n\n        visibleCount =\n            POSTS_PER_VIEW;\n\n\n        applyFilters();\n\n    }\n);\n\n\nresetButton.addEventListener(\n    \"click\",\n    function() {\n\n        searchInput.value =\n            \"\";\n\n\n        activeYear =\n            \"\";\n\n\n        visibleCount =\n            POSTS_PER_VIEW;\n\n\n        yearsContainer\n        .querySelectorAll(\n            \".tb-year\"\n        )\n        .forEach(\n            function(button) {\n\n                button.classList.toggle(\n                    \"active\",\n                    button.dataset.year === \"\"\n                );\n\n            }\n        );\n\n\n        applyFilters();\n\n    }\n);\n\n\nmoreButton.addEventListener(\n    \"click\",\n    function() {\n\n        visibleCount +=\n            POSTS_PER_VIEW;\n\n\n        render();\n\n    }\n);\n\n\n\/* ============================================================\n   ERREUR\n   ============================================================ *\/\n\nfunction showError(\n    error\n) {\n\n    console.error(\n        \"Actions locales :\",\n        error\n    );\n\n\n    totalElement.textContent =\n        \"\u2014\";\n\n\n    results.textContent =\n        \"\";\n\n\n    grid.innerHTML =\n        '<div class=\"tb-state\">' +\n\n        '<strong>Impossible de charger automatiquement les publications.<\/strong>' +\n\n        '<br><br>' +\n\n        'V\u00e9rifiez que l\u2019API REST de WordPress est accessible.' +\n\n        '<\/div>';\n\n}\n\n\n\/* ============================================================\n   INITIALISATION\n   ============================================================ *\/\n\nasync function init() {\n\n    try {\n\n\n        \/*\n         * CAT\u00c9GORIES\n         *\/\n\n        await loadCategories();\n\n\n        \/*\n         * TOUTES LES PUBLICATIONS\n         * 2017 \u2192 2026\n         *\/\n\n        const posts =\n            await loadPosts();\n\n\n        \/*\n         * IMPORTANT :\n         *\n         * 1. suppression Assembl\u00e9e nationale\n         * 2. suppression m\u00e9dias \/ agendas\n         * 3. conservation uniquement terrain local\n         *\/\n\n        allPosts =\n            posts\n            .filter(\n                function(post) {\n\n                    return (\n                        !isParliamentPost(post)\n                        &&\n                        !isExcludedOther(post)\n                        &&\n                        isLocalAction(post)\n                    );\n\n                }\n            )\n            .sort(\n                function(a,b) {\n\n                    return (\n                        new Date(b.date)\n                        -\n                        new Date(a.date)\n                    );\n\n                }\n            );\n\n\n        \/*\n         * COMPTEUR\n         *\/\n\n        totalElement.textContent =\n            allPosts.length;\n\n\n        \/*\n         * ANN\u00c9ES\n         *\/\n\n        buildYears();\n\n\n        \/*\n         * AFFICHAGE INITIAL\n         *\/\n\n        filteredPosts =\n            allPosts.slice();\n\n\n        render();\n\n    }\n\n    catch(error) {\n\n        showError(\n            error\n        );\n\n    }\n\n}\n\n\ninit();\n\n\n})();\n\n<\/script>\n\n<\/section>\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t\t\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"<p>4e circonscription de Meurthe-et-Moselle Mes actions locales Retrouvez mes d\u00e9placements, rencontres, visites, inaugurations, permanences, comm\u00e9morations et \u00e9v\u00e9nements dans la circonscription depuis 2017. \u2014 publications locales recens\u00e9es 2017 d\u00e9but de la p\u00e9riode 2026 ann\u00e9e la plus r\u00e9cente Sur le terrain Mon activit\u00e9 dans la circonscription Retrouvez les actions et d\u00e9placements locaux publi\u00e9s sur le site depuis&hellip; <br \/> <a class=\"button small blue\" href=\"https:\/\/thibaultbazin.fr\/index.php\/mes-actions-locales\/\">Lire la suite<\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":[],"amp_enabled":true,"_links":{"self":[{"href":"https:\/\/thibaultbazin.fr\/index.php\/wp-json\/wp\/v2\/pages\/31883"}],"collection":[{"href":"https:\/\/thibaultbazin.fr\/index.php\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/thibaultbazin.fr\/index.php\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/thibaultbazin.fr\/index.php\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/thibaultbazin.fr\/index.php\/wp-json\/wp\/v2\/comments?post=31883"}],"version-history":[{"count":10,"href":"https:\/\/thibaultbazin.fr\/index.php\/wp-json\/wp\/v2\/pages\/31883\/revisions"}],"predecessor-version":[{"id":31896,"href":"https:\/\/thibaultbazin.fr\/index.php\/wp-json\/wp\/v2\/pages\/31883\/revisions\/31896"}],"wp:attachment":[{"href":"https:\/\/thibaultbazin.fr\/index.php\/wp-json\/wp\/v2\/media?parent=31883"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}