{"id":29597,"date":"2020-05-18T20:25:21","date_gmt":"2020-05-18T19:25:21","guid":{"rendered":"https:\/\/demo.univ-djelfa.dz\/?page_id=29597"},"modified":"2026-04-30T19:54:04","modified_gmt":"2026-04-30T18:54:04","slug":"annuaire-universitaire","status":"publish","type":"page","link":"https:\/\/www.univ-djelfa.dz\/?page_id=29597","title":{"rendered":"Annuaire Universitaire"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-page\" data-elementor-id=\"29597\" class=\"elementor elementor-29597\" data-elementor-post-type=\"page\">\n\t\t\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-9c038a3 elementor-section-boxed elementor-section-height-default elementor-section-height-default exad-sticky-section-no\" data-id=\"9c038a3\" data-element_type=\"section\" data-settings=\"{&quot;ekit_has_onepagescroll_dot&quot;:&quot;yes&quot;}\">\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-f22d3c9 exad-sticky-section-no\" data-id=\"f22d3c9\" data-element_type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-4f8e411 exad-sticky-section-no elementor-widget elementor-widget-html\" data-id=\"4f8e411\" data-element_type=\"widget\" data-settings=\"{&quot;ekit_we_effect_on&quot;:&quot;none&quot;}\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<link rel=\"stylesheet\" href=\"https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/font-awesome\/6.4.0\/css\/all.min.css\">\n<link href=\"https:\/\/fonts.googleapis.com\/css2?family=Inter:wght@300;400;600;700;800&display=swap\" rel=\"stylesheet\">\n\n<div id=\"university-directory\" class=\"dir-app-wrapper\">\n    <header class=\"dir-header\">\n        <div class=\"header-icon-container\">\n            <i class=\"fas fa-id-badge\"><\/i>\n        <\/div>\n        <h1>Annuaire Universitaire<\/h1>\n        <p>Recherche rapide des coordonn\u00e9es du personnel de l'universit\u00e9<\/p>\n    <\/header>\n\n    <section class=\"search-section\">\n        <div class=\"search-box-container\">\n            <div class=\"search-input-group\">\n                <i class=\"fas fa-search search-icon-main\"><\/i>\n                <input \n                    type=\"text\" \n                    id=\"searchInput\" \n                    placeholder=\"Rechercher par nom...\" \n                    autocomplete=\"off\"\n                    aria-label=\"Rechercher\">\n                <ul id=\"suggestions\" class=\"suggestions-dropdown\"><\/ul>\n            <\/div>\n            <div class=\"search-actions\">\n                <button id=\"searchBtn\" class=\"btn-modern btn-primary\">\n                    <span>Rechercher<\/span>\n                <\/button>\n                <button id=\"clearBtn\" class=\"btn-modern btn-outline\" title=\"R\u00e9initialiser\">\n                    <i class=\"fas fa-sync-alt\"><\/i>\n                <\/button>\n            <\/div>\n        <\/div>\n        <div id=\"resultsCount\" class=\"search-stats-text\"><\/div>\n    <\/section>\n\n    <div id=\"loader\" class=\"modern-loader-wrapper\">\n        <div class=\"loader-circle\"><\/div>\n        <p>Traitement des donn\u00e9es en cours...<\/p>\n    <\/div>\n\n    <main id=\"results\" class=\"results-layout-grid\"><\/main>\n\n    <nav id=\"pagination\" class=\"pagination-nav-container\"><\/nav>\n<\/div>\n\n<style>\n:root {\n    --brand: #ac0b30;\n    --brand-hover: #8a0926;\n    --navy: #002d5a;\n    --text-dark: #1f2937;\n    --text-muted: #6b7280;\n    --bg-page: #f3f4f6;\n    --white: #ffffff;\n    --border: #e5e7eb;\n    --radius-xl: 16px;\n    --radius-md: 10px;\n    --shadow-sm: 0 1px 3px rgba(0,0,0,0.1);\n    --shadow-lg: 0 10px 15px -3px rgba(0,0,0,0.1);\n}\n\n.dir-app-wrapper {\n    max-width: 1200px;\n    margin: 40px auto;\n    padding: 0 20px;\n    font-family: 'Inter', sans-serif;\n    color: var(--text-dark);\n}\n\n\/* Header *\/\n.dir-header { text-align: center; margin-bottom: 40px; }\n.header-icon-container { \n    background: var(--brand); color: var(--white); width: 60px; height: 60px; \n    border-radius: 15px; display: flex; align-items: center; justify-content: center;\n    margin: 0 auto 15px; font-size: 1.8rem; box-shadow: 0 8px 20px rgba(172, 11, 48, 0.25);\n}\n.dir-header h1 { color: var(--navy); font-size: 2.2rem; font-weight: 800; margin: 0; letter-spacing: -0.5px; }\n.dir-header p { color: var(--text-muted); margin-top: 8px; font-size: 1rem; }\n\n\/* Search Box *\/\n.search-box-container {\n    background: var(--white); padding: 8px; border-radius: var(--radius-xl);\n    display: flex; gap: 10px; box-shadow: var(--shadow-sm); border: 1px solid var(--border);\n    position: relative;\n}\n.search-input-group { position: relative; flex: 1; }\n.search-icon-main { position: absolute; left: 18px; top: 50%; transform: translateY(-50%); color: var(--brand); z-index: 2; }\n\n#searchInput {\n    width: 100%; padding: 14px 14px 14px 48px; border: none; border-radius: var(--radius-md);\n    font-size: 1rem; background: #f9fafb; transition: 0.3s;\n}\n#searchInput:focus { background: var(--white); outline: 2px solid var(--brand); }\n\n\/* Suggestions Dropdown *\/\n.suggestions-dropdown {\n    position: absolute; top: calc(100% + 10px); left: 0; right: 0; background: white;\n    border-radius: var(--radius-md); box-shadow: var(--shadow-lg);\n    z-index: 100; list-style: none; padding: 0; margin: 0; display: none;\n    max-height: 250px; overflow-y: auto; border: 1px solid var(--border);\n}\n.suggestions-dropdown li {\n    padding: 12px 18px; cursor: pointer; border-bottom: 1px solid #f3f4f6;\n    font-size: 0.9rem; transition: 0.2s;\n}\n.suggestions-dropdown li:hover { background: #fff1f2; color: var(--brand); }\n\n.search-actions { display: flex; gap: 8px; }\n.btn-modern { border: none; border-radius: var(--radius-md); font-weight: 700; cursor: pointer; transition: 0.3s; }\n.btn-primary { background: var(--brand); color: var(--white); padding: 0 30px; }\n.btn-primary:hover { background: var(--brand-hover); transform: translateY(-1px); }\n.btn-outline { background: #f3f4f6; color: var(--text-muted); width: 48px; }\n\n.search-stats-text { margin-top: 12px; font-size: 0.9rem; color: var(--text-muted); padding-left: 5px; }\n\n\/* Results Grid *\/\n.results-layout-grid {\n    display: grid; gap: 24px; grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));\n    margin-top: 30px; min-height: 200px;\n}\n\n\/* Card Design *\/\n.card {\n    background: var(--white); border-radius: var(--radius-xl); padding: 24px;\n    border: 1px solid var(--border); transition: all 0.3s ease;\n    display: flex; flex-direction: column; position: relative;\n}\n.card:hover { transform: translateY(-5px); border-color: var(--brand); box-shadow: var(--shadow-lg); }\n.card::before {\n    content: \"\"; position: absolute; top: 0; left: 0; width: 4px; height: 100%;\n    background: var(--brand); opacity: 0; transition: 0.3s; border-radius: 4px 0 0 4px;\n}\n.card:hover::before { opacity: 1; }\n\n.card h3 { color: var(--navy); font-size: 1.2rem; font-weight: 700; margin: 0 0 15px; line-height: 1.4; }\n\n.info-row { display: flex; align-items: center; gap: 12px; margin-bottom: 12px; }\n.info-row i { color: var(--brand); width: 20px; font-size: 0.95rem; text-align: center; }\n.info-row span { font-size: 0.95rem; font-weight: 500; color: var(--text-dark); }\n.info-row small { display: block; color: var(--text-muted); font-size: 0.75rem; font-weight: 600; text-transform: uppercase; margin-bottom: 2px; }\n\n.email-box { \n    background: #f9fafb; border: 1px dashed var(--border); padding: 10px; \n    border-radius: var(--radius-md); cursor: pointer; margin-top: 5px; transition: 0.2s;\n}\n.email-box:hover { background: #fff1f2; border-color: var(--brand); }\n\n.card-actions { margin-top: auto; padding-top: 20px; }\n.btn-contact {\n    display: flex; align-items: center; justify-content: center; gap: 10px;\n    background: var(--navy); color: white !important; text-decoration: none; \n    padding: 12px; border-radius: var(--radius-md); font-weight: 600; font-size: 0.9rem;\n}\n.btn-contact:hover { background: var(--brand); }\n\n\/* Loader *\/\n.modern-loader-wrapper { display: none; text-align: center; margin: 50px 0; grid-column: 1\/-1; }\n.loader-circle { width: 40px; height: 40px; border: 3px solid #f3f3f6; border-top: 3px solid var(--brand); border-radius: 50%; animation: spin 0.8s linear infinite; margin: 0 auto 15px; }\n@keyframes spin { 100% { transform: rotate(360deg); } }\n\n.pagination-nav-container { display: flex; justify-content: center; gap: 8px; margin-top: 40px; }\n.page-link {\n    min-width: 40px; height: 40px; border: 1px solid var(--border); background: var(--white);\n    border-radius: 8px; cursor: pointer; font-weight: 600; transition: 0.2s;\n}\n.page-link.active { background: var(--brand); color: white; border-color: var(--brand); }\n\n@media (max-width: 600px) {\n    .search-box-container { flex-direction: column; }\n    .btn-primary { height: 50px; width: 100%; }\n}\n<\/style>\n\n<script>\nconst DirectoryApp = {\n    data: [],\n    filtered: [],\n    currentPage: 1,\n    itemsPerPage: 9,\n    debounceTimer: null,\n\n    init() {\n        this.cacheDOM();\n        this.bindEvents();\n        this.fetchData();\n    },\n\n    cacheDOM() {\n        this.input = document.getElementById('searchInput');\n        this.results = document.getElementById('results');\n        this.pagination = document.getElementById('pagination');\n        this.loader = document.getElementById('loader');\n        this.stats = document.getElementById('resultsCount');\n        this.suggestions = document.getElementById('suggestions');\n    },\n\n    bindEvents() {\n        \/\/ Recherche en direct (Debounce)\n        this.input.addEventListener('input', (e) => {\n            clearTimeout(this.debounceTimer);\n            this.debounceTimer = setTimeout(() => {\n                this.handleSuggestions(e.target.value);\n            }, 300);\n        });\n\n        \/\/ Fermer suggestions lors du clic ext\u00e9rieur\n        document.addEventListener('click', (e) => {\n            if (!this.input.contains(e.target)) this.suggestions.style.display = 'none';\n        });\n\n        document.getElementById('searchBtn').addEventListener('click', () => this.performSearch());\n        document.getElementById('clearBtn').addEventListener('click', () => this.reset());\n        this.input.addEventListener('keypress', (e) => e.key === 'Enter' && this.performSearch());\n    },\n\n    \/\/ Normalisation pour ignorer les accents et la casse\n    normalizeText(text) {\n        if (!text) return \"\";\n        return text.toString()\n            .toLowerCase()\n            .normalize(\"NFD\")\n            .replace(\/[\\u0300-\\u036f]\/g, \"\")\n            .trim();\n    },\n\n    async fetchData() {\n        this.loader.style.display = 'block';\n        try {\n            const res = await fetch('\/wp-content\/uploads\/annuaire.csv'); \/\/ V\u00e9rifiez ce chemin\n            const text = await res.text();\n            this.parseCSV(text);\n            this.loader.style.display = 'none';\n        } catch (e) {\n            this.loader.style.display = 'none';\n            this.results.innerHTML = \"<p style='color:red; text-align:center;'>Erreur de chargement des donn\u00e9es CSV.<\/p>\";\n        }\n    },\n\n    parseCSV(text) {\n        const lines = text.trim().split('\\n');\n        const headers = lines[0].split(',').map(h => h.trim());\n        \n        this.data = lines.slice(1).map(line => {\n            const values = line.split(\/,(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)\/);\n            const entry = {};\n            headers.forEach((h, i) => {\n                entry[h] = values[i] ? values[i].replace(\/\"\/g, '').trim() : '';\n            });\n            return entry;\n        });\n    },\n\n    handleSuggestions(val) {\n        const q = this.normalizeText(val);\n        if (q.length < 2) {\n            this.suggestions.style.display = 'none';\n            return;\n        }\n\n        const matches = this.data.filter(item => \n            this.normalizeText(item['Nom']).includes(q)\n        ).slice(0, 5);\n\n        if (matches.length > 0) {\n            this.suggestions.innerHTML = matches.map(m => `<li>${m['Nom']}<\/li>`).join('');\n            this.suggestions.style.display = 'block';\n            \n            this.suggestions.querySelectorAll('li').forEach(li => {\n                li.onclick = () => {\n                    this.input.value = li.textContent;\n                    this.suggestions.style.display = 'none';\n                    this.performSearch();\n                };\n            });\n        } else {\n            this.suggestions.style.display = 'none';\n        }\n    },\n\n    performSearch() {\n        const query = this.normalizeText(this.input.value);\n        if (!query) return;\n\n        this.suggestions.style.display = 'none';\n        this.loader.style.display = 'block';\n        this.results.innerHTML = '';\n\n        setTimeout(() => {\n            this.filtered = this.data.filter(item => {\n                return Object.values(item).some(val => \n                    this.normalizeText(val).includes(query)\n                );\n            });\n\n            this.loader.style.display = 'none';\n            this.currentPage = 1;\n            this.render();\n            this.stats.innerHTML = `<strong>${this.filtered.length}<\/strong> contacts trouv\u00e9s.`;\n        }, 300);\n    },\n\n    render() {\n        const start = (this.currentPage - 1) * this.itemsPerPage;\n        const items = this.filtered.slice(start, start + this.itemsPerPage);\n\n        if (items.length === 0) {\n            this.results.innerHTML = `\n                <div style=\"grid-column: 1\/-1; text-align: center; padding: 60px; color: var(--text-muted);\">\n                    <i class=\"fas fa-user-slash\" style=\"font-size: 3rem; opacity: 0.1; margin-bottom: 15px;\"><\/i>\n                    <p>Aucun r\u00e9sultat ne correspond \u00e0 votre recherche.<\/p>\n                <\/div>`;\n            this.pagination.innerHTML = '';\n            return;\n        }\n\n        this.results.innerHTML = items.map(item => `\n            <article class=\"card\">\n                <h3>${item['Nom'] || 'Anonyme'}<\/h3>\n                \n                <div class=\"info-row\">\n                    <i class=\"fas fa-briefcase\"><\/i>\n                    <div><small>Poste \/ Fonction<\/small><span>${item['Poste'] || '-'}<\/span><\/div>\n                <\/div>\n\n                <div class=\"info-row\">\n                    <i class=\"fas fa-university\"><\/i>\n                    <div><small>Structure \/ Entit\u00e9<\/small><span>${item['Structure'] || '-'}<\/span><\/div>\n                <\/div>\n\n                <div class=\"email-box\" onclick=\"DirectoryApp.copyEmail('${item['Email']}', this)\">\n                    <small>Email (Cliquez pour copier)<\/small>\n                    <div class=\"info-row\" style=\"margin-bottom:0;\">\n                        <i class=\"fas fa-envelope\"><\/i>\n                        <span style=\"font-family: sans-serif; font-size: 0.85rem; color: var(--brand);\">${item['Email'] || '-'}<\/span>\n                    <\/div>\n                <\/div>\n\n                <div class=\"card-actions\">\n                    <a href=\"mailto:${item['Email']}\" class=\"btn-contact\">\n                        <i class=\"fas fa-paper-plane\"><\/i> Envoyer un message\n                    <\/a>\n                <\/div>\n            <\/article>\n        `).join('');\n\n        this.renderPagination();\n    },\n\n    renderPagination() {\n        const total = Math.ceil(this.filtered.length \/ this.itemsPerPage);\n        if (total <= 1) { this.pagination.innerHTML = ''; return; }\n\n        let html = '';\n        for (let i = 1; i <= total; i++) {\n            if (i === 1 || i === total || (i >= this.currentPage - 1 && i <= this.currentPage + 1)) {\n                html += `<button class=\"page-link ${i === this.currentPage ? 'active' : ''}\" onclick=\"DirectoryApp.setPage(${i})\">${i}<\/button>`;\n            } else if (i === this.currentPage - 2 || i === this.currentPage + 2) {\n                html += `<span style=\"padding: 10px;\">...<\/span>`;\n            }\n        }\n        this.pagination.innerHTML = html;\n    },\n\n    setPage(p) {\n        this.currentPage = p;\n        this.render();\n        window.scrollTo({ top: this.input.offsetTop - 100, behavior: 'smooth' });\n    },\n\n    copyEmail(text, el) {\n        if (!text || text === '-') return;\n        navigator.clipboard.writeText(text).then(() => {\n            const originalHtml = el.innerHTML;\n            el.innerHTML = `<span style=\"color: green; font-size: 0.8rem; font-weight:bold;\"><i class=\"fas fa-check\"><\/i> Email copi\u00e9 !<\/span>`;\n            setTimeout(() => el.innerHTML = originalHtml, 2000);\n        });\n    },\n\n    reset() {\n        this.input.value = '';\n        this.results.innerHTML = '';\n        this.pagination.innerHTML = '';\n        this.stats.innerHTML = '';\n        this.filtered = [];\n        this.suggestions.style.display = 'none';\n    }\n};\n\ndocument.addEventListener('DOMContentLoaded', () => DirectoryApp.init());\n<\/script>\t\t\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<\/div>\n\t\t<\/section>\n\t\t\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"<p>Annuaire Universitaire Recherche rapide des coordonn\u00e9es du personnel de l&#8217;universit\u00e9 Rechercher Traitement des donn\u00e9es en cours&#8230;<\/p>\n","protected":false},"author":2,"featured_media":14085,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"_kad_post_transparent":"","_kad_post_title":"default","_kad_post_layout":"default","_kad_post_sidebar_id":"","_kad_post_content_style":"default","_kad_post_vertical_padding":"default","_kad_post_feature":"default","_kad_post_feature_position":"","_kad_post_header":false,"_kad_post_footer":false,"footnotes":""},"class_list":["post-29597","page","type-page","status-publish","has-post-thumbnail","hentry"],"lang":"fr","translations":{"fr":29597,"en":14357,"ar":126},"pll_sync_post":[],"_links":{"self":[{"href":"https:\/\/www.univ-djelfa.dz\/index.php?rest_route=\/wp\/v2\/pages\/29597","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.univ-djelfa.dz\/index.php?rest_route=\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/www.univ-djelfa.dz\/index.php?rest_route=\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/www.univ-djelfa.dz\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.univ-djelfa.dz\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=29597"}],"version-history":[{"count":23,"href":"https:\/\/www.univ-djelfa.dz\/index.php?rest_route=\/wp\/v2\/pages\/29597\/revisions"}],"predecessor-version":[{"id":34325,"href":"https:\/\/www.univ-djelfa.dz\/index.php?rest_route=\/wp\/v2\/pages\/29597\/revisions\/34325"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.univ-djelfa.dz\/index.php?rest_route=\/wp\/v2\/media\/14085"}],"wp:attachment":[{"href":"https:\/\/www.univ-djelfa.dz\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=29597"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}