Release 0.245: refactor articles list and update package

This commit is contained in:
2026-02-08 01:35:13 +01:00
parent 4aea594477
commit d709a3df7b
28 changed files with 936 additions and 339 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -827,7 +827,7 @@ body {
td {
border-color: $cHoverBackground;
a {
a:not(.btn) {
transition: .15s ease;
&:hover {
@@ -1726,7 +1726,7 @@ input:checked[type="checkbox"]:before {
text-align: right;
}
a {
a:not(.btn) {
color: $cBlue;
transition: .15s ease;
font-weight: 500;
@@ -1736,6 +1736,24 @@ input:checked[type="checkbox"]:before {
}
}
a.btn {
color: #fff;
&:hover,
&:focus {
color: #fff;
}
}
a.btn-default {
color: #000;
&:hover,
&:focus {
color: #000;
}
}
thead {
background-color: $cHoverBackground;

View File

@@ -1,115 +0,0 @@
<?php
global $gdb;
$grid = new \grid( 'pp_articles' );
$grid -> gdb_opt = $gdb;
$grid -> sql = 'SELECT *'
. 'FROM ( '
. 'SELECT '
. 'id, date_add, date_modify, status, '
. '( SELECT title FROM pp_articles_langs AS pal, pp_langs AS pl WHERE lang_id = pl.id AND article_id = pa.id AND title != \'\' ORDER BY o ASC LIMIT 1 ) AS title, '
. '( SELECT login FROM pp_users AS pu WHERE pu.id = pa.modify_by ) AS user '
. 'FROM '
. 'pp_articles AS pa WHERE status != -1 '
. ') AS q1 '
. 'WHERE '
. '1=1 [where] '
. 'ORDER BY '
. '[order_p1] [order_p2]';
$grid -> sql_count = 'SELECT '
. 'COUNT(0) FROM ( '
. 'SELECT '
. 'id, date_add, date_modify, status, '
. '( SELECT title FROM pp_articles_langs AS pal, pp_langs AS pl WHERE lang_id = pl.id AND article_id = pa.id AND title != \'\' ORDER BY o ASC LIMIT 1 ) AS title, '
. '( SELECT login FROM pp_users AS pu WHERE pu.id = pa.modify_by ) AS user '
. 'FROM '
. 'pp_articles AS pa WHERE status != -1 '
. ') AS q1 '
. 'WHERE '
. '1=1 [where] ';
$grid -> debug = true;
$grid -> order = [ 'column' => 'date_add', 'type' => 'DESC' ];
$grid -> search = [
[ 'name' => 'Tytuł', 'db' => 'title', 'type' => 'text' ],
[ 'name' => 'Aktywny', 'db' => 'status', 'type' => 'select', 'replace' => [ 'array' => [ 0 => 'nie', 1 => 'tak' ] ] ],
[ 'name' => 'Data dodania', 'db' => 'date_add', 'type' => 'date_range' ],
[ 'name' => 'Data modyfikacji', 'db' => 'date_modify', 'type' => 'date_range' ]
];
$grid -> columns_view = [
[
'name' => 'Lp.',
'th' => [ 'class' => 'g-lp' ],
'td' => [ 'class' => 'g-center' ],
'autoincrement' => true
],
[
'name' => 'Tytuł',
'db' => 'title',
'sort' => true,
'php' => 'echo "[title]"; echo "<small class=\'text-muted\'>" . \admin\factory\Articles::article_pages( [id] ) . "</small>";'
],
[
'name' => 'Aktywny',
'db' => 'status',
'replace' => [ 'array' => [ 0 => '<span style="color: #FF0000;">nie</span>', 1 => 'tak' ] ],
'td' => [ 'class' => 'g-center' ],
'th' => [ 'class' => 'g-center', 'style' => 'width: 150px;' ],
'sort' => true
],
[
'name' => 'Data dodania',
'db' => 'date_add',
'td' => [ 'class' => 'g-center' ],
'th' => [ 'class' => 'g-center', 'style' => 'width: 220px;' ],
'php' => 'echo date( "Y-m-d H:i", strtotime( "[date_add]" ) );'
],
[
'name' => 'Data modyfikacji',
'db' => 'date_modify',
'td' => [ 'class' => 'g-center' ],
'th' => [ 'class' => 'g-center', 'style' => 'width: 220px;' ],
'php' => 'echo date( "Y-m-d H:i", strtotime( "[date_modify]" ) );'
],
[
'name' => 'Modyfikowany przez',
'db' => 'user',
'td' => [ 'class' => 'g-center' ],
'th' => [ 'class' => 'g-center', 'style' => 'width: 220px;' ],
],
[
'name' => 'Akcja',
'db' => 'id',
'td' => [ 'class' => 'g-center' ],
'th' => [ 'class' => 'g-center', 'style' => 'width: 120px;' ],
'php' => 'echo "<a href=\'#\' class=\'button\' url=\'/" . \admin\factory\Articles::article_url( [id] ) . "\'>wybierz</a>";'
]
];
echo $grid -> draw();
?>
<style type="text/css">
body.sb-top.sb-top-sm .navbar.navbar-fixed-top + #sidebar_left + #content_wrapper {
padding-top: 0;
}
</style>
<script type="text/javascript">
function getUrlParam(paramName)
{
var reParam = new RegExp('(?:[\?&]|&amp;)' + paramName + '=([^&]+)', 'i');
var match = window.location.search.match(reParam);
return (match && match.length > 1) ? match[1] : '';
}
$( function()
{
$( '#sidebar_left, .navbar-fixed-top' ).hide();
var funcNum = getUrlParam('CKEditorFuncNum');
$( 'body' ).on( 'click', '.button', function()
{
window.opener.CKEDITOR.tools.callFunction(funcNum, $( this ).attr( 'url' ) );
window.close();
});
});
</script>

View File

@@ -1,100 +1,5 @@
<?php
global $gdb;
<?= \Tpl::view('components/table-list', ['list' => $this->viewModel]); ?>
$grid = new \grid( 'pp_articles' );
$grid -> gdb_opt = $gdb;
$grid -> sql = 'SELECT *'
. 'FROM ( '
. 'SELECT '
. 'id, date_add, date_modify, status, '
. '( SELECT title FROM pp_articles_langs AS pal, pp_langs AS pl WHERE lang_id = pl.id AND article_id = pa.id AND title != \'\' ORDER BY o ASC LIMIT 1 ) AS title, '
. '( SELECT login FROM pp_users AS pu WHERE pu.id = pa.modify_by ) AS user '
. 'FROM '
. 'pp_articles AS pa WHERE status != -1 '
. ') AS q1 '
. 'WHERE '
. '1=1 [where] '
. 'ORDER BY '
. '[order_p1] [order_p2]';
$grid -> sql_count = 'SELECT '
. 'COUNT(0) FROM ( '
. 'SELECT '
. 'id, date_add, date_modify, status, '
. '( SELECT title FROM pp_articles_langs AS pal, pp_langs AS pl WHERE lang_id = pl.id AND article_id = pa.id AND title != \'\' ORDER BY o ASC LIMIT 1 ) AS title, '
. '( SELECT login FROM pp_users AS pu WHERE pu.id = pa.modify_by ) AS user '
. 'FROM '
. 'pp_articles AS pa WHERE status != -1 '
. ') AS q1 '
. 'WHERE '
. '1=1 [where] ';
$grid -> debug = true;
$grid -> order = [ 'column' => 'date_add', 'type' => 'DESC' ];
$grid -> search = [
[ 'name' => 'Tytuł', 'db' => 'title', 'type' => 'text' ],
[ 'name' => 'Aktywny', 'db' => 'status', 'type' => 'select', 'replace' => [ 'array' => [ 0 => 'nie', 1 => 'tak' ] ] ],
[ 'name' => 'Data dodania', 'db' => 'date_add', 'type' => 'date_range' ],
[ 'name' => 'Data modyfikacji', 'db' => 'date_modify', 'type' => 'date_range' ]
];
$grid -> columns_view = [
[
'name' => 'Lp.',
'th' => [ 'class' => 'g-lp' ],
'td' => [ 'class' => 'g-center' ],
'autoincrement' => true
],
[
'name' => 'Tytuł',
'db' => 'title',
'sort' => true,
'php' => 'echo "<a href=\'/admin/articles/article_edit/id=[id]\'>[title]</a>"; echo "<small class=\'text-muted\'>" . \admin\factory\Articles::article_pages( [id] ) . "</small>";'
],
[
'name' => 'Aktywny',
'db' => 'status',
'replace' => [ 'array' => [ 0 => '<span style="color: #FF0000;">nie</span>', 1 => 'tak' ] ],
'td' => [ 'class' => 'g-center' ],
'th' => [ 'class' => 'g-center', 'style' => 'width: 150px;' ],
'sort' => true
],
[
'name' => 'Data dodania',
'db' => 'date_add',
'td' => [ 'class' => 'g-center' ],
'th' => [ 'class' => 'g-center', 'style' => 'width: 220px;' ],
'php' => 'echo date( "Y-m-d H:i", strtotime( "[date_add]" ) );'
],
[
'name' => 'Data modyfikacji',
'db' => 'date_modify',
'td' => [ 'class' => 'g-center' ],
'th' => [ 'class' => 'g-center', 'style' => 'width: 220px;' ],
'php' => 'echo date( "Y-m-d H:i", strtotime( "[date_modify]" ) );'
],
[
'name' => 'Modyfikowany przez',
'db' => 'user',
'td' => [ 'class' => 'g-center' ],
'th' => [ 'class' => 'g-center', 'style' => 'width: 220px;' ],
],
[
'name' => 'Edytuj',
'action' => [ 'type' => 'edit', 'url' => '/admin/articles/article_edit/id=[id]' ],
'th' => [ 'class' => 'g-center', 'style' => 'width: 70px;' ],
'td' => [ 'class' => 'g-center' ]
],
[
'name' => 'Usuń',
'action' => [ 'type' => 'delete', 'url' => '/admin/articles/article_delete/id=[id]' ],
'th' => [ 'class' => 'g-center', 'style' => 'width: 70px;' ],
'td' => [ 'class' => 'g-center' ]
]
];
$grid -> buttons = [
[
'label' => 'Dodaj artykuł',
'url' => '/admin/articles/article_edit/',
'icon' => 'fa-plus-circle',
'class' => 'btn-success'
]
];
echo $grid -> draw();
<?php if (!empty($this->viewModel->customScriptView)): ?>
<?= \Tpl::view($this->viewModel->customScriptView, ['list' => $this->viewModel]); ?>
<?php endif; ?>

View File

@@ -0,0 +1,219 @@
<?php
$list = $this->list;
$buildUrl = function(array $params = []) use ($list): string {
$query = array_merge($list->query, $params);
foreach ($query as $key => $value) {
if ($value === '' || $value === null) {
unset($query[$key]);
}
}
$qs = http_build_query($query);
return $list->basePath . ($qs ? ('?' . $qs) : '');
};
$currentSort = $list->sort['column'] ?? '';
$currentDir = strtoupper($list->sort['dir'] ?? 'DESC');
$page = max(1, (int)($list->pagination['page'] ?? 1));
$totalPages = max(1, (int)($list->pagination['total_pages'] ?? 1));
$total = (int)($list->pagination['total'] ?? 0);
$perPage = (int)($list->pagination['per_page'] ?? 15);
?>
<div class="panel">
<div class="panel-heading">
<div class="row">
<div class="col-sm-8">
<?php if (!empty($list->createUrl) && !empty($list->createLabel)): ?>
<a href="<?= htmlspecialchars($list->createUrl, ENT_QUOTES, 'UTF-8'); ?>" class="btn btn-success btn-sm">
<i class="fa fa-plus-circle mr5"></i><?= htmlspecialchars($list->createLabel, ENT_QUOTES, 'UTF-8'); ?>
</a>
<?php endif; ?>
</div>
<div class="col-sm-4 text-right">
<span class="text-muted">Wyników: <?= $total; ?></span>
</div>
</div>
</div>
<div class="panel-body">
<form method="get" action="<?= htmlspecialchars($list->basePath, ENT_QUOTES, 'UTF-8'); ?>" class="row mb15">
<?php foreach ($list->filters as $filter): ?>
<?php
$filterKey = (string)($filter['key'] ?? '');
$inputId = 'filter_' . preg_replace('/[^a-zA-Z0-9_]+/', '_', $filterKey);
?>
<div class="col-sm-2 mb10">
<label for="<?= htmlspecialchars($inputId, ENT_QUOTES, 'UTF-8'); ?>" class="control-label">
<?= htmlspecialchars((string)($filter['label'] ?? ''), ENT_QUOTES, 'UTF-8'); ?>
</label>
<?php if (($filter['type'] ?? '') === 'select'): ?>
<select
id="<?= htmlspecialchars($inputId, ENT_QUOTES, 'UTF-8'); ?>"
name="<?= htmlspecialchars($filter['key'], ENT_QUOTES, 'UTF-8'); ?>"
class="form-control input-sm"
title="<?= htmlspecialchars($filter['label'], ENT_QUOTES, 'UTF-8'); ?>"
>
<?php foreach (($filter['options'] ?? []) as $value => $label): ?>
<option value="<?= htmlspecialchars((string)$value, ENT_QUOTES, 'UTF-8'); ?>"<?= ((string)($filter['value'] ?? '') === (string)$value) ? ' selected="selected"' : ''; ?>>
<?= htmlspecialchars((string)$label, ENT_QUOTES, 'UTF-8'); ?>
</option>
<?php endforeach; ?>
</select>
<?php elseif (($filter['type'] ?? '') === 'date'): ?>
<input
type="date"
id="<?= htmlspecialchars($inputId, ENT_QUOTES, 'UTF-8'); ?>"
name="<?= htmlspecialchars($filter['key'], ENT_QUOTES, 'UTF-8'); ?>"
value="<?= htmlspecialchars((string)($filter['value'] ?? ''), ENT_QUOTES, 'UTF-8'); ?>"
class="form-control input-sm"
title="<?= htmlspecialchars($filter['label'], ENT_QUOTES, 'UTF-8'); ?>"
/>
<?php else: ?>
<input
type="text"
id="<?= htmlspecialchars($inputId, ENT_QUOTES, 'UTF-8'); ?>"
name="<?= htmlspecialchars($filter['key'], ENT_QUOTES, 'UTF-8'); ?>"
value="<?= htmlspecialchars((string)($filter['value'] ?? ''), ENT_QUOTES, 'UTF-8'); ?>"
class="form-control input-sm"
placeholder="<?= htmlspecialchars($filter['label'], ENT_QUOTES, 'UTF-8'); ?>"
title="<?= htmlspecialchars($filter['label'], ENT_QUOTES, 'UTF-8'); ?>"
/>
<?php endif; ?>
</div>
<?php endforeach; ?>
<input type="hidden" name="sort" value="<?= htmlspecialchars((string)$currentSort, ENT_QUOTES, 'UTF-8'); ?>" />
<input type="hidden" name="dir" value="<?= htmlspecialchars((string)$currentDir, ENT_QUOTES, 'UTF-8'); ?>" />
<input type="hidden" name="per_page" value="<?= $perPage; ?>" />
<div class="col-sm-12">
<button type="submit" class="btn btn-primary btn-sm">Szukaj</button>
<a href="<?= htmlspecialchars($list->basePath, ENT_QUOTES, 'UTF-8'); ?>" class="btn btn-default btn-sm">Wyczyść</a>
</div>
</form>
<div class="table-responsive">
<table class="table table-hover table-striped table-bordered mbn">
<thead>
<tr>
<?php foreach ($list->columns as $column): ?>
<?php
$sortKey = (string)($column['sort_key'] ?? ($column['key'] ?? ''));
$isAllowedSortKey = empty($list->sortableColumns) || in_array($sortKey, $list->sortableColumns, true);
$isSortable = !empty($column['sortable']) && $sortKey !== '' && $isAllowedSortKey;
$isCurrent = $isSortable && $currentSort === $sortKey;
$nextDir = ($isCurrent && $currentDir === 'ASC') ? 'DESC' : 'ASC';
$sortUrl = $buildUrl([
'sort' => $sortKey,
'dir' => $nextDir,
'page' => 1,
]);
?>
<th class="<?= htmlspecialchars((string)($column['class'] ?? ''), ENT_QUOTES, 'UTF-8'); ?>">
<?php if ($isSortable): ?>
<a href="<?= htmlspecialchars($sortUrl, ENT_QUOTES, 'UTF-8'); ?>">
<?= htmlspecialchars((string)($column['label'] ?? ''), ENT_QUOTES, 'UTF-8'); ?>
<?php if ($isCurrent): ?>
<span aria-hidden="true"><?= $currentDir === 'ASC' ? '↑' : '↓'; ?></span>
<?php else: ?>
<span class="text-muted" aria-hidden="true">↕</span>
<?php endif; ?>
</a>
<?php else: ?>
<?= htmlspecialchars((string)($column['label'] ?? ''), ENT_QUOTES, 'UTF-8'); ?>
<?php endif; ?>
</th>
<?php endforeach; ?>
<th class="text-center" style="width: 160px;">Akcje</th>
</tr>
</thead>
<tbody>
<?php if (is_array($list->rows) && !empty($list->rows)): ?>
<?php foreach ($list->rows as $row): ?>
<tr>
<?php foreach ($list->columns as $column): ?>
<?php
$key = $column['key'] ?? '';
$raw = !empty($column['raw']);
$value = $row[$key] ?? '';
?>
<td class="<?= htmlspecialchars((string)($column['class'] ?? ''), ENT_QUOTES, 'UTF-8'); ?>">
<?php if ($raw): ?>
<?= (string)$value; ?>
<?php else: ?>
<?= htmlspecialchars((string)$value, ENT_QUOTES, 'UTF-8'); ?>
<?php endif; ?>
</td>
<?php endforeach; ?>
<td class="text-center">
<?php foreach (($row['_actions'] ?? []) as $action): ?>
<a
href="<?= htmlspecialchars((string)($action['url'] ?? '#'), ENT_QUOTES, 'UTF-8'); ?>"
class="<?= htmlspecialchars((string)($action['class'] ?? 'btn btn-default btn-xs'), ENT_QUOTES, 'UTF-8'); ?>"
<?php if (!empty($action['confirm'])): ?>
onclick="return confirm('<?= htmlspecialchars((string)$action['confirm'], ENT_QUOTES, 'UTF-8'); ?>');"
<?php endif; ?>
>
<?= htmlspecialchars((string)($action['label'] ?? ''), ENT_QUOTES, 'UTF-8'); ?>
</a>
<?php endforeach; ?>
</td>
</tr>
<?php endforeach; ?>
<?php else: ?>
<tr>
<td colspan="<?= count($list->columns) + 1; ?>">
<div class="alert alert-danger mbn"><?= htmlspecialchars((string)$list->emptyMessage, ENT_QUOTES, 'UTF-8'); ?></div>
</td>
</tr>
<?php endif; ?>
</tbody>
</table>
</div>
<div class="row mt15">
<div class="col-sm-6">
<ul class="pagination">
<?php $prevPage = max(1, $page - 1); ?>
<?php $nextPage = min($totalPages, $page + 1); ?>
<li class="<?= $page <= 1 ? 'disabled' : ''; ?>">
<a href="<?= htmlspecialchars($buildUrl(['page' => 1]), ENT_QUOTES, 'UTF-8'); ?>"><i class="fa fa-fast-backward"></i></a>
</li>
<li class="<?= $page <= 1 ? 'disabled' : ''; ?>">
<a href="<?= htmlspecialchars($buildUrl(['page' => $prevPage]), ENT_QUOTES, 'UTF-8'); ?>"><i class="fa fa-backward"></i></a>
</li>
<?php for ($i = max(1, $page - 3); $i <= min($totalPages, $page + 3); $i++): ?>
<li class="<?= $i === $page ? 'active' : ''; ?>">
<a href="<?= htmlspecialchars($buildUrl(['page' => $i]), ENT_QUOTES, 'UTF-8'); ?>"><?= $i; ?></a>
</li>
<?php endfor; ?>
<li class="<?= $page >= $totalPages ? 'disabled' : ''; ?>">
<a href="<?= htmlspecialchars($buildUrl(['page' => $nextPage]), ENT_QUOTES, 'UTF-8'); ?>"><i class="fa fa-forward"></i></a>
</li>
<li class="<?= $page >= $totalPages ? 'disabled' : ''; ?>">
<a href="<?= htmlspecialchars($buildUrl(['page' => $totalPages]), ENT_QUOTES, 'UTF-8'); ?>"><i class="fa fa-fast-forward"></i></a>
</li>
</ul>
</div>
<div class="col-sm-6 text-right">
<form method="get" action="<?= htmlspecialchars($list->basePath, ENT_QUOTES, 'UTF-8'); ?>" class="form-inline">
<?php foreach ($list->query as $key => $value): ?>
<?php if ($key !== 'per_page' && $key !== 'page'): ?>
<input type="hidden" name="<?= htmlspecialchars((string)$key, ENT_QUOTES, 'UTF-8'); ?>" value="<?= htmlspecialchars((string)$value, ENT_QUOTES, 'UTF-8'); ?>" />
<?php endif; ?>
<?php endforeach; ?>
<input type="hidden" name="page" value="1" />
Wyświetlaj
<select name="per_page" class="form-control input-sm" onchange="this.form.submit()">
<?php foreach ($list->perPageOptions as $opt): ?>
<option value="<?= (int)$opt; ?>"<?= ((int)$opt === $perPage) ? ' selected="selected"' : ''; ?>><?= (int)$opt; ?></option>
<?php endforeach; ?>
</select>
rekordów
</form>
</div>
</div>
</div>
</div>