ver. 0.299: Table column visibility toggle with localStorage persistence

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-21 22:00:22 +01:00
parent 5eee2c6649
commit d2e85e94df
8 changed files with 320 additions and 71 deletions

View File

@@ -0,0 +1,180 @@
.table-list-table th,
.table-list-table td {
vertical-align: middle !important;
}
.table-list-table th.text-right,
.table-list-table td.text-right {
display: table-cell !important;
text-align: right !important;
justify-content: initial !important;
align-items: initial !important;
}
.table-list-table th:first-child,
.table-list-table td:first-child {
width: 70px;
white-space: nowrap;
}
.js-table-filters-form .js-filter-compact-select {
width: 100%;
min-width: 0;
max-width: none;
}
.table-list-table th.table-col-compact,
.table-list-table td.table-col-compact {
width: 120px;
min-width: 120px;
white-space: nowrap;
}
.table-list-per-page-form {
display: inline-flex;
align-items: center;
justify-content: flex-end;
flex-wrap: wrap;
gap: 8px;
}
.jconfirm.table-list-confirm-dialog .jconfirm-row {
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
}
.jconfirm.table-list-confirm-dialog .jconfirm-box-container {
width: 100%;
max-width: 560px;
padding-left: 12px;
padding-right: 12px;
margin: 0 auto;
}
.jconfirm.table-list-confirm-dialog .jconfirm-box {
width: 100% !important;
}
/* --- Column visibility toggle --- */
.table-list-header-actions {
display: inline-flex;
align-items: center;
gap: 10px;
}
.table-col-toggle-wrapper {
position: relative;
display: inline-block;
}
.table-col-toggle-dropdown {
display: none;
position: absolute;
right: 0;
top: 100%;
z-index: 1050;
min-width: 220px;
max-height: 400px;
overflow-y: auto;
background: #fff;
border: 1px solid #ddd;
border-radius: 4px;
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
padding: 0;
margin-top: 4px;
}
.table-col-toggle-dropdown.open {
display: block;
}
.table-col-toggle-header {
padding: 8px 12px;
font-weight: 600;
font-size: 12px;
color: #555;
border-bottom: 1px solid #eee;
background: #f8f8f8;
}
.table-col-toggle-item {
display: flex;
align-items: center;
padding: 5px 12px;
margin: 0;
font-weight: normal;
cursor: pointer;
font-size: 13px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
gap: 10px;
}
.table-col-toggle-item:hover {
background: #f5f5f5;
}
.table-col-toggle-footer {
padding: 6px 12px;
border-top: 1px solid #eee;
background: #f8f8f8;
text-align: center;
}
.table-list-table th.table-col-hidden,
.table-list-table td.table-col-hidden {
display: none;
}
/* Toggle switch */
.table-col-switch {
position: relative;
display: inline-block;
width: 34px;
min-width: 34px;
height: 18px;
}
.table-col-switch input {
opacity: 0;
width: 0;
height: 0;
position: absolute;
}
.table-col-switch-slider {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #ccc;
border-radius: 18px;
transition: background-color 0.2s;
}
.table-col-switch-slider:before {
position: absolute;
content: "";
height: 14px;
width: 14px;
left: 2px;
bottom: 2px;
background-color: #fff;
border-radius: 50%;
transition: transform 0.2s;
}
.table-col-switch input:checked + .table-col-switch-slider {
background-color: #5cb85c;
}
.table-col-switch input:checked + .table-col-switch-slider:before {
transform: translateX(16px);
}

View File

@@ -46,7 +46,30 @@ $isCompactColumn = function(array $column): bool {
<?php endif; ?>
</div>
<div class="col-sm-4 text-right">
<span class="text-muted">Wyników: <?= $total; ?></span>
<div class="table-list-header-actions">
<span class="text-muted">Wyników: <?= $total; ?></span>
<div class="table-col-toggle-wrapper">
<button type="button" class="btn btn-default btn-sm js-col-toggle-btn" title="Widoczność kolumn">
<i class="fa fa-columns"></i>
</button>
<div class="table-col-toggle-dropdown js-col-toggle-dropdown">
<div class="table-col-toggle-header">Widoczność kolumn</div>
<?php foreach ($list->columns as $colIndex => $column): ?>
<?php $colKey = (string)($column['key'] ?? 'col_' . $colIndex); ?>
<label class="table-col-toggle-item">
<span class="table-col-switch">
<input type="checkbox" class="js-col-toggle-checkbox" data-col-key="<?= htmlspecialchars($colKey, ENT_QUOTES, 'UTF-8'); ?>" checked />
<span class="table-col-switch-slider"></span>
</span>
<?= htmlspecialchars((string)($column['label'] ?? $colKey), ENT_QUOTES, 'UTF-8'); ?>
</label>
<?php endforeach; ?>
<div class="table-col-toggle-footer">
<button type="button" class="btn btn-default btn-xs js-col-toggle-reset">Pokaż wszystkie</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
@@ -130,8 +153,9 @@ $isCompactColumn = function(array $column): bool {
<table class="table table-hover table-striped table-bordered mbn table-list-table">
<thead>
<tr>
<?php foreach ($list->columns as $column): ?>
<?php foreach ($list->columns as $colIndex => $column): ?>
<?php
$colKey = (string)($column['key'] ?? 'col_' . $colIndex);
$sortKey = (string)($column['sort_key'] ?? ($column['key'] ?? ''));
$isAllowedSortKey = empty($list->sortableColumns) || in_array($sortKey, $list->sortableColumns, true);
$isSortable = !empty($column['sortable']) && $sortKey !== '' && $isAllowedSortKey;
@@ -147,7 +171,7 @@ $isCompactColumn = function(array $column): bool {
$headerClass = trim($headerClass . ' table-col-compact');
}
?>
<th class="<?= htmlspecialchars($headerClass, ENT_QUOTES, 'UTF-8'); ?>">
<th class="<?= htmlspecialchars($headerClass, ENT_QUOTES, 'UTF-8'); ?>" data-col-key="<?= htmlspecialchars($colKey, ENT_QUOTES, 'UTF-8'); ?>">
<?php if ($isSortable): ?>
<a href="<?= htmlspecialchars($sortUrl, ENT_QUOTES, 'UTF-8'); ?>">
<?= htmlspecialchars((string)($column['label'] ?? ''), ENT_QUOTES, 'UTF-8'); ?>
@@ -169,9 +193,10 @@ $isCompactColumn = function(array $column): bool {
<?php if (is_array($list->rows) && !empty($list->rows)): ?>
<?php foreach ($list->rows as $row): ?>
<tr>
<?php foreach ($list->columns as $column): ?>
<?php foreach ($list->columns as $colIndex => $column): ?>
<?php
$key = $column['key'] ?? '';
$colKey = (string)($column['key'] ?? 'col_' . $colIndex);
$raw = !empty($column['raw']);
$value = $row[$key] ?? '';
$cellClass = trim((string)($column['class'] ?? ''));
@@ -179,7 +204,7 @@ $isCompactColumn = function(array $column): bool {
$cellClass = trim($cellClass . ' table-col-compact');
}
?>
<td class="<?= htmlspecialchars($cellClass, ENT_QUOTES, 'UTF-8'); ?>">
<td class="<?= htmlspecialchars($cellClass, ENT_QUOTES, 'UTF-8'); ?>" data-col-key="<?= htmlspecialchars($colKey, ENT_QUOTES, 'UTF-8'); ?>">
<?php if ($raw): ?>
<?= (string)$value; ?>
<?php else: ?>
@@ -269,67 +294,6 @@ $isCompactColumn = function(array $column): bool {
</div>
</div>
<style type="text/css">
.table-list-table th,
.table-list-table td {
vertical-align: middle !important;
}
.table-list-table th.text-right,
.table-list-table td.text-right {
display: table-cell !important;
text-align: right !important;
justify-content: initial !important;
align-items: initial !important;
}
.table-list-table th:first-child,
.table-list-table td:first-child {
width: 70px;
white-space: nowrap;
}
.js-table-filters-form .js-filter-compact-select {
width: 100%;
min-width: 0;
max-width: none;
}
.table-list-table th.table-col-compact,
.table-list-table td.table-col-compact {
width: 120px;
min-width: 120px;
white-space: nowrap;
}
.table-list-per-page-form {
display: inline-flex;
align-items: center;
justify-content: flex-end;
flex-wrap: wrap;
gap: 8px;
}
.jconfirm.table-list-confirm-dialog .jconfirm-row {
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
}
.jconfirm.table-list-confirm-dialog .jconfirm-box-container {
width: 100%;
max-width: 560px;
padding-left: 12px;
padding-right: 12px;
margin: 0 auto;
}
.jconfirm.table-list-confirm-dialog .jconfirm-box {
width: 100% !important;
}
</style>
<script type="text/javascript">
(function($) {
if (!$) {
@@ -414,5 +378,96 @@ $isCompactColumn = function(array $column): bool {
}
}
);
// --- Column visibility toggle ---
var storageKey = 'tableListCols_' + <?= json_encode($list->basePath); ?>;
function getHiddenCols() {
try {
var data = localStorage.getItem(storageKey);
if (data) {
var parsed = JSON.parse(data);
if (Array.isArray(parsed)) {
return parsed;
}
}
} catch (e) {}
return [];
}
function saveHiddenCols(hiddenArr) {
try {
localStorage.setItem(storageKey, JSON.stringify(hiddenArr));
} catch (e) {}
}
function applyColumnVisibility(hiddenCols) {
var $table = $('.table-list-table');
$table.find('th[data-col-key], td[data-col-key]').each(function() {
var key = $(this).attr('data-col-key');
if (hiddenCols.indexOf(key) !== -1) {
$(this).addClass('table-col-hidden');
} else {
$(this).removeClass('table-col-hidden');
}
});
$('.js-col-toggle-checkbox').each(function() {
var key = $(this).attr('data-col-key');
$(this).prop('checked', hiddenCols.indexOf(key) === -1);
});
}
// Apply saved state on load
var hiddenCols = getHiddenCols();
if (hiddenCols.length) {
applyColumnVisibility(hiddenCols);
}
// Toggle dropdown open/close
$(document).off('click.colToggleBtn', '.js-col-toggle-btn');
$(document).on('click.colToggleBtn', '.js-col-toggle-btn', function(e) {
e.stopPropagation();
var $dropdown = $(this).siblings('.js-col-toggle-dropdown');
$dropdown.toggleClass('open');
});
// Prevent closing when clicking inside dropdown
$(document).off('click.colToggleDropdown', '.js-col-toggle-dropdown');
$(document).on('click.colToggleDropdown', '.js-col-toggle-dropdown', function(e) {
e.stopPropagation();
});
// Close dropdown on outside click
$(document).off('click.colToggleClose');
$(document).on('click.colToggleClose', function() {
$('.js-col-toggle-dropdown').removeClass('open');
});
// Checkbox change — toggle column
$(document).off('change.colToggle', '.js-col-toggle-checkbox');
$(document).on('change.colToggle', '.js-col-toggle-checkbox', function() {
var key = $(this).attr('data-col-key');
var isChecked = $(this).is(':checked');
var current = getHiddenCols();
if (isChecked) {
current = $.grep(current, function(v) { return v !== key; });
} else {
if (current.indexOf(key) === -1) {
current.push(key);
}
}
saveHiddenCols(current);
applyColumnVisibility(current);
});
// Reset — show all columns
$(document).off('click.colToggleReset', '.js-col-toggle-reset');
$(document).on('click.colToggleReset', '.js-col-toggle-reset', function() {
saveHiddenCols([]);
applyColumnVisibility([]);
});
})(window.jQuery);
</script>

View File

@@ -35,6 +35,7 @@
<script type="text/javascript" src="/libraries/functions.js"></script>
<script type="text/javascript" src="/admin/js/functions.js"></script>
<link rel="stylesheet" href="/admin/layout/style-css/style.css" />
<link rel="stylesheet" href="/admin/layout/style-css/table-list.css" />
</head>
<body>
<div class="admin-page">

View File

@@ -4,6 +4,16 @@ Logi zmian z migracji na Domain-Driven Architecture. Najnowsze na gorze.
---
## ver. 0.299 (2026-02-21) - Widoczność kolumn w tabelach
- **NEW**: Toggle widoczności kolumn w komponentach `table-list` — przycisk z ikoną kolumn, dropdown z toggle switchami
- **NEW**: Stan widoczności kolumn zapisywany w `localStorage` per tabela (klucz na bazie `basePath`)
- **NEW**: Przycisk "Pokaż wszystkie" resetujący widoczność
- **UPDATE**: Style z `table-list.php` wyekstrahowane do osobnego pliku `admin/layout/style-css/table-list.css`
- **UPDATE**: `admin/templates/site/main-layout.php` — podłączenie `table-list.css`
---
## ver. 0.297 (2026-02-19) - REST API produktów
- **NEW**: Endpoint `products` w REST API — lista, szczegóły, tworzenie, aktualizacja produktów

View File

@@ -18,14 +18,14 @@ Aktualizacje znajdują się w folderze `updates/0.XX/` gdzie XX oznacza dziesią
## Procedura tworzenia nowej aktualizacji
## Status biezacej aktualizacji (ver. 0.297)
## Status biezacej aktualizacji (ver. 0.299)
- Wersja udostepniona: `0.297` (data: 2026-02-19).
- Wersja udostepniona: `0.299` (data: 2026-02-21).
- Pliki publikacyjne:
- `updates/0.20/ver_0.297.zip`
- `updates/0.20/ver_0.299.zip`
- Pliki metadanych aktualizacji:
- `updates/changelog.php`
- `updates/versions.php` (`$current_ver = 297`)
- `updates/versions.php` (`$current_ver = 299`)
- Weryfikacja testow przed publikacja:
- `OK (687 tests, 1971 assertions)`

BIN
updates/0.20/ver_0.299.zip Normal file

Binary file not shown.

View File

@@ -1,3 +1,6 @@
<b>ver. 0.299 - 21.02.2026</b><br />
- NEW - Ukrywanie/pokazywanie kolumn w tabelach admina (toggle switch + localStorage)
<hr>
<b>ver. 0.298 - 20.02.2026</b><br />
- FIX - kilka poprawek po aktualizacji
<hr>

View File

@@ -1,5 +1,5 @@
<?
$current_ver = 298;
$current_ver = 299;
for ($i = 1; $i <= $current_ver; $i++)
{