406 lines
20 KiB
JavaScript
406 lines
20 KiB
JavaScript
/**
|
||
* Socle partagé des customisations admin (namespace window.ThalimAdmin).
|
||
* Chargé sur toutes les pages admin, avant les scripts de contexte
|
||
* (admin-rename, admin-post-edit, admin-profile, admin-taxonomy-list,
|
||
* admin-pods-modal) qui en dépendent.
|
||
*/
|
||
(function($) {
|
||
'use strict';
|
||
|
||
// ── Configuration ──────────────────────────────────────────
|
||
// Sélecteurs et identifiants Pods utilisés par les modules admin,
|
||
// centralisés pour qu'un renommage côté Pods ne demande qu'une édition ici.
|
||
var CONFIG = {
|
||
// Options désactivées dans le select Pods « Type d'annonce » (term IDs)
|
||
disabledCategoryIds: ['1', '12', '5', '20'],
|
||
// Catégorie « Séance de séminaire » (verrouillée dans la modale Pods)
|
||
seanceCategoryId: '12',
|
||
// Select Pods de la catégorie
|
||
categorySelect: '#pods-form-ui-pods-meta-categorie',
|
||
// IDs des éditeurs TinyMCE Pods à réparer (reinitEditor)
|
||
editors: {
|
||
bodyEn: 'pods-form-ui-pods-meta-body-en',
|
||
refBib: 'pods-form-ui-pods-meta-reference-bibliographique'
|
||
},
|
||
// Metaboxes Pods déplacées / observées
|
||
boxes: {
|
||
bodyEn: '#pods-meta-body-en',
|
||
typeDannonce: '#pods-meta-type-dannonce',
|
||
affichageAccueil: '#pods-meta-affichage-sur-laccueil',
|
||
thematique: '#pods-meta-thematique',
|
||
champsContextuels: '#pods-meta-champs-contextuels',
|
||
documentsJoints: '#pods-meta-documents-joints',
|
||
membres: '#pods-meta-membres'
|
||
},
|
||
// Classes des lignes Pods conditionnelles observées (MutationObserver)
|
||
rows: {
|
||
axes: 'pods-form-ui-row-name-axes-thematiques',
|
||
refBib: 'pods-form-ui-row-name-reference-bibliographique'
|
||
},
|
||
// Taxonomies dont la page liste reçoit l'info-bulle « FR // EN »
|
||
translateTaxonomies: ['axe_thematique', 'programme_de_recherche', 'post_tag']
|
||
};
|
||
|
||
// Exécute un bloc d'init de façon isolée : une exception dans un module
|
||
// n'empêche pas les modules suivants de s'initialiser.
|
||
function safeRun(name, fn) {
|
||
try {
|
||
fn();
|
||
} catch (err) {
|
||
if (window.console && console.error) {
|
||
console.error('[thalim-admin] ' + name + ' failed:', err);
|
||
}
|
||
}
|
||
}
|
||
|
||
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 updatePostboxVisibility() {
|
||
document.querySelectorAll('.postbox').forEach(function(postBox) {
|
||
if (postBox.id.startsWith('pods')) {
|
||
// body-en is controlled by language tabs — never auto-hide it
|
||
if ('#' + postBox.id === CONFIG.boxes.bodyEn) return;
|
||
var fields = postBox.querySelectorAll('tr');
|
||
var hasVisibleFields = Array.from(fields).some(function(field) {
|
||
return 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);
|
||
}
|
||
}
|
||
|
||
// 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);
|
||
}
|
||
});
|
||
}
|
||
}));
|
||
}
|
||
|
||
// ── Info-popovers (post / user / taxonomy) ─────────────────
|
||
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ès //',
|
||
'ex : Texte en français // 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ès //',
|
||
'ex : Titre de l’annonce // Title of the announcement'
|
||
]
|
||
},
|
||
{
|
||
selector: '#pods-meta-documents-joints .postbox-header h2',
|
||
lines: [
|
||
'Ajouter les images dans les documents.',
|
||
'Ajouter les légendes comme titre du document.'
|
||
]
|
||
},
|
||
{
|
||
selector: '#pods-meta-membres .postbox-header h2',
|
||
lines: [
|
||
'Le champ fonction change le libellé de la liste de personnes citées.',
|
||
'Le champ membre permet de lister les membres de Thalim liés à l’annonce.',
|
||
'Le champ autre personnes permet de lister des personnes extérieures à Thalim.'
|
||
]
|
||
},
|
||
{
|
||
selector: '#pods-meta-dates .postbox-header h2',
|
||
lines: [
|
||
'Pour entrer une date sans l’heure, régler l’heure sur 00 :00.'
|
||
]
|
||
},
|
||
{
|
||
selector: '#pods-meta-affichage-sur-laccueil .postbox-header h2',
|
||
lines: [
|
||
'Épingler l’annonce dans le diaporama la fait s’afficher avant les autres.'
|
||
]
|
||
},
|
||
{
|
||
selector: '#pods-meta-medias .postbox-header h2',
|
||
lines: [
|
||
'Pour ajouter un média Canal U, copier le lien depuis « Citer cette ressource ».',
|
||
'ex : 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');
|
||
});
|
||
});
|
||
}
|
||
}
|
||
|
||
// ── Reveal (#wpbody est masqué en CSS sur post/profil jusqu'à l'init) ──
|
||
function markReady() {
|
||
document.body.classList.add('admin-mods-ready');
|
||
}
|
||
|
||
// Fallback global : force le reveal après 2 s même si le script de
|
||
// contexte a planté ou n'a pas été chargé.
|
||
$(document).ready(function() {
|
||
setTimeout(markReady, 2000);
|
||
});
|
||
|
||
window.ThalimAdmin = {
|
||
CONFIG: CONFIG,
|
||
safeRun: safeRun,
|
||
isPostEditPage: isPostEditPage,
|
||
isProfileEditPage: isProfileEditPage,
|
||
getProfileForm: getProfileForm,
|
||
isPodsModal: isPodsModal,
|
||
ensureVisualMode: ensureVisualMode,
|
||
reinitEditor: reinitEditor,
|
||
updatePostboxVisibility: updatePostboxVisibility,
|
||
initInfoPopovers: initInfoPopovers,
|
||
markReady: markReady
|
||
};
|
||
|
||
})(jQuery);
|