Skip to content

Commit 3b8ee5d

Browse files
committed
Migrate style list page to grid view
1 parent c1a50c6 commit 3b8ee5d

File tree

6 files changed

+248
-137
lines changed

6 files changed

+248
-137
lines changed
Lines changed: 3 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,8 @@
11
{include file='header' pageTitle='wcf.acp.style.list'}
22

3-
<script data-relocate="true" src="{@$__wcf->getPath()}acp/js/WCF.ACP.Style.js?v={@LAST_UPDATE_TIME}"></script>
4-
<script data-relocate="true">
5-
$(function() {
6-
new WCF.ACP.Style.List();
7-
8-
document.querySelectorAll('.styleList .jsObjectAction[data-object-action="toggle"]').forEach((icon) => {
9-
icon.parentElement.addEventListener("click", (event) => {
10-
if (event.target !== icon) {
11-
event.preventDefault();
12-
13-
icon.click();
14-
}
15-
});
16-
});
17-
});
18-
</script>
19-
203
<header class="contentHeader">
214
<div class="contentHeaderTitle">
22-
<h1 class="contentTitle">{lang}wcf.acp.style.list{/lang} <span class="badge badgeInverse">{#$items}</span></h1>
5+
<h1 class="contentTitle">{lang}wcf.acp.style.list{/lang} <span class="badge badgeInverse">{#$gridView->countRows()}</span></h1>
236
</div>
247

258
<nav class="contentHeaderNavigation">
@@ -32,92 +15,8 @@
3215
</nav>
3316
</header>
3417

35-
{hascontent}
36-
<div class="paginationTop">
37-
{content}{pages print=true assign=pagesLinks controller="StyleList" link="pageNo=%d"}{/content}
38-
</div>
39-
{/hascontent}
40-
41-
<div class="section sectionContainerList">
42-
<ol class="containerList styleList jsObjectActionContainer" data-object-action-class-name="wcf\data\style\StyleAction">
43-
{foreach from=$objects item=style}
44-
<li class="jsObjectActionObject" data-object-id="{@$style->getObjectID()}">
45-
<div class="box128">
46-
<span class="styleListPreviewImage">
47-
<img src="{@$style->getPreviewImage()}" srcset="{@$style->getPreviewImage2x()} 2x" height="64" alt="">
48-
</span>
49-
<div class="details">
50-
<div class="containerHeadline">
51-
<h3><a href="{link controller='StyleEdit' id=$style->styleID}{/link}">{$style->styleName}</a></h3>
52-
{if $style->styleDescription}<small>{lang __optional=true}{@$style->styleDescription}{/lang}</small>{/if}
53-
</div>
54-
<dl class="plain inlineDataList">
55-
<dt>{lang}wcf.acp.style.users{/lang}</dt>
56-
<dd>{#$style->users}</dd>
57-
</dl>
58-
<dl class="plain inlineDataList">
59-
<dt>{lang}wcf.acp.style.styleVersion{/lang}</dt>
60-
<dd>{$style->styleVersion} ({$style->styleDate})</dd>
61-
</dl>
62-
<dl class="plain inlineDataList">
63-
<dt>{lang}wcf.acp.style.authorName{/lang}</dt>
64-
<dd>{if $style->authorURL}<a href="{$style->authorURL}">{$style->authorName}</a>{else}{$style->authorName}{/if}</dd>
65-
</dl>
66-
<nav class="jsMobileNavigation buttonGroupNavigation">
67-
<ul class="buttonList iconList" data-style-id="{@$style->styleID}">
68-
<li><a href="{link controller='StyleEdit' id=$style->styleID}{/link}" title="{lang}wcf.global.button.edit{/lang}" class="jsTooltip">{icon name='pencil'} <span class="invisible">{lang}wcf.global.button.edit{/lang}</span></a></li>
69-
<li><a href="{link controller='StyleExport' id=$style->styleID}{/link}" title="{lang}wcf.acp.style.exportStyle{/lang}" class="jsTooltip">{icon name='download'} <span class="invisible">{lang}wcf.acp.style.exportStyle{/lang}</span></a></li>
70-
71-
{if !$style->isDefault}
72-
<li>
73-
<button type="button" class="jsTooltip jsObjectAction" title="{lang}wcf.global.button.{if $style->isDisabled}enable{else}disable{/if}{/lang}" data-object-action="toggle">
74-
{if $style->isDisabled}
75-
{icon name='square'}
76-
{else}
77-
{icon name='square-check'}
78-
{/if}
79-
<span class="invisible">{lang}wcf.global.button.{if $style->isDisabled}enable{else}disable{/if}{/lang}</span>
80-
</button>
81-
</li>
82-
<li>
83-
<button type="button" class="jsSetAsDefault jsTooltip" title="{lang}wcf.acp.style.button.setAsDefault{/lang}">
84-
{icon name='circle-check'}
85-
<span class="invisible">{lang}wcf.acp.style.button.setAsDefault{/lang}</span>
86-
</button>
87-
</li>
88-
<li>
89-
<button type="button" class="jsDelete jsTooltip" title="{lang}wcf.global.button.delete{/lang}" data-confirm-message-html="{lang __encode=true}wcf.acp.style.delete.confirmMessage{/lang}">
90-
{icon name='xmark'}
91-
<span class="invisible">{lang}wcf.global.button.delete{/lang}</span>
92-
</button>
93-
</li>
94-
{/if}
95-
96-
{event name='itemButtons'}
97-
</ul>
98-
</nav>
99-
</div>
100-
</div>
101-
</li>
102-
{/foreach}
103-
</ol>
18+
<div class="section">
19+
{unsafe:$gridView->render()}
10420
</div>
10521

106-
<footer class="contentFooter">
107-
{hascontent}
108-
<div class="paginationBottom">
109-
{content}{@$pagesLinks}{/content}
110-
</div>
111-
{/hascontent}
112-
113-
<nav class="contentFooterNavigation">
114-
<ul>
115-
<li><a href="{link controller='StyleAdd'}{/link}" class="button">{icon name='plus'} <span>{lang}wcf.acp.menu.link.style.add{/lang}</span></a></li>
116-
<li><a href="{link controller='StyleImport'}{/link}" class="button">{icon name='upload'} <span>{lang}wcf.acp.menu.link.style.import{/lang}</span></a></li>
117-
118-
{event name='contentFooterNavigation'}
119-
</ul>
120-
</nav>
121-
</footer>
122-
12322
{include file='footer'}

wcfsetup/install/files/lib/acp/page/StyleListPage.class.php

Lines changed: 11 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,20 @@
22

33
namespace wcf\acp\page;
44

5-
use wcf\data\style\StyleList;
6-
use wcf\page\MultipleLinkPage;
5+
use wcf\page\AbstractGridViewPage;
6+
use wcf\system\gridView\AbstractGridView;
7+
use wcf\system\gridView\admin\StyleGridView;
78

89
/**
910
* Shows the style list page.
1011
*
11-
* @author Alexander Ebert
12-
* @copyright 2001-2019 WoltLab GmbH
13-
* @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
12+
* @author Alexander Ebert
13+
* @copyright 2001-2025 WoltLab GmbH
14+
* @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
1415
*
15-
* @property StyleList $objectList
16+
* @property UserRankGridView $gridView
1617
*/
17-
class StyleListPage extends MultipleLinkPage
18+
class StyleListPage extends AbstractGridViewPage
1819
{
1920
/**
2021
* @inheritDoc
@@ -26,32 +27,9 @@ class StyleListPage extends MultipleLinkPage
2627
*/
2728
public $neededPermissions = ['admin.style.canManageStyle'];
2829

29-
/**
30-
* @inheritDoc
31-
*/
32-
public $objectListClassName = StyleList::class;
33-
34-
/**
35-
* @inheritDoc
36-
*/
37-
public $sortField = 'style.isDefault DESC, style.styleName';
38-
39-
/**
40-
* @inheritDoc
41-
*/
42-
public $sortOrder = 'ASC';
43-
44-
/**
45-
* @inheritDoc
46-
*/
47-
public function initObjectList()
30+
#[\Override]
31+
protected function createGridViewController(): AbstractGridView
4832
{
49-
parent::initObjectList();
50-
51-
$this->objectList->sqlSelects = "(
52-
SELECT COUNT(*)
53-
FROM wcf1_user
54-
WHERE styleID = style.styleID
55-
) AS users";
33+
return new StyleGridView();
5634
}
5735
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php
2+
3+
namespace wcf\event\gridView\admin;
4+
5+
use wcf\event\IPsr14Event;
6+
use wcf\system\gridView\admin\StyleGridView;
7+
8+
/**
9+
* Indicates that the style grid view has been initialized.
10+
*
11+
* @author Marcel Werk
12+
* @copyright 2001-2025 WoltLab GmbH
13+
* @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
14+
* @since 6.2
15+
*/
16+
final class StyleGridViewInitialized implements IPsr14Event
17+
{
18+
public function __construct(public readonly StyleGridView $gridView) {}
19+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php
2+
3+
namespace wcf\event\interaction\admin;
4+
5+
use wcf\event\IPsr14Event;
6+
use wcf\system\interaction\admin\StyleInteractions;
7+
8+
/**
9+
* Indicates that the provider for style interactions is collecting interactions.
10+
*
11+
* @author Marcel Werk
12+
* @copyright 2001-2025 WoltLab GmbH
13+
* @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
14+
* @since 6.2
15+
*/
16+
final class StyleInteractionCollecting implements IPsr14Event
17+
{
18+
public function __construct(public readonly StyleInteractions $provider) {}
19+
}
Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
<?php
2+
3+
namespace wcf\system\gridView\admin;
4+
5+
use wcf\acp\form\StyleEditForm;
6+
use wcf\data\DatabaseObject;
7+
use wcf\data\DatabaseObjectList;
8+
use wcf\data\style\Style;
9+
use wcf\data\style\StyleList;
10+
use wcf\event\gridView\admin\StyleGridViewInitialized;
11+
use wcf\event\IPsr14Event;
12+
use wcf\system\gridView\AbstractGridView;
13+
use wcf\system\gridView\filter\TextFilter;
14+
use wcf\system\gridView\GridViewColumn;
15+
use wcf\system\gridView\GridViewRowLink;
16+
use wcf\system\gridView\renderer\DefaultColumnRenderer;
17+
use wcf\system\gridView\renderer\ILinkColumnRenderer;
18+
use wcf\system\gridView\renderer\NumberColumnRenderer;
19+
use wcf\system\gridView\renderer\ObjectIdColumnRenderer;
20+
use wcf\system\interaction\admin\StyleInteractions;
21+
use wcf\system\interaction\Divider;
22+
use wcf\system\interaction\EditInteraction;
23+
use wcf\system\interaction\ToggleInteraction;
24+
use wcf\system\WCF;
25+
use wcf\util\StringUtil;
26+
27+
/**
28+
* Grid view for the list of styles.
29+
*
30+
* @author Marcel Werk
31+
* @copyright 2001-2025 WoltLab GmbH
32+
* @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
33+
* @since 6.2
34+
*/
35+
final class StyleGridView extends AbstractGridView
36+
{
37+
public function __construct()
38+
{
39+
$this->addColumns([
40+
GridViewColumn::for('styleID')
41+
->label('wcf.global.objectID')
42+
->renderer(new ObjectIdColumnRenderer())
43+
->sortable(),
44+
GridViewColumn::for('styleName')
45+
->label('wcf.global.name')
46+
->sortable()
47+
->titleColumn()
48+
->renderer([
49+
new class extends DefaultColumnRenderer {
50+
#[\Override]
51+
public function render(mixed $value, DatabaseObject $row): string
52+
{
53+
\assert($row instanceof Style);
54+
55+
if ($row->isDefault) {
56+
$value .= \sprintf(
57+
' <span class="badge">%s</span>',
58+
WCF::getLanguage()->get('wcf.global.defaultValue')
59+
);
60+
}
61+
62+
if (!$row->styleDescription) {
63+
return $value;
64+
}
65+
66+
return \sprintf(
67+
'%s<br><small>%s</small>',
68+
$value,
69+
StringUtil::encodeHTML(WCF::getLanguage()->get($row->styleDescription))
70+
);
71+
}
72+
},
73+
])
74+
->filter(new TextFilter()),
75+
GridViewColumn::for('styleVersion')
76+
->label('wcf.acp.style.styleVersion')
77+
->sortable(),
78+
GridViewColumn::for('styleDate')
79+
->label('wcf.global.date')
80+
->sortable(),
81+
GridViewColumn::for('authorName')
82+
->label('wcf.acp.style.authorName')
83+
->sortable()
84+
->renderer([
85+
new class extends DefaultColumnRenderer implements ILinkColumnRenderer {
86+
#[\Override]
87+
public function render(mixed $value, DatabaseObject $row): string
88+
{
89+
\assert($row instanceof Style);
90+
91+
if (!$row->authorURL) {
92+
return $value;
93+
}
94+
95+
return \sprintf(
96+
'<a href="%s" class="externalURL">%s</a>',
97+
StringUtil::encodeHTML($row->authorURL),
98+
$value
99+
);
100+
}
101+
},
102+
])
103+
->filter(new TextFilter()),
104+
GridViewColumn::for('users')
105+
->label('wcf.acp.style.users')
106+
->sortable(true, 'users')
107+
->renderer(new NumberColumnRenderer()),
108+
]);
109+
110+
$provider = new StyleInteractions();
111+
$provider->addInteractions([
112+
new Divider(),
113+
new EditInteraction(StyleEditForm::class)
114+
]);
115+
$this->setInteractionProvider($provider);
116+
$this->addQuickInteraction(
117+
new ToggleInteraction(
118+
'enable',
119+
'core/styles/%s/enable',
120+
'core/styles/%s/disable',
121+
isAvailableCallback: static fn(Style $object) => !$object->isDefault
122+
)
123+
);
124+
$this->addRowLink(new GridViewRowLink(StyleEditForm::class));
125+
$this->setSortField('styleName');
126+
}
127+
128+
#[\Override]
129+
public function isAccessible(): bool
130+
{
131+
return WCF::getSession()->getPermission('admin.style.canManageStyle');
132+
}
133+
134+
#[\Override]
135+
protected function createObjectList(): DatabaseObjectList
136+
{
137+
$list = new StyleList();
138+
$list->sqlSelects = "(
139+
SELECT COUNT(*)
140+
FROM wcf1_user
141+
WHERE styleID = style.styleID
142+
) AS users";
143+
144+
return $list;
145+
}
146+
147+
#[\Override]
148+
protected function getInitializedEvent(): ?IPsr14Event
149+
{
150+
return new StyleGridViewInitialized($this);
151+
}
152+
}

0 commit comments

Comments
 (0)