Refactoring : sécurité (XSS), découpage en modules inc/* et js/admin/*, IDs résolus par slug, perf (caches, cron Gravatar, assets auto-hébergés), tests
This commit is contained in:
149
js/admin/admin-profile.js
Normal file
149
js/admin/admin-profile.js
Normal file
@@ -0,0 +1,149 @@
|
||||
/**
|
||||
* Pages profil / utilisateur (profile.php, user-edit.php, user-new.php) :
|
||||
* réordonnancement des sections natives, popovers d'aide, mode visuel forcé
|
||||
* sur les WYSIWYG Pods.
|
||||
* Dépend de admin-base.js (window.ThalimAdmin) — enqueue conditionnel.
|
||||
*/
|
||||
(function($) {
|
||||
'use strict';
|
||||
|
||||
var TA = window.ThalimAdmin;
|
||||
var safeRun = TA.safeRun;
|
||||
|
||||
// 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 = TA.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();
|
||||
TA.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() === 'À 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ôle') {
|
||||
roleLabel.textContent = 'Rôle sur le site';
|
||||
}
|
||||
}
|
||||
|
||||
$(document).ready(function() {
|
||||
if (!TA.isProfileEditPage()) return;
|
||||
|
||||
setTimeout(function() {
|
||||
safeRun('initProfileEditors', initProfileEditors);
|
||||
TA.markReady();
|
||||
}, 100);
|
||||
|
||||
// Force visual mode on all Pods WYSIWYG fields once everything is loaded
|
||||
$(window).on('load', function() {
|
||||
var scope = TA.getProfileForm() || document;
|
||||
scope.querySelectorAll('.pods-dfv-container-wysiwyg textarea').forEach(function(ta) {
|
||||
if (!ta.id) return;
|
||||
TA.ensureVisualMode(ta.id);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
})(jQuery);
|
||||
Reference in New Issue
Block a user