Skip to content

Commit 260ad70

Browse files
authored
Merge pull request #6246 from WoltLab/6.2-AdListPage-to-grid-view
Migrate `AdListPage` to grid view
2 parents fda5310 + 2ffa3b6 commit 260ad70

15 files changed

Lines changed: 545 additions & 137 deletions

File tree

Lines changed: 19 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,80 +1,37 @@
11
{include file='header' pageTitle='wcf.acp.ad.list'}
22

3-
<script data-relocate="true">
4-
require(['WoltLabSuite/Core/Ui/Sortable/List'], function (UiSortableList) {
5-
new UiSortableList({
6-
containerId: 'adList',
7-
className: 'wcf\\data\\ad\\AdAction',
8-
offset: {@$startIndex}
9-
});
10-
});
11-
</script>
12-
133
<header class="contentHeader">
144
<div class="contentHeaderTitle">
15-
<h1 class="contentTitle">{lang}wcf.acp.ad.list{/lang}{if $items} <span class="badge badgeInverse">{#$items}</span>{/if}</h1>
5+
<h1 class="contentTitle">{lang}wcf.acp.ad.list{/lang} <span class="badge badgeInverse">{#$gridView->countRows()}</span></h1>
166
</div>
177

188
<nav class="contentHeaderNavigation">
199
<ul>
10+
{if $gridView->countRows() > 1}
11+
<li>
12+
<button type="button" class="button jsChangeShowOrder">{icon name='up-down'} <span>{lang}wcf.global.changeShowOrder{/lang}</span></button>
13+
</li>
14+
{/if}
2015
<li><a href="{link controller='AdAdd'}{/link}" class="button">{icon name='plus'} <span>{lang}wcf.acp.menu.link.ad.add{/lang}</span></a></li>
2116

2217
{event name='contentHeaderNavigation'}
2318
</ul>
2419
</nav>
2520
</header>
2621

27-
{hascontent}
28-
<div class="paginationTop">
29-
{content}{pages print=true assign=pagesLinks controller="AdList" link="pageNo=%d"}{/content}
30-
</div>
31-
{/hascontent}
22+
<div class="section">
23+
{unsafe:$gridView->render()}
24+
</div>
3225

33-
{if $objects|count}
34-
<div class="section sortableListContainer" id="adList">
35-
<ol class="sortableList jsObjectActionContainer jsReloadPageWhenEmpty" data-object-id="0" start="{@($pageNo - 1) * $itemsPerPage + 1}" data-object-action-class-name="wcf\data\ad\AdAction">
36-
{foreach from=$objects item='ad'}
37-
<li class="sortableNode sortableNoNesting jsAd jsObjectActionObject" data-object-id="{@$ad->adID}">
38-
<span class="sortableNodeLabel">
39-
<a href="{link controller='AdEdit' object=$ad}{/link}">{$ad->adName}</a>
40-
41-
<span class="statusDisplay sortableButtonContainer">
42-
<span class="sortableNodeHandle">
43-
{icon name='arrows-up-down-left-right'}
44-
</span>
45-
{objectAction action="toggle" isDisabled=$ad->isDisabled}
46-
<a href="{link controller='AdEdit' object=$ad}{/link}" title="{lang}wcf.global.button.edit{/lang}" class="jsTooltip">{icon name='pencil'}</a>
47-
{objectAction action="delete" objectTitle=$ad->getTitle()}
48-
49-
{event name='itemButtons'}
50-
</span>
51-
</span>
52-
</li>
53-
{/foreach}
54-
</ol>
55-
</div>
56-
57-
<div class="formSubmit">
58-
<button type="button" class="button buttonPrimary" data-type="submit">{lang}wcf.global.button.saveSorting{/lang}</button>
59-
</div>
60-
61-
<footer class="contentFooter">
62-
{hascontent}
63-
<div class="paginationBottom">
64-
{content}{@$pagesLinks}{/content}
65-
</div>
66-
{/hascontent}
67-
68-
<nav class="contentFooterNavigation">
69-
<ul>
70-
<li><a href="{link controller='AdAdd'}{/link}" class="button">{icon name='plus'} <span>{lang}wcf.acp.menu.link.ad.add{/lang}</span></a></li>
71-
72-
{event name='contentFooterNavigation'}
73-
</ul>
74-
</nav>
75-
</footer>
76-
{else}
77-
<woltlab-core-notice type="info">{lang}wcf.global.noItems{/lang}</woltlab-core-notice>
78-
{/if}
26+
<script data-relocate="true">
27+
require(["WoltLabSuite/Core/Component/ChangeShowOrder"], ({ setup }) => {
28+
{jsphrase name='wcf.global.changeShowOrder'}
29+
30+
setup(
31+
document.querySelector('.jsChangeShowOrder'),
32+
'core/ads/show-order',
33+
);
34+
});
35+
</script>
7936

8037
{include file='footer'}

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

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@
22

33
namespace wcf\acp\page;
44

5-
use wcf\data\ad\AdList;
6-
use wcf\page\MultipleLinkPage;
5+
use wcf\page\AbstractGridViewPage;
6+
use wcf\system\gridView\AbstractGridView;
7+
use wcf\system\gridView\admin\AdGridView;
78

89
/**
910
* Lists the available ads.
@@ -12,9 +13,9 @@
1213
* @copyright 2001-2019 WoltLab GmbH
1314
* @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
1415
*
15-
* @extends MultipleLinkPage<AdList>
16+
* @extends AbstractGridViewPage<AdGridView>
1617
*/
17-
class AdListPage extends MultipleLinkPage
18+
class AdListPage extends AbstractGridViewPage
1819
{
1920
/**
2021
* @inheritDoc
@@ -31,13 +32,9 @@ class AdListPage extends MultipleLinkPage
3132
*/
3233
public $neededModules = ['MODULE_WCF_AD'];
3334

34-
/**
35-
* @inheritDoc
36-
*/
37-
public $objectListClassName = AdList::class;
38-
39-
/**
40-
* @inheritDoc
41-
*/
42-
public $sqlOrderBy = 'ad.showOrder';
35+
#[\Override]
36+
protected function createGridView(): AbstractGridView
37+
{
38+
return new AdGridView();
39+
}
4340
}

wcfsetup/install/files/lib/bootstrap/com.woltlab.wcf.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,11 @@ static function (\wcf\event\endpoint\ControllerCollecting $event) {
217217
$event->register(new \wcf\system\endpoint\controller\core\trophies\DeleteTrophy());
218218
$event->register(new \wcf\system\endpoint\controller\core\trophies\GetShowOrder());
219219
$event->register(new \wcf\system\endpoint\controller\core\trophies\ChangeShowOrder());
220+
$event->register(new \wcf\system\endpoint\controller\core\ads\EnableAd());
221+
$event->register(new \wcf\system\endpoint\controller\core\ads\DisableAd());
222+
$event->register(new \wcf\system\endpoint\controller\core\ads\DeleteAd());
223+
$event->register(new \wcf\system\endpoint\controller\core\ads\GetShowOrder());
224+
$event->register(new \wcf\system\endpoint\controller\core\ads\ChangeShowOrder());
220225
}
221226
);
222227

wcfsetup/install/files/lib/data/ad/AdAction.class.php

Lines changed: 1 addition & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,9 @@
33
namespace wcf\data\ad;
44

55
use wcf\data\AbstractDatabaseObjectAction;
6-
use wcf\data\ISortableAction;
76
use wcf\data\IToggleAction;
87
use wcf\data\TDatabaseObjectToggle;
98
use wcf\system\condition\ConditionHandler;
10-
use wcf\system\exception\UserInputException;
11-
use wcf\system\WCF;
129

1310
/**
1411
* Executes ad-related actions.
@@ -19,7 +16,7 @@
1916
*
2017
* @extends AbstractDatabaseObjectAction<Ad, AdEditor>
2118
*/
22-
class AdAction extends AbstractDatabaseObjectAction implements ISortableAction, IToggleAction
19+
class AdAction extends AbstractDatabaseObjectAction implements IToggleAction
2320
{
2421
use TDatabaseObjectToggle;
2522

@@ -67,62 +64,4 @@ public function delete()
6764

6865
return parent::delete();
6966
}
70-
71-
/**
72-
* @inheritDoc
73-
*/
74-
public function validateUpdatePosition()
75-
{
76-
WCF::getSession()->checkPermissions($this->permissionsUpdate);
77-
78-
if (!isset($this->parameters['data']['structure']) || !\is_array($this->parameters['data']['structure'])) {
79-
throw new UserInputException('structure');
80-
}
81-
82-
$adList = new AdList();
83-
$adList->setObjectIDs($this->parameters['data']['structure'][0]);
84-
$adList->readObjects();
85-
if (\count($adList) !== \count($this->parameters['data']['structure'][0])) {
86-
throw new UserInputException('structure');
87-
}
88-
89-
$this->readInteger('offset', true, 'data');
90-
}
91-
92-
/**
93-
* @inheritDoc
94-
*/
95-
public function update()
96-
{
97-
parent::update();
98-
99-
if (
100-
\count($this->objects) == 1
101-
&& isset($this->parameters['data']['showOrder'])
102-
&& $this->parameters['data']['showOrder'] != \reset($this->objects)->showOrder
103-
) {
104-
\reset($this->objects)->setShowOrder($this->parameters['data']['showOrder']);
105-
}
106-
}
107-
108-
/**
109-
* @inheritDoc
110-
*/
111-
public function updatePosition()
112-
{
113-
$sql = "UPDATE wcf1_ad
114-
SET showOrder = ?
115-
WHERE adID = ?";
116-
$statement = WCF::getDB()->prepare($sql);
117-
118-
$showOrder = $this->parameters['data']['offset'];
119-
WCF::getDB()->beginTransaction();
120-
foreach ($this->parameters['data']['structure'][0] as $adID) {
121-
$statement->execute([
122-
$showOrder++,
123-
$adID,
124-
]);
125-
}
126-
WCF::getDB()->commitTransaction();
127-
}
12867
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
3+
namespace wcf\event\gridView\admin;
4+
5+
use wcf\event\IPsr14Event;
6+
use wcf\system\gridView\admin\AdGridView;
7+
8+
/**
9+
* Indicates that the ad grid view has been initialized.
10+
*
11+
* @author Olaf Braun
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 AdGridViewInitialized implements IPsr14Event
17+
{
18+
public function __construct(public readonly AdGridView $param)
19+
{
20+
}
21+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
3+
namespace wcf\event\interaction\admin;
4+
5+
use wcf\event\IPsr14Event;
6+
use wcf\system\interaction\admin\AdInteractions;
7+
8+
/**
9+
* Indicates that the provider for ad interactions is collecting interactions.
10+
*
11+
* @author Olaf Braun
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 AdInteractionCollecting implements IPsr14Event
17+
{
18+
public function __construct(public readonly AdInteractions $param)
19+
{
20+
}
21+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
3+
namespace wcf\event\interaction\bulk\admin;
4+
5+
use wcf\event\IPsr14Event;
6+
use wcf\system\interaction\bulk\admin\AdBulkInteractions;
7+
8+
/**
9+
* Indicates that the provider for ad bulk interactions is collecting interactions.
10+
*
11+
* @author Olaf Braun
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 AdBulkInteractionCollecting implements IPsr14Event
17+
{
18+
public function __construct(public readonly AdBulkInteractions $param)
19+
{
20+
}
21+
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
<?php
2+
3+
namespace wcf\system\endpoint\controller\core\ads;
4+
5+
use Laminas\Diactoros\Response\JsonResponse;
6+
use Psr\Http\Message\ResponseInterface;
7+
use Psr\Http\Message\ServerRequestInterface;
8+
use wcf\data\ad\Ad;
9+
use wcf\data\ad\AdList;
10+
use wcf\system\cache\builder\AdCacheBuilder;
11+
use wcf\system\endpoint\IController;
12+
use wcf\system\endpoint\PostRequest;
13+
use wcf\system\exception\IllegalLinkException;
14+
use wcf\system\showOrder\ShowOrderHandler;
15+
use wcf\system\showOrder\ShowOrderItem;
16+
use wcf\system\WCF;
17+
18+
/**
19+
* API endpoint for changing the show order of ads.
20+
*
21+
* @author Olaf Braun
22+
* @copyright 2001-2025 WoltLab GmbH
23+
* @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
24+
* @since 6.2
25+
*/
26+
#[PostRequest('/core/ads/show-order')]
27+
final class ChangeShowOrder implements IController
28+
{
29+
public function __invoke(ServerRequestInterface $request, array $variables): ResponseInterface
30+
{
31+
$this->assertAdCanBeSorted();
32+
33+
$adList = new AdList();
34+
$adList->sqlOrderBy = 'showOrder ASC';
35+
$adList->readObjects();
36+
37+
$items = \array_map(
38+
static fn(Ad $ad) => new ShowOrderItem($ad->adID, $ad->getTitle()),
39+
$adList->getObjects()
40+
);
41+
42+
$sortedItems = (new ShowOrderHandler($items))->getSortedItemsFromRequest($request);
43+
$this->saveShowOrder($sortedItems);
44+
45+
return new JsonResponse([]);
46+
}
47+
48+
private function assertAdCanBeSorted(): void
49+
{
50+
if (!\MODULE_WCF_AD) {
51+
throw new IllegalLinkException();
52+
}
53+
54+
WCF::getSession()->checkPermissions(['admin.ad.canManageAd']);
55+
}
56+
57+
/**
58+
* @param list<ShowOrderItem> $items
59+
*/
60+
private function saveShowOrder(array $items): void
61+
{
62+
WCF::getDB()->beginTransaction();
63+
$sql = "UPDATE wcf1_ad
64+
SET showOrder = ?
65+
WHERE adID = ?";
66+
$statement = WCF::getDB()->prepare($sql);
67+
for ($i = 0, $length = \count($items); $i < $length; $i++) {
68+
$statement->execute([
69+
$i + 1,
70+
$items[$i]->id,
71+
]);
72+
}
73+
WCF::getDB()->commitTransaction();
74+
75+
AdCacheBuilder::getInstance()->reset();
76+
}
77+
}

0 commit comments

Comments
 (0)