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