(function($) { 'use strict'; function isPostEditPage() { return window.pagenow === 'post' || window.pagenow === 'post-new' // On CPTs, pagenow is the post_type slug — also catch them via the // body classes WP sets for any post.php / post-new.php screen. || document.body.classList.contains('post-php') || document.body.classList.contains('post-new-php'); } function isProfileEditPage() { return window.pagenow === 'profile' || window.pagenow === 'user-edit' || window.pagenow === 'user-new'; } function getProfileForm() { return document.querySelector('#your-profile, #createuser'); } function isPodsModal() { return new URLSearchParams(window.location.search).has('pods_modal'); } function renameArticlesToAnnonces() { const replacements = [ [/Tous les articles/g, 'Toutes les annonces'], [/Ajouter un article/g, 'Ajouter une annonce'], [/Modifier l.article/g, "Modifier l'annonce"], [/Pr\u00e9visualiser l.article/g, "Pr\u00e9visualiser l'annonce"], [/Afficher l.article/g, "Afficher l'annonce"], [/Voir l.article/g, "Voir l'annonce"], [/Article publi\u00e9/g, 'Annonce publi\u00e9e'], [/Article mis \u00e0 jour/g, 'Annonce mise \u00e0 jour'], [/Article planifi\u00e9/g, 'Annonce planifi\u00e9e'], [/Articles par page/g, 'Annonces par page'], [/Articles/g, 'Annonces'], [/Article/g, 'Annonce'], [/Rechercher des articles/g, 'Rechercher des annonces'], ]; function applyReplacements(text) { return replacements.reduce((t, [s, r]) => t.replace(s, r), text); } function replaceInTextNodes(el) { if (!el) return; const walker = document.createTreeWalker(el, NodeFilter.SHOW_TEXT); const nodes = []; while (walker.nextNode()) nodes.push(walker.currentNode); nodes.forEach(function(node) { const replaced = applyReplacements(node.textContent); if (replaced !== node.textContent) node.textContent = replaced; }); } // Menu latéral replaceInTextNodes(document.querySelector('#menu-posts')); // Titre de page (h1) et bouton d'ajout document.querySelectorAll('.wp-heading-inline, .page-title-action').forEach(replaceInTextNodes); // Notifications après sauvegarde (Article publié, mis à jour…) document.querySelectorAll('#message, .notice').forEach(replaceInTextNodes); // Boîte de publication — lien "Voir l'article" replaceInTextNodes(document.querySelector('.submitbox')); // Options d'écran — "Articles par page" replaceInTextNodes(document.querySelector('#screen-options-wrap')); // Bouton de recherche (attribut value + aria-label) var searchSubmit = document.querySelector('#search-submit'); if (searchSubmit) { if (searchSubmit.value) { searchSubmit.value = applyReplacements(searchSubmit.value); } var ariaLabel = searchSubmit.getAttribute('aria-label'); if (ariaLabel) { searchSubmit.setAttribute('aria-label', applyReplacements(ariaLabel)); } } // Titre de l'onglet du navigateur document.title = applyReplacements(document.title); } function updatePostboxVisibility() { document.querySelectorAll('.postbox').forEach((postBox) => { if (postBox.id.startsWith('pods')) { // body-en is controlled by language tabs — never auto-hide it if (postBox.id === 'pods-meta-body-en') return; const fields = postBox.querySelectorAll('tr'); const hasVisibleFields = Array.from(fields).some(field => field.style.display !== 'none'); postBox.style.display = hasVisibleFields ? 'block' : 'none'; } }); } // Force Visual (TinyMCE) mode on page load. // WP stores the last-used editor mode in localStorage and restores it at document.ready. // When Code mode is restored, TinyMCE is never initialised — tinymce.get() returns null. // Instead, check the wrapper's CSS class: // tmce-active = Visual mode (fine) // html-active = Code mode (switch to Visual) function ensureVisualMode(editorId, attempt) { attempt = attempt || 0; if (attempt > 15) return; var wrap = document.getElementById('wp-' + editorId + '-wrap'); if (!wrap) { setTimeout(function() { ensureVisualMode(editorId, attempt + 1); }, 200); return; } if (wrap.classList.contains('html-active')) { var ed = window.tinymce && tinymce.get(editorId); if (!ed || !ed.initialized) { // TinyMCE not ready yet — retry rather than calling switchEditors.go() prematurely setTimeout(function() { ensureVisualMode(editorId, attempt + 1); }, 200); return; } if (typeof switchEditors !== 'undefined') { switchEditors.go(editorId, 'tmce'); } return; } if (!wrap.classList.contains('tmce-active')) { // Mode not yet determined — retry setTimeout(function() { ensureVisualMode(editorId, attempt + 1); }, 200); } } // Phase 1: insert the tab bar and relocate #pods-meta-body-en. // The DOM move breaks TinyMCE's iframe (browsers reset iframe content on detach), // so we leave the container visible here and let Pods/TinyMCE initialise normally. // The broken iframe is repaired by reinitEditor() on first EN tab open. function setupBodyTabsDom() { var nativeEditor = document.getElementById('postdivrich') || document.getElementById('postdiv'); var bodyEnBox = document.getElementById('pods-meta-body-en'); if (!nativeEditor || !bodyEnBox) return; var tabBar = document.createElement('div'); tabBar.className = 'body-lang-tabs'; tabBar.innerHTML = '' + ''; nativeEditor.parentNode.insertBefore(tabBar, nativeEditor); // Move EN metabox to sit right after the native editor for correct visual layout. // Do NOT hide it yet — Pods must init TinyMCE with the container visible so the // iframe can measure its dimensions. Page is still opacity:0 so no flash. nativeEditor.parentNode.insertBefore(bodyEnBox, nativeEditor.nextSibling); } // Rebuild a TinyMCE editor whose iframe is broken (empty/non-interactive). // This happens when TinyMCE is initialised on a hidden (display:none) element: // the iframe can't measure dimensions and its document body stays empty. // // We reinit from tinyMCEPreInit.mceInit — first trying the editor's own config // (registered by Pods server-side), falling back to 'content' (the native WP editor). // // Inline toolbar positioning fix: // TinyMCE's 'wordpress' plugin captures document.getElementById(id+'_ifr') during // 'preinit' — before the iframe is created — so mceIframe is always null. // Fix: intercept getElementById during preinit so the 'wordpress' plugin captures // a proxyIframe instead of null. After init, proxy delegates to the real iframe. function reinitEditor(editorId) { var ed = window.tinymce && tinymce.get(editorId); // Preserve existing content before destroying the instance var savedContent = ''; if (ed) { try { savedContent = ed.getContent(); } catch (e) {} ed.remove(); } if (!savedContent) { var ta = document.getElementById(editorId); if (ta) savedContent = ta.value || ''; } if (!window.tinyMCEPreInit || !window.tinymce) return; // Use the editor's own server-side config if available, else clone from 'content' var baseInit = (tinyMCEPreInit.mceInit && tinyMCEPreInit.mceInit[editorId]) || (tinyMCEPreInit.mceInit && tinyMCEPreInit.mceInit['content']); if (!baseInit) return; // Proxy iframe: getBoundingClientRect() falls back to the editor wrap var wrapId = 'wp-' + editorId + '-wrap'; var proxyIframe = { getBoundingClientRect: function() { var el = document.getElementById(wrapId); return el ? el.getBoundingClientRect() : { top: 0, left: 0, right: window.innerWidth, bottom: window.innerHeight, width: window.innerWidth, height: window.innerHeight }; } }; var savedGetById = document.getElementById; var origSetup = baseInit.setup; var content = savedContent; tinymce.init($.extend({}, baseInit, { selector: '#' + editorId, setup: function(editor) { if (typeof origSetup === 'function') origSetup(editor); editor.on('focus', function() { window.wpActiveEditor = editorId; }); editor.on('preinit', function() { document.getElementById = function(id) { if (id === editorId + '_ifr') return proxyIframe; return savedGetById.call(document, id); }; setTimeout(function() { document.getElementById = savedGetById; }, 0); }); editor.on('init', function() { // Point proxy to real iframe var realIframe = savedGetById.call(document, editorId + '_ifr'); if (realIframe) { proxyIframe.getBoundingClientRect = function() { return realIframe.getBoundingClientRect(); }; } // Restore content that was in the textarea if (content) { editor.setContent(content); } }); } })); } // Phase 2: wire tab click handlers — runs at t=100ms after metabox reordering. function initBodyLanguageTabs() { var nativeEditor = document.getElementById('postdivrich') || document.getElementById('postdiv'); var bodyEnBox = document.getElementById('pods-meta-body-en'); var tabBar = document.querySelector('.body-lang-tabs'); if (!nativeEditor || !bodyEnBox || !tabBar) { // body_en not available (e.g. contributor role) — still force visual mode on main editor if (nativeEditor) ensureVisualMode('content'); return; } var enEditorId = 'pods-form-ui-pods-meta-body-en'; var enTmceReady = false; // Hide EN panel — page is still opacity:0, user won't see the switch bodyEnBox.style.display = 'none'; tabBar.querySelectorAll('.body-lang-tab').forEach(function(btn) { btn.addEventListener('click', function() { tabBar.querySelectorAll('.body-lang-tab').forEach(function(b) { b.classList.remove('is-active'); }); btn.classList.add('is-active'); var revealedPanel; if (btn.dataset.panel === 'fr') { bodyEnBox.style.display = 'none'; nativeEditor.style.opacity = '0'; nativeEditor.style.display = ''; revealedPanel = nativeEditor; } else { nativeEditor.style.display = 'none'; bodyEnBox.style.opacity = '0'; bodyEnBox.style.display = 'block'; revealedPanel = bodyEnBox; if (!enTmceReady) { enTmceReady = true; // Reinit while container is visible so TinyMCE can measure dimensions reinitEditor(enEditorId); } } // Notify TinyMCE to reflow, then fade in once layout is correct setTimeout(function() { window.dispatchEvent(new Event('resize')); requestAnimationFrame(function() { requestAnimationFrame(function() { revealedPanel.style.opacity = ''; }); }); }, 50); }); }); // Ensure both editors start in Visual (not Code) mode ensureVisualMode('content'); ensureVisualMode(enEditorId); } function groupAxesCheckboxes() { if (!window.thalimAxesGroups || !thalimAxesGroups.length) return; var row = document.querySelector('.pods-form-ui-row-name-axes-thematiques'); if (!row) return; var list = row.querySelector('ul'); if (!list) return; // Already grouped — nothing to do if (list.querySelector('.axes-group-label')) return; // Map existing
  • by checkbox value; preserve "add new" button var liMap = {}; var addNewItem = null; list.querySelectorAll('li').forEach(function(li) { if (li.classList.contains('pods-pick-add-new')) { addNewItem = li; return; } var cb = li.querySelector('input[type="checkbox"]'); if (cb) liMap[cb.value] = li; }); // Rebuild list in group order list.innerHTML = ''; thalimAxesGroups.forEach(function(group) { var labelLi = document.createElement('li'); labelLi.className = 'axes-group-label'; labelLi.textContent = group.label; list.appendChild(labelLi); group.terms.forEach(function(term) { var li = liMap[String(term.id)]; if (li) list.appendChild(li); }); }); if (addNewItem) list.appendChild(addNewItem); } var REF_BIB_EDITOR_ID = 'pods-form-ui-pods-meta-reference-bibliographique'; var refBibReinited = false; // Reinit the référence bibliographique TinyMCE editor. // Called at page load (if the field is already visible) and by the // MutationObserver (when the field becomes visible after a category change). function initRefBibEditor() { if (refBibReinited) return; var row = document.querySelector('.pods-form-ui-row-name-reference-bibliographique'); if (!row || row.style.display === 'none') return; refBibReinited = true; reinitEditor(REF_BIB_EDITOR_ID); ensureVisualMode(REF_BIB_EDITOR_ID); } function initAxesGroupObserver() { // Pods shows/hides conditional rows by removing inline style="display:none" // Watch the entire Pods meta form for style changes on the axes row var podsForm = document.querySelector('.pods-pick-values, #pods-meta-champs-contextuels, form#post'); if (!podsForm) podsForm = document.body; var observer = new MutationObserver(function(mutations) { for (var i = 0; i < mutations.length; i++) { var target = mutations[i].target; if (target.classList && target.classList.contains('pods-form-ui-row-name-axes-thematiques')) { if (target.style.display !== 'none') { setTimeout(groupAxesCheckboxes, 50); } } // Reinit TinyMCE on the référence bibliographique field when its // row becomes visible — Pods hides it with display:none which breaks // the TinyMCE iframe. Only reinit once per page load. if (!refBibReinited && target.classList && target.classList.contains('pods-form-ui-row-name-reference-bibliographique')) { if (target.style.display !== 'none') { setTimeout(initRefBibEditor, 100); } } } }); observer.observe(podsForm, { attributes: true, attributeFilter: ['style'], subtree: true }); } function initPostEditPage() { // Disable category options (CSS handles the color) const categorieSelect = document.querySelector('#pods-form-ui-pods-meta-categorie'); if (categorieSelect) { const categoriesToDisable = ['1', '12', '5', '20']; categorieSelect.querySelectorAll('option').forEach(option => { if (categoriesToDisable.includes(option.value)) { option.disabled = true; } }); } // Reorder meta boxes const sideSortables = document.querySelector('#side-sortables'); if (sideSortables) { const typeDannonce = document.querySelector('#pods-meta-type-dannonce'); const affichageAccueil = document.querySelector('#pods-meta-affichage-sur-laccueil'); const thematique = document.querySelector('#pods-meta-thematique'); if (typeDannonce) sideSortables.prepend(typeDannonce); if (affichageAccueil) sideSortables.appendChild(affichageAccueil); if (thematique) sideSortables.appendChild(thematique); } const submitDiv = document.querySelector('#submitdiv'); if (submitDiv && submitDiv.parentNode) { submitDiv.parentNode.appendChild(submitDiv); } const champsContextuels = document.querySelector('#pods-meta-champs-contextuels'); if (champsContextuels && champsContextuels.parentNode) { champsContextuels.parentNode.prepend(champsContextuels); } initBodyLanguageTabs(); initRefBibEditor(); groupAxesCheckboxes(); initAxesGroupObserver(); updatePostboxVisibility(); initDatePickerPopoverFix(); initInfoPopovers(); // Place #pods-meta-documents-joints in #normal-sortables, right after // #pods-meta-champs-contextuels. This keeps it out of #post-body-content // (the body editor section) regardless of whether champsContextuels is // currently visible. When champsContextuels is hidden it takes no space, // so documentsJoints simply appears first in #normal-sortables. const documentsJoints = document.querySelector('#pods-meta-documents-joints'); if (documentsJoints) { if (champsContextuels && champsContextuels.parentNode) { champsContextuels.parentNode.insertBefore(documentsJoints, champsContextuels.nextSibling); } else { const normalSortables = document.querySelector('#normal-sortables'); if (normalSortables) normalSortables.prepend(documentsJoints); } } // Inject separator row for the Membres grid layout var membresTbody = document.querySelector('#pods-meta-membres .form-table tbody'); if (membresTbody && !membresTbody.querySelector('.membres-grid-separator')) { var sep = document.createElement('tr'); sep.className = 'membres-grid-separator'; membresTbody.appendChild(sep); } updateMembresGridSeparator(); } var INFO_ICON = ''; var TRANSLATE_ICON = ''; var TRANSLATE_LINES = [ 'Traduction en anglais apr\u00e8s //', 'ex\u00a0: Texte en fran\u00e7ais // English text' ]; // Tips without a `page` key default to 'post'. // type: 'translate' uses the globe icon + green button style. var INFO_TIPS = [ // --- post edit page: info --- { selector: '.wp-heading-inline', lines: [ 'Saisir le titre anglais apr\u00e8s //', 'ex\u00a0: Titre de l\u2019annonce // Title of the announcement' ] }, { selector: '#pods-meta-documents-joints .postbox-header h2', lines: [ 'Ajouter les images dans les documents.', 'Ajouter les l\u00e9gendes comme titre du document.' ] }, { selector: '#pods-meta-membres .postbox-header h2', lines: [ 'Le champ fonction change le libell\u00e9 de la liste de personnes cit\u00e9es.', 'Le champ membre permet de lister les membres de Thalim li\u00e9s \u00e0 l\u2019annonce.', 'Le champ autre personnes permet de lister des personnes ext\u00e9rieures \u00e0 Thalim.' ] }, { selector: '#pods-meta-dates .postbox-header h2', lines: [ 'Pour entrer une date sans l\u2019heure, r\u00e9gler l\u2019heure sur 00\u202f:00.' ] }, { selector: '#pods-meta-affichage-sur-laccueil .postbox-header h2', lines: [ '\u00c9pingler l\u2019annonce dans le diaporama la fait s\u2019afficher avant les autres.' ] }, { selector: '#pods-meta-medias .postbox-header h2', lines: [ 'Pour ajouter un m\u00e9dia Canal\u00a0U, copier le lien depuis \u00ab\u00a0Citer cette ressource\u00a0\u00bb.', 'ex\u00a0: https://www.canal-u.tv/166564' ] }, // --- post edit page: translate --- { type: 'translate', selector: '#pods-meta-documents-joints .postbox-header h2', lines: TRANSLATE_LINES }, { type: 'translate', selector: '.pods-form-ui-row-name-sous-titre th', lines: TRANSLATE_LINES }, { type: 'translate', selector: '.pods-form-ui-row-name-lieu th', lines: TRANSLATE_LINES }, { type: 'translate', selector: '.pods-form-ui-row-name-titre-du-lien-externe-1 th', lines: TRANSLATE_LINES }, { type: 'translate', selector: '.pods-form-ui-row-name-titre-du-lien-externe-2 th', lines: TRANSLATE_LINES }, { type: 'translate', selector: '.pods-form-ui-row-name-titre-du-lien-externe-3 th', lines: TRANSLATE_LINES }, { type: 'translate', selector: '.pods-form-ui-row-name-fonction-organisation th', lines: TRANSLATE_LINES }, { type: 'translate', selector: '.pods-form-ui-row-name-fonction-intervention th', lines: TRANSLATE_LINES }, { type: 'translate', selector: '.pods-form-ui-row-name-fonction-candidat th', lines: TRANSLATE_LINES }, { type: 'translate', selector: '.pods-form-ui-row-name-fonction-realisation th', lines: TRANSLATE_LINES }, { type: 'translate', selector: '.pods-form-ui-row-name-fonction-dirige th', lines: TRANSLATE_LINES }, { type: 'translate', selector: '.pods-form-ui-row-name-fonction-redaction th', lines: TRANSLATE_LINES }, { type: 'translate', selector: '.pods-form-ui-row-name-fonction-auteur th', lines: TRANSLATE_LINES }, { type: 'translate', selector: '.pods-form-ui-row-name-fonction-responsable th', lines: TRANSLATE_LINES }, { type: 'translate', selector: '.pods-form-ui-row-name-autre-fonction-autre th', lines: TRANSLATE_LINES }, { type: 'translate', selector: '.pods-form-ui-row-name-autre-fonction-concerne th', lines: TRANSLATE_LINES }, { type: 'translate', selector: '.pods-form-ui-row-name-autre-fonction-directeur th', lines: TRANSLATE_LINES }, { type: 'translate', selector: '.pods-form-ui-row-name-autre-fonction-direction-d-ouvrage th',lines: TRANSLATE_LINES }, { type: 'translate', selector: '.pods-form-ui-row-name-autre-fonction-intervenant th', lines: TRANSLATE_LINES }, { type: 'translate', selector: '.pods-form-ui-row-name-autre-fonction-participants th', lines: TRANSLATE_LINES }, { type: 'translate', selector: '.pods-form-ui-row-name-type-autre th', lines: TRANSLATE_LINES }, // --- contenu_general edit page: translate --- { type: 'translate', selector: '.pods-form-ui-row-name-umr th', lines: TRANSLATE_LINES }, { type: 'translate', selector: '.pods-form-ui-row-name-thalim th', lines: TRANSLATE_LINES }, { type: 'translate', selector: '.pods-form-ui-row-name-siecles th', lines: TRANSLATE_LINES }, // --- user/profile edit page: translate --- { type: 'translate', page: 'user', selector: '.pods-form-ui-row-name-titre-du-lien-1 th', lines: TRANSLATE_LINES }, { type: 'translate', page: 'user', selector: '.pods-form-ui-row-name-titre-du-lien-2 th', lines: TRANSLATE_LINES }, { type: 'translate', page: 'user', selector: '.pods-form-ui-row-name-titre-du-lien-3 th', lines: TRANSLATE_LINES }, { type: 'translate', page: 'user', selector: '.pods-form-ui-row-name-titre-du-lien-4 th', lines: TRANSLATE_LINES }, { type: 'translate', page: 'user', selector: '.pods-form-ui-row-name-complement-de-role-1 th', lines: TRANSLATE_LINES }, { type: 'translate', page: 'user', selector: '.pods-form-ui-row-name-complement-de-role-2 th', lines: TRANSLATE_LINES }, { type: 'translate', page: 'user', selector: '.pods-form-ui-row-name-complement-de-role-3 th', lines: TRANSLATE_LINES }, { type: 'translate', page: 'user', selector: '.pods-form-ui-row-name-affichage-du-statut-1 th', lines: TRANSLATE_LINES }, { type: 'translate', page: 'user', selector: '.pods-form-ui-row-name-affichage-du-statut-2 th', lines: TRANSLATE_LINES }, { type: 'translate', page: 'user', selector: '.pods-form-ui-row-name-affichage-du-statut-3 th', lines: TRANSLATE_LINES }, { type: 'translate', page: 'user', selector: '.pods-form-ui-row-name-affiliation-autre th', lines: TRANSLATE_LINES }, { type: 'translate', page: 'user', selector: '.pods-form-ui-row-name-titre-de-these th', lines: TRANSLATE_LINES }, // --- taxonomy edit pages: translate --- { type: 'translate', page: 'taxonomy', selector: 'label[for="name"]', lines: TRANSLATE_LINES }, // --- user/profile edit page: info --- { page: 'user', selector: '.pods-form-ui-label-pods-meta-identifiant-hal', lines: [ 'Renseigner votre idHAL (en lettres), pas votre PersonId (en chiffres).' ] }, { page: 'user', selector: '.pods-form-ui-label-pods-meta-affichage-du-statut-1', lines: [ 'Texte de statut affiché sur le profil publique.' ] } ]; var _popoverCloseHandlerRegistered = false; function initInfoPopovers(currentPage) { currentPage = currentPage || 'post'; INFO_TIPS.forEach(function(tip) { if ((tip.page || 'post') !== currentPage) return; var el = document.querySelector(tip.selector); if (!el) return; var isTranslate = tip.type === 'translate'; var btn = document.createElement('button'); btn.type = 'button'; btn.className = isTranslate ? 'thalim-translate-btn' : 'thalim-info-btn'; btn.setAttribute('aria-label', isTranslate ? 'Traduction bilingue' : 'Informations'); btn.innerHTML = isTranslate ? TRANSLATE_ICON : INFO_ICON; var popover = document.createElement('div'); popover.className = 'thalim-info-popover' + (isTranslate ? ' thalim-translate-popover' : ''); popover.innerHTML = tip.lines.map(function(line) { return '

    ' + line + '

    '; }).join(''); var wrapper = document.createElement('span'); wrapper.className = 'thalim-info-wrapper'; wrapper.appendChild(btn); wrapper.appendChild(popover); el.appendChild(wrapper); btn.addEventListener('click', function(e) { e.stopPropagation(); var isOpen = popover.classList.contains('is-open'); document.querySelectorAll('.thalim-info-popover.is-open').forEach(function(p) { p.classList.remove('is-open'); }); if (!isOpen) { var rect = btn.getBoundingClientRect(); popover.style.top = (rect.bottom + 6) + 'px'; popover.style.left = (rect.left + rect.width / 2) + 'px'; popover.classList.add('is-open'); } }); popover.addEventListener('click', function(e) { e.stopPropagation(); }); }); if (!_popoverCloseHandlerRegistered) { _popoverCloseHandlerRegistered = true; document.addEventListener('click', function() { document.querySelectorAll('.thalim-info-popover.is-open').forEach(function(p) { p.classList.remove('is-open'); }); }); } } // Only native WP field sections — never touch Pods tables (they may contain TinyMCE editors) var PROFILE_SECTION_KEYS = [ 'user-language-wrap', 'user-first-name-wrap', 'user-email-wrap', 'user-pass1-wrap', 'upload-avatar-row', ]; // Desired order. Groups of 2 are wrapped in a flex row and displayed side by side. var PROFILE_ORDER = [ ['user-first-name-wrap', 'upload-avatar-row'], ['user-email-wrap'], ['user-language-wrap', 'user-pass1-wrap'], ]; function reorderProfileSections() { var form = getProfileForm(); if (!form) return; var pairMap = {}; form.querySelectorAll('table.form-table').forEach(function(table) { PROFILE_SECTION_KEYS.forEach(function(key) { if (pairMap[key] || !table.querySelector('.' + key)) return; // Find the associated heading: first try preceding sibling in same parent, // then look for an h2/h3 inside the same wrapper element. var h2 = null; var el = table.previousElementSibling; while (el) { if (el.tagName === 'H2' || el.tagName === 'H3') { h2 = el; break; } if (el.tagName === 'TABLE') break; el = el.previousElementSibling; } if (!h2 && table.parentElement !== form) { h2 = table.parentElement.querySelector('h2, h3'); } // The unit to move: if h2 and table share a non-form wrapper, move the wrapper. var wrapper = null; if (h2 && h2.parentElement !== form && h2.parentElement === table.parentElement) { wrapper = h2.parentElement; } pairMap[key] = { h2: h2, table: table, wrapper: wrapper }; }); }); // Remove all matched units from DOM (dedup by actual element) var removed = new Set(); function removeEl(el) { if (el && !removed.has(el)) { removed.add(el); el.remove(); } } Object.values(pairMap).forEach(function(unit) { if (unit.wrapper) { removeEl(unit.wrapper); } else { removeEl(unit.h2); removeEl(unit.table); } }); // Re-insert in declared order before the submit button var submitAnchor = form.querySelector('p.submit'); function append(el) { if (submitAnchor && submitAnchor.parentNode) form.insertBefore(el, submitAnchor); else form.appendChild(el); } function appendUnit(unit) { if (unit.wrapper) { append(unit.wrapper); } else { if (unit.h2) append(unit.h2); append(unit.table); } } PROFILE_ORDER.forEach(function(group) { var available = group.filter(function(key) { return !!pairMap[key]; }); if (!available.length) return; // Dedup: two keys may resolve to the same table/wrapper var seen = new Set(); var units = []; available.forEach(function(key) { var unit = pairMap[key]; var id = unit.wrapper || unit.table; if (!seen.has(id)) { seen.add(id); units.push(unit); } }); if (units.length === 1) { appendUnit(units[0]); } else { var row = document.createElement('div'); row.className = 'profile-section-row'; units.forEach(function(unit) { var col = document.createElement('div'); col.className = 'profile-section-col'; if (unit.wrapper) { col.appendChild(unit.wrapper); } else { if (unit.h2) col.appendChild(unit.h2); col.appendChild(unit.table); } row.appendChild(col); }); append(row); } }); } function initProfileEditors() { reorderProfileSections(); initInfoPopovers('user'); // Hide the "À propos du compte" section heading document.querySelectorAll('#your-profile h2, #adduser h2, #createuser h2').forEach(function(h2) { if (h2.textContent.trim() === '\u00c0 propos du compte') { h2.style.display = 'none'; } }); // Rename "Rôle" label to "Rôle sur le site" var roleLabel = document.querySelector('label[for="role"]'); if (roleLabel && roleLabel.textContent.trim() === 'R\u00f4le') { roleLabel.textContent = 'R\u00f4le sur le site'; } } // Gutenberg's Popover component closes on outside click via focusout detection. // But if focus never enters the popover, focusout never fires and clicking outside // does nothing. Fix: focus the popover container as soon as it appears in the DOM. function initDatePickerPopoverFix() { var observer = new MutationObserver(function(mutations) { for (var i = 0; i < mutations.length; i++) { var added = mutations[i].addedNodes; for (var j = 0; j < added.length; j++) { var node = added[j]; if (node.nodeType !== 1) continue; var content = node.classList.contains('components-popover__content') ? node : node.querySelector && node.querySelector('.components-popover__content'); if (content) { var c = content; requestAnimationFrame(function() { if (!c.hasAttribute('tabindex')) c.setAttribute('tabindex', '-1'); c.focus(); }); } } } }); observer.observe(document.body, { childList: true, subtree: true }); } function updateMembresGridSeparator() { var sep = document.querySelector('#pods-meta-membres .membres-grid-separator'); if (!sep) return; var autreRows = document.querySelectorAll('#pods-meta-membres [class*="pods-form-ui-row-name-autre-"]'); var anyVisible = Array.from(autreRows).some(function(row) { return row.style.display !== 'none'; }); sep.style.display = anyVisible ? '' : 'none'; } // Inject a "Type de programme" filter select into the taxonomy search form. // The form already has hidden taxonomy/post_type fields so the select value // is submitted with them and picked up by pre_get_terms server-side. function initProgrammeFilter() { var form = document.querySelector('form.search-form'); if (!form) return; var types = [ 'Programme subventionné', 'Autre programme', 'Ancien programme' ]; // Read current filter value from the URL. var params = new URLSearchParams(window.location.search); var current = params.get('type_de_programme') || ''; var select = document.createElement('select'); select.name = 'type_de_programme'; select.id = 'filter-type-de-programme'; select.style.cssText = 'margin-right:6px;'; var blank = document.createElement('option'); blank.value = ''; blank.textContent = 'Tous les types'; select.appendChild(blank); types.forEach(function(type) { var opt = document.createElement('option'); opt.value = type; opt.textContent = type; if (type === current) opt.selected = true; select.appendChild(opt); }); // Insert before the first

    (search-box) inside the form. var searchBox = form.querySelector('p.search-box'); form.insertBefore(select, searchBox || null); } $(document).ready(function() { renameArticlesToAnnonces(); if (isPostEditPage()) { setupBodyTabsDom(); } setTimeout(() => { if (isPostEditPage()) { initPostEditPage(); } if (isProfileEditPage()) { initProfileEditors(); } var TRANSLATE_TAXONOMIES = ['axe_thematique', 'programme_de_recherche', 'post_tag']; var isTaxonomyListPage = TRANSLATE_TAXONOMIES.some(function(tax) { return window.location.search.indexOf('taxonomy=' + tax) !== -1; }); if (isTaxonomyListPage) { initInfoPopovers('taxonomy'); } if (window.location.search.indexOf('taxonomy=programme_de_recherche') !== -1) { initProgrammeFilter(); } document.body.classList.add('admin-mods-ready'); }, 100); // Fallback: force reveal after 2s in case the 100ms path failed (e.g. JS error mid-init) setTimeout(() => { document.body.classList.add('admin-mods-ready'); }, 2000); $('#pods-form-ui-pods-meta-categorie').change(function() { setTimeout(function() { updatePostboxVisibility(); updateMembresGridSeparator(); }, 10); }); if (isProfileEditPage() || window.pagenow === 'edit-tags' || window.pagenow === 'term') { $(window).on('load', function() { var scope = getProfileForm() || document; scope.querySelectorAll('.pods-dfv-container-wysiwyg textarea').forEach(function(ta) { if (!ta.id) return; ensureVisualMode(ta.id); }); }); } if (isPodsModal()) { $(window).on('load', function() { var itemId = $('#post_ID').val(); if (window.PodsDFV && itemId) { window.PodsDFV.setFieldValue('post', itemId, 'categorie', '12', 0); } // Lock category select to 12 in iframe — delay to run after Pods React re-render setTimeout(function() { var $select = $('#pods-form-ui-pods-meta-categorie'); if ($select.length) { $select.find('option').each(function() { this.disabled = this.value !== '12'; }); $select.val('12'); } updatePostboxVisibility(); }, 200); }); } }); })(jQuery);