업데이트 README.md, .github/README.en.md
[liberty-mw-skin.git] / LibertyTemplate.php
blob042055b5b1ade42c4d8ccaa5caa7ca3f80828632
1 <?php // @codingStandardsIgnoreLine
3 use MediaWiki\MediaWikiServices;
4 use MediaWiki\Revision\RevisionRecord;
6 class LibertyTemplate extends BaseTemplate {
7 /**
8 * execute() Method
9 */
10 public function execute() {
11 global $wgLibertyAdSetting, $wgLibertyMobileReplaceAd;
13 $skin = $this->getSkin();
14 $user = $skin->getUser();
15 $request = $skin->getRequest();
16 $action = $request->getVal( 'action', 'view' );
17 $title = $skin->getTitle();
18 $LibertyUserSidebarSettings = $user->getOption( 'liberty-layout-sidebar' );
20 $this->html( 'headelement' );
22 <header>
23 <div class="nav-wrapper navbar-fixed-top">
24 <?php $this->navMenu(); ?>
25 </div>
26 </header>
27 <section>
28 <div class="content-wrapper">
29 <?php if ( $LibertyUserSidebarSettings == false ) { ?>
30 <aside>
31 <div class="liberty-sidebar">
32 <div class="live-recent-wrapper">
33 <?php $this->liveRecent(); ?>
34 </div>
35 <?php if ( isset( $wgLibertyAdSetting[ 'right' ] ) && $wgLibertyAdSetting[ 'right' ] ) {
36 $this->buildAd( 'right' );
37 } ?>
38 </div>
39 </aside>
40 <?php } ?>
41 <div class="container-fluid liberty-content">
42 <div class="liberty-content-header">
43 <?php if (
44 $this->data['sitenotice'] &&
45 !$request->getCookie( 'disable-notice' )
46 ) { ?>
47 <div class="alert alert-dismissible fade in alert-info liberty-notice" role="alert">
48 <button type="button" class="close" data-dismiss="alert" aria-label="Close">
49 <span aria-hidden="true">&times;</span>
50 </button>
51 <?php $this->html( 'sitenotice' ); ?>
52 </div>
53 <?php } ?>
54 <?php if ( isset( $wgLibertyAdSetting['header'] ) && $wgLibertyAdSetting['header'] ) {
55 $this->buildAd( 'header' );
57 $this->contentsToolbox(); ?>
58 <div class="title">
59 <h1>
60 <?php $this->html( 'title' ); ?>
61 </h1>
62 </div>
63 <div class="contentSub" <?php $this->html( 'userlangattributes' ); ?>>
64 <?php $this->html( 'subtitle' ); ?>
65 </div>
66 </div>
67 <div class="liberty-content-main" id="content">
68 <?php if ( $this->data['newtalk'] ) { ?>
69 <div class="usermessage"><?php $this->html( 'newtalk' ) ?></div>
70 <?php }
71 if ( $this->data['catlinks'] ) {
72 $this->html( 'catlinks' );
75 <article class="mw-body-content" id="mw-content-text">
76 <?php $this->html( 'bodycontent' ); ?>
77 </article>
78 <?php
79 if ( isset( $wgLibertyAdSetting['belowarticle'] ) && $wgLibertyAdSetting['belowarticle'] ) {
80 $this->buildAd( 'belowarticle' );
83 </div>
84 <footer>
86 <div class="liberty-footer">
87 <?php
88 if ( $this->data['dataAfterContent'] ) {
89 $this->html( 'dataAfterContent' );
92 <?php if ( isset( $wgLibertyAdSetting['bottom'] ) && $wgLibertyAdSetting['bottom'] ) {
93 $this->buildAd( 'bottom' );
95 if ( isset( $wgLibertyMobileReplaceAd ) && $wgLibertyMobileReplaceAd &&
96 isset( $wgLibertyAdSetting[ 'right' ] ) && $wgLibertyAdSetting[ 'right' ] ) { ?>
97 <div class="mobile-ads"></div>
98 <?php } ?>
99 <?php $this->footer(); ?>
100 </div>
101 </footer>
102 <div id="liberty-bottombtn">
103 <div class="scroll-button" id="liberty-scrollup"><i class="fas fa-angle-up"></i></div>
104 <div class="scroll-button" id="liberty-scrolldown"><i class="fas fa-angle-down"></i></div>
105 </div>
106 </div>
107 </div>
108 </section>
109 <?php
110 // Only load AdSense JS is ads are enabled in site configuration
111 if ( isset( $wgLibertyAdSetting['client'] ) && $wgLibertyAdSetting['client'] ) {
112 // @codingStandardsIgnoreLine
113 echo( '<script async defer src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>' );
116 <?php $this->loginModal(); ?>
117 <?php
118 $this->printTrail();
119 $this->html( 'debughtml' );
120 echo Html::closeElement( 'body' );
121 echo Html::closeElement( 'html' );
122 echo "\n";
126 * Nav menu function, build top menu.
128 protected function navMenu() {
129 $linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
130 $skin = $this->getSkin();
132 <nav class="navbar navbar-dark">
133 <a class="navbar-brand" href="<?php echo Title::newMainPage()->getLocalURL(); ?>"></a>
134 <ul class="nav navbar-nav">
135 <li class="nav-item">
136 <?php echo $linkRenderer->makeKnownLink(
137 new TitleValue( NS_SPECIAL, 'Recentchanges' ),
138 // @codingStandardsIgnoreStart
139 new HtmlArmor('<span class="fas fa-sync"></span><span class="hide-title">' . $skin->msg( 'recentchanges' )->plain() . '</span>'),
140 // @codingStandardsIgnoreEnd )
142 'class' => 'nav-link',
143 'title' => Linker::titleAttrib( 'n-recentchanges', 'withaccess' ),
144 'accesskey' => Linker::accesskey( 'n-recentchanges' )
145 ] );?>
146 </li>
147 <li class="nav-item">
148 <?php echo $linkRenderer->makeKnownLink(
149 new TitleValue( NS_SPECIAL, 'Randompage' ),
150 // @codingStandardsIgnoreStart
151 new HtmlArmor('<span class="fa fa-random"></span><span class="hide-title">' . $skin->msg('randompage')->plain() . '</span>'),
152 // @codingStandardsIgnoreEnd
154 'class' => 'nav-link',
155 'title' => Linker::titleAttrib( 'n-randompage', 'withaccess' ),
156 'accesskey' => Linker::accesskey( 'n-randompage' )
158 ); ?>
159 </li>
160 <?php echo $this->renderPortal( $this->parseNavbar() ); ?>
161 </ul>
162 <?php $this->loginBox(); ?>
163 <?php $this->getNotification(); ?>
164 <?php $this->searchBox(); ?>
165 </nav>
166 <?php
170 * Search box function, build top menu's search box.
172 protected function searchBox() {
173 $skin = $this->getSkin();
175 <form action="<?php $this->text( 'wgScript' ); ?>" id="searchform" class="form-inline">
176 <input type="hidden" name="title" value="<?php $this->text( 'searchtitle' ); ?>" />
177 <div class="input-group">
178 <?php echo $this->makeSearchInput( [ 'class' => 'form-control', 'id' => 'searchInput' ] ); ?>
179 <span class="input-group-btn">
180 <?php
181 // @codingStandardsIgnoreStart
183 <button type="submit" name="go" value="<?php echo $skin->msg( 'go' )->plain() ?>"id="searchGoButton" class="btn btn-secondary" type="button"><span class="fa fa-eye"></span></button>
184 <button type="submit" name="fulltext" value="<?php echo $skin->msg( 'searchbutton' )->plain() ?>"id="mw-searchButton" class="btn btn-secondary" type="button">
185 <span class="fa fa-search"></span></button>
186 <?php
187 // @codingStandardsIgnoreEnd
189 </span>
190 </div>
191 </form>
192 <?php
196 * Login box function, build top menu's login button.
198 protected function loginBox() {
199 global $wgLibertyUseGravatar;
201 $skin = $this->getSkin();
202 $user = $skin->getUser();
203 $linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
205 <div class="navbar-login">
206 <?php
207 // If the user is logged in...
208 if ( $user->isRegistered() ) {
209 $personalTools = $this->getPersonalTools();
210 // ...and Gravatar is enabled in site config...
211 if ( $wgLibertyUseGravatar ) {
212 // ...and the user has a confirmed email...
213 if ( $user->getEmailAuthenticationTimestamp() ) {
214 // ...then, and only then, build the correct Gravatar URL
215 $email = trim( $user->getEmail() );
216 $email = strtolower( $email );
217 $email = md5( $email ) . '?d=identicon';
218 } else {
219 $email = '00000000000000000000000000000000?d=identicon&f=y';
221 $avatar = Html::element( 'img', [
222 'class' => 'profile-img',
223 'src' => '//secure.gravatar.com/avatar/' . $email
224 ] );
225 } else {
226 $avatar = '';
229 // SocialProfile support
230 if ( class_exists( 'wAvatar' ) ) {
231 $avatar = new wAvatar( $user->getId(), 'm' );
232 $avatar = $avatar->getAvatarURL( [
233 'class' => 'profile-img'
234 ] );
237 <div class="dropdown login-menu">
238 <a class="dropdown-toggle" type="button" id="login-menu"
239 data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
240 <?php echo $avatar; ?>
241 </a>
242 <div class="dropdown-menu dropdown-menu-right login-dropdown-menu"
243 aria-labelledby="login-menu">
244 <?php echo $linkRenderer->makeKnownLink(
245 Title::makeTitle( NS_USER, $user->getName() ),
246 $user->getName(),
248 'id' => 'pt-userpage',
249 'class' => 'dropdown-item',
250 'title' => Linker::titleAttrib( 'pt-userpage', 'withaccess' ),
251 'accesskey' => Linker::accesskey( 'pt-userpage' )
253 ); ?>
254 <div class="dropdown-divider"></div>
255 <?php
256 if ( class_exists( 'EchoEvent' ) ) {
257 $notiCount = 0;
258 if (
259 isset( $personalTools['notifications-alert'] ) &&
260 $personalTools['notifications-alert'] &&
261 isset( $personalTools['notifications-notice'] ) &&
262 $personalTools['notifications-notice']
264 $notiCount = $personalTools['notifications-alert']['links'][0]['data']['counter-num'] +
265 $personalTools['notifications-notice']['links'][0]['data']['counter-num'];
267 echo $linkRenderer->makeKnownLink(
268 new TitleValue( NS_SPECIAL, 'Notifications' ),
269 $skin->msg( 'notifications' )->plain() . ( $notiCount ? " ($notiCount)" : '' ),
271 'class' => 'dropdown-item',
272 'title' => $skin->msg( 'tooltip-pt-notifications-notice' )->text()
277 <?php echo $linkRenderer->makeKnownLink(
278 SpecialPage::getTitleFor( 'Contributions', $user->getName() ),
279 $skin->msg( 'mycontris' )->plain(),
281 'class' => 'dropdown-item',
282 'title' => Linker::titleAttrib( 'pt-mycontris', 'withaccess' ),
283 'accesskey' => Linker::accesskey( 'pt-mycontris' )
285 ); ?>
286 <?php echo $linkRenderer->makeKnownLink(
287 Title::makeTitle( NS_USER_TALK, $user->getName() ),
288 $skin->msg( 'mytalk' )->plain(),
290 'class' => 'dropdown-item',
291 'title' => Linker::titleAttrib( 'pt-mytalk', 'withaccess' ),
292 'accesskey' => Linker::accesskey( 'pt-mytalk' )
294 ); ?>
295 <?php echo $linkRenderer->makeKnownLink(
296 SpecialPage::getTitleFor( 'Watchlist' ),
297 $skin->msg( 'watchlist' )->plain(),
299 'class' => 'dropdown-item',
300 'title' => Linker::titleAttrib( 'pt-watchlist', 'withaccess' ),
301 'accesskey' => Linker::accesskey( 'pt-watchlist' )
303 ); ?>
304 <div class="dropdown-divider"></div>
305 <?php echo $linkRenderer->makeKnownLink(
306 SpecialPage::getTitleFor( 'Preferences' ),
307 $skin->msg( 'preferences' )->plain(),
309 'class' => 'dropdown-item',
310 'title' => Linker::titleAttrib( 'pt-preferences', 'withaccess' ),
311 'accesskey' => Linker::accesskey( 'pt-preferences' )
313 ); ?>
314 <div class="dropdown-divider view-logout"></div>
315 <a href="<?php echo $personalTools['logout']['links'][0]['href']; ?>"
316 class="dropdown-item view-logout"
317 title="<?php echo Linker::titleAttrib( 'pt-logout', 'withaccess' ); ?>">
318 <?php echo $skin->msg( 'logout' )->plain(); ?></a>
319 </div>
320 </div>
321 <a href="<?php echo $personalTools['logout']['links'][0]['href']; ?>"
322 class="hide-logout logout-btn"
323 title="<?php echo Linker::titleAttrib( 'pt-logout', 'withaccess' ); ?>">
324 <span class="fa fa-sign-out"></span></a>
325 <?php } else { ?>
326 <a href="#" class="none-outline" data-toggle="modal" data-target="#login-modal">
327 <span class="fa fa-sign-in"></span>
328 </a>
329 <?php } ?>
330 </div>
331 <?php
335 * Login model function, build login menu model.
337 protected function loginModal() {
338 $skin = $this->getSkin();
339 $title = $skin->getTitle();
340 $linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
342 // Probably no point in rendering a login window for the users who are
343 // already logged in?
344 if ( $skin->getUser()->isRegistered() ) {
345 return;
348 // Turn off Continuous Integration warnings about "too long" lines which are
349 // perfectly acceptable in this particular context
350 // @codingStandardsIgnoreStart
352 <div class="modal fade login-modal" id="login-modal" tabindex="-1" role="dialog" aria-labelledby="login-modalLabel" aria-hidden="true">
353 <div class="modal-dialog modal-sm" role="document">
354 <div class="modal-content">
355 <div class="modal-header">
356 <button type="button" class="close" data-dismiss="modal" aria-label="Close">
357 <span aria-hidden="true">&times;</span>
358 </button>
359 <h4 class="modal-title"><?php echo $skin->msg('liberty-login')->plain() ?></h4>
360 </div>
361 <div class="modal-body">
362 <div id="modal-login-alert" class="alert alert-hidden alert-danger" role="alert">
363 </div>
364 <form id="modal-loginform" name="userlogin" class="modal-loginform" method="post">
365 <input class="loginText form-control" id="wpName1" tabindex="1" placeholder="<?php echo $skin->msg('userlogin-yourname-ph')->plain() ?>" value="" name="lgname">
366 <label for="inputPassword" class="sr-only"><?php echo $skin->msg('userlogin-yourpassword')->plain() ?></label>
367 <input class="loginPassword form-control" id="wpPassword1" tabindex="2" placeholder="<?php echo $skin->msg('userlogin-yourpassword-ph')->plain() ?>" type="password" name="lgpassword">
368 <div class="modal-checkbox">
369 <input name="lgremember" type="checkbox" value="1" id="lgremember" tabindex="3">
370 <label for="lgremember"><?php echo $skin->msg('liberty-remember')->plain() ?></label>
371 </div>
372 <input class="btn btn-success btn-block" type="submit" value="<?php echo $skin->msg('liberty-login-btn')->plain() ?>" tabindex="4">
373 <?php echo $linkRenderer->makeKnownLink(
374 SpecialPage::getTitleFor('Userlogin'),
375 $skin->msg('userlogin-joinproject'),
377 'class' => 'btn btn-primary btn-block',
378 'tabindex' => 5,
379 'type' => 'submit'
382 'type' => 'signup',
383 'returnto' => $title
385 ); ?>
386 <?php echo $linkRenderer->makeKnownLink(
387 SpecialPage::getTitleFor('PasswordReset'),
388 $skin->msg('liberty-forgot-pw')->plain()
389 ); ?>
390 <br>
391 <?php echo $linkRenderer->makeKnownLink(
392 SpecialPage::getTitleFor('Userlogin'),
393 $skin->msg('liberty-login-alter')->plain()
394 ); ?>
395 <input type="hidden" name="action" value="login" />
396 <input type="hidden" name="format" value="json" />
397 </form>
398 </div>
399 <div class="modal-footer">
400 <button type="button" class="btn btn-secondary" data-dismiss="modal"><?php echo $skin->msg('liberty-btn-close')->plain(); ?></button>
401 <button type="button" class="btn btn-primary"><?php echo $skin->msg('liberty-btn-save-changes')->plain(); ?></button>
402 </div>
403 </div>
404 </div>
405 </div>
406 <?php
407 // Turn Continuous Integration stuff back on
408 // @codingStandardsIgnoreEnd
412 * Live recent function, build right side's Recent menus.
414 protected function liveRecent() {
415 global $wgLibertyEnableLiveRC,
416 $wgLibertyMaxRecent,
417 $wgLibertyLiveRCArticleNamespaces,
418 $wgLibertyLiveRCTalkNamespaces;
419 // Don't bother outputting this if the live RC feature is disabled in
420 // site configuration
421 if ( !$wgLibertyEnableLiveRC ) {
422 return;
424 $skin = $this->getSkin();
425 $linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
426 $articleNS = implode( "|", $wgLibertyLiveRCArticleNamespaces );
427 $talkNS = implode( "|", $wgLibertyLiveRCTalkNamespaces );
429 <div class="live-recent" data-article-ns="<?php echo $articleNS ?>"
430 data-talk-ns="<?php echo $talkNS ?>">
431 <div class="live-recent-header">
432 <ul class="nav nav-tabs">
433 <li class="nav-item">
434 <a href="javascript:" class="nav-link active" id="liberty-recent-tab1">
435 <?php echo $skin->msg( 'recentchanges' )->plain() ?>
436 </a>
437 </li>
438 <li class="nav-item">
439 <a href="javascript:" class="nav-link" id="liberty-recent-tab2">
440 <?php echo $skin->msg( 'liberty-recent-discussions' )->plain() ?>
441 </a>
442 </li>
443 </ul>
444 </div>
445 <div class="live-recent-content">
446 <ul class="live-recent-list" id="live-recent-list">
447 <?php echo str_repeat(
448 '<li><span class="recent-item">&nbsp;</span></li>',
449 $wgLibertyMaxRecent
450 ); ?>
451 </ul>
452 </div>
453 <div class="live-recent-footer">
454 <?php echo $linkRenderer->makeKnownLink(
455 SpecialPage::getTitleFor( 'Recentchanges' ),
456 new HtmlArmor( '<span class="label label-info">' .
457 $skin->msg( 'liberty-view-more' )->plain() .
458 '</span>' )
459 ); ?>
460 </div>
461 </div>
462 <?php
466 * Contents tool box function, build article tool menu that will show at article title right.
468 protected function contentsToolbox() {
469 $skin = $this->getSkin();
470 $user = $skin->getUser();
471 $watchlistManager = MediaWikiServices::getInstance()->getWatchlistManager();
472 $title = $skin->getTitle();
473 $revid = $skin->getRequest()->getText( 'oldid' );
474 $watched = $watchlistManager->isWatchedIgnoringRights( $user, $skin->getRelevantTitle() ) ? 'unwatch' : 'watch';
475 $editable = isset( $this->data['content_navigation']['views']['edit'] );
476 $action = $skin->getRequest()->getVal( 'action', 'view' );
477 $permissionManager = MediaWikiServices::getInstance()->getPermissionManager();
478 $linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
479 if ( $title->getNamespace() != NS_SPECIAL ) {
480 $companionTitle = $title->isTalkPage() ? $title->getSubjectPage() : $title->getTalkPage();
482 <div class="content-tools">
483 <div class="btn-group" role="group" aria-label="content-tools">
484 <?php
485 if ( $action != 'edit' ) {
486 $editIcon = $editable ? '<i class="fa fa-edit"></i> ' : '<i class="fa fa-lock"></i> ';
487 echo $linkRenderer->makeKnownLink(
488 $title,
489 new HtmlArmor( $editIcon . $skin->msg( 'edit' )->plain() ),
491 'class' => 'btn btn-secondary tools-btn',
492 'id' => 'ca-edit',
493 'title' => Linker::titleAttrib( 'ca-edit', 'withaccess' ),
494 'accesskey' => Linker::accesskey( 'ca-edit' )
496 $revid ? [ 'action' => 'edit', 'oldid' => $revid ] : [ 'action' => 'edit' ]
499 if ( $action == 'edit' || $action == 'history' ) {
500 echo $linkRenderer->makeKnownLink(
501 $title,
502 $titlename = $skin->msg( 'article' )->plain(),
504 'class' => 'btn btn-secondary tools-btn',
505 'title' => Linker::titleAttrib( 'ca-nstab-main', 'withaccess' ),
506 'accesskey' => Linker::accesskey( 'ca-nstab-main' )
510 if ( $companionTitle && $action != 'edit' ) {
511 if ( $title->isTalkPage() && $action != 'history' ) {
512 $titlename = $skin->msg( 'nstab-main' )->plain();
513 $additionalArrayStuff = [
514 'title' => Linker::titleAttrib( 'ca-nstab-main', 'withaccess' ),
515 'accesskey' => Linker::accesskey( 'ca-nstab-main' )
517 } else {
518 $titlename = $skin->msg( 'talk' )->plain();
519 $additionalArrayStuff = [
520 'title' => Linker::titleAttrib( 'ca-talk', 'withaccess' ),
521 'accesskey' => Linker::accesskey( 'ca-talk' )
524 echo $linkRenderer->makeKnownLink(
525 $companionTitle,
526 $titlename,
528 'class' => 'btn btn-secondary tools-btn',
529 ] + $additionalArrayStuff
532 if ( $action != 'history' ) {
533 echo $linkRenderer->makeKnownLink(
534 $title,
535 $skin->msg( 'history' )->plain(),
537 'class' => 'btn btn-secondary tools-btn',
538 'title' => Linker::titleAttrib( 'ca-history', 'withaccess' ),
539 'accesskey' => Linker::accesskey( 'ca-history' )
541 [ 'action' => 'history' ]
544 if ( $action == 'view' ) { ?>
545 <button type="button" class="btn btn-secondary tools-btn tools-share">
546 <i class="far fa-share-square"></i>
547 <?php echo $skin->msg( 'liberty-share' )->plain() ?>
548 </button>
549 <?php } ?>
550 <?php
551 // @codingStandardsIgnoreStart
553 <button type="button" class="btn btn-secondary tools-btn dropdown-toggle" data-toggle="dropdown" aria-expanded="false">
554 <span class="caret"></span>
555 </button>
556 <?php
557 // @codingStandardsIgnoreEnd
559 <div class="dropdown-menu dropdown-menu-right" role="menu">
560 <?php
561 if ( $title->inNamespaces( NS_USER, NS_USER_TALK ) ) {
562 // "User contributions" link on user and user talk pages
563 echo $linkRenderer->makeKnownLink(
564 SpecialPage::getTitleFor( 'Contributions', $title->getText() ),
565 $skin->msg( 'contributions' )->escaped(),
567 'class' => 'dropdown-item',
568 'title' => Linker::titleAttrib( 't-contributions', 'withaccess' ),
569 'accesskey' => Linker::accesskey( 't-contributions' )
573 echo $linkRenderer->makeKnownLink(
574 $title,
575 $skin->msg( 'liberty-purge' )->plain(),
577 'class' => 'dropdown-item',
578 'title' => $skin->msg( 'liberty-tooltip-purge' )->plain() . ' [alt+shift+p]',
579 'accesskey' => 'p'
581 [ 'action' => 'purge' ]
583 echo $linkRenderer->makeKnownLink(
584 $title,
585 $skin->msg( $watched )->plain(),
587 'class' => 'dropdown-item',
588 'title' => Linker::titleAttrib( 'ca-' . $watched, 'withaccess' ),
589 'accesskey' => Linker::accesskey( 'ca-' . $watched )
591 [ 'action' => $watched ]
593 echo $linkRenderer->makeKnownLink(
594 SpecialPage::getTitleFor( 'Whatlinkshere', $title ),
595 $skin->msg( 'whatlinkshere' )->plain(),
597 'class' => 'dropdown-item',
598 'title' => Linker::titleAttrib( 't-whatlinkshere', 'withaccess' ),
599 'accesskey' => Linker::accesskey( 't-whatlinkshere' )
602 echo $linkRenderer->makeKnownLink(
603 $title,
604 $skin->msg( 'liberty-info' )->plain(),
606 'class' => 'dropdown-item',
607 'title' => $skin->msg( 'liberty-tooltip-info' )->plain(),
609 [ 'action' => 'info' ]
611 if ( $permissionManager->quickUserCan( 'move', $user, $title ) && $title->exists() ) {
612 echo $linkRenderer->makeKnownLink(
613 SpecialPage::getTitleFor( 'Movepage', $title ),
614 $skin->msg( 'move' )->plain(),
616 'class' => 'dropdown-item',
617 'title' => Linker::titleAttrib( 'ca-move', 'withaccess' ),
618 'accesskey' => Linker::accesskey( 'ca-move' )
622 if ( $permissionManager->quickUserCan( 'protect', $user, $title ) ) { ?>
623 <div class="dropdown-divider"></div>
624 <?php
625 // different labels depending on whether the page is or isn't protected
626 $protectionMsg = $title->isProtected() ? 'unprotect' : 'protect';
627 echo $linkRenderer->makeKnownLink(
628 $title,
629 $skin->msg( $protectionMsg )->plain(),
631 'class' => 'dropdown-item',
632 'title' => Linker::titleAttrib( 'ca-' . $protectionMsg, 'withaccess' ),
633 'accesskey' => Linker::accesskey( 'ca-' . $protectionMsg )
635 [ 'action' => 'protect' ]
636 ); ?>
637 <?php } ?>
638 <?php if ( $permissionManager->quickUserCan( 'delete', $user, $title ) && $title->exists() ) {
640 <div class="dropdown-divider"></div>
641 <?php echo $linkRenderer->makeKnownLink(
642 $title,
643 $skin->msg( 'delete' )->plain(),
645 'class' => 'dropdown-item',
646 'title' => Linker::titleAttrib( 'ca-delete', 'withaccess' ),
647 'accesskey' => Linker::accesskey( 'ca-delete' )
649 [ 'action' => 'delete' ]
650 ); ?>
651 <?php } ?>
652 </div>
653 </div>
654 </div>
655 <?php
660 * Footer function, build footer.
662 protected function footer() {
663 foreach ( $this->getFooterLinks() as $category => $links ) { ?>
664 <ul class="footer-<?php echo $category; ?>">
665 <?php foreach ( $links as $link ) { ?>
666 <li class="footer-<?php echo $category; ?>-<?php echo $link; ?>">
667 <?php $this->html( $link ); ?>
668 </li>
669 <?php } ?>
670 </ul>
671 <?php
673 $footericons = $this->get( 'footericons' );
674 if ( count( $footericons ) ) {
676 <ul class="footer-icons">
677 <?php
678 foreach ( $footericons as $blockName => $footerIcons ) {
680 <li class="footer-<?php echo htmlspecialchars( $blockName ); ?>ico">
681 <?php
682 foreach ( $footerIcons as $icon ) {
683 echo $this->getSkin()->makeFooterIcon( $icon );
686 </li>
687 <?php
690 <li class="designedbylibre">
691 <a href="//librewiki.net">
692 <?php // @codingStandardsIgnoreLine
694 <img src="<?php echo $this->getSkin()->getConfig()->get( 'StylePath' ); //phpcs:ignore
695 ?>/Liberty/img/designedbylibre.png" style="height:31px" alt="Designed by Librewiki">
696 </a>
697 </li>
698 </ul>
699 <?php
704 * Get Notification function, build notification menu.
706 protected function getNotification() {
707 $personalTools = $this->getPersonalTools();
708 if (
709 isset( $personalTools['notifications-alert'] ) &&
710 $personalTools['notifications-alert']['links'][0]['data']['counter-num']
712 echo $this->makeListItem( 'notifications-alert', $personalTools['notifications-alert'] );
714 if (
715 isset( $personalTools['notifications-notice'] ) &&
716 $personalTools['notifications-notice']['links'][0]['data']['counter-num']
718 echo $this->makeListItem( 'notifications-notice', $personalTools['notifications-notice'] );
723 * Render Portal function, build top menu contents.
725 * @param array $contents Menu data that will made by parseNavbar function.
727 protected function renderPortal( $contents ) {
728 $skin = $this->getSkin();
729 $user = $skin->getUser();
730 $userGroup = $user->getGroups();
731 $userRights = MediaWikiServices::getInstance()->getPermissionManager()->getUserPermissions( $user );
733 foreach ( $contents as $content ) {
734 if ( !$content ) {
735 break;
737 if ( ( $content['right'] && !in_array( $content['right'], $userRights ) ) ||
738 ( $content['group'] && !in_array( $content['group'], $userGroup ) )
740 continue;
743 echo Html::openElement( 'li', [
744 'class' => [ 'dropdown', 'nav-item' ]
745 ] );
747 array_push( $content['classes'], 'nav-link' );
749 if ( is_array( $content['children'] ) && count( $content['children'] ) > 1 ) {
750 array_push( $content['classes'], 'dropdown-toggle', 'dropdown-toggle-fix' );
753 echo Html::openElement( 'a', [
754 'class' => $content['classes'],
755 'data-toggle' => is_array( $content['children'] ) &&
756 count( $content['children'] ) > 1 ? 'dropdown' : '',
757 'role' => 'button',
758 'aria-haspopup' => 'true',
759 'aria-expanded' => 'true',
760 'title' => $content['title'],
761 'href' => $content['href']
762 ] );
764 if ( isset( $content['icon'] ) ) {
765 echo Html::rawElement( 'span', [
766 'class' => 'fa fa-' . $content['icon']
767 ] );
770 if ( isset( $content['text'] ) ) {
771 echo Html::rawElement( 'span', [
772 'class' => 'hide-title'
773 ], $content['text'] );
776 echo Html::closeElement( 'a' );
778 if ( is_array( $content['children'] ) && count( $content['children'] ) ) {
779 echo Html::openElement( 'div', [
780 'class' => 'dropdown-menu',
781 'role' => 'menu'
782 ] );
784 foreach ( $content['children'] as $child ) {
785 if ( ( $child['right'] && !in_array( $child['right'], $userRights ) ) ||
786 ( $child['group'] && !in_array( $child['group'], $userGroup ) )
788 continue;
790 array_push( $child['classes'], 'dropdown-item' );
792 if ( is_array( $child['children'] ) ) {
793 array_push( $child['classes'], 'dropdown-toggle', 'dropdown-toggle-sub' );
796 echo Html::openElement( 'a', [
797 'accesskey' => $child['access'],
798 'class' => $child['classes'],
799 'href' => $child['href'],
800 'title' => $child['title']
801 ] );
803 if ( isset( $child['icon'] ) ) {
804 echo Html::rawElement( 'span', [
805 'class' => 'fa fa-' . $child['icon']
806 ] );
809 if ( isset( $child['text'] ) ) {
810 echo $child['text'];
813 echo Html::closeElement( 'a' );
815 if (
816 is_array( $content['children'] ) &&
817 count( $content['children'] ) > 2 &&
818 !empty( $child['children'] )
820 echo Html::openElement( 'div', [
821 'class' => 'dropdown-menu dropdown-submenu',
822 'role' => 'menu'
823 ] );
825 foreach ( $child['children'] as $sub ) {
826 if ( ( $sub['right'] && !in_array( $sub['right'], $userRights ) ) ||
827 ( $sub['group'] && !in_array( $sub['group'], $userGroup ) )
829 continue;
831 array_push( $sub['classes'], 'dropdown-item' );
833 echo Html::openElement( 'a', [
834 'accesskey' => $sub['access'],
835 'class' => $sub['classes'],
836 'href' => $sub['href'],
837 'title' => $sub['title']
838 ] );
840 if ( isset( $sub['icon'] ) ) {
841 echo Html::rawElement( 'span', [
842 'class' => 'fa fa-' . $sub['icon']
843 ] );
846 if ( isset( $sub['text'] ) ) {
847 echo $sub['text'];
850 echo Html::closeElement( 'a' );
853 echo Html::closeElement( 'div' );
857 echo Html::closeElement( 'div' );
860 echo Html::closeElement( 'li' );
865 * Parse [[MediaWiki:Liberty-Navbar]].
867 * Its format is:
868 * * <icon name>|Name of the menu displayed to the user
869 * ** link target|Link title (can be the name of an interface message)
871 * @return array Menu data
873 protected function parseNavbar() {
874 global $wgArticlePath;
876 $headings = [];
877 $currentHeading = null;
878 $userName = $this->getSkin()->getUser()->getName();
879 $userLang = $this->getSkin()->getLanguage()->mCode;
880 $globalData = ContentHandler::getContentText( WikiPage::factory(
881 Title::newFromText( 'Liberty-Navbar', NS_MEDIAWIKI )
882 )->getContent( RevisionRecord::RAW ) );
883 $globalLangData = ContentHandler::getContentText( WikiPage::factory(
884 Title::newFromText( 'Liberty-Navbar/' . $userLang, NS_MEDIAWIKI )
885 )->getContent( RevisionRecord::RAW ) );
886 $userData = ContentHandler::getContentText( WikiPage::factory(
887 Title::newFromText( $userName . '/Liberty-Navbar', NS_USER )
888 )->getContent( RevisionRecord::RAW ) );
889 if ( !empty( $userData ) ) {
890 $data = $userData;
891 } elseif ( !empty( $globalLangData ) ) {
892 $data = $globalLangData;
893 } else {
894 $data = $globalData;
896 // Well, [[MediaWiki:Liberty-Navbar]] *should* have some content, but
897 // if it doesn't, bail out here so that we don't trigger E_NOTICEs
898 // about undefined indexes later on
899 if ( empty( $data ) ) {
900 return $headings;
903 $lines = explode( "\n", $data );
905 $types = [ 'icon', 'display', 'title', 'link', 'access', 'class' ];
907 foreach ( $lines as $line ) {
908 $line = rtrim( $line, "\r" );
909 if ( $line[0] !== '*' ) {
910 // Line does not start with '*'
911 continue;
913 if ( $line[1] !== '*' ) {
914 // First level menu
915 $data = [];
916 $split = explode( '|', $line );
917 $split[0] = substr( $split[0], 1 );
918 foreach ( $split as $key => $value ) {
919 $valueArr = explode( '=', trim( $value ) );
920 if ( isset( $valueArr[1] ) ) {
921 $data[$valueArr[0]] = $valueArr[1];
922 } else {
923 $data[$types[$key]] = trim( $value );
927 // Icon
928 $icon = isset( $data['icon'] ) ? htmlentities( $data['icon'], ENT_QUOTES, 'UTF-8' ) : null;
930 // Group
931 $group = isset( $data['group'] ) ? htmlentities( $data['group'], ENT_QUOTES, 'UTF-8' ) : null;
933 // Right
934 $right = isset( $data['right'] ) ? htmlentities( $data['right'], ENT_QUOTES, 'UTF-8' ) : null;
936 // support the usual [[MediaWiki:Sidebar]] syntax of
937 // ** link target|<some MW: message name> and if the
938 // thing on the right side of the pipe isn't the name of a MW:
939 // message, then and _only_ then render it as-is
940 if ( isset( $data['display'] ) ) {
941 $textObj = wfMessage( $data['display'] );
942 if ( $textObj->isDisabled() ) {
943 $text = htmlentities( $data['display'], ENT_QUOTES, 'UTF-8' );
944 } else {
945 $text = $textObj->text();
947 } else {
948 $text = "";
951 // If icon and text both empty
952 if ( empty( $icon ) && empty( $text ) ) {
953 continue;
956 // Title
957 if ( isset( $data['title'] ) ) {
958 $titleObj = wfMessage( $data['title'] );
959 if ( $titleObj->isDisabled() ) {
960 $title = htmlentities( $data['title'], ENT_QUOTES, 'UTF-8' );
961 } else {
962 $title = $titleObj->text();
964 } else {
965 $title = $text;
968 // Link href
969 if ( isset( $data['link'] ) ) {
970 // @todo CHECKME: Should this use wfUrlProtocols() or somesuch instead?
971 if ( preg_match( '/^((?:(?:http(?:s)?)?:)?\/\/(?:.{4,}))$/i', $data['link'] ) ) {
972 $href = htmlentities( $data['link'], ENT_QUOTES, 'UTF-8' );
973 } else {
974 $href = str_replace( '%3A', ':', urlencode( $data['link'] ) );
975 $href = str_replace( '$1', $href, $wgArticlePath );
977 } else {
978 $href = null;
981 if ( isset( $data['access'] ) ) {
982 // Access
983 $access = preg_match( '/^([0-9a-z]{1})$/i', $data['access'] ) ? $data['access'] : '';
984 } else {
985 $access = null;
988 if ( isset( $data['class'] ) ) {
989 // Classes
990 $classes = explode( ',', htmlentities( $data['class'], ENT_QUOTES, 'UTF-8' ) );
991 foreach ( $classes as $key => $value ) {
992 $classes[$key] = trim( $value );
994 } else {
995 $classes = [];
998 $item = [
999 'access' => $access,
1000 'classes' => $classes,
1001 'href' => $href,
1002 'icon' => $icon,
1003 'text' => $text,
1004 'title' => $title,
1005 'group' => $group,
1006 'right' => $right
1008 $level2Children = &$item['children'];
1009 $headings[] = $item;
1010 continue;
1012 if ( $line[2] !== '*' ) {
1013 // Second level menu
1014 $data = [];
1015 $split = explode( '|', $line );
1016 $split[0] = substr( $split[0], 2 );
1017 foreach ( $split as $key => $value ) {
1018 $valueArr = explode( '=', trim( $value ) );
1019 if ( isset( $valueArr[1] ) ) {
1020 $data[$valueArr[0]] = $valueArr[1];
1021 } else {
1022 $data[$types[$key]] = trim( $value );
1026 // Icon
1027 $icon = isset( $data['icon'] ) ? htmlentities( $data['icon'], ENT_QUOTES, 'UTF-8' ) : null;
1029 // Group
1030 $group = isset( $data['group'] ) ? htmlentities( $data['group'], ENT_QUOTES, 'UTF-8' ) : null;
1032 // Right
1033 $right = isset( $data['right'] ) ? htmlentities( $data['right'], ENT_QUOTES, 'UTF-8' ) : null;
1035 // support the usual [[MediaWiki:Sidebar]] syntax of
1036 // ** link target|<some MW: message name> and if the
1037 // thing on the right side of the pipe isn't the name of a MW:
1038 // message, then and _only_ then render it as-is
1039 if ( isset( $data['display'] ) ) {
1040 $textObj = wfMessage( $data['display'] );
1041 if ( $textObj->isDisabled() ) {
1042 $text = htmlentities( $data['display'], ENT_QUOTES, 'UTF-8' );
1043 } else {
1044 $text = $textObj->text();
1046 } else {
1047 $text = "";
1050 // If icon and text both empty
1051 if ( empty( $icon ) && empty( $text ) ) {
1052 continue;
1055 // Title
1056 if ( isset( $data['title'] ) ) {
1057 $titleObj = wfMessage( $data['title'] );
1058 if ( $titleObj->isDisabled() ) {
1059 $title = htmlentities( $data['title'], ENT_QUOTES, 'UTF-8' );
1060 } else {
1061 $title = $titleObj->text();
1063 } else {
1064 $title = $text;
1067 if ( isset( $data['link'] ) ) {
1068 // Link href
1069 // @todo CHECKME: Should this use wfUrlProtocols() or somesuch instead?
1070 if ( preg_match( '/^((?:(?:http(?:s)?)?:)?\/\/(?:.{4,}))$/i', $data['link'] ) ) {
1071 $href = htmlentities( $data['link'], ENT_QUOTES, 'UTF-8' );
1072 } else {
1073 $href = str_replace( '%3A', ':', urlencode( $data['link'] ) );
1074 $href = str_replace( '$1', $href, $wgArticlePath );
1078 if ( isset( $data['access'] ) ) {
1079 // Access
1080 $access = preg_match( '/^([0-9a-z]{1})$/i', $data['access'] ) ? $data['access'] : '';
1081 } else {
1082 $access = null;
1085 if ( isset( $data['class'] ) ) {
1086 // Classes
1087 $classes = explode( ',', htmlentities( $data['class'], ENT_QUOTES, 'UTF-8' ) );
1088 foreach ( $classes as $key => $value ) {
1089 $classes[$key] = trim( $value );
1091 } else {
1092 $classes = [];
1095 $item = [
1096 'access' => $access,
1097 'classes' => $classes,
1098 'href' => $href,
1099 'icon' => $icon,
1100 'text' => $text,
1101 'title' => $title,
1102 'group' => $group,
1103 'right' => $right
1105 $level3Children = &$item['children'];
1106 $level2Children[] = $item;
1107 continue;
1109 if ( $line[3] !== '*' ) {
1110 // Third level menu
1111 $data = [];
1112 $split = explode( '|', $line );
1113 $split[0] = substr( $split[0], 3 );
1114 foreach ( $split as $key => $value ) {
1115 $valueArr = explode( '=', trim( $value ) );
1116 if ( isset( $valueArr[1] ) ) {
1117 $data[$valueArr[0]] = $valueArr[1];
1118 } else {
1119 $data[$types[$key]] = trim( $value );
1123 // Icon
1124 $icon = isset( $data['icon'] ) ? htmlentities( $data['icon'], ENT_QUOTES, 'UTF-8' ) : null;
1126 // Group
1127 $group = isset( $data['group'] ) ? htmlentities( $data['group'], ENT_QUOTES, 'UTF-8' ) : null;
1129 // Right
1130 $right = isset( $data['right'] ) ? htmlentities( $data['right'], ENT_QUOTES, 'UTF-8' ) : null;
1132 // support the usual [[MediaWiki:Sidebar]] syntax of
1133 // ** link target|<some MW: message name> and if the
1134 // thing on the right side of the pipe isn't the name of a MW:
1135 // message, then and _only_ then render it as-is
1136 if ( isset( $data['display'] ) ) {
1137 $textObj = wfMessage( $data['display'] );
1138 if ( $textObj->isDisabled() ) {
1139 $text = htmlentities( $data['display'], ENT_QUOTES, 'UTF-8' );
1140 } else {
1141 $text = $textObj->text();
1143 } else {
1144 $text = "";
1147 // If icon and text both empty
1148 if ( empty( $icon ) && empty( $text ) ) {
1149 continue;
1152 // Title
1153 if ( isset( $data['title'] ) ) {
1154 $titleObj = wfMessage( $data['title'] );
1155 if ( $titleObj->isDisabled() ) {
1156 $title = htmlentities( $data['title'], ENT_QUOTES, 'UTF-8' );
1157 } else {
1158 $title = $titleObj->text();
1160 } else {
1161 $title = $text;
1164 // Link href
1165 // @todo CHECKME: Should this use wfUrlProtocols() or somesuch instead?
1166 if ( preg_match( '/^((?:(?:http(?:s)?)?:)?\/\/(?:.{4,}))$/i', $data['link'] ) ) {
1167 $href = htmlentities( $data['link'], ENT_QUOTES, 'UTF-8' );
1168 } else {
1169 $href = str_replace( '%3A', ':', urlencode( $data['link'] ) );
1170 $href = str_replace( '$1', $href, $wgArticlePath );
1173 // Access
1174 if ( isset( $data['access'] ) ) {
1175 $access = preg_match( '/^([0-9a-z]{1})$/i', $data['access'] ) ? $data['access'] : '';
1176 } else {
1177 $access = null;
1180 if ( isset( $data['class'] ) ) {
1181 // Classes
1182 $classes = explode( ',', htmlentities( $data['class'], ENT_QUOTES, 'UTF-8' ) );
1183 foreach ( $classes as $key => $value ) {
1184 $classes[$key] = trim( $value );
1186 } else {
1187 $classes = [];
1190 $item = [
1191 'access' => $access,
1192 'classes' => $classes,
1193 'href' => $href,
1194 'icon' => $icon,
1195 'text' => $text,
1196 'title' => $title,
1197 'group' => $group,
1198 'right' => $right
1200 $level3Children[] = $item;
1201 continue;
1202 } else {
1203 // Not supported
1204 continue;
1208 return $headings;
1212 * Build an AdSense ad unit wrapped in a div tag.
1214 * @param string $position Ad position
1216 protected function buildAd( $position ) {
1217 global $wgLibertyAdSetting;
1219 $adFormat = 'auto';
1220 $fullWidthResponsive = 'true';
1221 if ( $position === 'header' ) {
1222 $adFormat = 'horizontal';
1223 $fullWidthResponsive = 'false';
1226 <div class="<?php echo $position; ?>-ads">
1227 <ins class="adsbygoogle"
1228 data-full-width-responsive="<?php echo $fullWidthResponsive; ?>"
1229 data-ad-client="<?php echo $wgLibertyAdSetting['client']; ?>"
1230 data-ad-slot="<?php echo $wgLibertyAdSetting[$position]; ?>"
1231 data-ad-format="<?php echo $adFormat; ?>">
1232 </ins>
1233 </div>
1234 <?php