diff --git a/frontend/js/admin/sections/access.js b/frontend/js/admin/sections/access.js
index aa26b92..2e1c955 100644
--- a/frontend/js/admin/sections/access.js
+++ b/frontend/js/admin/sections/access.js
@@ -396,7 +396,10 @@
/* ════════ режим «Матрица» (класс × контент одним экраном) ════════ */
function matrixHeadCells(classes) {
return classes.map(c =>
- `
${esc(c.name)} | `).join('');
+ `
+
+ | `).join('');
}
function matrixBody() {
const classes = _matrix.classes || [];
@@ -410,7 +413,10 @@
return `
| `;
}).join('');
- return `| ${esc(it.title)} | ${cells}
`;
+ return `|
+
+ | ${cells}
`;
}).join('');
if (!rows) return '';
return `| ${TYPE_LABEL[type] || type} |
${rows}`;
@@ -453,6 +459,40 @@
}
function mxSearch(v) { _mSearch = v; const b = document.getElementById('acc-mx-body'); if (b) b.innerHTML = matrixBody(); }
+ function mxRepaint() { const b = document.getElementById('acc-mx-body'); if (b) b.innerHTML = matrixBody(); }
+ function mxApply(o, type, ref, open) {
+ const arr = o[type] || (o[type] = []);
+ const i = arr.indexOf(ref);
+ if (open && i < 0) arr.push(ref);
+ if (!open && i >= 0) arr.splice(i, 1);
+ }
+ /* строка матрицы: открыть/закрыть один контент всем классам */
+ async function mxRowBulk(type, ref) {
+ const classes = _matrix.classes || [];
+ const allOpen = classes.length && classes.every(c => ((_matrix.open[c.id] || {})[type] || []).includes(ref));
+ const open = !allOpen;
+ if (!open && !confirm(`Закрыть «${contentTitle(type, ref)}» у всех классов?`)) return;
+ try {
+ await Promise.all(classes.map(c => LS.accessSetRule(type, ref, 'class', c.id, open ? 1 : null)));
+ classes.forEach(c => mxApply(_matrix.open[c.id] || (_matrix.open[c.id] = {}), type, ref, open));
+ mxRepaint();
+ } catch (e) { LS.toast('Ошибка: ' + e.message, 'error'); _matrix = null; renderMatrix(); }
+ }
+ /* столбец матрицы: открыть/закрыть весь контент одному классу */
+ async function mxColBulk(classId) {
+ const items = CONTENT_TYPES.flatMap(t => itemsOf(t).map(it => [t, it[keyName(t)]]));
+ const o = _matrix.open[classId] || (_matrix.open[classId] = {});
+ const allOpen = items.length && items.every(([t, ref]) => (o[t] || []).includes(ref));
+ const open = !allOpen;
+ const cls = (_matrix.classes.find(c => c.id === classId) || {}).name || ('#' + classId);
+ if (!open && !confirm(`Закрыть весь контент у класса «${cls}»?`)) return;
+ try {
+ await Promise.all(items.map(([t, ref]) => LS.accessSetRule(t, ref, 'class', classId, open ? 1 : null)));
+ items.forEach(([t, ref]) => mxApply(o, t, ref, open));
+ mxRepaint();
+ } catch (e) { LS.toast('Ошибка: ' + e.message, 'error'); _matrix = null; renderMatrix(); }
+ }
+
/* ── режим ── */
function setMode(m) {
if (m === _mode) return;
@@ -472,6 +512,8 @@
window.accClassBulk = classBulk;
window.accMx = mxToggle;
window.accMxSearch = mxSearch;
+ window.accMxRowBulk = mxRowBulk;
+ window.accMxColBulk = mxColBulk;
window.accLeftSearch = leftSearch;
window.AdminSections = window.AdminSections || {};