a0b704b2d9b1cf66e9192e84d8a20ce3af670272
[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;
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 = $this->getSkin()->getLanguage()->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 $wgHideInterlanguageLinks;
96
97 if ( $wgHideInterlanguageLinks ) {
98 return '';
99 }
100
101 $a = $this->getSkin()->getOutput()->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 ( $this->getSkin()->getLanguage()->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 ( $this->getSkin()->getLanguage()->isRTL() ) {
130 $s .= '</span>';
131 }
132
133 return $s;
134 }
135
136 // @fixed
137 function pageTitleLinks() {
138 $s = array();
139 $footlinks = $this->getFooterLinks();
140
141 foreach ( $footlinks['places'] as $item ) {
142 $s[] = $this->data[$item];
143 }
144
145 return $this->getSkin()->getLanguage()->pipeList( $s );
146 }
147
148 function bottomLinks() {
149 $sep = wfMessage( 'pipe-separator' )->escaped() . "\n";
150
151 $s = '';
152 if ( $this->getSkin()->getOutput()->isArticleRelated() ) {
153 $element[] = '<strong>' . $this->editThisPage() . '</strong>';
154
155 if ( $this->getSkin()->getUser()->isLoggedIn() ) {
156 $element[] = $this->watchThisPage();
157 }
158
159 $element[] = $this->talkLink();
160 $element[] = $this->historyLink();
161 $element[] = $this->whatLinksHere();
162 $element[] = $this->watchPageLinksLink();
163
164 $title = $this->getSkin()->getTitle();
165
166 if (
167 $title->getNamespace() == NS_USER ||
168 $title->getNamespace() == NS_USER_TALK
169 ) {
170 $id = User::idFromName( $title->getText() );
171 $ip = User::isIP( $title->getText() );
172
173 # Both anons and non-anons have contributions list
174 if ( $id || $ip ) {
175 $element[] = $this->userContribsLink();
176 }
177
178 if ( $this->getSkin()->showEmailUser( $id ) ) {
179 $element[] = $this->emailUserLink();
180 }
181 }
182
183 $s = implode( $element, $sep );
184
185 if ( $title->getArticleID() ) {
186 $s .= "\n<br />";
187
188 // Delete/protect/move links for privileged users
189 if ( $this->getSkin()->getUser()->isAllowed( 'delete' ) ) {
190 $s .= $this->deleteThisPage();
191 }
192
193 if ( $this->getSkin()->getUser()->isAllowed( 'protect' ) ) {
194 $s .= $sep . $this->protectThisPage();
195 }
196
197 if ( $this->getSkin()->getUser()->isAllowed( 'move' ) ) {
198 $s .= $sep . $this->moveThisPage();
199 }
200 }
201
202 $s .= "<br />\n" . $this->otherLanguages();
203 }
204
205 return $s;
206 }
207
208 function editThisPage() {
209 if ( !$this->getSkin()->getOutput()->isArticleRelated() ) {
210 $s = wfMessage( 'protectedpage' )->text();
211 } else {
212 $title = $this->getSkin()->getTitle();
213 if ( $title->quickUserCan( 'edit' ) && $title->exists() ) {
214 $t = wfMessage( 'editthispage' )->text();
215 } elseif ( $title->quickUserCan( 'create' ) && !$title->exists() ) {
216 $t = wfMessage( 'create-this-page' )->text();
217 } else {
218 $t = wfMessage( 'viewsource' )->text();
219 }
220
221 $s = Linker::linkKnown(
222 $title,
223 $t,
224 array(),
225 $this->getSkin()->editUrlOptions()
226 );
227 }
228
229 return $s;
230 }
231
232 function deleteThisPage() {
233 $diff = $this->getSkin()->getRequest()->getVal( 'diff' );
234 $title = $this->getSkin()->getTitle();
235
236 if ( $title->getArticleID() && ( !$diff ) && $this->getSkin()->getUser()->isAllowed( 'delete' ) ) {
237 $t = wfMessage( 'deletethispage' )->text();
238
239 $s = Linker::linkKnown(
240 $title,
241 $t,
242 array(),
243 array( 'action' => 'delete' )
244 );
245 } else {
246 $s = '';
247 }
248
249 return $s;
250 }
251
252 function protectThisPage() {
253 $diff = $this->getSkin()->getRequest()->getVal( 'diff' );
254 $title = $this->getSkin()->getTitle();
255
256 if ( $title->getArticleID() && ( ! $diff ) && $this->getSkin()->getUser()->isAllowed( 'protect' ) ) {
257 if ( $title->isProtected() ) {
258 $text = wfMessage( 'unprotectthispage' )->text();
259 $query = array( 'action' => 'unprotect' );
260 } else {
261 $text = wfMessage( 'protectthispage' )->text();
262 $query = array( 'action' => 'protect' );
263 }
264
265 $s = Linker::linkKnown(
266 $title,
267 $text,
268 array(),
269 $query
270 );
271 } else {
272 $s = '';
273 }
274
275 return $s;
276 }
277
278 function watchThisPage() {
279 // Cache
280 $title = $this->getSkin()->getTitle();
281
282 if ( $this->getSkin()->getOutput()->isArticleRelated() ) {
283 if ( $this->getSkin()->getUser()->isWatched( $title ) ) {
284 $text = wfMessage( 'unwatchthispage' )->text();
285 $query = array(
286 'action' => 'unwatch',
287 'token' => UnwatchAction::getUnwatchToken( $title, $this->getSkin()->getUser() ),
288 );
289 $id = 'mw-unwatch-link';
290 } else {
291 $text = wfMessage( 'watchthispage' )->text();
292 $query = array(
293 'action' => 'watch',
294 'token' => WatchAction::getWatchToken( $title, $this->getSkin()->getUser() ),
295 );
296 $id = 'mw-watch-link';
297 }
298
299 $s = Linker::linkKnown(
300 $title,
301 $text,
302 array( 'id' => $id ),
303 $query
304 );
305 } else {
306 $s = wfMessage( 'notanarticle' )->text();
307 }
308
309 return $s;
310 }
311
312 function moveThisPage() {
313 if ( $this->getSkin()->getTitle()->quickUserCan( 'move' ) ) {
314 return Linker::linkKnown(
315 SpecialPage::getTitleFor( 'Movepage' ),
316 wfMessage( 'movethispage' )->text(),
317 array(),
318 array( 'target' => $this->getSkin()->getTitle()->getPrefixedDBkey() )
319 );
320 } else {
321 // no message if page is protected - would be redundant
322 return '';
323 }
324 }
325
326 function historyLink() {
327 return Linker::link(
328 $this->getSkin()->getTitle(),
329 wfMessage( 'history' )->escaped(),
330 array( 'rel' => 'archives' ),
331 array( 'action' => 'history' )
332 );
333 }
334
335 function whatLinksHere() {
336 return Linker::linkKnown(
337 SpecialPage::getTitleFor( 'Whatlinkshere', $this->getSkin()->getTitle()->getPrefixedDBkey() ),
338 wfMessage( 'whatlinkshere' )->escaped()
339 );
340 }
341
342 function userContribsLink() {
343 return Linker::linkKnown(
344 SpecialPage::getTitleFor( 'Contributions', $this->getSkin()->getTitle()->getDBkey() ),
345 wfMessage( 'contributions' )->escaped()
346 );
347 }
348
349 function emailUserLink() {
350 return Linker::linkKnown(
351 SpecialPage::getTitleFor( 'Emailuser', $this->getSkin()->getTitle()->getDBkey() ),
352 wfMessage( 'emailuser' )->escaped()
353 );
354 }
355
356 function watchPageLinksLink() {
357 if ( !$this->getSkin()->getOutput()->isArticleRelated() ) {
358 return wfMessage( 'parentheses', wfMessage( 'notanarticle' )->text() )->escaped();
359 } else {
360 return Linker::linkKnown(
361 SpecialPage::getTitleFor( 'Recentchangeslinked', $this->getSkin()->getTitle()->getPrefixedDBkey() ),
362 wfMessage( 'recentchangeslinked-toolbox' )->escaped()
363 );
364 }
365 }
366
367 function talkLink() {
368 $title = $this->getSkin()->getTitle();
369 if ( NS_SPECIAL == $title->getNamespace() ) {
370 # No discussion links for special pages
371 return '';
372 }
373
374 $linkOptions = array();
375
376 if ( $title->isTalkPage() ) {
377 $link = $title->getSubjectPage();
378 switch( $link->getNamespace() ) {
379 case NS_MAIN:
380 $text = wfMessage( 'articlepage' );
381 break;
382 case NS_USER:
383 $text = wfMessage( 'userpage' );
384 break;
385 case NS_PROJECT:
386 $text = wfMessage( 'projectpage' );
387 break;
388 case NS_FILE:
389 $text = wfMessage( 'imagepage' );
390 # Make link known if image exists, even if the desc. page doesn't.
391 if ( wfFindFile( $link ) )
392 $linkOptions[] = 'known';
393 break;
394 case NS_MEDIAWIKI:
395 $text = wfMessage( 'mediawikipage' );
396 break;
397 case NS_TEMPLATE:
398 $text = wfMessage( 'templatepage' );
399 break;
400 case NS_HELP:
401 $text = wfMessage( 'viewhelppage' );
402 break;
403 case NS_CATEGORY:
404 $text = wfMessage( 'categorypage' );
405 break;
406 default:
407 $text = wfMessage( 'articlepage' );
408 }
409 } else {
410 $link = $title->getTalkPage();
411 $text = wfMessage( 'talkpage' );
412 }
413
414 $s = Linker::link( $link, $text->text(), array(), array(), $linkOptions );
415
416 return $s;
417 }
418
419 /**
420 * @return string
421 *
422 * @fixed
423 */
424 function beforeContent() {
425 ob_start();
426 ?>
427 <div id="content">
428 <div id="topbar">
429 <p id="sitetitle">
430 <a href="<?php echo htmlspecialchars( $this->data['nav_urls']['mainpage']['href'] ) ?>">
431 <?php echo wfMessage( 'sitetitle' )->escaped() ?>
432 </a>
433 </p>
434 <p id="sitesub"><?php echo wfMessage( 'sitesubtitle' )->escaped() ?></p>
435
436 <p id="toplinks">
437 <span id="syslinks"><?php echo $this->sysLinks() ?></span>
438 <span id="variantlinks"><?php echo $this->variantLinks() ?></span>
439 </p>
440 <div id="linkcollection">
441 <div id="langlinks"><?php echo str_replace( '<br />', '', $this->otherLanguages() ) ?></div>
442 <?php echo $this->getSkin()->getCategories() ?>
443 <div id="titlelinks"><?php echo $this->pageTitleLinks() ?></div>
444 <?php if ( $this->data['newtalk'] ) { ?>
445 <div class="usermessage"><strong><?php echo $this->data['newtalk'] ?></strong></div>
446 <?php } ?>
447 </div>
448 </div>
449 <div id="article">
450 <?php if ( $this->getSkin()->getSiteNotice() ) { ?>
451 <div id="siteNotice"><?php echo $this->getSkin()->getSiteNotice() ?></div>
452 <?php } ?>
453 <h1 id="firstHeading"><span dir="auto"><?php echo $this->data['title'] ?></span></h1>
454 <?php if ( $this->translator->translate( 'tagline' ) ) { ?>
455 <p class="tagline"><?php echo htmlspecialchars( $this->translator->translate( 'tagline' ) ) ?></p>
456 <?php } ?>
457 <?php if ( $this->getSkin()->getOutput()->getSubtitle() ) { ?>
458 <p class="subtitle"><?php echo $this->getSkin()->getOutput()->getSubtitle() ?></p>
459 <?php } ?>
460 <?php if ( $this->getSkin()->subPageSubtitle() ) { ?>
461 <p class="subpages"><?php echo $this->getSkin()->subPageSubtitle() ?></p>
462 <?php } ?>
463 <?php
464 $s = ob_get_contents();
465 ob_end_clean();
466
467 return $s;
468 }
469
470 /**
471 * @return string
472 *
473 * @fixed
474 */
475 function afterContent() {
476 ob_start();
477 ?>
478 </div>
479 <div id='footer'>
480 <?php
481 // Page-related links
482 echo $this->bottomLinks();
483 echo "\n<br />";
484
485 // Footer and second searchbox
486 echo $this->getSkin()->getLanguage()->pipeList( array(
487 $this->getSkin()->mainPageLink(),
488 $this->getSkin()->aboutLink(),
489 $this->searchForm( 'footer' )
490 ) );
491 echo "\n<br />";
492
493 // Standard footer info
494 $footlinks = $this->getFooterLinks();
495 if ( $footlinks['info'] ) {
496 foreach ( $footlinks['info'] as $item ) {
497 echo $this->data[$item] . ' ';
498 }
499 }
500 ?>
501 </div>
502 </div>
503 <?php echo $this->quickBar() ?>
504 <?php
505 $s = ob_get_contents();
506 ob_end_clean();
507
508 return $s;
509 }
510
511 /**
512 * @return string
513 *
514 * @fixed
515 */
516 function sysLinks() {
517 $s = array(
518 $this->getSkin()->mainPageLink(),
519 Linker::linkKnown(
520 Title::newFromText( wfMessage( 'aboutpage' )->inContentLanguage()->text() ),
521 wfMessage( 'about' )->text()
522 ),
523 Linker::linkKnown(
524 Title::newFromText( wfMessage( 'helppage' )->inContentLanguage()->text() ),
525 wfMessage( 'help' )->text()
526 ),
527 Linker::linkKnown(
528 Title::newFromText( wfMessage( 'faqpage' )->inContentLanguage()->text() ),
529 wfMessage( 'faq' )->text()
530 ),
531 );
532
533 $personalUrls = $this->data['personal_urls'];
534 if ( $this->data['loggedin'] ) {
535 $s[] = $this->makeLink( 'logout', $personalUrls['logout'] );
536 } else {
537 if ( $personalUrls['createaccount'] ) { // Controlled by $wgUseCombinedLoginLink
538 $s[] = $this->makeLink( 'createaccount', $personalUrls['createaccount'] );
539 }
540 if ( $personalUrls['login'] ) {
541 $s[] = $this->makeLink( 'login', $personalUrls['login'] );
542 }
543 if ( $personalUrls['anonlogin'] ) {
544 $s[] = $this->makeLink( 'anonlogin', $personalUrls['anonlogin'] );
545 }
546 }
547
548 return $this->getSkin()->getLanguage()->pipeList( $s );
549 }
550
551
552
553
554 /**
555 * @param $heading string
556 * @return string
557 *
558 * @fixed
559 */
560 function menuHead( $heading ) {
561 return "\n<h6>" . htmlspecialchars( $heading ) . "</h6>";
562 }
563
564 /**
565 * Compute the sidebar
566 * @access private
567 *
568 * @return string
569 *
570 * @fixed
571 */
572 function quickBar(){
573 $s = "\n<div id='quickbar'>";
574
575 $sep = "<br />\n";
576
577 $plain_bar = $this->data['sidebar'];
578 $bar = array();
579
580 // Massage the sidebar
581 // We want to place SEARCH at the beginning and a lot of stuff before TOOLBOX (or at the end, if it's missing)
582 $additions_done = false;
583 while ( !$additions_done ) {
584 $bar = array(); // Empty it out
585
586 // Always display search on top
587 $bar['SEARCH'] = true;
588
589 foreach ( $plain_bar as $heading => $links ) {
590 if ( $heading == 'TOOLBOX' ) {
591 if( $links !== NULL ) {
592 // If this is not a toolbox prosthetic we inserted outselves, fill it out
593 $plain_bar['TOOLBOX'] = $this->getToolbox();
594 }
595
596 // And insert the stuff
597
598 // "This page" and "Edit" menus
599 // We need to do some massaging here... we reuse all of the items, except for $...['views']['view'],
600 // as $...['namespaces']['main'] and $...['namespaces']['talk'] together serve the same purpose.
601 // We also don't use $...['variants'], these are displayed in the top menu.
602 $content_navigation = $this->data['content_navigation'];
603 $qbpageoptions = array_merge(
604 $content_navigation['namespaces'],
605 array(
606 'history' => $content_navigation['views']['history'],
607 'watch' => $content_navigation['actions']['watch'],
608 'unwatch' => $content_navigation['actions']['unwatch'],
609 )
610 );
611 $content_navigation['actions']['watch'] = null;
612 $content_navigation['actions']['unwatch'] = null;
613 $qbedit = array_merge(
614 array(
615 'edit' => $content_navigation['views']['edit'],
616 'addsection' => $content_navigation['views']['addsection'],
617 ),
618 $content_navigation['actions']
619 );
620 $bar['qbedit'] = $qbedit;
621 $bar['qbpageoptions'] = $qbpageoptions;
622
623 // Personal tools ("My pages")
624 $bar['qbmyoptions'] = $this->getPersonalTools();
625 $bar['qbmyoptions']['login'] = false;
626 $bar['qbmyoptions']['anonlogin'] = false;
627 $bar['qbmyoptions']['logout'] = false;
628 $bar['qbmyoptions']['createaccount'] = false;
629
630 $additions_done = true;
631 }
632
633 // Re-insert current heading, unless it's SEARCH
634 if ( $heading != 'SEARCH' ) {
635 $bar[$heading] = $plain_bar[$heading];
636 }
637 }
638
639 // If TOOLBOX is missing, $additions_done is still false
640 if ( !$additions_done ) {
641 $plain_bar['TOOLBOX'] = false;
642 }
643 }
644
645 foreach ( $bar as $heading => $links ) {
646 if ( $heading == 'SEARCH' ) {
647 $s .= $this->menuHead( wfMessage( 'qbfind' )->text() );
648 $s .= $this->searchForm( 'sidebar' );
649 } elseif ( $heading == 'LANGUAGES' ) {
650 // discard these; we display languages below page content
651 } else {
652 if ( $links ) {
653 // Use the navigation heading from standard sidebar as the "browse" section
654 if ( $heading == 'navigation' ) {
655 $heading = 'qbbrowse';
656 }
657 if ( $heading == 'TOOLBOX' ) {
658 $heading = 'toolbox';
659 }
660
661 $headingMsg = wfMessage( $heading );
662 $any_link = false;
663 $t = $this->menuHead( $headingMsg->exists() ? $headingMsg->text() : $heading );
664
665 foreach ( $links as $key => $link ) {
666 // Can be empty due to rampant sidebar massaging we're doing above
667 if ( $link ) {
668 $any_link = true;
669 $t .= $this->makeListItem( $key, $link, array( 'tag' => 'span' ) ) . $sep;
670 }
671 }
672
673 if ( $any_link ) {
674 $s .= $t;
675 }
676 }
677 }
678 }
679
680 $s .= $sep . "\n</div>\n";
681 return $s;
682 }
683
684 /**
685 * @param $label string
686 * @return string
687 *
688 * @fixed
689 */
690 function searchForm( $which ) {
691 global $wgUseTwoButtonsSearchForm;
692
693 $search = $this->getSkin()->getRequest()->getText( 'search' );
694 $action = $this->data['searchaction'];
695 $s = "<form id=\"searchform-" . htmlspecialchars($which) . "\" method=\"get\" class=\"inline\" action=\"$action\">";
696 if( $which == 'footer' ) {
697 $s .= wfMessage( 'qbfind' )->text() . ": ";
698 }
699
700 $s .= "<input type='text' class=\"mw-searchInput\" name=\"search\" size=\"14\" value=\""
701 . htmlspecialchars( substr( $search, 0, 256 ) ) . "\" />"
702 . ($which == 'footer' ? " " : "<br />")
703 . "<input type='submit' class=\"searchButton\" name=\"go\" value=\"" . wfMessage( 'searcharticle' )->escaped() . "\" />";
704
705 if( $wgUseTwoButtonsSearchForm ) {
706 $s .= " <input type='submit' class=\"searchButton\" name=\"fulltext\" value=\"" . wfMessage( 'search' )->escaped() . "\" />\n";
707 } else {
708 $s .= '<div><a href="' . $action . '" rel="search">' . wfMessage( 'powersearch-legend' )->escaped() . "</a></div>\n";
709 }
710
711 $s .= '</form>';
712
713 return $s;
714 }
715 }