CologneBlue rewrite: fix beforeContent() and afterContent()
[lhc/web/wiklou.git] / skins / CologneBlue.php
1 <?php
2 /**
3 * Cologne Blue: A nicer-looking alternative to Standard.
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 * http://www.gnu.org/copyleft/gpl.html
19 *
20 * @todo document
21 * @file
22 * @ingroup Skins
23 */
24
25 if( !defined( 'MEDIAWIKI' ) ) {
26 die( -1 );
27 }
28
29 /**
30 * @todo document
31 * @ingroup Skins
32 */
33 class SkinCologneBlue extends SkinTemplate {
34 var $skinname = 'cologneblue', $stylename = 'cologneblue',
35 $template = 'CologneBlueTemplate';
36 var $useHeadElement = true;
37
38 /**
39 * @param $out OutputPage
40 */
41 function setupSkinUserCss( OutputPage $out ){
42 $out->addModuleStyles( 'mediawiki.legacy.shared' );
43 $out->addModuleStyles( 'mediawiki.legacy.oldshared' );
44 $out->addModuleStyles( 'skins.cologneblue' );
45 }
46
47 }
48
49 class CologneBlueTemplate extends BaseTemplate {
50 function execute() {
51 $this->html( 'headelement' );
52 echo $this->beforeContent();
53 $this->html( 'bodytext' );
54 echo "\n";
55 echo $this->afterContent();
56 $this->html( 'dataAfterContent' );
57 $this->printTrail();
58 echo "\n</body></html>";
59 }
60
61
62 /**
63 * Language/charset variant links for classic-style skins
64 * @return string
65 */
66 function variantLinks() {
67 $s = '';
68
69 /* show links to different language variants */
70 global $wgDisableLangConversion, $wgLang;
71
72 $title = $this->getSkin()->getTitle();
73 $lang = $title->getPageLanguage();
74 $variants = $lang->getVariants();
75
76 if ( !$wgDisableLangConversion && sizeof( $variants ) > 1
77 && !$title->isSpecialPage() ) {
78 foreach ( $variants as $code ) {
79 $varname = $lang->getVariantname( $code );
80
81 if ( $varname == 'disable' ) {
82 continue;
83 }
84 $s = $wgLang->pipeList( array(
85 $s,
86 '<a href="' . htmlspecialchars( $title->getLocalURL( 'variant=' . $code ) ) . '" lang="' . $code . '" hreflang="' . $code . '">' . htmlspecialchars( $varname ) . '</a>'
87 ) );
88 }
89 }
90
91 return $s;
92 }
93
94 function otherLanguages() {
95 global $wgOut, $wgLang, $wgHideInterlanguageLinks;
96
97 if ( $wgHideInterlanguageLinks ) {
98 return '';
99 }
100
101 $a = $wgOut->getLanguageLinks();
102
103 if ( 0 == count( $a ) ) {
104 return '';
105 }
106
107 $s = wfMessage( 'otherlanguages' )->text() . wfMessage( 'colon-separator' )->text();
108 $first = true;
109
110 if ( $wgLang->isRTL() ) {
111 $s .= '<span dir="ltr">';
112 }
113
114 foreach ( $a as $l ) {
115 if ( !$first ) {
116 $s .= wfMessage( 'pipe-separator' )->escaped();
117 }
118
119 $first = false;
120
121 $nt = Title::newFromText( $l );
122 $text = Language::fetchLanguageName( $nt->getInterwiki() );
123
124 $s .= Html::element( 'a',
125 array( 'href' => $nt->getFullURL(), 'title' => $nt->getText(), 'class' => "external" ),
126 $text == '' ? $l : $text );
127 }
128
129 if ( $wgLang->isRTL() ) {
130 $s .= '</span>';
131 }
132
133 return $s;
134 }
135
136 // @fixed
137 function pageTitleLinks() {
138 global $wgLang;
139
140 $s = array();
141 $footlinks = $this->getFooterLinks();
142
143 foreach ( $footlinks['places'] as $item ) {
144 $s[] = $this->data[$item];
145 }
146
147 return $wgLang->pipeList( $s );
148 }
149
150 function bottomLinks() {
151 global $wgOut, $wgUser;
152 $sep = wfMessage( 'pipe-separator' )->escaped() . "\n";
153
154 $s = '';
155 if ( $wgOut->isArticleRelated() ) {
156 $element[] = '<strong>' . $this->editThisPage() . '</strong>';
157
158 if ( $wgUser->isLoggedIn() ) {
159 $element[] = $this->watchThisPage();
160 }
161
162 $element[] = $this->talkLink();
163 $element[] = $this->historyLink();
164 $element[] = $this->whatLinksHere();
165 $element[] = $this->watchPageLinksLink();
166
167 $title = $this->getSkin()->getTitle();
168
169 if (
170 $title->getNamespace() == NS_USER ||
171 $title->getNamespace() == NS_USER_TALK
172 ) {
173 $id = User::idFromName( $title->getText() );
174 $ip = User::isIP( $title->getText() );
175
176 # Both anons and non-anons have contributions list
177 if ( $id || $ip ) {
178 $element[] = $this->userContribsLink();
179 }
180
181 if ( $this->getSkin()->showEmailUser( $id ) ) {
182 $element[] = $this->emailUserLink();
183 }
184 }
185
186 $s = implode( $element, $sep );
187
188 if ( $title->getArticleID() ) {
189 $s .= "\n<br />";
190
191 // Delete/protect/move links for privileged users
192 if ( $wgUser->isAllowed( 'delete' ) ) {
193 $s .= $this->deleteThisPage();
194 }
195
196 if ( $wgUser->isAllowed( 'protect' ) ) {
197 $s .= $sep . $this->protectThisPage();
198 }
199
200 if ( $wgUser->isAllowed( 'move' ) ) {
201 $s .= $sep . $this->moveThisPage();
202 }
203 }
204
205 $s .= "<br />\n" . $this->otherLanguages();
206 }
207
208 return $s;
209 }
210
211 function editThisPage() {
212 global $wgOut;
213
214 if ( !$wgOut->isArticleRelated() ) {
215 $s = wfMessage( 'protectedpage' )->text();
216 } else {
217 $title = $this->getSkin()->getTitle();
218 if ( $title->quickUserCan( 'edit' ) && $title->exists() ) {
219 $t = wfMessage( 'editthispage' )->text();
220 } elseif ( $title->quickUserCan( 'create' ) && !$title->exists() ) {
221 $t = wfMessage( 'create-this-page' )->text();
222 } else {
223 $t = wfMessage( 'viewsource' )->text();
224 }
225
226 $s = Linker::linkKnown(
227 $title,
228 $t,
229 array(),
230 $this->getSkin()->editUrlOptions()
231 );
232 }
233
234 return $s;
235 }
236
237 function deleteThisPage() {
238 global $wgUser, $wgRequest;
239
240 $diff = $wgRequest->getVal( 'diff' );
241 $title = $this->getSkin()->getTitle();
242
243 if ( $title->getArticleID() && ( !$diff ) && $wgUser->isAllowed( 'delete' ) ) {
244 $t = wfMessage( 'deletethispage' )->text();
245
246 $s = Linker::linkKnown(
247 $title,
248 $t,
249 array(),
250 array( 'action' => 'delete' )
251 );
252 } else {
253 $s = '';
254 }
255
256 return $s;
257 }
258
259 function protectThisPage() {
260 global $wgUser, $wgRequest;
261
262 $diff = $wgRequest->getVal( 'diff' );
263 $title = $this->getSkin()->getTitle();
264
265 if ( $title->getArticleID() && ( ! $diff ) && $wgUser->isAllowed( 'protect' ) ) {
266 if ( $title->isProtected() ) {
267 $text = wfMessage( 'unprotectthispage' )->text();
268 $query = array( 'action' => 'unprotect' );
269 } else {
270 $text = wfMessage( 'protectthispage' )->text();
271 $query = array( 'action' => 'protect' );
272 }
273
274 $s = Linker::linkKnown(
275 $title,
276 $text,
277 array(),
278 $query
279 );
280 } else {
281 $s = '';
282 }
283
284 return $s;
285 }
286
287 function watchThisPage() {
288 global $wgOut, $wgUser;
289
290 // Cache
291 $title = $this->getSkin()->getTitle();
292
293 if ( $wgOut->isArticleRelated() ) {
294 if ( $wgUser->isWatched( $title ) ) {
295 $text = wfMessage( 'unwatchthispage' )->text();
296 $query = array(
297 'action' => 'unwatch',
298 'token' => UnwatchAction::getUnwatchToken( $title, $wgUser ),
299 );
300 $id = 'mw-unwatch-link';
301 } else {
302 $text = wfMessage( 'watchthispage' )->text();
303 $query = array(
304 'action' => 'watch',
305 'token' => WatchAction::getWatchToken( $title, $wgUser ),
306 );
307 $id = 'mw-watch-link';
308 }
309
310 $s = Linker::linkKnown(
311 $title,
312 $text,
313 array( 'id' => $id ),
314 $query
315 );
316 } else {
317 $s = wfMessage( 'notanarticle' )->text();
318 }
319
320 return $s;
321 }
322
323 function moveThisPage() {
324 if ( $this->getSkin()->getTitle()->quickUserCan( 'move' ) ) {
325 return Linker::linkKnown(
326 SpecialPage::getTitleFor( 'Movepage' ),
327 wfMessage( 'movethispage' )->text(),
328 array(),
329 array( 'target' => $this->getSkin()->getTitle()->getPrefixedDBkey() )
330 );
331 } else {
332 // no message if page is protected - would be redundant
333 return '';
334 }
335 }
336
337 function historyLink() {
338 return Linker::link(
339 $this->getSkin()->getTitle(),
340 wfMessage( 'history' )->escaped(),
341 array( 'rel' => 'archives' ),
342 array( 'action' => 'history' )
343 );
344 }
345
346 function whatLinksHere() {
347 return Linker::linkKnown(
348 SpecialPage::getTitleFor( 'Whatlinkshere', $this->getSkin()->getTitle()->getPrefixedDBkey() ),
349 wfMessage( 'whatlinkshere' )->escaped()
350 );
351 }
352
353 function userContribsLink() {
354 return Linker::linkKnown(
355 SpecialPage::getTitleFor( 'Contributions', $this->getSkin()->getTitle()->getDBkey() ),
356 wfMessage( 'contributions' )->escaped()
357 );
358 }
359
360 function emailUserLink() {
361 return Linker::linkKnown(
362 SpecialPage::getTitleFor( 'Emailuser', $this->getSkin()->getTitle()->getDBkey() ),
363 wfMessage( 'emailuser' )->escaped()
364 );
365 }
366
367 function watchPageLinksLink() {
368 global $wgOut;
369
370 if ( !$wgOut->isArticleRelated() ) {
371 return wfMessage( 'parentheses', wfMessage( 'notanarticle' )->text() )->escaped();
372 } else {
373 return Linker::linkKnown(
374 SpecialPage::getTitleFor( 'Recentchangeslinked', $this->getSkin()->getTitle()->getPrefixedDBkey() ),
375 wfMessage( 'recentchangeslinked-toolbox' )->escaped()
376 );
377 }
378 }
379
380 function talkLink() {
381 $title = $this->getSkin()->getTitle();
382 if ( NS_SPECIAL == $title->getNamespace() ) {
383 # No discussion links for special pages
384 return '';
385 }
386
387 $linkOptions = array();
388
389 if ( $title->isTalkPage() ) {
390 $link = $title->getSubjectPage();
391 switch( $link->getNamespace() ) {
392 case NS_MAIN:
393 $text = wfMessage( 'articlepage' );
394 break;
395 case NS_USER:
396 $text = wfMessage( 'userpage' );
397 break;
398 case NS_PROJECT:
399 $text = wfMessage( 'projectpage' );
400 break;
401 case NS_FILE:
402 $text = wfMessage( 'imagepage' );
403 # Make link known if image exists, even if the desc. page doesn't.
404 if ( wfFindFile( $link ) )
405 $linkOptions[] = 'known';
406 break;
407 case NS_MEDIAWIKI:
408 $text = wfMessage( 'mediawikipage' );
409 break;
410 case NS_TEMPLATE:
411 $text = wfMessage( 'templatepage' );
412 break;
413 case NS_HELP:
414 $text = wfMessage( 'viewhelppage' );
415 break;
416 case NS_CATEGORY:
417 $text = wfMessage( 'categorypage' );
418 break;
419 default:
420 $text = wfMessage( 'articlepage' );
421 }
422 } else {
423 $link = $title->getTalkPage();
424 $text = wfMessage( 'talkpage' );
425 }
426
427 $s = Linker::link( $link, $text->text(), array(), array(), $linkOptions );
428
429 return $s;
430 }
431
432 /**
433 * @return string
434 *
435 * @fixed
436 */
437 function beforeContent() {
438 ob_start();
439 ?>
440 <div id="content">
441 <div id="topbar">
442 <p id="sitetitle">
443 <a href="<?php echo htmlspecialchars( $this->data['nav_urls']['mainpage']['href'] ) ?>">
444 <?php echo wfMessage( 'sitetitle' )->escaped() ?>
445 </a>
446 </p>
447 <p id="sitesub"><?php echo wfMessage( 'sitesubtitle' )->escaped() ?></p>
448
449 <p id="toplinks">
450 <span id="syslinks"><?php echo $this->sysLinks() ?></span>
451 <span id="variantlinks"><?php echo $this->variantLinks() ?></span>
452 </p>
453 <div id="linkcollection">
454 <div id="langlinks"><?php echo str_replace( '<br />', '', $this->otherLanguages() ) ?></div>
455 <?php echo $this->getSkin()->getCategories() ?>
456 <div id="titlelinks"><?php echo $this->pageTitleLinks() ?></div>
457 <?php if ( $this->data['newtalk'] ) { ?>
458 <div class="usermessage"><strong><?php echo $this->data['newtalk'] ?></strong></div>
459 <?php } ?>
460 </div>
461 </div>
462 <div id="article">
463 <?php if ( $this->getSkin()->getSiteNotice() ) { ?>
464 <div id="siteNotice"><?php echo $this->getSkin()->getSiteNotice() ?></div>
465 <?php } ?>
466 <h1 id="firstHeading"><span dir="auto"><?php echo $this->data['title'] ?></span></h1>
467 <?php if ( $this->translator->translate( 'tagline' ) ) { ?>
468 <p class="tagline"><?php echo htmlspecialchars( $this->translator->translate( 'tagline' ) ) ?></p>
469 <?php } ?>
470 <?php if ( $this->getSkin()->getOutput()->getSubtitle() ) { ?>
471 <p class="subtitle"><?php echo $this->getSkin()->getOutput()->getSubtitle() ?></p>
472 <?php } ?>
473 <?php if ( $this->getSkin()->subPageSubtitle() ) { ?>
474 <p class="subpages"><?php echo $this->getSkin()->subPageSubtitle() ?></p>
475 <?php } ?>
476 <?php
477 $s = ob_get_contents();
478 ob_end_clean();
479
480 return $s;
481 }
482
483 /**
484 * @return string
485 *
486 * @fixed
487 */
488 function afterContent() {
489 ob_start();
490 ?>
491 </div>
492 <div id='footer'>
493 <?php
494 // Page-related links
495 echo $this->bottomLinks();
496 echo "\n<br />";
497
498 // Footer and second searchbox
499 echo $this->getSkin()->getLanguage()->pipeList( array(
500 $this->getSkin()->mainPageLink(),
501 $this->getSkin()->aboutLink(),
502 $this->searchForm( 'footer' )
503 ) );
504 echo "\n<br />";
505
506 // Standard footer info
507 $footlinks = $this->getFooterLinks();
508 if ( $footlinks['info'] ) {
509 foreach ( $footlinks['info'] as $item ) {
510 echo $this->data[$item] . ' ';
511 }
512 }
513 ?>
514 </div>
515 </div>
516 <?php echo $this->quickBar() ?>
517 <?php
518 $s = ob_get_contents();
519 ob_end_clean();
520
521 return $s;
522 }
523
524 /**
525 * @return string
526 *
527 * @fixed
528 */
529 function sysLinks() {
530 $s = array(
531 $this->getSkin()->mainPageLink(),
532 Linker::linkKnown(
533 Title::newFromText( wfMessage( 'aboutpage' )->inContentLanguage()->text() ),
534 wfMessage( 'about' )->text()
535 ),
536 Linker::linkKnown(
537 Title::newFromText( wfMessage( 'helppage' )->inContentLanguage()->text() ),
538 wfMessage( 'help' )->text()
539 ),
540 Linker::linkKnown(
541 Title::newFromText( wfMessage( 'faqpage' )->inContentLanguage()->text() ),
542 wfMessage( 'faq' )->text()
543 ),
544 );
545
546 $personalUrls = $this->data['personal_urls'];
547 if ( $this->data['loggedin'] ) {
548 $s[] = $this->makeLink( 'logout', $personalUrls['logout'] );
549 } else {
550 if ( $personalUrls['createaccount'] ) { // Controlled by $wgUseCombinedLoginLink
551 $s[] = $this->makeLink( 'createaccount', $personalUrls['createaccount'] );
552 }
553 if ( $personalUrls['login'] ) {
554 $s[] = $this->makeLink( 'login', $personalUrls['login'] );
555 }
556 if ( $personalUrls['anonlogin'] ) {
557 $s[] = $this->makeLink( 'anonlogin', $personalUrls['anonlogin'] );
558 }
559 }
560
561 return $this->getSkin()->getLanguage()->pipeList( $s );
562 }
563
564
565
566
567 /**
568 * @param $heading string
569 * @return string
570 *
571 * @fixed
572 */
573 function menuHead( $heading ) {
574 return "\n<h6>" . htmlspecialchars( $heading ) . "</h6>";
575 }
576
577 /**
578 * Compute the sidebar
579 * @access private
580 *
581 * @return string
582 *
583 * @fixed
584 */
585 function quickBar(){
586 $s = "\n<div id='quickbar'>";
587
588 $sep = "<br />\n";
589
590 $plain_bar = $this->data['sidebar'];
591 $bar = array();
592
593 // Massage the sidebar
594 // We want to place SEARCH at the beginning and a lot of stuff before TOOLBOX (or at the end, if it's missing)
595 $additions_done = false;
596 while ( !$additions_done ) {
597 $bar = array(); // Empty it out
598
599 // Always display search on top
600 $bar['SEARCH'] = true;
601
602 foreach ( $plain_bar as $heading => $links ) {
603 if ( $heading == 'TOOLBOX' ) {
604 if( $links !== NULL ) {
605 // If this is not a toolbox prosthetic we inserted outselves, fill it out
606 $plain_bar['TOOLBOX'] = $this->getToolbox();
607 }
608
609 // And insert the stuff
610
611 // "This page" and "Edit" menus
612 // We need to do some massaging here... we reuse all of the items, except for $...['views']['view'],
613 // as $...['namespaces']['main'] and $...['namespaces']['talk'] together serve the same purpose.
614 // We also don't use $...['variants'], these are displayed in the top menu.
615 $content_navigation = $this->data['content_navigation'];
616 $qbpageoptions = array_merge(
617 $content_navigation['namespaces'],
618 array(
619 'history' => $content_navigation['views']['history'],
620 'watch' => $content_navigation['actions']['watch'],
621 'unwatch' => $content_navigation['actions']['unwatch'],
622 )
623 );
624 $content_navigation['actions']['watch'] = null;
625 $content_navigation['actions']['unwatch'] = null;
626 $qbedit = array_merge(
627 array(
628 'edit' => $content_navigation['views']['edit'],
629 'addsection' => $content_navigation['views']['addsection'],
630 ),
631 $content_navigation['actions']
632 );
633 $bar['qbedit'] = $qbedit;
634 $bar['qbpageoptions'] = $qbpageoptions;
635
636 // Personal tools ("My pages")
637 $bar['qbmyoptions'] = $this->getPersonalTools();
638 $bar['qbmyoptions']['login'] = false;
639 $bar['qbmyoptions']['anonlogin'] = false;
640 $bar['qbmyoptions']['logout'] = false;
641 $bar['qbmyoptions']['createaccount'] = false;
642
643 $additions_done = true;
644 }
645
646 // Re-insert current heading, unless it's SEARCH
647 if ( $heading != 'SEARCH' ) {
648 $bar[$heading] = $plain_bar[$heading];
649 }
650 }
651
652 // If TOOLBOX is missing, $additions_done is still false
653 if ( !$additions_done ) {
654 $plain_bar['TOOLBOX'] = false;
655 }
656 }
657
658 foreach ( $bar as $heading => $links ) {
659 if ( $heading == 'SEARCH' ) {
660 $s .= $this->menuHead( wfMessage( 'qbfind' )->text() );
661 $s .= $this->searchForm( 'sidebar' );
662 } elseif ( $heading == 'LANGUAGES' ) {
663 // discard these; we display languages below page content
664 } else {
665 if ( $links ) {
666 // Use the navigation heading from standard sidebar as the "browse" section
667 if ( $heading == 'navigation' ) {
668 $heading = 'qbbrowse';
669 }
670 if ( $heading == 'TOOLBOX' ) {
671 $heading = 'toolbox';
672 }
673
674 $headingMsg = wfMessage( $heading );
675 $any_link = false;
676 $t = $this->menuHead( $headingMsg->exists() ? $headingMsg->text() : $heading );
677
678 foreach ( $links as $key => $link ) {
679 // Can be empty due to rampant sidebar massaging we're doing above
680 if ( $link ) {
681 $any_link = true;
682 $t .= $this->makeListItem( $key, $link, array( 'tag' => 'span' ) ) . $sep;
683 }
684 }
685
686 if ( $any_link ) {
687 $s .= $t;
688 }
689 }
690 }
691 }
692
693 $s .= $sep . "\n</div>\n";
694 return $s;
695 }
696
697 /**
698 * @param $label string
699 * @return string
700 *
701 * @fixed
702 */
703 function searchForm( $which ) {
704 global $wgUseTwoButtonsSearchForm;
705
706 $search = $this->getSkin()->getRequest()->getText( 'search' );
707 $action = $this->data['searchaction'];
708 $s = "<form id=\"searchform-" . htmlspecialchars($which) . "\" method=\"get\" class=\"inline\" action=\"$action\">";
709 if( $which == 'footer' ) {
710 $s .= wfMessage( 'qbfind' )->text() . ": ";
711 }
712
713 $s .= "<input type='text' class=\"mw-searchInput\" name=\"search\" size=\"14\" value=\""
714 . htmlspecialchars( substr( $search, 0, 256 ) ) . "\" />"
715 . ($which == 'footer' ? " " : "<br />")
716 . "<input type='submit' class=\"searchButton\" name=\"go\" value=\"" . wfMessage( 'searcharticle' )->escaped() . "\" />";
717
718 if( $wgUseTwoButtonsSearchForm ) {
719 $s .= " <input type='submit' class=\"searchButton\" name=\"fulltext\" value=\"" . wfMessage( 'search' )->escaped() . "\" />\n";
720 } else {
721 $s .= '<div><a href="' . $action . '" rel="search">' . wfMessage( 'powersearch-legend' )->escaped() . "</a></div>\n";
722 }
723
724 $s .= '</form>';
725
726 return $s;
727 }
728 }