884 lines
40 KiB
JavaScript
884 lines
40 KiB
JavaScript
(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 =
|
|
'<button type="button" class="body-lang-tab is-active" data-panel="fr">Fran\u00e7ais</button>' +
|
|
'<button type="button" class="body-lang-tab" data-panel="en">English</button>';
|
|
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 <li> 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 = '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"/><path d="M12 11v6"/><path d="M12 8v.01" stroke-width="2"/></svg>';
|
|
var TRANSLATE_ICON = '<svg width="13" height="13" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"/><path d="M2 12h20"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg>';
|
|
|
|
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 '<p>' + line + '</p>';
|
|
}).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 <p> (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);
|