Skip to content

Commit 016e253

Browse files
committed
Refactor header navigation
1 parent 39db81c commit 016e253

File tree

2 files changed

+218
-106
lines changed

2 files changed

+218
-106
lines changed

src/libraries/NewsPost.php

+51
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,45 @@ public static function getAllNews($reverse) {
153153
return null;
154154
}
155155

156+
public static function getNewsPostsByLastEdited(int $count)
157+
{
158+
if (!isset(Common::$database))
159+
{
160+
Common::$database = DatabaseDriver::getDatabaseObject();
161+
}
162+
163+
$stmt = Common::$database->prepare(
164+
'SELECT
165+
`category_id`,
166+
`content`,
167+
`created_datetime`,
168+
`edited_count`,
169+
`edited_datetime`,
170+
`id`,
171+
`options_bitmask`,
172+
`title`,
173+
`user_id`
174+
FROM `news_posts`
175+
ORDER BY IFNULL(`edited_datetime`, `created_datetime`) DESC
176+
LIMIT ' . $count . ';'
177+
);
178+
179+
$r = $stmt->execute();
180+
if (!$r)
181+
{
182+
throw new QueryException('Cannot query news posts by last edited');
183+
}
184+
185+
$r = [];
186+
while ($row = $stmt->fetch(PDO::FETCH_OBJ))
187+
{
188+
$r[] = new self($row);
189+
}
190+
191+
$stmt->closeCursor();
192+
return $r;
193+
}
194+
156195
public static function getNewsPostsByUserId($user_id) {
157196
if (!isset(Common::$database)) {
158197
Common::$database = DatabaseDriver::getDatabaseObject();
@@ -283,6 +322,18 @@ public function getUserId() {
283322
return $this->user_id;
284323
}
285324

325+
public function isMarkdown() {
326+
return ($this->options_bitmask & self::OPTION_MARKDOWN);
327+
}
328+
329+
public function isPublished() {
330+
return ($this->options_bitmask & self::OPTION_PUBLISHED);
331+
}
332+
333+
public function isRSSExempt() {
334+
return ($this->options_bitmask & self::OPTION_RSS_EXEMPT);
335+
}
336+
286337
protected static function normalize(StdClass &$data) {
287338
$data->category_id = (int) $data->category_id;
288339
$data->content = (string) $data->content;

src/templates/header.inc.phtml

+167-106
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,13 @@ namespace BNETDocs\Templates;
33
use \BNETDocs\Libraries\Authentication;
44
use \BNETDocs\Libraries\Document;
55
use \BNETDocs\Libraries\Logger;
6+
use \BNETDocs\Libraries\NewsPost;
67
use \BNETDocs\Libraries\Packet;
78
use \BNETDocs\Libraries\User;
89
use \BNETDocs\Libraries\VersionInfo;
910
use \CarlBennett\MVC\Libraries\Common;
1011
use \CarlBennett\MVC\Libraries\DatabaseDriver;
1112
use \LogicException;
12-
$_header_user = Authentication::$user;
1313
if (!isset($title))
1414
{
1515
throw new LogicException('template variable not set before include of header template: $title');
@@ -28,20 +28,7 @@ function _header_active($url, $sr)
2828
else
2929
return ' active';
3030
}
31-
if (isset(Authentication::$user))
32-
{
33-
$_header_user = Authentication::$user;
34-
$_header_user_url = $_header_user->getURI();
35-
$_header_staff = ($_header_user && $_header_user->isStaff());
36-
} else {
37-
$_header_user = null;
38-
$_header_user_url = null;
39-
$_header_staff = null;
40-
}
41-
$_header_documents = Document::getDocumentsByLastEdited(10);
42-
$_header_packets = Packet::getPacketsByLastEdited(10);
43-
$_header_navigation_config = Common::$config->bnetdocs->navigation;
44-
$_header_user_register_disabled = Common::$config->bnetdocs->user_register_disabled;
31+
$_header_user = Authentication::$user;
4532
$_unique_asset = (
4633
!Common::$config->bnetdocs->asset_versioning ? '' :
4734
(
@@ -50,6 +37,170 @@ $_unique_asset = (
5037
'?v=' . date('YmdHis')
5138
)
5239
);
40+
$_header_nav = [
41+
['label' => 'Welcome', 'url' => '/welcome'],
42+
['label' => 'Community', 'dropdown' => [
43+
['label' => 'Discord', 'url' => '/discord', 'visible' => (Common::$config->discord->enabled)],
44+
['label' => '-', 'visible' => (Common::$config->discord->enabled)],
45+
['label' => 'Contributors', 'url' => '/credits'],
46+
['label' => 'Donate to Us', 'url' => '/donate'],
47+
['label' => 'Server List', 'url' => '/servers'],
48+
['label' => 'Users', 'url' => '/user/index'],
49+
['label' => '-'],
50+
['label' => 'Privacy Notice', 'url' => '/privacy'],
51+
['label' => 'Disclaimer & TOS', 'url' => '/legal'],
52+
['label' => '-'],
53+
['label' => 'File Archive', 'url' => 'https://files.bnetdocs.org/'],
54+
['label' => 'BNETDocs Redux', 'url' => 'https://redux.bnetdocs.org/'],
55+
]],
56+
['label' => 'Documents', 'dropdown' => [
57+
['label' => 'All Documents', 'url' => '/document/index', 'class' => 'text-info'],
58+
['label' => '-'],
59+
['label' => 'Create Document', 'url' => '/document/create', 'class' => 'text-success', 'acl' => User::OPTION_ACL_DOCUMENT_CREATE],
60+
['label' => '-', 'acl' => User::OPTION_ACL_DOCUMENT_CREATE],
61+
['label' => '', 'recent_documents' => true],
62+
]],
63+
['label' => 'News', 'dropdown' => [
64+
['label' => 'All News', 'url' => '/news', 'class' => 'text-info'],
65+
['label' => '-'],
66+
['label' => 'Create News Post', 'url' => '/news/create', 'class' => 'text-success', 'acl' => User::OPTION_ACL_NEWS_CREATE],
67+
['label' => '-', 'acl' => User::OPTION_ACL_NEWS_CREATE],
68+
['label' => '', 'recent_news' => true],
69+
]],
70+
['label' => 'Packets', 'dropdown' => [
71+
['label' => 'All Packets', 'url' => '/packet/index', 'class' => 'text-info'],
72+
['label' => '-'],
73+
['label' => 'Create Packet', 'url' => '/packet/create', 'class' => 'text-success', 'acl' => User::OPTION_ACL_PACKET_CREATE],
74+
['label' => '-', 'acl' => User::OPTION_ACL_PACKET_CREATE],
75+
['label' => '', 'recent_packets' => true],
76+
]],
77+
['label' => 'Admin', 'acl' => User::OPTION_ACL_SERVER_CREATE | User::OPTION_ACL_EVENT_LOG_VIEW, 'class' => 'text-danger', 'dropdown' => [
78+
['label' => 'Create Server', 'url' => '/server/create', 'class' => 'text-success', 'acl' => User::OPTION_ACL_SERVER_CREATE],
79+
['label' => 'Event Logs', 'url' => '/eventlog/index', 'acl' => User::OPTION_ACL_EVENT_LOG_VIEW],
80+
]],
81+
];
82+
/* <a>Account</a>
83+
<a href="<?=Common::relativeUrlToAbsolute('/user/changepassword')?>">Change Password</a>
84+
<a href="<?=Common::relativeUrlToAbsolute('/user/update')?>">Update Profile</a>*/
85+
function _header_nav_html($nav)
86+
{
87+
function _line(string $format) { call_user_func_array('printf', func_get_args()) . PHP_EOL; }
88+
89+
ob_start();
90+
_line('<nav class="navbar navbar-expand-lg navbar-dark bg-primary mb-3">');
91+
92+
// Brand
93+
_line('<a class="navbar-brand" style="color:#00ccad;" href="%s"><img class="float-left mr-2" src="%s" style="height:32px;" /> %s</a>',
94+
Common::$config->bnetdocs->navigation->front_page, '/a/VSZX0bJ.png', 'BNETDocs'
95+
);
96+
97+
// Collapsible Hamburger Menu (Start)
98+
_line('<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation"><span class="navbar-toggler-icon"></span></button>');
99+
_line('<div class="collapse navbar-collapse" id="navbarSupportedContent">');
100+
101+
// Navbar (Start)
102+
_line('<ul class="navbar-nav mr-auto">');
103+
104+
function _nav_loop(array $nav, bool $dropdown)
105+
{
106+
foreach ($nav as $item)
107+
{
108+
if (!isset($item['label'])) continue;
109+
if (isset($item['visible']) && !$item['visible']) continue;
110+
111+
if (isset($item['acl']))
112+
{
113+
if (!Authentication::$user) continue;
114+
if (!(Authentication::$user->getOptionsBitmask() & $item['acl'])) continue;
115+
}
116+
117+
if ($item['label'] == '-') { _line('<div class="dropdown-divider"></div>'); continue; }
118+
119+
$class = $item['class'] ?? '';
120+
if (!empty($class)) $class = ' ' . $class;
121+
122+
if (isset($item['recent_documents']) && $item['recent_documents'])
123+
{
124+
_line('<div class="dropdown-header">Recently Edited Documents</div>');
125+
$recent_documents = Document::getDocumentsByLastEdited(10);
126+
$acl_doc_modify = (Authentication::$user && (Authentication::$user->getOptionsBitmask() & User::OPTION_ACL_DOCUMENT_MODIFY));
127+
foreach ($recent_documents as $doc)
128+
{
129+
if (!$doc->isPublished() && !$acl_doc_modify) continue;
130+
$doc_class = ($doc->isPublished() ? '' : ' text-warning');
131+
_line('<a class="dropdown-item%s" href="%s">%s</a>', $doc_class, $doc->getURI(), filter_var($doc->getTitle(), FILTER_SANITIZE_FULL_SPECIAL_CHARS));
132+
}
133+
}
134+
else if (isset($item['recent_news']) && $item['recent_news'])
135+
{
136+
_line('<div class="dropdown-header">Recent News</div>');
137+
$recent_news = NewsPost::getNewsPostsByLastEdited(10);
138+
$acl_news_modify = (Authentication::$user && (Authentication::$user->getOptionsBitmask() & User::OPTION_ACL_NEWS_MODIFY));
139+
foreach ($recent_news as $news)
140+
{
141+
if (!$news->isPublished() && !$acl_neews_modify) continue;
142+
$news_class = ($news->isPublished() ? '' : ' text-warning');
143+
_line('<a class="dropdown-item%s" href="%s">%s</a>', $news_class, $news->getURI(), filter_var($news->getTitle(), FILTER_SANITIZE_FULL_SPECIAL_CHARS));
144+
}
145+
}
146+
else if (isset($item['recent_packets']) && $item['recent_packets'])
147+
{
148+
_line('<div class="dropdown-header">Recently Edited Packets</div>');
149+
$recent_packets = Packet::getPacketsByLastEdited(10);
150+
$acl_pkt_modify = (Authentication::$user && (Authentication::$user->getOptionsBitmask() & User::OPTION_ACL_PACKET_MODIFY));
151+
foreach ($recent_packets as $pkt)
152+
{
153+
if (!$pkt->isPublished() && !$acl_pkt_modify) continue;
154+
$pkt_class = ($pkt->isPublished() ? '' : ' text-warning');
155+
_line('<a class="dropdown-item%s" href="%s">%s</a>', $pkt_class, $pkt->getURI(), filter_var($pkt->getName(), FILTER_SANITIZE_FULL_SPECIAL_CHARS));
156+
}
157+
}
158+
else if (!$dropdown)
159+
{
160+
if (isset($item['url'])) printf('<li class="nav-item"><a class="nav-link%s" href="%s">%s</a></li>' . PHP_EOL, $class, $item['url'], filter_var($item['label'], FILTER_SANITIZE_FULL_SPECIAL_CHARS));
161+
}
162+
else if ($dropdown)
163+
{
164+
if (isset($item['url'])) printf('<a class="dropdown-item%s" href="%s">%s</a>' . PHP_EOL, $class, $item['url'], filter_var($item['label'], FILTER_SANITIZE_FULL_SPECIAL_CHARS));
165+
}
166+
167+
if (isset($item['dropdown']))
168+
{
169+
_line('<li class="nav-item dropdown">');
170+
$navbarName = str_replace(' ', '_', $item['label']);
171+
_line('<a class="nav-link dropdown-toggle%s" href="#" id="navbar%sDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">%s</a>', $class, $navbarName, $item['label']);
172+
_line('<div class="dropdown-menu" aria-labelledby="navbar%sDropdown">', $navbarName);
173+
_nav_loop($item['dropdown'], true);
174+
_line('</div></li>');
175+
}
176+
}
177+
}
178+
_nav_loop($nav, false);
179+
180+
// Navbar (End)
181+
_line('</ul>');
182+
183+
// Account
184+
if (!Authentication::$user)
185+
{
186+
_line('<a class="btn btn-sm btn-outline-secondary my-2 my-sm-0" tabindex="-1" href="%s">Log in</a>', Common::relativeUrlToAbsolute('/user/login'));
187+
if (!Common::$config->bnetdocs->user_register_disabled)
188+
{
189+
_line('<a class="btn btn-sm btn-outline-success my-2 my-sm-0 ml-2" tabindex="-2" href="%s">Register</a>', Common::relativeUrlToAbsolute('/user/register'));
190+
}
191+
}
192+
else
193+
{
194+
_line('<span class="nav-item navbar-text mx-3"><a href="%s">%s</a></span>', Authentication::$user->getURI(), filter_var(Authentication::$user->getName(), FILTER_SANITIZE_FULL_SPECIAL_CHARS));
195+
_line('<a class="btn btn-sm btn-outline-danger my-2 my-sm-0" tabindex="-1" href="%s">Log out</a>', Common::relativeUrlToAbsolute('/user/logout'));
196+
}
197+
198+
// Collapsible Hamburger Menu (End)
199+
_line('</div>');
200+
201+
_line('</nav>');
202+
return ob_get_clean();
203+
}
53204
/*$_campaign_battleforthenet = (
54205
!empty( Common::$config->bnetdocs->campaigns->battleforthenet ) ?
55206
'<script type="text/javascript" src="' .
@@ -114,95 +265,5 @@ $_campaign_vultr = (
114265
</head>
115266
<body class="d-flex flex-column h-100">
116267

117-
<nav class="navbar navbar-expand-lg navbar-dark bg-primary mb-3">
118-
<a class="navbar-brand" style="color:#00ccad;" href="<?=Common::relativeUrlToAbsolute($_header_navigation_config->front_page)?>"><img src="<?=Common::relativeUrlToAbsolute('/a/VSZX0bJ.png')?>" style="float:left;margin-right:6px;height:32px;"/> BNETDocs</a>
119-
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
120-
<span class="navbar-toggler-icon"></span>
121-
</button>
122-
<div class="collapse navbar-collapse" id="navbarSupportedContent">
123-
<ul class="navbar-nav mr-auto">
124-
<li class="nav-item<?=_header_active('/welcome', false)?>">
125-
<a class="nav-link" href="<?=Common::relativeUrlToAbsolute('/welcome')?>">Welcome<?=_header_active('/welcome', true)?></a>
126-
</li>
127-
<? if (Common::$config->discord->enabled) { ?>
128-
<li class="nav-item<?=_header_active('/discord', false)?>">
129-
<a class="nav-link" href="<?=Common::relativeUrlToAbsolute('/discord')?>">Discord<?=_header_active('/discord', true)?></a>
130-
</li>
131-
<? } ?>
132-
<li class="nav-item<?=_header_active('/document/', false)?> dropdown">
133-
<a class="nav-link dropdown-toggle" href="#" id="navbarDocumentsDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Documents</a>
134-
<div class="dropdown-menu" aria-labelledby="navbarDocumentsDropdown">
135-
<a class="dropdown-item<?=_header_active('/document/index', false)?> text-info" href="<?=Common::relativeUrlToAbsolute('/document/index')?>">All Documents<?=_header_active('/document/index', true)?></a>
136-
<? if ($_header_staff) { ?>
137-
<div class="dropdown-divider"></div>
138-
<a class="dropdown-item<?=_header_active('/document/create', false)?> text-success" href="<?=Common::relativeUrlToAbsolute('/document/create')?>">Create Document<?=_header_active('/document/create', true)?></a>
139-
<div class="dropdown-divider"></div>
140-
<? }?>
141-
<div class="dropdown-header">Recently Edited Documents</div>
142-
<? foreach ($_header_documents as $doc) { $doc_url_part = '/document/' . $doc->getId(); ?>
143-
<a class="dropdown-item<?=_header_active($doc_url_part, false)?>" href="<?=$doc->getURI()?>"><?=filter_var($doc->getTitle(), FILTER_SANITIZE_FULL_SPECIAL_CHARS)?><?=_header_active($doc_url_part, true)?></a>
144-
<? } ?>
145-
</div>
146-
</li>
147-
<li class="nav-item<?=_header_active('/packet/', false)?> dropdown">
148-
<a class="nav-link dropdown-toggle" href="#" id="navbarPacketsDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Packets</a>
149-
<div class="dropdown-menu" aria-labelledby="navbarPacketsDropdown">
150-
<a class="dropdown-item<?=_header_active('/packet/index', false)?> text-info" href="<?=Common::relativeUrlToAbsolute('/packet/index')?>">All Packets<?=_header_active('/packet/index', true)?></a>
151-
<? if ($_header_staff) { ?>
152-
<div class="dropdown-divider"></div>
153-
<a class="dropdown-item<?=_header_active('/packet/create', false)?> text-success" href="<?=Common::relativeUrlToAbsolute('/packet/create')?>">Create Packet<?=_header_active('/packet/create', true)?></a>
154-
<div class="dropdown-divider"></div>
155-
<? }?>
156-
<div class="dropdown-header">Recently Edited Packets</div>
157-
<? foreach ($_header_packets as $pkt) { $pkt_url_part = '/packet/' . $pkt->getId(); ?>
158-
<a class="dropdown-item<?=_header_active($pkt_url_part, false)?>" href="<?=$pkt->getURI()?>"><?=filter_var($pkt->getName(), FILTER_SANITIZE_FULL_SPECIAL_CHARS)?><?=_header_active($pkt_url_part, true)?></a>
159-
<? } ?>
160-
</div>
161-
</li>
162-
</ul>
163-
<? if (!$_header_user) { ?>
164-
<a class="btn btn-sm btn-outline-success my-2 my-sm-0" tabindex="-1" href="<?=Common::relativeUrlToAbsolute('/user/login?return=' . rawurlencode((getenv('REQUEST_URI') == '/user/logout' ? '/tools' : getenv('REQUEST_URI'))))?>">Log in</a>
165-
<? } else { ?>
166-
<span class="nav-item navbar-text mx-3"><a href="<?=$_header_user->getURI()?>"><?=$_header_user->getName()?></a><?=($_header_user->isDisabled() ? ' <span class="font-weight-bold text-danger">(Disabled)</span>' : '')?></span>
167-
<a class="btn btn-sm btn-outline my-2 my-sm-0" tabindex="-1" href="<?=Common::relativeUrlToAbsolute('/user/logout')?>">Log out</a>
168-
<? } ?>
169-
</div>
170-
</nav>
171-
<!--
172-
<a href="<?=Common::relativeUrlToAbsolute('/credits')?>">Contributors</a>
173-
<?php if (Common::$config->discord->enabled) { ?>
174-
<a href="<?=Common::relativeUrlToAbsolute('/discord')?>">Discord</a>
175-
<?php } ?>
176-
<a href="<?=Common::relativeUrlToAbsolute('/donate')?>">Donate</a>
177-
<a href="<?=Common::relativeUrlToAbsolute('/user/index')?>">Members</a>
178-
<a href="<?=Common::relativeUrlToAbsolute('/news')?>">News</a>
179-
<a href="<?=Common::relativeUrlToAbsolute('/servers')?>">Servers</a>
180-
<a>Account</a>
181-
<?php if ($_header_user) { ?>
182-
<a href="<?=Common::relativeUrlToAbsolute('/user/logout')?>">Logout</a>
183-
<a href="<?=Common::relativeUrlToAbsolute('/user/changepassword')?>">Change Password</a>
184-
<a href="<?=Common::relativeUrlToAbsolute('/user/update')?>">Update Profile</a>
185-
<a href="<?=Common::relativeUrlToAbsolute($_header_user_url)?>">View Profile</a>
186-
<?php } else { ?>
187-
<a href="<?=Common::relativeUrlToAbsolute('/user/login?return=' . rawurlencode(getenv('REQUEST_URI')))?>">Log In</a>
188-
<?php if (!$_header_user_register_disabled) { ?>
189-
<a href="<?=Common::relativeUrlToAbsolute('/user/register')?>">Create</a>
190-
<?php } ?>
191-
<?php } ?>
192-
<a>The Docs</a>
193-
<a href="<?=Common::relativeUrlToAbsolute('/packet/index')?>">Packet Index</a>
194-
<a>Other Pages</a>
195-
<a href="<?=Common::relativeUrlToAbsolute('//files.bnetdocs.org/')?>">File Archive</a>
196-
<a href="<?=Common::relativeUrlToAbsolute('/privacy')?>">Privacy Notice</a>
197-
<a href="<?=Common::relativeUrlToAbsolute('/legal')?>">Legal Policies</a>
198-
<a href="<?=Common::relativeUrlToAbsolute('//redux.bnetdocs.org/')?>">BNETDocs Redux</a>
199-
<?php if ($_header_staff) { ?>
200-
<a>Site Admin</a>
201-
<a href="<?=Common::relativeUrlToAbsolute('/document/create')?>">Create Document</a>
202-
<a href="<?=Common::relativeUrlToAbsolute('/news/create')?>">Create News Post</a>
203-
<a href="<?=Common::relativeUrlToAbsolute('/packet/create')?>">Create Packet</a>
204-
<a href="<?=Common::relativeUrlToAbsolute('/server/create')?>">Create Server</a>
205-
<a href="<?=Common::relativeUrlToAbsolute('/eventlog/index')?>">Event Log</a>
206-
<?php } ?>
207-
-->
268+
<?=_header_nav_html($_header_nav)?>
208269
<main>

0 commit comments

Comments
 (0)